| | |
| | | jmd_encode_yuv = env->GetMethodID(clazz,"encodeYUV","([B)V"); |
| | | jmd_encode_pcm = env->GetMethodID(clazz,"encodePCM","([B)V"); |
| | | jmd_get_sps_pps = env->GetMethodID(clazz,"getSpsPpsData","()[B"); |
| | | jmd_get_audio_seq = env->GetMethodID(clazz,"getAudioSeqData","()[B"); |
| | | } |
| | | |
| | | void MediaEncoderCall::encodeYUV(uint8_t* yuvBuffer, int width, int height) { |
| | |
| | | } |
| | | |
| | | void MediaEncoderCall::getSpsPps(uint8_t **data,int *length){ |
| | | getJvmBytes(jmd_get_sps_pps,data,length); |
| | | } |
| | | |
| | | void MediaEncoderCall::getAudioSeqData(uint8_t **data,int *length){ |
| | | getJvmBytes(jmd_get_audio_seq,data,length); |
| | | } |
| | | |
| | | void MediaEncoderCall::getJvmBytes(jmethodID method,uint8_t **data,int *length){ |
| | | JNIEnv *env_child; |
| | | javaVM->AttachCurrentThread(&env_child, 0); |
| | | jbyteArray bytes = reinterpret_cast<jbyteArray> (env_child->CallObjectMethod(instance, jmd_get_sps_pps)); |
| | | jbyteArray bytes = reinterpret_cast<jbyteArray> (env_child->CallObjectMethod(instance, method)); |
| | | if (!bytes) { |
| | | LOGE("Java returned null byte array"); |
| | | return; |
| | |
| | | void init(JNIEnv *env_); |
| | | void encodePCM(uint8_t* pcmBuffer, int width, int height); |
| | | void getSpsPps(uint8_t **data,int *length); |
| | | void getAudioSeqData(uint8_t **data,int *length); |
| | | |
| | | |
| | | private: |
| | | JavaVM *javaVM; |
| | | JNIEnv *env = 0; |
| | | jobject instance; |
| | | jmethodID jmd_get_sps_pps; |
| | | jmethodID jmd_get_sps_pps,jmd_get_audio_seq; |
| | | jmethodID jmd_encode_yuv,jmd_encode_pcm; |
| | | |
| | | void getJvmBytes(jmethodID method,uint8_t **data,int *length); |
| | | |
| | | }; |
| | | |
| | | #endif //LIVEPROJECT_MEDIA_ENCODER_CALL_H |
| | |
| | | } |
| | | |
| | | void LivePusher::sendAudioHeader() { |
| | | uint8_t *packet = new uint8_t[2]; |
| | | packet[0] = 0x12; |
| | | packet[1] = 0x8; |
| | | pushAAC(packet,2,RTMP_GetTime() - start_time); |
| | | free(packet); |
| | | |
| | | uint8_t *data;int size; |
| | | mediaEncoderCall->getAudioSeqData(&data,&size); |
| | | if(size == 0){ |
| | | data = new uint8_t[2]; |
| | | data[0] = 0x12; |
| | | data[1] = 0x08; |
| | | } |
| | | pushAAC(data,2,RTMP_GetTime() - start_time); |
| | | free(data); |
| | | } |
| | | |
| | | void LivePusher::pushAAC(uint8_t *data, int size, uint32_t time) { |
| | | //LOGE("sendFrame pushAAC 0x%02X 0x%02X 0x%02X 0x%02X %d",data[0],aacData[1],aacData[2],aacData[3],size); |
| | | //LOGE("sendFrame pushAAC 0x%02X 0x%02X 0x%02X 0x%02X %d",data[0],data[1],data[2],data[3],size); |
| | | |
| | | if(isLive != 1){ |
| | | return; |
| | |
| | | output[offset++] = 0xAF; // SoundFormat: AAC, SoundRate: 44.1kHz, SoundSize: 16-bit, SoundType: Stereo |
| | | output[offset++] = data[0] == 0x12 ? 0x00:0x01; //aac raw data |
| | | |
| | | //flv VideoTagBody --raw aac data |
| | | memcpy(output + offset, data, size); // data + AAC_ADTS_HEADER_SIZE -> data, |
| | | // (adts_len - AAC_ADTS_HEADER_SIZE) -> size |
| | | |
| | | memcpy(output + offset, data, size); // data + AAC_ADTS_HEADER_SIZE -> data, |
| | | // (adts_len - AAC_ADTS_HEADER_SIZE) -> size |
| | | |
| | | //previous tag size |
| | | addFooter(output,offset += size,body_len + FLV_TAG_HEAD_LEN); |
| | |
| | | var mediaCodec264 : MediaCodec; |
| | | var mediaCodecAAC : MediaCodec; |
| | | var spsPpsBytes:ByteArray? = null; |
| | | var audioSeqBytes:ByteArray? = null; |
| | | var startTime = 0L; |
| | | |
| | | constructor(){ |
| | |
| | | //Log.i(TAG , "encode: pusher bufferInfo.flags:${bufferInfo.flags}") |
| | | // 通过 JNI 将 H.264 数据发送到 C++ |
| | | if ((bufferInfo.flags and MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) { |
| | | /*parseSpsPps(outputBuffer , bufferInfo.size) |
| | | // 发送 SPS 和 PPS 到 Native |
| | | native_sent_sps_pps(sps!! , pps!!)*/ |
| | | |
| | | spsPpsBytes = ByteArray(bufferInfo.size) |
| | | outputBuffer.get(spsPpsBytes) |
| | | //Log.i(TAG , "encode: pusher BUFFER_FLAG_CODEC_CONFIG:${bufferInfo.size}") |
| | |
| | | |
| | | val bufferInfo = MediaCodec.BufferInfo() |
| | | var outputBufferIndex = mediaCodecAAC.dequeueOutputBuffer(bufferInfo , 10000) |
| | | /*if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { |
| | | val mediaFormat : MediaFormat = mediaCodecAAC.getOutputFormat() |
| | | var seqBuffer = mediaFormat.getByteBuffer("csd-0") |
| | | val seqBytes = ByteArray(seqBuffer!!.remaining()) |
| | | seqBuffer.get(seqBytes, 0, seqBytes.size) |
| | | seqBuffer.clear() |
| | | Log.i(TAG , "initEncoderFLV: spspps: ${spsBytes.size} ${ppsBytes.size}") |
| | | }*/ |
| | | //Log.i(TAG , "encodePCM: pusher outputBufferIndex:${outputBufferIndex} ${bufferInfo.flags}") |
| | | if (outputBufferIndex >= 0) { |
| | | val outputBuffer : ByteBuffer = mediaCodecAAC.getOutputBuffer(outputBufferIndex) !! |
| | | /*val aacData = ByteArray(bufferInfo.size + 7) // ADTS 头 + AAC 数据 |
| | | addADTSToPacket(aacData , bufferInfo.size + 7) |
| | | outputBuffer[aacData , 7 , bufferInfo.size] // 复制 AAC 数据*/ |
| | | val aacData = ByteArray(bufferInfo.size ) |
| | | outputBuffer[aacData] |
| | | if(bufferInfo.flags != 0){ |
| | | audioSeqBytes = ByteArray(bufferInfo.size ) |
| | | outputBuffer[audioSeqBytes] |
| | | }else{ |
| | | /*val aacData = ByteArray(bufferInfo.size + 7) // ADTS 头 + AAC 数据 |
| | | addADTSToPacket(aacData , bufferInfo.size + 7) |
| | | outputBuffer[aacData , 7 , bufferInfo.size] // 复制 AAC 数据*/ |
| | | val aacData = ByteArray(bufferInfo.size ) |
| | | outputBuffer[aacData] |
| | | // 这里可以通过 JNI 传给 C++ |
| | | native_send_aac(aacData,time - startTime) |
| | | } |
| | | outputBuffer.clear() |
| | | // 这里可以通过 JNI 传给 C++ |
| | | native_send_aac(aacData,time - startTime) |
| | | mediaCodecAAC.releaseOutputBuffer(outputBufferIndex , false) |
| | | } |
| | | } |
| | |
| | | return spsPpsBytes!!; |
| | | } |
| | | |
| | | fun getAudioSeqData():ByteArray{ |
| | | audioSeqBytes?.let { |
| | | return it; |
| | | }; |
| | | return ByteArray(0); |
| | | } |
| | | |
| | | private fun addADTSToPacket(packet : ByteArray , packetLen : Int) { |
| | | val profile = 2 // AAC LC |
| | | val freqIdx = 4 // 44100Hz |