Runt
2025-04-04 49be01c8fd58a15b16012dc528673343ff7d73b9
优化
4 files modified
79 ■■■■ changed files
app/src/main/cpp/media_encoder_call.cpp 11 ●●●●● patch | view | raw | blame | history
app/src/main/cpp/media_encoder_call.h 5 ●●●● patch | view | raw | blame | history
app/src/main/cpp/pusher/live_pusher.cpp 23 ●●●●● patch | view | raw | blame | history
app/src/main/java/com/runt/live/media/EncodeHelper.kt 40 ●●●● patch | view | raw | blame | history
app/src/main/cpp/media_encoder_call.cpp
@@ -28,6 +28,7 @@
    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) {
@@ -62,9 +63,17 @@
}
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;
app/src/main/cpp/media_encoder_call.h
@@ -17,15 +17,18 @@
    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
app/src/main/cpp/pusher/live_pusher.cpp
@@ -192,15 +192,20 @@
}
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;
@@ -224,10 +229,8 @@
    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);
app/src/main/java/com/runt/live/media/EncodeHelper.kt
@@ -22,6 +22,7 @@
    var mediaCodec264 : MediaCodec;
    var mediaCodecAAC : MediaCodec;
    var spsPpsBytes:ByteArray? = null;
    var audioSeqBytes:ByteArray? = null;
    var startTime = 0L;
    constructor(){
@@ -143,10 +144,6 @@
                    //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}")
@@ -182,16 +179,30 @@
            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)
            }
        }
@@ -209,6 +220,13 @@
        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