基于网络流音视频包的音视频解码思路

本篇文章对自己项目中的网络媒体流解码流程进行了梳理和总结。本文中的方法不同于一般打开文件或流进行读写的流程,不需要通过avformat_open_input,avformat_find_stream_info等操作获取AVFormatContext,然后遍历不同流信息。此处直接通过解析音视频sequence header包,获取相应的参数来初始化对应的AVCodec和AVCodecContext,然后使用AVCodecContext进行后续的解码操作。由于项目中直接获取到了音视频包,所以也省去了av_read_frame操作。

一般流程:

前提:av_register_all()

1. 构造AVCodec

2. 构造AVCodecContext

3. 解码(注意输入的数据格式)

 

音频解码(关键函数 avcodec_decode_audio4):

1. 构造AVCodec(AAC为例)

codec = avcodec_find_decoder(AV_CODEC_ID_AAC);

2. 构造AVCodecContext

codec_ctx = avcodec_alloc_context3(codec);
// these params are neccesary when decoding
codec_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
codec_ctx->sample_rate = 44100;
codec_ctx->channels = channels;
codec_ctx->channel_layout = AV_CH_LAYOUT_MONO;
if (channels == 2) {
    codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
}
// 可选参数aac audio sequence header,当前不设置可以正常解析
//codec_ctx->extradata = (uint8_t*)extradata;
//codec_ctx->extradata_size = extradata_size;

// 别忘了open codec context
if ((ret=avcodec_open2(codec_ctx, codec, NULL)) < 0) {
    error("avcodec_open2 audio codec(AAC) failed.");
    return ret;
}

3. 解码(注意输入的数据格式)

AVPacket pkt;
av_init_packet(&pkt);
pkt.data = (uint8_t*)unit->bytes;
pkt.size = unit->size;
frame = av_frame_alloc();
do { int got_frame = 0; // pkt should be raw aac audio data, that is, without aac header.
// 纯aac音频数据,不包含任何容器头或编码格式头
ret = avcodec_decode_audio4(codec_ctx, frame, &got_frame, &pkt); trace("ret=%d, got_frame=%d, decoded frame size=%d", ret, got_frame, frame->linesize[0]); if (ret < 0) { char err[1000]; av_make_error_string(err, 1000, ret); error("avcodec_decode_audio4 failed. err=%s", err); break; } if (!got_frame) { ret = ERROR_AAC_NO_FRAME; error("avcodec_decode_audio4 no frame."); break; } } while (false); av_free_packet(&pkt);

 

视频解码(关键函数 avcodec_decode_video2):

1. 构造AVCodec(H.264为例)

codec = avcodec_find_decoder(AV_CODEC_ID_H264);

2. 构造AVCodecContext

codec_ctx = avcodec_alloc_context3(codec);
// extradata(video sequence header SPS, PPS) is neccesary when decoding
codec_ctx->extradata = (uint8_t*)extradata;
codec_ctx->extradata_size = extradata_size;
// 别忘了 open codec ctx
if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
    error("avcodec_open2 video codec(H264) failed.");
    return -1;
}

3. 解码(注意输入的数据格式)

AVPacket pkt;
av_init_packet(&pkt);
pkt.data = (uint8_t*)unit->bytes;
pkt.size = unit->size;
frame = av_frame_alloc();

do {
    int got_picture = 0;
    // pkt should be NAL unit, that is, with 1 byte header. 
// 如果是ibmf(iso basic media file format)格式,需要在nalu unit前面加上可变字长的Unit length字段
// 如果是annexb格式,没有测试过,如果纯nalu数据解码不正常,可以尝试加入nalu的starting code(0x000001/0x00000001)测试。 ret = avcodec_decode_video2(codec_ctx, frame, &got_picture, &pkt); trace("ret=%d, got_picture=%d, decoded frame size=%d", ret, got_picture, frame->linesize[0]*3/2); if (ret < 0) { error("avcodec_decode_video2 failed. ret=%d", ret); break; } if (!got_picture) { ret = ERROR_H264_NO_FRAME; error("avcodec_decode_video2 no frame."); break; } } while (false); av_free_packet(&pkt);

 

posted on 2017-02-11 17:25  BestWill  阅读(1617)  评论(0编辑  收藏  举报

导航