FFmpeg avformat_find_stream_info函数优化

简介:

背景
        一般的应用场景对实时点播速度要求不高的情况下,可以设置探测码流的延时和探测数据的大小,代码如下:
    pFormatContext->probesize = 500 *1024;
    pFormatContext->max_analyze_duration = 5 * AV_TIME_BASE;//AV_TIME_BASE是定义的时间标准,代表1秒

弊端

        这样设置probesize和max_analyze_duration是可以减少探测时间,但是是以牺牲成功率为代价的,有时候探测不到流信息,就会播不出来,

出现在网络丢包的情况下(使用UDP进行视频数据的传输)或者网路特别复杂,跨越多个网段


场景
    要求点播时间不超过1秒,允许指定摄像机的视频参数如下:
当前只考虑视频流,后续会添加音频流,已知输入的流格式video: H264 1920*1080 25fps

实施方案
    当前采用FFmpeg 3.4版本,参考博客采用的是比较旧的版本2.2.0版本,有些函数已经被废弃,有些函数已经发生了改变,但是基本思路是不变的:
通过手动指定解码器参数,来取代avformat_find_stream_info函数探测流格式


AVStream* CDecoder::CreateStream(AVFormatContext* pFormatContext, int nCodecType)

{

AVStream *st = avformat_new_stream(pFormatContext, NULL);

if (!st)

return NULL;

st->codecpar->codec_type = (AVMediaType)nCodecType;

return st;

}



int CDecoder::GetVideoExtraData(AVFormatContext* pFormatContext, int nVideoIndex)

{

int  type, size, flags, pos, stream_type;

int ret = -1;

int64_t dts;

bool got_extradata = false;


if (!pFormatContext || nVideoIndex < 0 || nVideoIndex > 2)

return ret;


for (;; avio_skip(pFormatContext->pb, 4)) {

pos = avio_tell(pFormatContext->pb);

type = avio_r8(pFormatContext->pb);

size = avio_rb24(pFormatContext->pb);

dts = avio_rb24(pFormatContext->pb);

dts |= avio_r8(pFormatContext->pb) << 24;

avio_skip(pFormatContext->pb, 3);


if (0 == size)

break;

if (FLV_TAG_TYPE_AUDIO == type || FLV_TAG_TYPE_META == type) {

/*if audio or meta tags, skip them.*/

avio_seek(pFormatContext->pb, size, SEEK_CUR);

}

else if (type == FLV_TAG_TYPE_VIDEO) {

/*if the first video tag, read the sps/pps info from it. then break.*/

size -= 5;

pFormatContext->streams[nVideoIndex]->codecpar->extradata = (uint8_t*)av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);

if (NULL == pFormatContext->streams[nVideoIndex]->codecpar->extradata)

break;

memset(pFormatContext->streams[nVideoIndex]->codecpar->extradata, 0, size + FF_INPUT_BUFFER_PADDING_SIZE);

memcpy(pFormatContext->streams[nVideoIndex]->codecpar->extradata, pFormatContext->pb->buf_ptr + 5, size);

pFormatContext->streams[nVideoIndex]->codecpar->extradata_size = size;

ret = 0;

got_extradata = true;

}

else {

/*The type unknown,something wrong.*/

break;

}


if (got_extradata)

break;

}


return ret;

}


int CDecoder::InitDecode(AVFormatContext *pFormatContext)

{

int video_index = -1;

int audio_index = -1;

int ret = -1;


if (!pFormatContext)

return ret;


/*

Get video stream index, if no video stream then create it.

And audio so on.

*/

if (0 == pFormatContext->nb_streams) {

CreateStream(pFormatContext, AVMEDIA_TYPE_VIDEO);

CreateStream(pFormatContext, AVMEDIA_TYPE_AUDIO);

video_index = 0;

audio_index = 1;

}

else if (1 == pFormatContext->nb_streams) {

if (AVMEDIA_TYPE_VIDEO == pFormatContext->streams[0]->codecpar->codec_type) {

CreateStream(pFormatContext, AVMEDIA_TYPE_AUDIO);

video_index = 0;

audio_index = 1;

}

else if (AVMEDIA_TYPE_AUDIO == pFormatContext->streams[0]->codecpar->codec_type) {

CreateStream(pFormatContext, AVMEDIA_TYPE_VIDEO);

video_index = 1;

audio_index = 0;

}

}

else if (2 == pFormatContext->nb_streams) {

if (AVMEDIA_TYPE_VIDEO == pFormatContext->streams[0]->codecpar->codec_type) {

video_index = 0;

audio_index = 1;

}

else if (AVMEDIA_TYPE_VIDEO == pFormatContext->streams[1]->codecpar->codec_type) {

video_index = 1;

audio_index = 0;

}

}


/*Error. I can't find video stream.*/

if (video_index != 0 && video_index != 1)

return ret;


//Init the audio codec(AAC).

pFormatContext->streams[audio_index]->codecpar->codec_id = AV_CODEC_ID_AAC;

pFormatContext->streams[audio_index]->codecpar->sample_rate = 44100;

pFormatContext->streams[audio_index]->codecpar->bits_per_coded_sample = 16;

pFormatContext->streams[audio_index]->codecpar->channels = 2;

pFormatContext->streams[audio_index]->codecpar->channel_layout = 3;

pFormatContext->streams[audio_index]->pts_wrap_bits = 32;

pFormatContext->streams[audio_index]->time_base.den = 1000;

pFormatContext->streams[audio_index]->time_base.num = 1;


//Init the video codec(H264).

pFormatContext->streams[video_index]->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;

pFormatContext->streams[video_index]->codecpar->codec_id = AV_CODEC_ID_H264;

pFormatContext->streams[video_index]->codecpar->format = 12;

pFormatContext->streams[video_index]->codecpar->bits_per_raw_sample = 8;

pFormatContext->streams[video_index]->codecpar->profile = 66;

pFormatContext->streams[video_index]->codecpar->level = 42;

pFormatContext->streams[video_index]->codecpar->width = 1920;

pFormatContext->streams[video_index]->codecpar->height = 1080;

pFormatContext->streams[video_index]->codecpar->sample_aspect_ratio.num = 0;

pFormatContext->streams[video_index]->codecpar->sample_aspect_ratio.den = 1;



pFormatContext->streams[video_index]->pts_wrap_bits = 64;

pFormatContext->streams[video_index]->time_base.den = 1200000;

pFormatContext->streams[video_index]->time_base.num = 1;

pFormatContext->streams[video_index]->avg_frame_rate.den = 1;

pFormatContext->streams[video_index]->avg_frame_rate.num = 25;

/*Need to change, different condition has different frame_rate. 'r_frame_rate' is new in ffmepg2.3.3*/

pFormatContext->streams[video_index]->r_frame_rate.den = 25;

pFormatContext->streams[video_index]->r_frame_rate.num = 1;

/* H264 need sps/pps for decoding, so read it from the first video tag.*/

ret = GetVideoExtraData(pFormatContext, video_index);


/*Update the AVFormatContext Info*/

pFormatContext->nb_streams = 1;

/*empty the buffer.*/

pFormatContext->pb->buf_ptr = pFormatContext->pb->buf_end;


return ret;

}


已有的方案

AVDictionary* pOptions = NULL;

pFormatCtx->probesize = 200 *1024;

pFormatCtx->max_analyze_duration = 3 * AV_TIME_BASE;


//Retrieve stream information

 if (avformat_find_stream_info(pFormatCtx, &pOptions) < 0)

 {

 return -1; // Couldn't find stream information

 }


现有方案

InitDecode(pFormatCtx);


警告

在上述的解决方案中,采用了av_malloc分配内存,但是没有进行内存的释放,是否会随着pFormatCtx的释放而释放,不至于导致内存泄露,当然经过测试,并没有走到这一步


优化效果

通过测试,速度优化了1200毫秒


参考

http://blog.csdn.net/STN_LCD/article/details/74935760

https://jiya.io/archives/vlc_optimize_1.html






     本文转自fengyuzaitu 51CTO博客,原文链接:http://blog.51cto.com/fengyuzaitu/1982996,如需转载请自行联系原作者

相关文章
|
6月前
|
设计模式 编解码 C++
【ffmpeg 视频播放】深入探索:ffmpeg视频播放优化策略与设计模式的实践应用(一)
【ffmpeg 视频播放】深入探索:ffmpeg视频播放优化策略与设计模式的实践应用
198 0
|
6月前
|
设计模式 存储 缓存
【ffmpeg 视频播放】深入探索:ffmpeg视频播放优化策略与设计模式的实践应用(二)
【ffmpeg 视频播放】深入探索:ffmpeg视频播放优化策略与设计模式的实践应用
110 0
|
1月前
FFmpeg中结构释放小函数
本文介绍了FFmpeg中用于释放不同结构体内存的泛化变参模板函数CleanUp,以及如何特化该模板以释放AVFormatContext、AVCodecContext、AVPacket、AVFrame和uint8_t*类型的内存,并提供了一个测试文件来演示这些函数的使用。
21 3
|
4月前
|
存储 编解码 容器
FFmpeg avformat_open_input() 函数返回错误protocol not found解决方法(实测有效!附简单FFMPEG的编解码流程)
我个人出现这个错误的时候是在打开文件时报的错误,开始以为我需要加上资源文件,那样QT确实能检测到文件的存在,但是在Debug中他是检测不到这个文件的。
442 1
|
6月前
|
编解码 算法 C++
【ffmpeg 基础函数】详解FFmpeg中的av_packet_ref函数
【ffmpeg 基础函数】详解FFmpeg中的av_packet_ref函数
64 0
|
6月前
|
设计模式 编解码 算法
【ffmpeg 视频播放】深入探索:ffmpeg视频播放优化策略与设计模式的实践应用(三)
【ffmpeg 视频播放】深入探索:ffmpeg视频播放优化策略与设计模式的实践应用
88 0
|
6月前
|
设计模式 存储 缓存
【ffmpeg C++ 播放器优化实战】优化你的视频播放器:使用策略模式和单例模式进行视频优化
【ffmpeg C++ 播放器优化实战】优化你的视频播放器:使用策略模式和单例模式进行视频优化
208 0
|
6月前
|
编解码 测试技术
ffmpeg中的时间单位以及时间转换函数(av_q2d av_rescale_q)
ffmpeg中的时间单位以及时间转换函数(av_q2d av_rescale_q)
166 0
|
6月前
|
算法
FFmpeg关键函数介绍
FFmpeg关键函数介绍
46 0
|
6月前
|
API 开发工具 C语言
解决新版本ffmpeg找不到avpriv_io_delete函数等问题
解决新版本ffmpeg找不到avpriv_io_delete函数等问题
99 0