Android音视频系列

FFmpeg用C++多线程解码音频数据

2019-11-11  本文已影响0人  ZebraWei

版权声明:本文为卫伟学习总结文章,转载请注明出处!
上几篇文章详解的介绍了使用MediaRecord和AudioRecord两种对音频进行采集的技术,以及FFmpeg包的编辑和裁剪,生成安卓使用的.so库的技术。本文章将详细介绍使用FFmpeg进行音频解码操作。
一、音频解码过程
音频解码过程如下图所示:

二、获取音频Meta信息
对于amr格式的音频文件而言,如何去获取它的采样率以及是否单声道。如果用ffmpeg那很easy就能解决。但问题是不会,那么我们就只能用其他的第三方库。当然如果你了解其原理,甚至可以自己分析二进制文件。

int audio_stream_idx;
AVStream *audio_stream;

av_register_all();
avformat_network_init();
pFormatCtx = avformat_alloc_context();
if(avformat_open_input(&pFormatCtx, url, NULL, NULL) != 0)
{
    if(LOG_DEBUG)
    {
        LOGE("can not open url :%s", url);
    }
    return;
}
if(avformat_find_stream_info(pFormatCtx, NULL) < 0)
{
    if(LOG_DEBUG)
    {
        LOGE("can not find streams from %s", url);
    }
    return;
}

// 获取采样率和通道
audio_stream_idx = av_find_best_stream(pFormatCtx, AVMediaType::AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
audio_stream = pFormatCtx->streams[audio_stream_idx];
LOGE("采样率:%d, 通道数: %d", audio_stream->codecpar->sample_rate, audio_stream->codecpar->channels);

二、解码音频数据
关于解码函数 avcodec_decode_audio4 已经过时了,取而代之的是 avcodec_send_packet 和 avcodec_receive_frame 。
void WlFFmpeg::start() {

if(audio == NULL)
{
    if(LOG_DEBUG)
    {
        LOGE("audio is null");
        return;
    }
}

int count = 0;

while(1)
{
    AVPacket *avPacket = av_packet_alloc();
    if(av_read_frame(pFormatCtx, avPacket) == 0)
    {
        if(avPacket->stream_index == audio->streamIndex) //音频帧数据
        {
            //解码操作
            count++;
            if(LOG_DEBUG)
            {
                LOGE("解码第 %d 帧", count);
            }
            av_packet_free(&avPacket);
            av_free(avPacket);

        } else{
            av_packet_free(&avPacket);
            av_free(avPacket);
        }
    } else{
        if(LOG_DEBUG)
        {
            LOGE("decode finished");
        }
        av_packet_free(&avPacket);
        av_free(avPacket);
        break;
    }
}

三、子线程下进行解码操作

WlFFmpeg::WlFFmpeg(WlCallJava *callJava, const char *url) {
this->callJava = callJava;
this->url = url;
}

void *decodeFFmpeg(void *data)
{
WlFFmpeg *wlFFmpeg = (WlFFmpeg *) data;
wlFFmpeg->decodeFFmpegThread();
pthread_exit(&wlFFmpeg->decodeThread);
}

void WlFFmpeg::parpared() {

pthread_create(&decodeThread, NULL, decodeFFmpeg, this);

}

[代码](链接: https://pan.baidu.com/s/1RrqmBf2adXygilH5PEMnaQ
密码:v8ef
上一篇下一篇

猜你喜欢

热点阅读