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

原文地址:https://www.cnblogs.com/tony-yang-flutter/p/15209651.html