zoukankan      html  css  js  c++  java
  • Android使用FFMpeg生成pcm格式音频,并利用AudioTrack播放出来

    一、场景

       1.可任意选择一个媒体文件(avi、mp4、ts、mp3),解析除媒体文件的音频,并保存为pcm,然后利用AudioTrack播放pcm。

       2.主要类介绍Java文件:

          a.PcmDecoder.java 用于和jni通讯的java类,里面定义了三个方法,初始化:init、解码:decode、销毁:destroy

          b.UserAudioTrackPlayPCMActivity.java类,用于选择媒体文件,初始化编码器以及播放音频pcm文件

          c.AudioTrackPlayer.java 用于播放pcm文件

      3.主要C++文件:

          a.pcm_decoder.cpp 其中的方法和PcmDecoder.java文件功能对应,用于java调用jni

          b.pcm_deocder_controller.cpp pcm解码器封装类

          c.pcm_real_decoder.cpp 具体的初始化以及解码类

      4.代码框架图:

        

        5.其实大体上就分两部分:第一部分是解码部分,将媒体文件解码为pcm。第二部分是播放,利用AudioTrack播放器播放解码出PCM文件。注意,解码出的pcm是裸数据由于没有给pcm裸数据增加头,所以一般的播放器是播放不出来的。所以要用AudioTrack进行验证。

    二、代码演示

      1.UserAudioTrackPlayPCMActivity.java 

    package com.yw.ffmpeg;
    
    import android.os.Bundle;
    import android.widget.Button;
    import android.widget.TextView;
    
    import androidx.annotation.Nullable;
    
    import com.yw.ffmpeg.decoder.PcmDecoder;
    import com.yw.ffmpeg.player.AudioTrackPlayer;
    
    import java.io.File;
    
    /**
     * @ProjectName: AndroidFFMpeg
     * @Package: com.yw.ffmpeg
     * @ClassName: 使用AudioTrack播放PCM文件
     * @Description: 使用AudioTrack播放PCM文件
     * @Author: wei.yang
     * @CreateDate: 2021/8/20 10:02
     * @UpdateUser: 更新者:wei.yang
     * @UpdateDate: 2021/8/20 10:02
     * @UpdateRemark: 更新说明:
     * @Version: 1.0
     */
    public class UserAudioTrackPlayPCMActivity extends BaseActivity {
        //选择文件
        private Button btnChoiceVideo;
        //选择文件的路径
        private TextView tvVideoFilePath;
        //生成pcm文件
        private Button btnGeneratePCM;
        //生成的pcm路径
        private TextView tvPcmPath;
        //使用AudioTrack播放pcm裸数据
        private Button btnUseAudioTrackPaly;
        private PcmDecoder pcmDecoder;
        private String orgPath = null;
    
        /**
         * 测试步骤
         * 1.选择一个视频文件
         * 2.将视频文件和音频文件分离
         * 3.将分离后的音频文件解码并保存为PCM
         * 4.利用AudioTrack播放PCM
         *
         * @param savedInstanceState
         */
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_user_audio_track_play_pcm);
            initViews();
            pcmDecoder = new PcmDecoder();
        }
    
        private void initViews() {
            btnChoiceVideo = findViewById(R.id.btnChoiceVideo);
            btnChoiceVideo.setOnClickListener(v -> {
                choiceVideo();
            });
            tvVideoFilePath = findViewById(R.id.tvVideoFilePath);
            btnGeneratePCM = findViewById(R.id.btnGeneratePCM);
            btnGeneratePCM.setOnClickListener(v -> {
                if (pcmDecoder != null) {
                    if (orgPath != null) {
    //                    new Thread() {
    //                        @Override
    //                        public void run() {
                        try {
                            int ret = pcmDecoder.init(orgPath, "/mnt/sdcard/110119.pcm");
                            if (ret >= 0) {
                                pcmDecoder.decode();
                                pcmDecoder.destroy();
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
    //                        }
    //                    }.start();
    
    
                    }
                }
            });
            tvPcmPath = findViewById(R.id.tvPcmPath);
            btnUseAudioTrackPaly = findViewById(R.id.btnUseAudioTrackPaly);
            btnUseAudioTrackPaly.setOnClickListener(v -> {
                AudioTrackPlayer.getAudioTrackPlayer().start(new File("/mnt/sdcard/110119.pcm"));
            });
    
        }
    
        @Override
        public void videoPathCallback(String videoPath) {
            orgPath = videoPath;
        }
    
        static {
            System.loadLibrary("native-lib");
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if (pcmDecoder != null) {
                pcmDecoder.destroy();
            }
            AudioTrackPlayer.getAudioTrackPlayer().release();
        }
    
    
    
    
    
    }
    

      

      2.AudioTrackPlayer.java

    package com.yw.ffmpeg.player;
    
    import android.media.AudioFormat;
    import android.media.AudioManager;
    import android.media.AudioTrack;
    import android.net.rtp.AudioStream;
    
    import com.yw.ffmpeg.utils.LogUtil;
    
    import java.io.File;
    import java.io.FileInputStream;
    
    /**
     * @ProjectName: AndroidFFMpeg
     * @Package: com.yw.ffmpeg.player
     * @ClassName: AudioTrackPlayer
     * @Description: 使用AudioTrack播放音频文件
     * @Author: wei.yang
     * @CreateDate: 2021/8/31 10:26
     * @UpdateUser: 更新者:wei.yang
     * @UpdateDate: 2021/8/31 10:26
     * @UpdateRemark: 更新说明:
     * @Version: 1.0
     * * ps:
     *  * 1.AudioTrack是Android SDK提供的最底层的音频播放API,因此只允许输入裸数据
     *  * <p>
     *  * AudioTrack的工作流程
     *  * 1.根据音频参数信息配置出一个AudioTrack实例
     *  * 2.调用play方法将AudioTrack切换到播放状态
     *  * 3.启动播放线程,循环向AudioTrack缓冲区中写入音频数据
     *  * 4.当数据写完或者停止播放的时候,停止播放线程并释放所有资源
     *  * <p>
     *  * AudioTrack的构造函数
     *  * AudioTrack(int streamType,int sampleRateInHz,int channelConfig,int audioFormat,int bufferSizeInBytes,int mode)
     *  * 1.streamType:音频管理策略。如:在AudioManager中的STREAM_VOICE_CALL:电话声音、STREAM_SYSTEM:系统声音、STREAM_RING:铃声、STREAM_MUSIC:音乐声、STREAM_ALARM:警告声,STREAM_NOTIFICATION:通知声
     *  * 2.sampleRateInHz:采样率,即播放音频每秒钟会有多少次采样。如:8000,16000,22050、24000、44100、48000
     *  * 3.channelConfig:声道。AudioFormat中的可选值为CHANNEL_IN_MONO(单声道)。CHANNEL_IN_STEREO(立体声)
     *  * 4.audioFormat:采样格式,ENCODING_PCM_16BIT(16bit)、ENCODING_PCM_8BIT(8bit),注意,前者是可以兼容所有Android手机的。
     *  * 5.bufferSizeInBytes:AudioTrack内部的音频缓冲区的大小,通过getMinBufferSize来确定这个缓冲区的大小
     *  * 6.mode:播放模式,MODE_STATIC:需要一次性将所有的数据都写入播放缓冲区中,简单高效,通常用于播放铃声、系统提醒的音频片段、MODE_STREAM:需要按照一定的时间间隔不间断地写入音频数据,理论上它可以应用于任何音频播放的场景
     */
    public class AudioTrackPlayer {
        private static final String TAG = "AudioTrackPlayer:";
        private static final int HZ = 0xac44;
        private AudioTrack audioTrack;
    
        private AudioTrackPlayer() {
            int minBufferSize = AudioTrack.getMinBufferSize(HZ, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
            LogUtil.log(TAG + "minBufferSize:" + minBufferSize);
            audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, HZ, AudioFormat.CHANNEL_CONFIGURATION_STEREO,
                    AudioFormat.ENCODING_PCM_16BIT, minBufferSize * 2, AudioTrack.MODE_STREAM);
            audioTrack.setStereoVolume(1.0f, 1.0f);// 设置当前音量大小
            audioTrack.play();//调用play方法将AudioTrack切换到播放状态
        }
    
        private static AudioTrackPlayer instance = null;
    
        public static synchronized AudioTrackPlayer getAudioTrackPlayer() {
            if (instance == null) {
                instance = new AudioTrackPlayer();
            }
            return instance;
        }
    
        /**
         * 开始播放pcm文件
         *
         * @param pcmFile
         */
        public void start(File pcmFile) {
            new Thread() {
                @Override
                public void run() {
                    try {
                        FileInputStream fileInputStream = new FileInputStream(pcmFile);
                        fileInputStream.skip(0x2c);
                        byte buffer[] = new byte[16 * 10000];
                        while (fileInputStream.read(buffer) >= 0) {
                            System.out.println("write pcm data");
                            audioTrack.write(buffer, 0, buffer.length);
                        }
                        fileInputStream.close();
                        fileInputStream = null;
                        audioTrack.stop();
                        audioTrack.release();
                        audioTrack = null;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        }
    
        /**
         * 停止播放
         */
        public void stop() {
            if (audioTrack != null) {
                audioTrack.stop();
            }
        }
    
        /**
         * 销毁
         */
        public void release() {
            if (audioTrack != null) {
                audioTrack.stop();
                audioTrack.release();
                audioTrack = null;
            }
        }
    }
    

      

      3.PcmDecoder.java

    public class PcmDecoder {
        /**
         * 初始化解码器
         * @param mediaFilePath 原始媒体文件路径
         * @param pcmFilePath 目标pcm文件生成路径
         * @return
         */
        public native int init(String mediaFilePath,String pcmFilePath);
    
        /**
         * 开始解码
         */
        public native void decode();
    
        /**
         * 销毁解码器
         */
        public native void destroy();
    }
    

      

      4.pcm_decoder.cpp

    extern "C" {
    /**
     * 初始化
     * @param env
     * @param obj
     * @param mediaFilePath 待解码的媒体文件路径
     * @param pcmFilePath  生成pcm文件的路径
     * @return
     */
    PCMDecoderController *controller;
    JNIEXPORT jint JNICALL
    Java_com_yw_ffmpeg_decoder_PcmDecoder_init(JNIEnv *env, jobject obj, jstring mediaFilePath,
                                               jstring pcmFilePath) {
        //将jni字符串转换为c能识别的字符数组
        const char *pcmPath = env->GetStringUTFChars(pcmFilePath, NULL);
        const char *mediaPath = env->GetStringUTFChars(mediaFilePath, NULL);
        controller = new PCMDecoderController();
        controller->init(mediaPath, pcmPath);
        //销毁字符串
        env->ReleaseStringUTFChars(mediaFilePath, mediaPath);
        env->ReleaseStringUTFChars(pcmFilePath, pcmPath);
        return 0;
    }
    
    /**
     * 解码
     * @param env
     * @param obj
     */
    JNIEXPORT void JNICALL Java_com_yw_ffmpeg_decoder_PcmDecoder_decode(JNIEnv *env, jobject obj) {
        if (controller) {
            controller->decode();
        }
    }
    /**
     * 销毁
     * @param env
     * @param obj
     */
    JNIEXPORT void JNICALL Java_com_yw_ffmpeg_decoder_PcmDecoder_destroy(JNIEnv *env, jobject obj) {
        if (controller) {
            controller->destroy();
            delete controller;
            controller = NULL;
        }
    }
    }
    

      

      5.pcm_deocder_controller.cpp

    #include "pcm_decoder_controller.h"
    
    PCMDecoderController::PCMDecoderController() {
        realDecoder = NULL;
        pcmFile = NULL;
    }
    
    PCMDecoderController::~PCMDecoderController() {
    
    }
    
    void PCMDecoderController::init(const char *orgFilePath, const char *pcmFilePath) {
        //初始化decoder
        RealDecoder *tempDecoder = new RealDecoder();
        int metaData[2];
        tempDecoder->getMusicMeta(orgFilePath, metaData);
        delete tempDecoder;
        //初始化采样率
        sampleRate = metaData[0];
        int byteCountPreSec = sampleRate * 2 * 16 / 8;
        packetBufferSize = (int) ((byteCountPreSec / 2) * 0.2);
        realDecoder = new RealDecoder();
        realDecoder->init(orgFilePath, packetBufferSize);
        __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "init PCMDecoderController success");
        pcmFile = fopen(pcmFilePath, "wb+");
        __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "init pcmFile success");
    
    }
    
    void PCMDecoderController::decode() {
        __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "start decode audio data");
        while (true) {
            AudioPacket *packet = realDecoder->decodePacket();
            if (-1 == packet->size) {
                break;
            }
            __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "write buffer to file");
            fwrite(packet->buffer, sizeof(short), packet->size, pcmFile);
        }
    }
    
    void PCMDecoderController::destroy() {
        if (NULL != realDecoder) {
            realDecoder->destroy();
            delete realDecoder;
            realDecoder = NULL;
        }
        if (NULL != pcmFile) {
            fclose(pcmFile);
            pcmFile = NULL;
        }
    }
    

      

      6.pcm_real_decoder.cpp

    #include "pcm_real_decoder.h"
    
    RealDecoder::RealDecoder() {
        this->seek_seconds = 0.0f;
        this->seek_req = false;
        this->seek_resp = false;
        mediaFilePath = NULL;
    }
    
    RealDecoder::~RealDecoder() {
        if (NULL != mediaFilePath) {
            delete[] mediaFilePath;
            mediaFilePath = NULL;
        }
    
    }
    
    int RealDecoder::getMusicMeta(const char *fileString, int *metaData) {
        init(fileString);
        int sampleRate = avCodecContext->sample_rate;
        __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "%d", "sampleRate:", sampleRate);
        int bitRate = avCodecContext->bit_rate;
        __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "%d", "bitRate:", bitRate);
        destroy();
        metaData[0] = sampleRate;
        metaData[1] = bitRate;
        return 0;
    }
    
    void RealDecoder::init(const char *fileString, int packetBufferSizeParam) {
        init(fileString);
        packetBufferSize = packetBufferSizeParam;
    }
    
    int RealDecoder::init(const char *audioFile) {
        __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "init:");
        audioBuffer = NULL;
        position = -1.0f;
        audioBufferCursor = 0;
        audioBufferSize = 0;
        swrContext = NULL;
        swrBuffer = NULL;
        swrBufferSize = 0;
        seek_success_read_frame_success = true;
        isNeedFirstFrameCorrectFlag = true;
        firstFrameCorrectionInSecs = 0.0f;
        av_register_all();
        avFormatContext = avformat_alloc_context();
        //打开输入文件
        __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "Open Input File");
        if (NULL == mediaFilePath) {
            int length = strlen(audioFile);
            mediaFilePath = new char[length + 1];
            //由于最后一个是'' 所以memset的长度要设置为length+1
            //作用是在一段内存块中填充某个给定的值,它对较大的结构体或数组进行清零操作的一种最快方法。
            memset(mediaFilePath, 0, length + 1);
            memcpy(mediaFilePath, audioFile, length + 1);
        }
    
        int result = avformat_open_input(&avFormatContext, audioFile, NULL, NULL);
        if (result != 0) {
            __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "Open Input File Fail");
            return -1;
        } else {
            __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "Open Input File success");
        }
        avFormatContext->max_analyze_duration = 50000;
        //检查文件中的流信息
        result = avformat_find_stream_info(avFormatContext, NULL);
        if (result < 0) {
            __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "find stream Fail");
            return -1;
        } else {
            __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "find stream success");
        }
        stream_index = av_find_best_stream(avFormatContext, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
        if (stream_index == -1) {
            __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "find audio fail");
            return -1;
        }
        //获取音频流
        AVStream *audioStream = avFormatContext->streams[stream_index];
        if (audioStream->time_base.den && audioStream->time_base.num) {
            time_base = av_q2d(audioStream->time_base);
        } else if (audioStream->codec->time_base.den && audioStream->codec->time_base.num) {
            time_base = av_q2d(audioStream->codec->time_base);
        }
        //获取音频流解码器上下文
        avCodecContext = audioStream->codec;
        //根据加码器上下文找到解码器
        AVCodec *avCodec = avcodec_find_decoder(avCodecContext->codec_id);
        if (avCodec == NULL) {
            __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "find decode fail");
            return -1;
        } else {
            __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "find decode success");
        }
        //打开解码器
        result = avcodec_open2(avCodecContext, avCodec, NULL);
        if (result < 0) {
            __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "open decode fail");
            return -1;
        } else {
            __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "open decode success");
        }
        //判断是否需要resampler,重采样
        if (!audioCodecIsSupported()) {
            __android_log_print(ANDROID_LOG_ERROR, "RealDecoder",
                                "because of audio Codec Is Not Supported so we will init swresampler...");
            /**
              * 初始化resampler
              * @param s               Swr context, can be NULL
              * @param out_ch_layout   output channel layout (AV_CH_LAYOUT_*)
              * @param out_sample_fmt  output sample format (AV_SAMPLE_FMT_*).
              * @param out_sample_rate output sample rate (frequency in Hz)
              * @param in_ch_layout    input channel layout (AV_CH_LAYOUT_*)
              * @param in_sample_fmt   input sample format (AV_SAMPLE_FMT_*).
              * @param in_sample_rate  input sample rate (frequency in Hz)
              * @param log_offset      logging level offset
              * @param log_ctx         parent logging context, can be NULL
              */
            __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "start init swrContext");
            swrContext = swr_alloc_set_opts(NULL, av_get_default_channel_layout(OUT_PUT_CHANNELS),
                                            AV_SAMPLE_FMT_S16, avCodecContext->sample_rate,
                                            av_get_default_channel_layout(avCodecContext->channels),
                                            avCodecContext->sample_fmt, avCodecContext->sample_rate, 0,
                                            NULL);
            __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "end init swrContext");
            if (!swrContext || swr_init(swrContext)) {
                if (swrContext)
                    swr_free(&swrContext);
                avcodec_close(avCodecContext);
                __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "init resampler failed...");
                return -1;
            }
    
    
        }
        //初始化AVFrame
        audioFrame = av_frame_alloc();
        __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "open create audioFrame success");
        return -1;
    }
    
    /**
     * 检测音频编码是否支持S16
     * @return
     */
    bool RealDecoder::audioCodecIsSupported() {
        if (avCodecContext->sample_fmt == AV_SAMPLE_FMT_S16) {
            return true;
        }
        return false;
    }
    
    /**
     * 解码Packet
     * @return
     */
    AudioPacket *RealDecoder::decodePacket() {
        short *samples = new short[packetBufferSize];
        int stereoSampleSize = readSamples(samples, packetBufferSize);
        AudioPacket *samplePacket = new AudioPacket();
        if (stereoSampleSize > 0) {
            //构造成一个packet
            samplePacket->buffer = samples;
            samplePacket->size = stereoSampleSize;
            /** 这里由于每一个packet的大小不一样有可能是200ms 但是这样子position就有可能不准确了 **/
            samplePacket->position = position;
        } else {
            samplePacket->size = -1;
        }
        return samplePacket;
    }
    
    int RealDecoder::readSamples(short *samples, int size) {
        if (seek_req) {
            audioBufferCursor = audioBufferSize;
        }
        int sampleSize = size;
        while (size > 0) {
            if (audioBufferCursor < audioBufferSize) {
                int audioBufferDataSize = audioBufferSize - audioBufferCursor;
                int copySize = MIN(size, audioBufferDataSize);
                memcpy(samples + (sampleSize - size), audioBuffer + audioBufferCursor, copySize * 2);
                size -= copySize;
                audioBufferCursor += copySize;
            } else {
                if (readFrame() < 0) {
                    break;
                }
            }
    //		LOGI("size is %d", size);
        }
        int fillSize = sampleSize - size;
        if (fillSize == 0) {
            return -1;
        }
        return fillSize;
    }
    
    void RealDecoder::seek_frame() {
        __android_log_print(ANDROID_LOG_ERROR, "RealDecoder",
                            "
     seek frame firstFrameCorrectionInSecs is %.6f, seek_seconds=%f, position=%f 
    ",
                            firstFrameCorrectionInSecs, seek_seconds, position);
        float targetPosition = seek_seconds;
        float currentPosition = position;
        float frameDuration = duration;
        if (targetPosition < currentPosition) {
            this->destroy();
            this->init(mediaFilePath);
            //这里GT的测试样本会差距25ms 不会累加
            currentPosition = 0.0;
        }
        int readFrameCode = -1;
        while (true) {
            av_init_packet(&packet);
            readFrameCode = av_read_frame(avFormatContext, &packet);
            if (readFrameCode >= 0) {
                currentPosition += frameDuration;
                if (currentPosition >= targetPosition) {
                    break;
                }
            }
    //		LOGI("currentPosition is %.3f", currentPosition);
            av_free_packet(&packet);
        }
        seek_resp = true;
        seek_req = false;
        seek_success_read_frame_success = false;
    }
    
    /**
     * 读取视频中的每一帧
     * @return
     */
    int RealDecoder::readFrame() {
        if (seek_req) {
            this->seek_frame();
        }
        int ret = 1;
        av_init_packet(&packet);
        int gotFrame = -1;
        int readFrameCode = -1;
        while (true) {
            readFrameCode = av_read_frame(avFormatContext, &packet);
            if (readFrameCode >= 0) {
                if (packet.stream_index == stream_index) {//说明是音频数据
                    int len = avcodec_decode_audio4(avCodecContext, audioFrame, &gotFrame, &packet);
                    if (len < 0) {
                        __android_log_print(ANDROID_LOG_ERROR, "RealDecoder",
                                            "decode audio error, skip packet");
                    }
                    if (gotFrame) {
                        int numChannels = OUT_PUT_CHANNELS;
                        int numFrames = 0;
                        void *audioData;
                        if (swrContext) {
                            const int ratio = 2;
                            const int bufSize = av_samples_get_buffer_size(NULL,
                                                                           numChannels,
                                                                           audioFrame->nb_samples *
                                                                           ratio,
                                                                           AV_SAMPLE_FMT_S16, 1);
                            if (!swrBuffer || swrBufferSize < bufSize) {
                                swrBufferSize = bufSize;
                                swrBuffer = realloc(swrBuffer, swrBufferSize);
                            }
                            byte *outbuf[2] = {(byte *) swrBuffer, NULL};
                            numFrames = swr_convert(swrContext, outbuf,
                                                    audioFrame->nb_samples * ratio,
                                                    (const uint8_t **) audioFrame->data,
                                                    audioFrame->nb_samples);
                            if (numFrames < 0) {
                                __android_log_print(ANDROID_LOG_ERROR, "RealDecoder",
                                                    "fail resample audio");
                                ret = -1;
                                break;
                            }
                            audioData = swrBuffer;
                        } else {
                            if (avCodecContext->sample_fmt != AV_SAMPLE_FMT_S16) {
                                __android_log_print(ANDROID_LOG_ERROR, "RealDecoder",
                                                    "bucheck, audio format is invalid");
                                ret = -1;
                                break;
                            }
                            audioData = audioFrame->data[0];
                            numFrames = audioFrame->nb_samples;
                        }
                        if (isNeedFirstFrameCorrectFlag && position >= 0) {
                            float expectedPosition = position + duration;
                            float actualPosition =
                                    av_frame_get_best_effort_timestamp(audioFrame) * time_base;
                            firstFrameCorrectionInSecs = actualPosition - expectedPosition;
                            isNeedFirstFrameCorrectFlag = false;
                        }
                        duration = av_frame_get_pkt_duration(audioFrame) * time_base;
                        position = av_frame_get_best_effort_timestamp(audioFrame) * time_base -
                                   firstFrameCorrectionInSecs;
                        if (!seek_success_read_frame_success) {
                            __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "position is %.6f",
                                                position);
                            actualSeekPosition = position;
                            seek_success_read_frame_success = true;
                        }
                        audioBufferSize = numFrames * numChannels;
    //					LOGI(" 
     duration is %.6f position is %.6f audioBufferSize is %d
    ", duration, position, audioBufferSize);
                        audioBuffer = (short *) audioData;
                        audioBufferCursor = 0;
                        break;
                    }
                }
            } else {
                ret = -1;
                break;
            }
        }
        av_free_packet(&packet);
        return ret;
    }
    
    
    void RealDecoder::destroy() {
    //	LOGI("start destroy!!!");
        if (NULL != swrBuffer) {
            free(swrBuffer);
            swrBuffer = NULL;
            swrBufferSize = 0;
        }
        if (NULL != swrContext) {
            swr_free(&swrContext);
            swrContext = NULL;
        }
        if (NULL != audioFrame) {
            av_free(audioFrame);
            audioFrame = NULL;
        }
        if (NULL != avCodecContext) {
            avcodec_close(avCodecContext);
            avCodecContext = NULL;
        }
        if (NULL != avFormatContext) {
            __android_log_print(ANDROID_LOG_ERROR, "RealDecoder", "leave LiveReceiver::destory");
            avformat_close_input(&avFormatContext);
            avFormatContext = NULL;
        }
    //	LOGI("end destroy!!!");
    }
    

      

    三、源代码下载

      Gitee

  • 相关阅读:
    CSS3相关编码规范
    WEB开发中常见的漏洞
    Python常用端口扫描
    33、Django实战第33天:我的消息
    32、Django实战第32天:我的收藏
    31、Django实战第31天:我的课程
    30、Django实战第30天:修改邮箱和用户信息
    29、Django实战第29天:修改密码和头像
    28、Django实战第28天:个人信息展示
    27、Django实战第27天:全局搜索功能开发
  • 原文地址:https://www.cnblogs.com/tony-yang-flutter/p/15209651.html
Copyright © 2011-2022 走看看