rtsp流媒体播放器----ffmpeg相关代码走读(一)
来源:互联网 发布:apache pulsar 编辑:程序博客网 时间:2024/05/16 08:54
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_class av_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_demuxer 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; } } /* 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); // 将获取到的帧数据添加到队列里面去,其实就是个list queue_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
初始化值为NULL
,fmt
和options
我们这里用的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,};
0 0
- rtsp流媒体播放器----ffmpeg相关代码走读(一)
- RTSP流媒体播放器实现
- RTSP流媒体播放器实现
- RTSP流媒体播放器实现
- RTSP流媒体播放器实现
- RTSP流媒体播放器实现
- RTSP流媒体播放器实现
- RTSP HTTP流媒体播放器demo
- 嵌入式 RTSP流媒体播放器实现
- 流媒体开发RTSP视频播放器
- RTSP流媒体播放分析
- RTSP流媒体播放分析
- RTSP流媒体播放分析
- RTSP 流媒体播放地址
- android RTSP流媒体播放
- 使用FFmpeg播放rtsp
- 关于Github上FFMPEG流媒体播放器
- android rtsp流媒体播放介绍
- stdarg的用法(可变参数的用法)
- 简谈JAVA基础--Map容器--HasMap
- 随机森林原理-R语言简单实例
- ChemDraw可以画球棍模型吗?常见模型类型介绍
- 基于Mybatis的sql动态查询和模糊查询的实现
- rtsp流媒体播放器----ffmpeg相关代码走读(一)
- C语言指针导学(2)——指针的定义及运算
- 蓝桥杯 ADV-92 算法提高 求最大公约数
- python 统计列表中各元素出现的次数
- JSP中的EL表达式详细介绍
- 解决Sublime text3关掉白色边框
- 大数据学习笔记之四十五 深度学习和机器学习的区别
- 蓝桥杯 ADV-95 算法提高 字符串比较
- 蓝桥杯 ADV-96 算法提高 复数求和