将你给出的条目设置进入你给到的 pm 中 如果条目存在 则覆盖他
小提示:如果AV_DICT_DONT_STRDUP_KEY宏和AV_DICT_DONT_STRDUP_VAL被设置了 这些参数会在出错时释放
警告:添加一个全新的条目到pm会使所有已存在的条目失效 可以使用av_dict_get得到
参数 pm:一个指向AVDictionary结构体的二重指针 如果*pm为空 那么一个AVDictionay结构体会被分配然后使*pm等于他
参数 key:添加进入*pm的key值 (类似于词典 key-value的形式去设置一些参数)到底是会发生覆盖还是添加一个新key取决于你设置的第三个参数 flags
参数 value 添加进入*pm的value值 (类似于词典 key-value的形式去设置一些参数)到底是会发生覆盖还是添加一个新value 取决于你设置的第三个参数 flags 如果传递一个空值将会导致已经存在的条目被删除
返回值: >=0表示成功 否则表示失败
首先讲这个的原因是许多ffmpeg 函数最后都能传入一个AVDictionary来做一些设置
tips:如何通过AVDictionary 设置ffmpeg各种参数 详见另一篇文章 FFMPEG Tips (5) 如何利用 AVDictionary 配置参数_Jhuster的专栏的技术博客_51CTO博客
设置超时回调 特别是网络流 经常是会超时的 这很常见 所以基本是需要设置的 这个东西
回调函数必须是线程安全的 即使你的程序运行在单线程环境下也必须是线程安全的 因为一些解码器内部工作时是多线程的
分配一个AVFormatContext结构体
avformat_free_context()可以用来释放这个结构体和任何一切AVFormatContext内分配的东西比如AVIOContext
打开输入流并且读他的头部 编解码器此时并未打开 打开的流必须通过avformat_close_input()来关闭 通过读头的过程 解复用器就能正常工作了 以后就可以通过av_read_frame来读取AVPacket
参数 ps:指向用户刚刚通过avformat_alloc_context函数分配得来的AVFormatContext 如果用户还没通过avformat_alloc_context也没事内部会分配内存并写入ps
参数 url:打开流的URL
参数fmt:如果非空 则强制指定特定的输入格式 否则输入格式由ffmpeg内部确定
参数 options:包含了AVFormatContext和解复用器私有参数的dictionary 在返回时 这个参数会被销毁并且被替换为包含未找到选项的dictionary 也就是说如果你乱填一些ffmpeg不支持的选项 ffmpeg会直接给你返回回来 也许是空的
返回值:返回0表示成功 返回AVERROR表示失败
tips:如果你想使用自定义io输入 提前分配avio结构体 并且设置他的pb成员 关于如何自定义io输入模式 请看
ffmpeg avio 自定义读取AVPacket(aac数据)并写入文件_杀神李的博客-CSDN博客
函数内部会把整个解复用解码流程走一遍 读取数个AVPacket来拿到复用格式中流的信息 比如到底有几条流 音频流还是视频流还是字幕流 这些流是用的什么格式 比如h.264 h.265 aac 这些流适合用什么编码解码解码
这个函数对于没有头的文件格式是非常有效的 比如MPEG
这个方法即使在MPEG-2重复帧模式下也会计算真实帧率
文件指针位置并不会因为这个函数读取了数个AVPacket而发生变化
读取过后的数个AVPacket可能会被缓冲用作之后的处理 比如av_read_frame
参数 ic:你刚刚打开的AVFormatContext
参数 options:如果非null,则为指向dictionary的指针的ic.nb_streams长数组,其中第i个成员包含对应于第i个流的编解码器选项。
返回值:>=0表示成功 AVERROR_xxx表示失败
这个方法不会保证打开所有的编解码器去读取数个AVPacket 所以在返回时 options非空是正常的
接下来 让用户以某种方式决定需要什么信息,这样ffmpeg内部就不会浪费时间去获取用户不需要的东西
找到用户最希望的流的索引 因为没有索引的话 你后面通过av_read_frame读出来的AVPaket你就无法分辨到底是音频的Packet还是视频的Packet 所以必须通过这个函数去找到流索引 AVPacket里有一个字段来表明他是属于哪一个索引的
参数 ic:上文的AVFormatContext
参数 AVMediaType type:你希望找到的流的类型 比如音频视频字幕等等
参数 wanted_stream_nb:用户希望的流的索引 ffmpeg尽量满足 实在满足不了 也只能返回你不希望的 设置-1自动选择
参数 related_stream:尝试去找到与你指定type相关的流 如果没有的话 设置-1
参数 decoder_ret:如果非空 返回你指定的流的编解码器 后面就可以直接打开了 不然的话你需要手动根据流信息去查找 通过调用avcodec_find_decoder这个函数
参数 flags:一些选项
返回值:你指定的type的流的索引 返回AVERROR_STREAM_NOT_FOUND表示压根没找到你指定的类型 如果找到了流但是没有对应的解码器 一样是会返回AVERROR_STREAM_NOT_FOUND
tips:如果返回成功 并且decoder_ret非空 那么ffmpeg保证给你返回的decoder是有效的 是可以直接打开的
分配编解码器上下文结构体内存 然后设置为默认值 这个编解码器上下文必须通过avcodec_free_context()来释放
参数 codec:如果非空 特定于你传入的编解码器的内存被分配并且初始化 如果你传了codec 但是后面又使用avcodec_open2来打开其他编解码器是非法的
如果空 然后特定于编解码器的默认值将不会被初始化,这可能会导致次优的默认设置,这可能会导致默认设置不理想(这主要对编码器来说很重要,例如libx264)。
返回值:充满默认值的编解码器上下文 或者空表示失败
根据提供的编解码器参数的值填充编解码器上下文。在编解码器中,任何在par中有对应字段的已分配字段将被释放并替换为par中对应字段的副本。在编解码器中没有对应字段的字段将不会被修改。通过这个函数后
参数 codec:编解码器上下文
参数 par: 流中关于编解码器的信息 在上文 find_stream_info时候就已经填充了AVStream里的AVCodecParametes 所以这里可以直接传入
返回值:>=0表示成功 或者返回AVERROR表示失败
初始化编解码器上下文来使用编解码器 在使用这个方法之前 确保你已经使用avcodec_alloc_context3()来分配内存了 通过以下四个函数来找到编解码器是非常简单的
avcodec_find_decoder_by_name()
avcodec_find_encoder_by_name()
avcodec_find_decoder()avcodec_find_encoder()
警告:这个方法不是线程安全的
在调用这个方法之前请不要使用解码流程 如avcodec_send_packet和av_receive_frame
参数 avctx:需要初始化的编解码器上下文
参数 codec:需要打开的编解码器 如果之前你通过avcodec_alloc_context3这个函数来指定了需要打开什么编解码器 那么你就不能传入其他的编解码器
参数 options:你想要对上下文和编解码器所做的一些设置 在返回时没有找到的选项会给你返回出来 比如你乱填一些ffmpeg不支持的选项
返回值: 0表示成功 负数表示发生错误
分配一个AVFrame的内存并且初始化为默认值 通过这个函数分配的内存必须通过av_frame_free()来释放掉
返回值:AVFrame
注意这个函数只会分配AVFrame本身的内存而不会去分配实际的data buffer的内存 缓冲区内存必须通过av_frame_get_buffer函数分配 或者手动分配 上一张图就懂我在说什么了
具体实现类似于智能指针 内部会有一个引用计数去维护他 ffmpeg内存管理详见其他文章
分配一个AVPacket的内存然后初始化为默认值 分配后的内存必须通过 av_packet_free来释放掉
返回值:AVPacket
注意这个方法和 av_frame_alloc一样只会初始化他本身的字段 而不会去初始化他的data buffer 如果你想同时初始化data buffer你应该选择 av_new_packet
初始化AVPacket的可选字段
注意这个不会去改变 data和size字段 这两个字段需要分别初始化
返回流中的下一个packet 他并不会保证这个AVPacket对于解码器是有效的 也就是说可能这个AVPacket你打开的编解码器根本解码不了 他会把流中的信息变成一个一个的AVPacket 你每调用一次返回一个AVPacket 并且他不会省略AVPacket中没用的信息(比如h.264中的sps pps sei等信息)来给编解码器提供最多的信息
如果传入的pkt的buf是NULL的 那么在你下一次调用av_read_frame和直到你调用avformat_close_input的时候他都是有效的 并且是永远有效 buf不会被释放也不会被更改
所以在你下一次调用av_read_frame的时候确保你已经使用av_packet_unref来释放掉了他的buf
对于视频来说 一个AVPacket恰好就包含了完整的一帧数据(并且可能夹杂了一些其他的信息)关于这个还挺重要的 以后再写文章描述吧 包括AVPacket和NALU之间的关系
对于音频来说 如果他的帧长是固定的 那么有可能一个AVPacket包含了几个帧 如果他的帧长是可变的 那么一个AVPacket只包含一个音频帧
tips:音频帧这个概念其实挺模糊的 他更像是一种规定 在发送方与接收方之间的一种约定 以后一起写个文章描述
其中 pkt的pts(显示时间戳) dts(解码时间戳) duration(建议的持续时间)这三个字段是基于AVStream中的time_base字段来计算的 如果你的视频中含有B帧 那么pkt中的pts是无效的 所以你最好是依赖dts来进行解码负荷
参数 s:上下文
参数pkt:经过你av_packet_alloc之后的pkt
返回值:0表示ok 负数表示失败
释放packet内存 如果他拥有buf的引用计数 那么会首先释放掉他的引用计数
直接使用=是发生的浅拷贝 内部引用计数并不会加1 如果使用这个函数则是深拷贝 内部引用计数加1
给解码器提供原始的packet数据 就是把packet数据送去解码器解码 在内部,这个调用将复制相关的AVCodecContext字段,这可能会影响每个包的解码,并在包实际解码时应用它们 为什么可能会影响 举一个例子 比如
AVCodecContext.skip_frame字段 他复制过后就会去填充这个字段 这个字段指示解码器丢弃使用此函数发送的包所包含的帧。比如一个包可能包含多个音频帧 其中一些可能会丢弃
注意:在你传入的pkt的data buf字段必须是字节对齐的 不然的话就有可能会访问越界 因为一些比特流读取器是按照每一次4字节或者每一次8字节来读取的 如果字节不对齐 则有可能导致访问越界
注意:在使用这个API的时候请不要和一些老的API混用同一个AVCodecContext 不然有可能会造成一些不可预料的结果 建议老API就不要再使用了
tips:在使用本API之前确保你已经使用avcodec_open2来打开了编解码器
参数 avctx:上下文
参数 avpkt:通常是一个视频帧或者是几个音频帧 这个函数并不会去改变你pkt的buf数据 但是他会创造一个引用计数去指向你的data buf 如果你传入的buf没有引用计数 就是说你传入了一个没有数据的packet 那么他会创造一个引用计数 不像老一代的API 这个data buf中的数据是会被完全读取的 如果AVPacket中包含了多个帧 那么在你下一次send packet之前 你是需要去调用多次avcodec_receive_frame去读取frame的而不是一次 这个参数可以是NULL 如果你传入NULL 那么就认为你传入了一个flush packet 代表已经读到了流的结尾 第一次发flush packet会成功 以后发的都返回AVERROR_EOF,如果你发送flush packet时 解码器中还有frame没有读取完成 那么这些东西会在下一次av_receive_frame的时候返回
返回值:0表示成功
AVERROR(EAGAIN):现在解码器的状态不可以发送AVPacket 也就是说你还没有调用av_receive_frame去获取输出 那么你就不能再传入AVPacket
AVERROR_EOF:解码器已经被flush了 没有新的包可以被发送进去了 如果你发送了多个flush packet 那么也是返回这个错误
AVERROR(EINVAL):编解码器未打开 需要打开
AVERROR(ENOMEM):未知原因导致packet无法加入内部的队列 或者是一些解码错误导致的
返回解码后的视频帧或音频帧
参数 avctx:编解码器上下文
参数 frame:内部会给你申请一个data buf并添加引用计数去装解码后的音频帧或者视频帧 如果你传入的frame拥有data buf的引用计数 那么在操作之前 会首先抹去你的引用计数
返回值:0表示成功
AVERROR(EAGAIN):现在解码器的状态不可以接受AVFrame 也就是说你还没有调用av_send_packet去输入 那么你就不能再获取AVFrame
AVERROR_EOF:解码器已经被flush了 没有新的包可以被接收了
AVERROR(EINVAL):编解码器未打开 需要打开
AVERROR_INPUT_CHANGED:当设置flag AV_CODEC_FLAG_DROPCHANGED时适用 表示当前frame的一些属性发生了变化