版本说明
以往FFmpeg版本中保存视音频流信息参数是AVStream结构体中的AVCodecContext字段。当前FFmpeg版本是3.4,新的版本已经将AVStream结构体中的AVCodecContext字段定义为废弃属性。因此无法像以前旧的版本直接通过如下的代码获取到AVCodecContext结构体参数:
AVCodecContext* pAVCodecContext = avcodec_alloc_context3(NULL);
pAVCodecContext = pAVFormatContext->streams[videoStream]->codec;
当前版本保存视音频流信息的结构体AVCodecParameters,FFmpeg提供了函数avcodec_parameters_to_context将音频流信息拷贝到新的AVCodecContext结构体中
函数说明
将AVCodecParameters结构体中码流参数拷贝到AVCodecContext结构体中,并且重新拷贝一份extradata内容,涉及到的视频的关键参数有format, width, height, codec_type等,这些参数在优化avformat_find_stream_info函数的时候,手动指定该参数通过InitDecoder函数解码统一指定H264,分辨率是1920*1080
调用avformat_open_input打开网络流后,下一步调用av_find_stream_info从网络流中读取视音频流的信息,通过调试查看AVCodecParameters结构体的视频参数
int avcodec_parameters_to_context(AVCodecContext *codec,
const AVCodecParameters *par)
{
codec->codec_type = par->codec_type;//AVMEDIA_TYPE_VIDEO
codec->codec_id = par->codec_id;//AV_CODEC_ID_H264
codec->codec_tag = par->codec_tag;//0
codec->bit_rate = par->bit_rate;//0
codec->bits_per_coded_sample = par->bits_per_coded_sample;//0
codec->bits_per_raw_sample = par->bits_per_raw_sample;//8
codec->profile = par->profile;//66
codec->level = par->level;//42
switch (par->codec_type) {
case AVMEDIA_TYPE_VIDEO:
codec->pix_fmt = par->format;//12
codec->width = par->width;//1920
codec->height = par->height;//1080
codec->field_order = par->field_order;//AV_FIELD_PROGRESSIVE
codec->color_range = par->color_range;//AVCOL_RANGE_JPEG
codec->color_primaries = par->color_primaries;//AVCOL_PRI_BT709
codec->color_trc = par->color_trc;//AVCOL_TRC_BT709
codec->colorspace = par->color_space;//AVCOL_SPC_BT709
codec->chroma_sample_location = par->chroma_location;//AVCHROMA_LOC_LEFT
codec->sample_aspect_ratio = par->sample_aspect_ratio;//num=0,den=1
codec->has_b_frames = par->video_delay;//0
break;
case AVMEDIA_TYPE_AUDIO:
codec->sample_fmt = par->format;
codec->channel_layout = par->channel_layout;
codec->channels = par->channels;
codec->sample_rate = par->sample_rate;
codec->block_align = par->block_align;
codec->frame_size = par->frame_size;
codec->delay =
codec->initial_padding = par->initial_padding;
codec->trailing_padding = par->trailing_padding;
codec->seek_preroll = par->seek_preroll;
break;
case AVMEDIA_TYPE_SUBTITLE:
codec->width = par->width;
codec->height = par->height;
break;
}
//extradata保存SPS/PPS信息,重新拷贝一份到AVCodecContext中,用于解码
if (par->extradata) {
av_freep(&codec->extradata);
codec->extradata = av_mallocz(par->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
if (!codec->extradata)
return AVERROR(ENOMEM);
memcpy(codec->extradata, par->extradata, par->extradata_size);
codec->extradata_size = par->extradata_size;
}
return 0;
}
代码定义
typedef struct AVStream
{
#if FF_API_LAVF_AVCTX
/**
* @deprecated use the codecpar struct instead
*/
attribute_deprecated
AVCodecContext *codec;
#endif
}
说明:
当手动指定编码格式的时候,说明探测码流格式的代码是可以省略的,例如
avformat_open_input
avformat_find_stream_info
在其他章节中调用InitDecoder函数替换上面的函数
历史函数
//将输入编解码器上下文信息 copy 给输出编解码器上下文
//ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);
//ret = avcodec_parameters_from_context(out_stream->codecpar, in_stream->codec);
//ret = avcodec_parameters_to_context(out_stream->codec, in_stream->codecpar);
函数使用例子
AVFormatContext *pFormatCtx = NULL;
if (avformat_open_input(&pFormatCtx, file, NULL, NULL) != 0)
{
std::cout << "打开文件失败" << std::endl;
return -1;
}
if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
{
std::cout << "探测文件格式失败" << std::endl;
return -1;
}
int nAudioStreamIndex = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
if (nAudioStreamIndex == -1)
{
std::cout << "寻找音频流失败" << std::endl;
return -1;
}
//先通过avformat_find_stream_info探测码流格式,
//找到对应的解码器
//然后将探测码流的格式信息,复制到新的解码器上
AVCodecParameters *pCodecParameters = pFormatCtx->streams[nAudioStreamIndex]->codecpar;
pCodec = avcodec_find_decoder(pCodecParameters->codec_id);
if (pCodec == NULL)
{
std::cout << "不支持该音频格式" << std::endl;
return -1;
}
pCodecCtx = avcodec_alloc_context3(pCodec);
if (avcodec_parameters_to_context(pCodecCtx, pCodecParameters) != 0)
{
std::cout << "复制音频信息失败" << std::endl;
return -1;
}