2019独角兽企业重金招聘Python工程师标准>>>

前言

本文主要介绍了一些在ffmpeg中经常用到的方法以及一些常用结构体,本文将会在系列过程中不断完善,如果你发现本文依然很简陋,不要着急,慢慢会丰富起来的。

内存分配方法

内存管理永远是c的精髓,即便受无数人诟病,戕害了一代代程序员,但是本身却依旧如此具有魅力。

av_malloc / av_mallocz

这是在ffmpeg中经常出现的一个方法,用于分配内存空间。定义在mem.c文件中

void *av_malloc(size_t size)
{void *ptr = NULL;/* let's disallow possibly ambiguous cases */if (size > (max_alloc_size - 32))return NULL;#if HAVE_POSIX_MEMALIGNif (size) //OS X on SDK 10.6 has a broken posix_memalign implementationif (posix_memalign(&ptr, ALIGN, size))ptr = NULL;
#elif HAVE_ALIGNED_MALLOCptr = _aligned_malloc(size, ALIGN);
#elif HAVE_MEMALIGN
#ifndef __DJGPP__ptr = memalign(ALIGN, size);
#elseptr = memalign(size, ALIGN);
#endif/* Why 64?* Indeed, we should align it:*   on  4 for 386*   on 16 for 486*   on 32 for 586, PPro - K6-III*   on 64 for K7 (maybe for P3 too).* Because L1 and L2 caches are aligned on those values.* But I don't want to code such logic here!*//* Why 32?* For AVX ASM. SSE / NEON needs only 16.* Why not larger? Because I did not see a difference in benchmarks ...*//* benchmarks with P3* memalign(64) + 1          3071, 3051, 3032* memalign(64) + 2          3051, 3032, 3041* memalign(64) + 4          2911, 2896, 2915* memalign(64) + 8          2545, 2554, 2550* memalign(64) + 16         2543, 2572, 2563* memalign(64) + 32         2546, 2545, 2571* memalign(64) + 64         2570, 2533, 2558** BTW, malloc seems to do 8-byte alignment by default here.*/
#elseptr = malloc(size);
#endifif(!ptr && !size) {size = 1;ptr= av_malloc(1);}
#if CONFIG_MEMORY_POISONINGif (ptr)memset(ptr, FF_MEMORY_POISON, size);
#endifreturn ptr;
}void *av_mallocz(size_t size)
{void *ptr = av_malloc(size);if (ptr)memset(ptr, 0, size);return ptr;
}

方法看上去很复杂,但是实际上多是多平台处理的代码,实际作用大概就是调用memalign(malloc或realloc返回的内存块地址都是8的倍数(如果是64位系统,则为16的倍数)。如果你需要更大的粒度,请使用memalign或valloc。)来分配指定大小的内存空间。

av_mallocz 方法是在av_malloc基础上再将分配所得的内存全部空间都置为0.

av_realloc / av_realloc_f / av_reallocp

void *av_realloc(void *ptr, size_t size)
{/* let's disallow possibly ambiguous cases */if (size > (max_alloc_size - 32))return NULL;#if HAVE_ALIGNED_MALLOCreturn _aligned_realloc(ptr, size + !size, ALIGN);
#elsereturn realloc(ptr, size + !size);
#endif
}void *av_realloc_f(void *ptr, size_t nelem, size_t elsize)
{size_t size;void *r;if (av_size_mult(elsize, nelem, &size)) {av_free(ptr);return NULL;}r = av_realloc(ptr, size);if (!r)av_free(ptr);return r;
}int av_reallocp(void *ptr, size_t size)
{void *val;if (!size) {av_freep(ptr);return 0;}memcpy(&val, ptr, sizeof(val));val = av_realloc(val, size);if (!val) {av_freep(ptr);return AVERROR(ENOMEM);}memcpy(ptr, &val, sizeof(val));return 0;
}

用于重新分配内存大小,相当于realloc不同的是在分配的时候会对size进行一些操作。假设我的size是110101,那么!size就是 1010,相加之后就是 111111,变成了一个2的指数倍数。相当于对其了。

av_realloc_f作用类似,他会把两个size_t表示的小相乘,再调用av_realloc进行重新分配。

av_reallocp 是现将原来内存中的内容拷贝出来,再使用av_realoc进行分配内存,分配完成之后再将原来的内存拷回去。

av_free / av_freep

void av_free(void *ptr)
{
#if HAVE_ALIGNED_MALLOC_aligned_free(ptr);
#elsefree(ptr);
#endif
}void av_freep(void *arg)
{void *val;memcpy(&val, arg, sizeof(val));memcpy(arg, &(void *){ NULL }, sizeof(val));av_free(val);
}

av_free表示其实就是free,释放内存。

av_freep的作用是释放内存,并且将指针置NULL。

常用结构体

AVFormatContext

这个结构体在ffmpeg中基本上是一个基础一样的存在,主要用于处理封装(muxer)和解封装(demuxer)。

定义在avformat.h头文件中。一个视频是由多个音频通道和视频通道组成的,这里在demuxer时就会将元视频的所有通道拆分成出来。

/*** Format I/O context.* sizeof(AVFormatContext) must not be used outside libav*, use* 使用 avformat_alloc_context() 方法来创建AVFormatContext 结构体* 使用 avformat_free_context() 来释放**/
typedef struct AVFormatContext {/*** avformat_alloc_context() 方法自动设置,包含一些预设的信息。* Exports (de)muxer private options if they exist.*/const AVClass *av_class;/***输入数据的格式,仅在解封装的时候使用,一般会通过avformat_open_input方法赋值** Demuxing only, set by avformat_open_input().*/struct AVInputFormat *iformat;/*** 仅在封装的时候使用,用户自己设置,并且需要在调用avformat_write_header之前调用** Muxing only, must be set by the caller before avformat_write_header().*/struct AVOutputFormat *oformat;....../*** I/O context.** - demuxing: either set by the user before avformat_open_input() (then*             the user must close it manually) or set by avformat_open_input().* - muxing: set by the user before avformat_write_header(). The caller must*           take care of closing / freeing the IO context.** Do NOT set this field if AVFMT_NOFILE flag is set in* iformat/oformat.flags. In such a case, the (de)muxer will handle* I/O in some other way and this field will be NULL.* 输入数据的缓存*/AVIOContext *pb;/*** Flags modifying the (de)muxer behaviour. A combination of AVFMT_FLAG_*.* Set by the user before avformat_open_input() / avformat_write_header().* 这是一个标志位,用来标记 demuxer和muxer中的一些情况*/int flags;...../*** Number of elements in AVFormatContext.streams.** Set by avformat_new_stream(), must not be modified by any other code.* 音视频流的个数*/unsigned int nb_streams;/*** A list of all streams in the file. New streams are created with* avformat_new_stream().** - demuxing: streams are created by libavformat in avformat_open_input().*             If AVFMTCTX_NOHEADER is set in ctx_flags, then new streams may also*             appear in av_read_frame().* - muxing: streams are created by the user before avformat_write_header().** Freed by libavformat in avformat_free_context().* 音视频流*/AVStream **streams;...../*** 输入或者输出文件地址** - demuxing: 通过 avformat_open_input() 设置* - muxing: 用户自己设置**/char *url;/*** Position of the first frame of the component, in* AV_TIME_BASE fractional seconds. NEVER set this value directly:* It is deduced from the AVStream values.** Demuxing only, set by libavformat.*/int64_t start_time;/*** 时长 单位:微秒us,转换为秒需要除以1000000)*/int64_t duration;/*** 比特率 比特率(单位bps,转换为kbps需要除以1000)*/int64_t bit_rate;..../*** 元数据*/AVDictionary *metadata;...} AVFormatContext;

avformat_alloc_context方法实现在option.c文件中,

AVFormatContext *avformat_alloc_context(void)
{AVFormatContext *ic;ic = av_malloc(sizeof(AVFormatContext));if (!ic) return ic;avformat_get_context_defaults(ic);ic->internal = av_mallocz(sizeof(*ic->internal));if (!ic->internal) {avformat_free_context(ic);return NULL;}ic->internal->offset = AV_NOPTS_VALUE;ic->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;ic->internal->shortest_end = AV_NOPTS_VALUE;return ic;
}

除了分配对象之外,还初始化了一些参数。比如internal,av_class等。

AVStream

AVStream是存储每一个视频/音频流信息的结构体,定义在avformat.h中

typedef struct AVStream {int index;    /**< stream index in AVFormatContext 一般AVStream都会数组形式存储在一个AVFormatContext中,而这个index就表示它在这个数组中的位置*//*** Format-specific stream ID.* decoding: set by libavformat* encoding: set by the user, replaced by libavformat if left unset*/int id;
#if FF_API_LAVF_AVCTX/*** @deprecated use the codecpar struct instead * 用来描述这个流的codec信息 新版本中AVStream中这个字段即将被废弃,已经不建议使用*/attribute_deprecatedAVCodecContext *codec;
#endifvoid *priv_data;/*** This is the fundamental unit of time (in seconds) in terms* of which frame timestamps are represented.* 时基。通过该值可以把PTS,DTS转化为真正的时间。PTS*time_base=真正的时间* decoding: set by libavformat* encoding: May be set by the caller before avformat_write_header() to*           provide a hint to the muxer about the desired timebase. In*           avformat_write_header(), the muxer will overwrite this field*           with the timebase that will actually be used for the timestamps*           written into the file (which may or may not be related to the*           user-provided one, depending on the format).*/AVRational time_base;/*** Decoding: pts of the first frame of the stream in presentation order, in stream time base.* Only set this if you are absolutely 100% sure that the value you set* it to really is the pts of the first frame.* This may be undefined (AV_NOPTS_VALUE).* @note The ASF header does NOT contain a correct start_time the ASF* demuxer must NOT set this.*/int64_t start_time;/*** Decoding: duration of the stream, in stream time base.* If a source file does not specify a duration, but does specify* a bitrate, this value will be estimated from bitrate and file size.** Encoding: May be set by the caller before avformat_write_header() to* provide a hint to the muxer about the estimated duration.* 视频/音频流长度*/int64_t duration;int64_t nb_frames;                 ///< number of frames in this stream if known or 0int disposition; /**< AV_DISPOSITION_* bit field */enum AVDiscard discard; ///< Selects which packets can be discarded at will and do not need to be demuxed./*** sample aspect ratio (0 if unknown)* - encoding: Set by user.* - decoding: Set by libavformat.*/AVRational sample_aspect_ratio;/*** 元数据信息*/AVDictionary *metadata;/*** Average framerate* 帧率* - demuxing: May be set by libavformat when creating the stream or in*             avformat_find_stream_info().* - muxing: May be set by the caller before avformat_write_header().*/AVRational avg_frame_rate;/*** For streams with AV_DISPOSITION_ATTACHED_PIC disposition, this packet* will contain the attached picture.* 附带的图片。比如说一些MP3,AAC音频文件附带的专辑封面。* decoding: set by libavformat, must not be modified by the caller.* encoding: unused*/AVPacket attached_pic;......../*** Codec parameters associated with this stream. Allocated and freed by* libavformat in avformat_new_stream() and avformat_free_context()* respectively.* 新版本中替代AVCodecContext的结构体,用来表示codec的一些参数。能够和AVCodecContext相互转化*    avcodec_parameters_to_context*    avcodec_parameters_from_context* - demuxing: filled by libavformat on stream creation or in*             avformat_find_stream_info()* - muxing: filled by the caller before avformat_write_header()*/AVCodecParameters *codecpar;...........} AVStream;

该结构体一般会在avformat_new_stream()中进行初始化,并且填入AVFormatContext中。avformat_new_stream这个方法一般会在AVInputFormat的read_head中调用,但是到了现在的ffmpeg这个规则已经松动,不是所有情况都会在read_head中调用的。

AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c)
{AVStream *st;int i;AVStream **streams;if (s->nb_streams >= FFMIN(s->max_streams, INT_MAX/sizeof(*streams))) {if (s->max_streams < INT_MAX/sizeof(*streams))av_log(s, AV_LOG_ERROR, "Number of streams exceeds max_streams parameter (%d), see the documentation if you wish to increase it\n", s->max_streams);return NULL;}//分配内存streams = av_realloc_array(s->streams, s->nb_streams + 1, sizeof(*streams));if (!streams)return NULL;s->streams = streams;st = av_mallocz(sizeof(AVStream));if (!st)return NULL;if (!(st->info = av_mallocz(sizeof(*st->info)))) {av_free(st);return NULL;}st->info->last_dts = AV_NOPTS_VALUE;#if FF_API_LAVF_AVCTX
FF_DISABLE_DEPRECATION_WARNINGS//初始化 AVCodecContext 之后版本这一步将不再需要st->codec = avcodec_alloc_context3(c);if (!st->codec) {av_free(st->info);av_free(st);return NULL;}
FF_ENABLE_DEPRECATION_WARNINGS
#endifst->internal = av_mallocz(sizeof(*st->internal));if (!st->internal)goto fail;//初始化 AVCodecParametersst->codecpar = avcodec_parameters_alloc();if (!st->codecpar)goto fail;//以下代码为初始化的AVSteam填入默认值st->internal->avctx = avcodec_alloc_context3(NULL);if (!st->internal->avctx)goto fail;........s->streams[s->nb_streams++] = st;return st;
fail:free_stream(&st);return NULL;
}

avcodec_alloc_context3的代码实际上并不复杂,不再贴出来,作用就是分配AVCodecContext的内存,并且附上默认值……

avcodec_parameters_alloc实际上也是这样,分配内存,附上默认值。

AVCodec

表示一个或者编码器组件,类似于AVOutputFormat和AVInputFormat。

AVCodecContext

ffmpeg中最重要,也是最庞大的一个结构体,就像AVFormatContext表示demuxer和muxer的上下文,那么AVCodecContext久表示了encodec和decodec的上下文。

AVOutputFormat

描述一个 muxer组件。

AVInputFormat

描述一个demuxer组件。

URLProtocol

描述一个协议,比如文件协议,比如rtsp协议等。定义了打开文件,读取文件的函数指针。

typedef struct URLProtocol {const char *name;int     (*url_open)( URLContext *h, const char *url, int flags);/*** This callback is to be used by protocols which open further nested* protocols. options are then to be passed to ffurl_open()/ffurl_connect()* for those nested protocols.*/int     (*url_open2)(URLContext *h, const char *url, int flags, AVDictionary **options);int     (*url_accept)(URLContext *s, URLContext **c);int     (*url_handshake)(URLContext *c);/*** Read data from the protocol.* If data is immediately available (even less than size), EOF is* reached or an error occurs (including EINTR), return immediately.* Otherwise:* In non-blocking mode, return AVERROR(EAGAIN) immediately.* In blocking mode, wait for data/EOF/error with a short timeout (0.1s),* and return AVERROR(EAGAIN) on timeout.* Checking interrupt_callback, looping on EINTR and EAGAIN and until* enough data has been read is left to the calling function; see* retry_transfer_wrapper in avio.c.*/int     (*url_read)( URLContext *h, unsigned char *buf, int size);int     (*url_write)(URLContext *h, const unsigned char *buf, int size);int64_t (*url_seek)( URLContext *h, int64_t pos, int whence);int     (*url_close)(URLContext *h);int (*url_read_pause)(URLContext *h, int pause);int64_t (*url_read_seek)(URLContext *h, int stream_index,int64_t timestamp, int flags);int (*url_get_file_handle)(URLContext *h);int (*url_get_multi_file_handle)(URLContext *h, int **handles,int *numhandles);int (*url_get_short_seek)(URLContext *h);int (*url_shutdown)(URLContext *h, int flags);int priv_data_size;const AVClass *priv_data_class;int flags;int (*url_check)(URLContext *h, int mask);int (*url_open_dir)(URLContext *h);int (*url_read_dir)(URLContext *h, AVIODirEntry **next);int (*url_close_dir)(URLContext *h);int (*url_delete)(URLContext *h);int (*url_move)(URLContext *h_src, URLContext *h_dst);const char *default_whitelist;
} URLProtocol;

URLContext

相当于文件的上下文,其中一个成员变量就是URLProtocol。

typedef struct URLContext {const AVClass *av_class;    /**< information for av_log(). Set by url_open(). */const struct URLProtocol *prot;void *priv_data; 相应通信方式的句柄,对于文件为fd句柄,对于网络为socket句柄等char *filename;             /**< specified URL */int flags;int max_packet_size;        /**< if non zero, the stream is packetized with this max packet size */int is_streamed;            /**< true if streamed (no seek possible), default = false */int is_connected;AVIOInterruptCB interrupt_callback;int64_t rw_timeout;         /**< maximum time to wait for (network) read/write operation completion, in mcs */const char *protocol_whitelist;const char *protocol_blacklist;int min_packet_size;        /**< if non zero, the stream is packetized with this min packet size */
} URLContext;

AVDictionary

实际上这是一个键值对类型,可以说就是在c中的一个简易map类型

struct AVDictionary {int count;AVDictionaryEntry *elems;
};
typedef struct AVDictionaryEntry {char *key;char *value;
} AVDictionaryEntry;

AVCodecParser

解析器,我们最常见的可能就是Gson这种json解析器了。ffmpeg中也有解析器,主要是用于将数据切片。

AVCodecParser用于解析输入的数据流并把它们分成一帧一帧的压缩编码数据。比较形象的说法就是把长长的一段连续的数据“切割”成一段段的数据。

typedef struct AVCodecParser {int codec_ids[5]; /* several codec IDs are permitted */int priv_data_size;int (*parser_init)(AVCodecParserContext *s);/* This callback never returns an error, a negative value means that* the frame start was in a previous packet. */int (*parser_parse)(AVCodecParserContext *s,AVCodecContext *avctx,const uint8_t **poutbuf, int *poutbuf_size,const uint8_t *buf, int buf_size);void (*parser_close)(AVCodecParserContext *s);int (*split)(AVCodecContext *avctx, const uint8_t *buf, int buf_size);struct AVCodecParser *next;
} AVCodecParser;

转载于:https://my.oschina.net/zzxzzg/blog/1806996

ffmpeg源码分析 (二)相关推荐

  1. FFMPEG源码分析(二)

    ffmpeg源码分析之数据流 本文主要介绍ffmpeg的数据流,在ffmpeg中主要分有三个主要用途用于媒体流的解码播放,媒体流的转换(解码之后再编码)和媒体流录制. 媒体流的解码播放 在ffmpeg ...

  2. 【投屏】Scrcpy源码分析二(Client篇-连接阶段)

    Scrcpy源码分析系列 [投屏]Scrcpy源码分析一(编译篇) [投屏]Scrcpy源码分析二(Client篇-连接阶段) [投屏]Scrcpy源码分析三(Client篇-投屏阶段) [投屏]Sc ...

  3. FFMPEG源码分析(一)

    FFMPEG源码分析(一) ffmpeg之前公司项目中就使用过,但是多停留于应用层面,实现某个功能时,需要哪些结构体以及调用哪些函数.最近想系统的学习一下ffmpeg,于是开始看雷霄骅https:// ...

  4. 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 二 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) [Andr ...

  5. FFMPEG 源码分析

    FFMPEG基本概念: ffmpeg是一个开源的编解码框架,它提供了一个音视频录制,解码和编码库.FFMPEG是在linux下开发的,但也有windows下的编译版本. ffmpeg项目由以下几部分组 ...

  6. SpringBoot源码分析(二)之自动装配demo

    SpringBoot源码分析(二)之自动装配demo 文章目录 SpringBoot源码分析(二)之自动装配demo 前言 一.创建RedissonTemplate的Maven服务 二.创建测试服务 ...

  7. FFmpeg源码分析-直播延迟-内存泄漏

    FFmpeg源码分析-直播延迟-内存泄漏|FFmpeg源码分析方法|ffmpeg播放为什么容易产生延迟|解复用.解码内存泄漏分析 专注后台服务器开发,包括C/C++,Linux,Nginx,ZeroM ...

  8. gSOAP 源码分析(二)

    gSOAP 源码分析(二) 2012-5-24 flyfish 一 gSOAP XML介绍 Xml的全称是EXtensible Markup Language.可扩展标记语言.仅仅是一个纯文本.适合用 ...

  9. Android Q 10.1 KeyMaster源码分析(二) - 各家方案的实现

    写在之前 这两篇文章是我2021年3月初看KeyMaster的笔记,本来打算等分析完KeyMaster和KeyStore以后再一起做成一系列贴出来,后来KeyStore的分析中断了,这一系列的文章就变 ...

  10. ffmpeg源码分析-parse_optgroup

    本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8 ffmpeg 源码分析系列以一条简单的命令开始,ffmpeg -i a.mp4 b.flv,分析其内部逻辑. a. ...

最新文章

  1. 低版本系统兼容的ActionBar(四)添加Tab+添加自定义的Tab视图+Fragment
  2. LeetCode Remove Nth Node From End of List
  3. 【C 语言】字符串操作 ( 使用 数组下标 操作字符串 | 使用 char * 指针 操作字符串 )
  4. python画图视频_如何在视频文件的第一帧上画图,然后继续显示整个视频
  5. 基于PCA方法的ORL人脸识别及Python代码实现
  6. cmos和ttl_TTL电平和CMOS电平的区别
  7. 为什么需要建设中台?
  8. 【雕爷学编程】Arduino动手做(16)---数字触摸传感器
  9. 跟KingDZ学HTML5之八 HTML5之Web Save
  10. NetBeans启动firstcup错误
  11. BR/EDR控制器: 链接管理协议LMP(Link Manager protocol)
  12. centos7上部署php7遇到的坑
  13. 关于并发量的简单计算公式
  14. js试题及答案(五)
  15. zencart iis 伪静态设置 测试可用
  16. python基于PHP+MySQL的在线音乐点歌系统
  17. [内附完整源码和文档] 基于Android的手机音乐播放器的设计与实现
  18. 【BZOJ1818】【CQOI2010】【XSY2428】内部白点(树状数组+扫描线)
  19. TreeMap的用法
  20. Android 共享元素动画

热门文章

  1. OUC课程评价小程序(测试报告)
  2. 两个集合相减怎么算_什么是集合的减法运算??,集合运算问题-
  3. GDB多线程调试(调试命令+调试演示)
  4. VS2010+OPENCV3.4.1永久配置
  5. 全球地名中英文对照表(G)
  6. 手机拍摄全景图并且使用Threejs实现VR全景,超简单WebVR
  7. php怎么魔方加密,深度解析php混淆加密解密的手段,希望对大家解读魔方加密有所帮助 [tihuan]...
  8. Kali 安装 Nessus 详细过程
  9. linux学习什么?
  10. 医院借力泛微:落地高效、合规的数字化内控管理系统