音视频开发(二)——解码

基于QT+FFMPEG的音视频开发(二)——解码

	我的大部分学习都来自雷神,没有基础去雷神博客转转,每次都有很多收获。

https://blog.csdn.net/leixiaohua1020/article/details/42658139

一、解码一般步骤

avformat_open_input();                //解封装
avformat_find_stream_info();          //获取流信息
avcodec_find_decoder();               //寻找解码器
avcodec_alloc_context3();             //打开解码器上下文
avcodec_parameters_to_context();      //复制
avcodec_open2();                      //打开解码器
av_read_frame();                      //读取音视频流
avcodec_send_packet();               
avcodec_receive_frame();              //最后为解码

主要流程图可以去雷神那看看,对于像我这样的初学者很有帮助。

二、avi解码yuv、pcm

我的Demo视频的封装格式为avi,视频轨为mpeg4,音频轨为mp3,解码以后输出像素文件yuv和音频裸流pcm。

1. 解码yuv、

根据步骤,先是解封装和获取音视频流信息。

	const char *file = "E:/workspace/my.avi";
    AVFormatContext *ic;
    ic = avformat_alloc_context();

    if(avformat_open_input(&ic, file, NULL, NULL) != 0)
    {
        cout << "cannot open file : " << file;
        return -1;
    }

    if(avformat_find_stream_info(ic, NULL) < 0)
    {
        cout << "cannot find stream infomation" << endl;
        return -1;
    }

然后遍历流信息,分离音视频。

int video_index = -1;
int i;
for(i = 0; i < ic->nb_streams; i++)
{
    if(ic->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
    {
        video_index = i;
        break;
    }
}

if(video_index == -1)
{
    cout << "not find video stream" << endl;
    return -1;
}

接下来就是寻找并打开解码器

	AVCodec *vCodec = avcodec_find_decoder(ic->streams[video_index]->codecpar->codec_id);
    if(vCodec == NULL)
    {
        cout << "not find video decoder" << endl;
        return -1;
    }
    AVCodecContext *vCC = avcodec_alloc_context3(vCodec);
    avcodec_parameters_to_context(vCC, ic->streams[video_index]->codecpar);
    if(avcodec_open2(vCC, vCodec, NULL) < 0)
    {
        cout << "cannot open video decoder" << endl;
        return -1;
    }

最后读取帧数据并解码

while(av_read_frame(ic, pkt) >= 0)
{
    if(pkt->stream_index == video_index)
    {
        int ret = avcodec_send_packet(vCC, pkt);
        if(ret < 0)
        {
            cout << "send packet for decoding video failed" << endl;
            return -1;
        }
        ret = avcodec_receive_frame(vCC, frame);
        if(ret < 0)
        {
            cout << "error during decoding video : " << ret << endl;
            return -1;
        }
    }
    av_packet_unref(pkt);
}

2. 音频同理

const char *file = "E:/workspace/my.avi";

AVFormatContext *ic;
ic = avformat_alloc_context();

if(avformat_open_input(&ic, file, NULL, NULL) != 0)
{
    cout << "cannot open file : " << file;
    return -1;
}

if(avformat_find_stream_info(ic, NULL) < 0)
{
    cout << "cannot find stream infomation" << endl;
    return -1;
}

int audio_index = -1;

int i;
for(i = 0; i < ic->nb_streams; i++)
{
     if(ic->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
     {
          audio_index =i;
          break;
     }
}

if(audio_index == -1)
{
    cout << "not find audio stream" << endl;
    return -1;
} 

AVCodec *aCodec = avcodec_find_decoder(ic->streams[audio_index]->codecpar->codec_id);
if(aCodec == NULL)
{
    cout << "not find audio decoder" << endl;
    return -1;
}
AVCodecContext *aCC = avcodec_alloc_context3(aCodec);
avcodec_parameters_to_context(aCC, ic->streams[audio_index]->codecpar);
if(avcodec_open2(aCC, aCodec, NULL) < 0)
{
    cout << "cannot open audio decoder" << endl;
    return -1;
}

while(av_read_frame(ic, pkt) >= 0)
{
    if(pkt->stream_index == audio_index)
    {
        int ret = avcodec_send_packet(aCC, pkt);
        if(ret < 0)
        {
            cout << "send packet for decoding audio failed" << endl;
            return -1;
        }
        ret = avcodec_receive_frame(aCC, frame);
        if(ret < 0)
        {
            cout << "error during decoding audio : " << ret << endl;
            return -1;
        }
    }
    av_packet_unref(pkt);
}

源码

最后,将音视频解码放一起,并输出yuv与pcm文件。
别忘了最后释放内存。

int main(int argc, char *argv[])
{
    const char *file = "E:/workspace/my.avi";

    AVFormatContext *ic;
    ic = avformat_alloc_context();

    if(avformat_open_input(&ic, file, NULL, NULL) != 0)
    {
        cout << "cannot open file : " << file;
        return -1;
    }

    if(avformat_find_stream_info(ic, NULL) < 0)
    {
        cout << "cannot find stream infomation" << endl;
        return -1;
    }

    int video_index = -1;
    int audio_index = -1;

    int i;
    for(i = 0; i < ic->nb_streams; i++)
    {
        if(ic->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
            video_index = i;
        else if(ic->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
            audio_index =i;
    }

    if(video_index == -1)
    {
        cout << "not find video stream" << endl;
        return -1;
    }
    if(audio_index == -1)
    {
        cout << "not find audio stream" << endl;
        return -1;
    }

    AVCodec *vCodec = avcodec_find_decoder(ic->streams[video_index]->codecpar->codec_id);
    if(vCodec == NULL)
    {
        cout << "not find video decoder" << endl;
        return -1;
    }
    AVCodecContext *vCC = avcodec_alloc_context3(vCodec);
    avcodec_parameters_to_context(vCC, ic->streams[video_index]->codecpar);
    if(avcodec_open2(vCC, vCodec, NULL) < 0)
    {
        cout << "cannot open video decoder" << endl;
        return -1;
    }

    AVCodec *aCodec = avcodec_find_decoder(ic->streams[audio_index]->codecpar->codec_id);
    if(aCodec == NULL)
    {
        cout << "not find audio decoder" << endl;
        return -1;
    }
    AVCodecContext *aCC = avcodec_alloc_context3(aCodec);
    avcodec_parameters_to_context(aCC, ic->streams[audio_index]->codecpar);
    if(avcodec_open2(aCC, aCodec, NULL) < 0)
    {
        cout << "cannot open audio decoder" << endl;
        return -1;
    }

    AVFrame *frame = av_frame_alloc();  //暂存解码数据
    AVFrame *yuv = av_frame_alloc();
    int yuv_bufferSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, 800,
                                                  600, 1);
    uint8_t *yuv_buffer = (uint8_t*)av_malloc(yuv_bufferSize);
    av_image_fill_arrays(yuv->data, yuv->linesize, yuv_buffer, AV_PIX_FMT_YUV420P,
                         800, 600, 1);


    int channels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
    int samples = aCC->frame_size;
    int audio_bufferSize = av_samples_get_buffer_size(NULL, channels, samples,
                                                    AV_SAMPLE_FMT_S16, 1);
    uint8_t *audio_buffer = (uint8_t*)av_malloc(192000 * 2);


    AVPacket *pkt = (AVPacket*)av_malloc(sizeof(AVPacket));

    FILE *yuv_file = fopen("out.yuv", "wb");
    FILE *pcm_file = fopen("out.pcm", "wb");

    while(av_read_frame(ic, pkt) >= 0)
    {
        if(pkt->stream_index == video_index)
        {
            int ret = avcodec_send_packet(vCC, pkt);
            if(ret < 0)
            {
                cout << "send packet for decoding video failed" << endl;
                return -1;
            }
            ret = avcodec_receive_frame(vCC, frame);
            if(ret < 0)
            {
                cout << "error during decoding video : " << ret << endl;
                return -1;
            }
            
            SwsContext *sws = sws_alloc_context();
            sws = sws_getCachedContext(sws, vCC->width, vCC->height,
                                       vCC->pix_fmt, 800, 600,
                                       AV_PIX_FMT_YUV420P, SWS_BICUBIC,
                                       NULL, NULL, NULL);

            sws_scale(sws, (const uint8_t*const*)frame->data, frame->linesize,
                      0, vCC->height, yuv->data, yuv->linesize);

            int y_size = 800 * 600;
            fwrite(yuv->data[0], 1, y_size, yuv_file);
            fwrite(yuv->data[1], 1, y_size / 4, yuv_file);
            fwrite(yuv->data[2], 1, y_size / 4, yuv_file);
            cout << "1 video frame ok" << endl;
        }
        else if(pkt->stream_index == audio_index)
        {
            int ret = avcodec_send_packet(aCC, pkt);
            if(ret < 0)
            {
                cout << "send packet for decoding audio failed" << endl;
                return -1;
            }
            ret = avcodec_receive_frame(aCC, frame);
            if(ret < 0)
            {
                cout << "error during decoding audio : " << ret << endl;
                return -1;
            }
            int64_t in_channel_layout = av_get_default_channel_layout(aCC->channels);
            SwrContext *swr1 = swr_alloc();
            swr1 = swr_alloc_set_opts(swr1, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16,
                                      44100, in_channel_layout, aCC->sample_fmt,
                                      aCC->sample_rate, 0, NULL);
            swr_init(swr1);

            swr_convert(swr1, &audio_buffer, 192000,
                        (const uint8_t**)frame->data, frame->nb_samples);

            fwrite(audio_buffer, 1, audio_bufferSize, pcm_file);
            cout << "1 audio frame ok" << endl;
        }
        av_packet_unref(pkt);
    }
	fclose(yuv_file);
	fclose(pcm_file);
	av_free(audio_buffer);
	av_free(yuv_buffer);
	av_frame_free(&yuv);
	av_frame_free(&frame);
	avcodec_free_context(&vCC);
	avcodec_free_context(&aCC);
	sws_freeContext(sws);
	swr_free(&swr);
	avformat_close_input(&ic);
    return 0;
}

不足之处请多多指教

猜你喜欢

转载自blog.csdn.net/Mr__Hu/article/details/90751831