失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > rtsp流媒体播放器----ffmpeg相关代码走读(一)

rtsp流媒体播放器----ffmpeg相关代码走读(一)

时间:2021-01-23 02:48:00

相关推荐

rtsp流媒体播放器----ffmpeg相关代码走读(一)

rtsp流媒体播放器—-ffmpeg相关代码走读(一)

本文介绍avformat_open_input和init_input两个函数

直接贴代码如下

avformat_open_input 函数

int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options){AVFormatContext *s = *ps;int ret = 0;AVDictionary *tmp = NULL;ID3v2ExtraMeta *id3v2_extra_meta = NULL;if (!s && !(s = avformat_alloc_context()))return AVERROR(ENOMEM);if (!s->av_class){ // 如果用户自己申请了s那么就必须同时申请s->av_classav_log(0, AV_LOG_ERROR, "Input context has not been properly allocated by avformat_alloc_context() and is not NULL either\n");return AVERROR(EINVAL);}if (fmt)s->iformat = fmt;if (options)av_dict_copy(&tmp, *options, 0);if ((ret = av_opt_set_dict(s, &tmp)) < 0)goto fail;// 此函数打开查找需要rtsp输入流if ((ret = init_input(s, filename, &tmp)) < 0)goto fail;/* check filename in case an image number is expected */if (s->iformat->flags & AVFMT_NEEDNUMBER) {if (!av_filename_number_test(filename)) {ret = AVERROR(EINVAL);goto fail;}}s->duration = s->start_time = AV_NOPTS_VALUE;av_strlcpy(s->filename, filename, sizeof(s->filename));/* allocate private data */if (s->iformat->priv_data_size > 0) { // rtsp 播放器此处对应的iformat就是ff_rtsp_demuxerif (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) {ret = AVERROR(ENOMEM);goto fail;}if (s->iformat->priv_class) { // 这里的 priv_class 就是 rtsp_demuxer_class*(const AVClass**)s->priv_data = s->iformat->priv_class;av_opt_set_defaults(s->priv_data);if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0)goto fail;}}/* e.g. AVFMT_NOFILE formats will not have a AVIOContext */if (s->pb)ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta);// 执行rtsp拉流动作if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header)if ((ret = s->iformat->read_header(s)) < 0)goto fail;if (id3v2_extra_meta &&(ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0)goto fail;ff_id3v2_free_extra_meta(&id3v2_extra_meta);// 将获取到的帧数据添加到队列里面去,其实就是个listqueue_attached_pictures(s);if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->pb && !s->data_offset)s->data_offset = avio_tell(s->pb);// 最大buffer数据量大小s->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;if (options) {av_dict_free(options);*options = tmp;}*ps = s;return 0;fail:ff_id3v2_free_extra_meta(&id3v2_extra_meta);av_dict_free(&tmp);if (s->pb && !(s->flags & AVFMT_FLAG_CUSTOM_IO))avio_close(s->pb);avformat_free_context(s);*ps = NULL;return ret;}

1,s初始化值为NULLfmtoptions我们这里用的NULL

2,默认的入参*ps应该是 NULL, 此处申请实际对象s的内存

if (!s && !(s = avformat_alloc_context()))return AVERROR(ENOMEM);

3,此处查找需要的demuxer

其实就是将对象s对应的字段iformat设置为ff_rtsp_demuxer,该变量定义在rtspdec.c文件中。

if ((ret = init_input(s, filename, &tmp)) < 0)goto fail;

4,申请对象s的私有数据s->priv_data

播放器此处对应的iformat就是ff_rtsp_demuxer,所以s->iformat->priv_data_size值其实就是ff_rtsp_demuxer.priv_data_size

同理可以知道这里的priv_class就是rtsp_demuxer_class

/* allocate private data */if (s->iformat->priv_data_size > 0) { if (!(s->priv_data = av_mallocz(s->iformat->priv_data_size))) {ret = AVERROR(ENOMEM);goto fail;}if (s->iformat->priv_class) { // 这里的 priv_class 就是 rtsp_demuxer_class*(const AVClass**)s->priv_data = s->iformat->priv_class;av_opt_set_defaults(s->priv_data);if ((ret = av_opt_set_dict(s->priv_data, &tmp)) < 0)goto fail;}}

5,执行rtsp拉流动作

这里其实调用的是rtsp_read_header.,后面重点分析。

if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header)if ((ret = s->iformat->read_header(s)) < 0)goto fail;

6,将获取到的帧数据添加到队列里面去

其实就是个list

queue_attached_pictures(s);

7,最后成功返回0

init_input函数

该函数定义如下:

static int init_input(AVFormatContext *s, const char *filename, AVDictionary **options){int ret;AVProbeData pd = {filename, NULL, 0};if (s->pb) {s->flags |= AVFMT_FLAG_CUSTOM_IO;if (!s->iformat)return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, s->probesize);else if (s->iformat->flags & AVFMT_NOFILE)av_log(s, AV_LOG_WARNING, "Custom AVIOContext makes no sense and ""will be ignored with AVFMT_NOFILE format.\n");return 0;}if ( (s->iformat && s->iformat->flags & AVFMT_NOFILE) ||(!s->iformat && (s->iformat = av_probe_input_format(&pd, 0))))return 0;if ((ret = avio_open2(&s->pb, filename, AVIO_FLAG_READ | s->avio_flags,&s->interrupt_callback, options)) < 0)return ret;if (s->iformat)return 0;return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, s->probesize);}

查表确定当前输入格式

av_probe_input_format这个函数返回了查找到的输入格式,ffmpeg会遍历所有注册的demuxer,最精确匹配的将被返回。

if ( (s->iformat && s->iformat->flags & AVFMT_NOFILE) ||(!s->iformat && (s->iformat = av_probe_input_format(&pd, 0))))return 0;

对象ff_rtsp_demuxer等定义于rtspdec.c文件中

static const AVClass rtsp_demuxer_class = {.class_name= "RTSP demuxer",.item_name= av_default_item_name,.option = ff_rtsp_options,.version = LIBAVUTIL_VERSION_INT,};AVInputFormat ff_rtsp_demuxer = {.name = "rtsp",.long_name= NULL_IF_CONFIG_SMALL("RTSP input format"),.priv_data_size = sizeof(RTSPState),.read_probe= rtsp_probe,.read_header = rtsp_read_header,.read_packet = rtsp_read_packet,.read_close= rtsp_read_close,.read_seek= rtsp_read_seek,.flags= AVFMT_NOFILE,.read_play= rtsp_read_play,.read_pause= rtsp_read_pause,.priv_class= &rtsp_demuxer_class,};

如果觉得《rtsp流媒体播放器----ffmpeg相关代码走读(一)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。