av_write_frame()
来源:互联网 发布:数据库文件提取数据 编辑:程序博客网 时间:2024/05/19 11:49
首先编码的大致流程如下:
(1)avformat_alloc_output_context2()
(2)avfomat_write_header()
(3)avcodec_send_frame()/avcodec_receive_packet()
(4)av_write_frame()
(5)av_write_trailer()
av_write_frame()用于输出一帧视音频数据,它的声明位于libavformat\avformat.h,如下所示。
/** * Write a packet to an output media file. * * This function passes the packet directly to the muxer, without any buffering * or reordering. The caller is responsible for correctly interleaving the * packets if the format requires it. Callers that want libavformat to handle * the interleaving should call av_interleaved_write_frame() instead of this * function. * * @param s media file handle * @param pkt The packet containing the data to be written. Note that unlike * av_interleaved_write_frame(), this function does not take * ownership of the packet passed to it (though some muxers may make * an internal reference to the input packet). * * This parameter can be NULL (at any time, not just at the end), in * order to immediately flush data buffered within the muxer, for * muxers that buffer up data internally before writing it to the * output. * * Packet's @ref AVPacket.stream_index "stream_index" field must be * set to the index of the corresponding stream in @ref * AVFormatContext.streams "s->streams". It is very strongly * recommended that timing information (@ref AVPacket.pts "pts", @ref * AVPacket.dts "dts", @ref AVPacket.duration "duration") is set to * correct values. * @return < 0 on error, = 0 if OK, 1 if flushed and there is no more data to flush * * @see av_interleaved_write_frame() */ int av_write_frame(AVFormatContext *s, AVPacket *pkt);
参数:
s:用于输出的AVFormatContext。
pkt:等待输出的AVPacket。
函数正常执行后返回值等于0。
av_write_frame()的调用关系如下图所示。
av_write_frame()的定义位于libavformat\mux.c,如下所示。
int av_write_frame(AVFormatContext *s, AVPacket *pkt) { int ret; ret = check_packet(s, pkt); if (ret < 0) return ret; //Packet为NULL,Flush Encoder if (!pkt) { if (s->oformat->flags & AVFMT_ALLOW_FLUSH) { ret = s->oformat->write_packet(s, NULL); if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS) avio_flush(s->pb); if (ret >= 0 && s->pb && s->pb->error < 0) ret = s->pb->error; return ret; } return 1; } ret = compute_pkt_fields2(s, s->streams[pkt->stream_index], pkt); if (ret < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) return ret; //写入 ret = write_packet(s, pkt); if (ret >= 0 && s->pb && s->pb->error < 0) ret = s->pb->error; if (ret >= 0) s->streams[pkt->stream_index]->nb_frames++; return ret; }
从源代码可以看出,av_write_frame()主要完成了以下几步工作:
(1)调用check_packet()做一些简单的检测
(2)调用compute_pkt_fields2()设置AVPacket的一些属性值
(3)调用write_packet()写入数据
下面分别看一下这几个函数功能。
一、check_packet()定义位于libavformat\mux.c,如下所示。
static int check_packet(AVFormatContext *s, AVPacket *pkt) { if (!pkt) return 0; if (pkt->stream_index < 0 || pkt->stream_index >= s->nb_streams) { av_log(s, AV_LOG_ERROR, "Invalid packet stream index: %d\n", pkt->stream_index); return AVERROR(EINVAL); } if (s->streams[pkt->stream_index]->codec->codec_type == AVMEDIA_TYPE_ATTACHMENT) { av_log(s, AV_LOG_ERROR, "Received a packet for an attachment stream.\n"); return AVERROR(EINVAL); } return 0; }
从代码中可以看出,check_packet()的功能比较简单:首先检查一下输入的AVPacket是否为空,如果为空,则是直接返回;然后检查一下AVPacket的stream_index(标记了该AVPacket所属的AVStream)设置是否正常,如果为负数或者大于AVStream的个数,则返回错误信息;最后检查AVPacket所属的AVStream是否属于attachment stream。
二、compute_pkt_fields2()的代码很长,下面简要介绍他的功能。
compute_pkt_fields2()主要有两方面的功能:
(1)计算AVPacket的duration, dts等信息;
(2)用于检查pts、dts这些参数的合理性(例如PTS是否一定大于DTS)。
三、write_packet()函数最关键的地方就是调用了AVOutputFormat中写入数据的方法。和avformat_write_header类似。如果AVPacket中的flag标记中包含AV_PKT_FLAG_UNCODED_FRAME,就会调用AVOutputFormat的write_uncoded_frame()函数;如果不包含那个标记,就会调用write_packet()函数。write_packet()实际上是一个函数指针,指向特定的AVOutputFormat中的实现函数。
在这里我们举例子看一下FLV封装格式对应的AVOutputFormat,它的定义位于libavformat\flvenc.c,如下所示。
AVOutputFormat ff_flv_muxer = { .name = "flv", .long_name = NULL_IF_CONFIG_SMALL("FLV (Flash Video)"), .mime_type = "video/x-flv", .extensions = "flv", .priv_data_size = sizeof(FLVContext), .audio_codec = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_ADPCM_SWF, .video_codec = AV_CODEC_ID_FLV1, .write_header = flv_write_header, .write_packet = flv_write_packet, .write_trailer = flv_write_trailer, .codec_tag = (const AVCodecTag* const []) { flv_video_codec_ids, flv_audio_codec_ids, 0 }, .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT, };
write_packet()最终会调用到flv_write_packet函数。
- av_write_frame
- av_write_frame()
- av_write_frame 与 av_interleaved_write_frame
- av_write_frame 与 av_interleaved_write_frame
- av_write_frame 与 av_interleaved_write_frame
- FFmpeg源代码简单分析:av_write_frame()
- ffmpeg源码跟踪笔记之av_write_frame 与 av_interleaved_write_frame
- ffmpeg——av_write_frame/av_interleaved_write_frame写文件包
- ffmpeg源码简析(六)编码-av_write_frame(),av_write_trailer()
- mysql分库分表方案浅析
- quartz定时任务框架调度机制解析
- 单链表(带表头)
- Django 基础
- 单调栈的总结
- av_write_frame()
- JavaSE学习----StringBuffer/StringBuilder类
- [安全漏洞公告专区]RHSA-2017:1615: kernel security and bug fix update漏洞预警及修复办法
- VGGNet 《VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE-SCALE IMAGE RECOGNITION》学习笔记
- 在 Chrome 中清除、启用和管理 Cookie
- 9.8 遇到的一些问题 maven部署项目,mysql区分大小写
- Java多线程里总线锁定和缓存一致性的问题
- Educational Codeforces Round 28 Four Segments 前缀和 + 思维
- hdu 4366 分块 or 线段树。