参考链接:

  • FFmpeg源代码简单分析:av_write_trailer()_雷霄骅的博客-CSDN博客_av_malloc

av_write_trailer()

  • av_write_trailer()用于输出文件尾,它的声明位于libavformat\avformat.h,如下所示
/*** Write the stream trailer to an output media file and free the* file private data.** May only be called after a successful call to avformat_write_header.** @param s media file handle* @return 0 if OK, AVERROR_xxx on error*/
int av_write_trailer(AVFormatContext *s);
  • 它只需要指定一个参数,即用于输出的AVFormatContext。
  • 函数正常执行后返回值等于0。
  • av_write_trailer()的定义位于libavformat\mux.c,如下所示。
int av_write_trailer(AVFormatContext *s)
{FFFormatContext *const si = ffformatcontext(s);AVPacket *const pkt = si->parse_pkt;int ret1, ret = 0;for (unsigned i = 0; i < s->nb_streams; i++) {AVStream *const st  = s->streams[i];FFStream *const sti = ffstream(st);if (sti->bsfc) {ret1 = write_packets_from_bsfs(s, st, pkt, 1/*interleaved*/);if (ret1 < 0)av_packet_unref(pkt);if (ret >= 0)ret = ret1;}}ret1 = interleaved_write_packet(s, pkt, 1, 0);if (ret >= 0)ret = ret1;if (s->oformat->write_trailer) {if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb)avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);if (ret >= 0) {ret = s->oformat->write_trailer(s);} else {s->oformat->write_trailer(s);}}deinit_muxer(s);if (s->pb)avio_flush(s->pb);if (ret == 0)ret = s->pb ? s->pb->error : 0;for (unsigned i = 0; i < s->nb_streams; i++) {av_freep(&s->streams[i]->priv_data);av_freep(&ffstream(s->streams[i])->index_entries);}if (s->oformat->priv_class)av_opt_free(s->priv_data);av_freep(&s->priv_data);av_packet_unref(si->pkt);return ret;
}
  • 从源代码可以看出av_write_trailer()主要完成了以下两步工作:

    • (1)循环调用输出将还未输出的AVPacket。
    • (2)调用AVOutputFormat的write_trailer(),输出文件尾。

AVOutputFormat->write_trailer()

  • AVOutputFormat的write_trailer()是一个函数指针,指向特定的AVOutputFormat中的实现函数。
  • 我们以FLV对应的AVOutputFormat为例,看一下它的定义,如下所示。
const 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,.init           = flv_init,.write_header   = flv_write_header,.write_packet   = flv_write_packet,.write_trailer  = flv_write_trailer,.check_bitstream= flv_check_bitstream,.codec_tag      = (const AVCodecTag* const []) {flv_video_codec_ids, flv_audio_codec_ids, 0},.flags          = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS |AVFMT_TS_NONSTRICT,.priv_class     = &flv_muxer_class,
};
  • 从FLV对应的AVOutputFormat结构体的定义我们可以看出,write_trailer()指向了flv_write_trailer()函数

flv_write_trailer()

  • flv_write_trailer()函数的定义位于libavformat\flvenc.c,如下所示。
static int flv_write_trailer(AVFormatContext *s)
{int64_t file_size;AVIOContext *pb = s->pb;FLVContext *flv = s->priv_data;int build_keyframes_idx = flv->flags & FLV_ADD_KEYFRAME_INDEX;int i, res;int64_t cur_pos = avio_tell(s->pb);if (build_keyframes_idx) {FLVFileposition *newflv_posinfo, *p;avio_seek(pb, flv->videosize_offset, SEEK_SET);put_amf_double(pb, flv->videosize);avio_seek(pb, flv->audiosize_offset, SEEK_SET);put_amf_double(pb, flv->audiosize);avio_seek(pb, flv->lasttimestamp_offset, SEEK_SET);put_amf_double(pb, flv->lasttimestamp);avio_seek(pb, flv->lastkeyframetimestamp_offset, SEEK_SET);put_amf_double(pb, flv->lastkeyframetimestamp);avio_seek(pb, flv->lastkeyframelocation_offset, SEEK_SET);put_amf_double(pb, flv->lastkeyframelocation + flv->keyframe_index_size);avio_seek(pb, cur_pos, SEEK_SET);res = shift_data(s);if (res < 0) {goto end;}avio_seek(pb, flv->keyframes_info_offset, SEEK_SET);put_amf_string(pb, "filepositions");put_amf_dword_array(pb, flv->filepositions_count);for (newflv_posinfo = flv->head_filepositions; newflv_posinfo; newflv_posinfo = newflv_posinfo->next) {put_amf_double(pb, newflv_posinfo->keyframe_position + flv->keyframe_index_size);}put_amf_string(pb, "times");put_amf_dword_array(pb, flv->filepositions_count);for (newflv_posinfo = flv->head_filepositions; newflv_posinfo; newflv_posinfo = newflv_posinfo->next) {put_amf_double(pb, newflv_posinfo->keyframe_timestamp);}newflv_posinfo = flv->head_filepositions;while (newflv_posinfo) {p = newflv_posinfo->next;if (p) {newflv_posinfo->next = p->next;av_free(p);p = NULL;} else {av_free(newflv_posinfo);newflv_posinfo = NULL;}}put_amf_string(pb, "");avio_w8(pb, AMF_END_OF_OBJECT);avio_seek(pb, cur_pos + flv->keyframe_index_size, SEEK_SET);}end:if (flv->flags & FLV_NO_SEQUENCE_END) {av_log(s, AV_LOG_DEBUG, "FLV no sequence end mode open\n");} else {/* Add EOS tag */for (i = 0; i < s->nb_streams; i++) {AVCodecParameters *par = s->streams[i]->codecpar;FLVStreamContext *sc = s->streams[i]->priv_data;if (par->codec_type == AVMEDIA_TYPE_VIDEO &&(par->codec_id == AV_CODEC_ID_H264 || par->codec_id == AV_CODEC_ID_MPEG4))put_avc_eos_tag(pb, sc->last_ts);}}file_size = avio_tell(pb);if (build_keyframes_idx) {flv->datasize = file_size - flv->datastart_offset;avio_seek(pb, flv->datasize_offset, SEEK_SET);put_amf_double(pb, flv->datasize);}if (!(flv->flags & FLV_NO_METADATA)) {if (!(flv->flags & FLV_NO_DURATION_FILESIZE)) {/* update information */if (avio_seek(pb, flv->duration_offset, SEEK_SET) < 0) {av_log(s, AV_LOG_WARNING, "Failed to update header with correct duration.\n");} else {put_amf_double(pb, flv->duration / (double)1000);}if (avio_seek(pb, flv->filesize_offset, SEEK_SET) < 0) {av_log(s, AV_LOG_WARNING, "Failed to update header with correct filesize.\n");} else {put_amf_double(pb, file_size);}}}return 0;
}
  • 从flv_write_trailer()的源代码可以看出该函数做了以下两步工作:  位于end:之后的两段代码

    • (1)如果视频流是H.264,则添加包含EOS(End Of Stream) NALU的Tag。
    • (2)更新FLV的时长信息,以及文件大小信息。
  • 其中,put_avc_eos_tag()函数用于添加包含EOS NALU的Tag(包含结尾的一个PreviousTagSize),如下所示。
static void put_avc_eos_tag(AVIOContext *pb, unsigned ts)
{avio_w8(pb, FLV_TAG_TYPE_VIDEO);avio_wb24(pb, 5);               /* Tag Data Size */put_timestamp(pb, ts);avio_wb24(pb, 0);               /* StreamId = 0 */avio_w8(pb, 23);                /* ub[4] FrameType = 1, ub[4] CodecId = 7 */avio_w8(pb, 2);                 /* AVC end of sequence */avio_wb24(pb, 0);               /* Always 0 for AVC EOS. */avio_wb32(pb, 16);              /* Size of FLV tag */
}
  • 可以参考FLV封装格式理解上述函数。AVCVIDEOPACKET的格式,如下所示

  • 可以看出包含EOS NALU的AVCVIDEOPACKET的AVCPacketType为2。
  • 在这种情况下,AVCVIDEOPACKET的CompositionTime字段取0,并且无需包含Data字段。

FFmpeg源代码简单分析-编码-av_write_trailer()相关推荐

  1. FFmpeg源代码简单分析:av_write_trailer()

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

  2. FFmpeg源代码简单分析-编码-avcodec_encode_video()已被send_frame 和 receive_packet替代

    参考链接 FFmpeg源代码简单分析:avcodec_encode_video()_雷霄骅的博客-CSDN博客_avcodec_encode_video2 avcodec_encode_video() ...

  3. FFmpeg源代码简单分析:libavdevice的gdigrab

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

  4. FFmpeg源代码简单分析:libavdevice的avdevice_register_all()

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

  5. FFmpeg源代码简单分析:configure

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

  6. FFmpeg源代码简单分析:makefile

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

  7. FFmpeg源代码简单分析:libswscale的sws_getContext()

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

  8. FFmpeg源代码简单分析:结构体成员管理系统-AVOption

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

  9. FFmpeg源代码简单分析:结构体成员管理系统-AVClass

    ===================================================== FFmpeg的库函数源代码分析文章列表: [架构图] FFmpeg源代码结构图 - 解码 F ...

最新文章

  1. mysql安装提示create_MySQL5.1安装时出现Cannot create windows service for mysql.error:0
  2. 常用的键盘按键(一些小技巧)
  3. XtraBackup做mysql主从同步
  4. linux keepalived 脚本,Linux下 keepalived 的安装和配置
  5. 移动简单网站开发遇到的问题,备忘或者分享
  6. Tomcat线程连接池参数优化
  7. Git安装及密钥的生成并上传本地文件到GitHub上
  8. Vue2.0+ElementUI+PageHelper实现的表格分页
  9. 安卓窗口动画修改制作心得
  10. SqlBulkCopy批量数据导入(EF实现)
  11. Spring-cloud Config Server 3种配置方式
  12. css盒模型(附图解)
  13. 让金山词霸 支持谷歌翻译
  14. 1.7.1 计算机网络体系结构的形成
  15. MFC程序的生死因果
  16. Unity3D性能优化 之 内存优化篇
  17. 【计算机毕业设计】在线考试系统
  18. webpack中将打包后的文件复制到指定路径
  19. python打印异常_python异常输出
  20. 修改windowsXP iis连接数方法

热门文章

  1. 新浪A股、港股、美股、股票期权行情接口
  2. 【c++】保留两位小数
  3. MySql数据库记录相差14小时排错,使用Java访问Mysql数据库时出现时区异常的解决方案
  4. 开发利器之Mac下的MacPorts
  5. 乐山计算机学校老师最受欢迎,乐山市计算机学校优秀教师白杉杉
  6. 互联网,因特网和万维网的区别是什么?
  7. 西方投资组合理论及其新发展综述
  8. 为什么大部分公司的数据库系统仍然要使用oracle?
  9. 计算机毕业设计Java网上书店管理系统(源码+系统+mysql数据库+Lw文档)
  10. JS中substr和substring