FFmpeg源代码简单分析-编码-av_write_trailer()

参考链接:

  • 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字段。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/445936.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FFmpeg源代码简单分析-其他-日志输出系统(av_log()等)

参考链接 FFmpeg源代码简单分析&#xff1a;日志输出系统&#xff08;av_log()等&#xff09;_雷霄骅的博客-CSDN博客_ffmpeg源码分析 日志输出系统&#xff08;av_log()等&#xff09; 本文分析一下FFmpeg的日志&#xff08;Log&#xff09;输出系统的源代码。日志输出部分的…

FFmpeg源代码简单分析-其他-AVClass和AVoption

参考链接 FFmpeg源代码简单分析&#xff1a;结构体成员管理系统-AVClass_雷霄骅的博客-CSDN博客FFmpeg源代码简单分析&#xff1a;结构体成员管理系统-AVOption_雷霄骅的博客-CSDN博客 概述 AVOption用于在FFmpeg中描述结构体中的成员变量。它最主要的作用可以概括为两个字&a…

FFmpeg源代码简单分析-其他-libswscale的sws_getContext()

参考链接 FFmpeg源代码简单分析&#xff1a;libswscale的sws_getContext()_雷霄骅的博客-CSDN博客 libswscale的sws_getContext() FFmpeg中类库libswsscale用于图像处理&#xff08;缩放&#xff0c;YUV/RGB格式转换&#xff09;libswscale是一个主要用于处理图片像素数据的类…

FFmpeg源代码简单分析-其他-libswscale的sws_scale()

参考链接 FFmpeg源代码简单分析&#xff1a;libswscale的sws_scale()_雷霄骅的博客-CSDN博客_bad dst image pointers libswscale的sws_scale() FFmpeg的图像处理&#xff08;缩放&#xff0c;YUV/RGB格式转换&#xff09;类库libswsscale中的sws_scale()函数。libswscale是一…

FFmpeg源代码简单分析-其他-libavdevice的gdigrab

参考链接 FFmpeg源代码简单分析&#xff1a;libavdevice的gdigrab_雷霄骅的博客-CSDN博客_gdigrab libavdevice的gdigrab GDIGrab用于在Windows下屏幕录像&#xff08;抓屏&#xff09;gdigrab的源代码位于libavdevice\gdigrab.c。关键函数的调用关系图如下图所示。图中绿色背…

Ubuntu安装GmSSL库适用于ubuntu18和ubuntu20版本

参考链接 编译与安装【GmSSL】GmSSL 与 OpenSSL 共存的安装方法_阿卡基YUAN的博客-CSDN博客_openssl和gmssl在Linux下安装GmSSL_百里杨的博客-CSDN博客_安装gmssl ubuntu18操作 需要超级管理员权限本人将下载的安装包master.zip和安装的位置都设定在/usr/local下创建文件夹/u…

Windows7右键菜单栏添加打开cmd项

背景简介 众所周知&#xff0c;在Linux桌面操作系统中的工作目录窗口中&#xff0c;单击鼠标右键&#xff0c;弹出的菜单栏通常有一项“打开终端”&#xff0c;然后移动鼠标点击该项&#xff0c;就可以打开Shell窗口&#xff0c;在当前工作目录进行命令行操作。 但是&#xf…

在ubuntu环境下执行openssl编译和安装

参考链接 工具系列 | Ubuntu18.04安装Openssl-1.1.1_Tinywan的技术博客_51CTO博客密码学专题 openssl编译和安装_MY CUP OF TEA的博客-CSDN博客_openssl 编译安装 下载 /source/index.html编译 使用命令sudo tar -xvzf openssl-1.1.1q.tar.gz 解压。使用cd openssl-1.1.1q/进…

chrome 使用gpu 加速_一招解决 Chrome / Edge 卡顿缓慢 让浏览器重回流畅顺滑

最近一段时间,我发现电脑上的 Chrome 谷歌浏览器越用越卡了。特别是网页打开比较多,同时还有视频播放时,整个浏览器的响应速度都会变得非常缓慢,视频也会卡顿掉帧。 我用的是 iMac / 32GB 内存 / Intel 四核 i7 4Ghz CPU,硬件性能应该足以让 Chrome 流畅打开几十个网页标签…

CLion运行程序时添加命令行参数 即设置argv输入参数

参考链接 CLion运行程序时添加命令行参数_三丰杂货铺的博客-CSDN博客_clion命令行参数 操作流程 Run -> Edit -> Configuration -> Program arguments那里添内容最快捷的方式是&#xff0c;点击锤子编译图标和运行图标之间的的图标&#xff0c;进行Edit Configurati…

openssl实现双向认证教程(服务端代码+客户端代码+证书生成)

参考链接 openssl实现双向认证教程&#xff08;服务端代码客户端代码证书生成&#xff09;_huang714的博客-CSDN博客_ssl_ctx_load_verify_locations基于openssl实现https双向身份认证及安全通信_tutu-hu的博客-CSDN博客_基于openssl实现 注意事项 openssl版本差异很可能导致程…

基于openssl和国密算法生成CA、服务器和客户端证书

参考链接 国密自签名证书生成_三雷科技的博客-CSDN博客_国密证书生成openssl采用sm2进行自签名的方法_dong_beijing的博客-CSDN博客_openssl sm 前提说明 OpenSSL 1.1.1q 5 Jul 2022 已经实现了国密算法查看是否支持SM2算法openssl ecparam -list_curves | grep -i sm2参考…

基于Gmssl库静态编译,实现服务端和客户端之间的SSL通信

前情提要 将gmssl库采取静态编译的方式&#xff0c;存储在/usr/local/gmssl路径下&#xff0c;核心文件涵盖 include、lib和bin等Ubuntu安装GmSSL库适用于ubuntu18和ubuntu20版本_MY CUP OF TEA的博客-CSDN博客 代码 server #include <stdio.h> #include <stdlib.h&g…

基于SM2证书实现SSL通信

参考链接 ​​​​​基于openssl和国密算法生成CA、服务器和客户端证书_MY CUP OF TEA的博客-CSDN博客基于上述链接&#xff0c;使用国密算法生成CA、服务器和客户端证书&#xff0c;并实现签名认证openssl实现双向认证教程&#xff08;服务端代码客户端代码证书生成&#xff…

使用Clion软件实现基于国密SM2-SM3的SSL安全通信

参考链接 Ubuntu安装GmSSL库适用于ubuntu18和ubuntu20版本_MY CUP OF TEA的博客-CSDN博客CLion运行程序时添加命令行参数 即设置argv输入参数_MY CUP OF TEA的博客-CSDN博客基于SM2证书实现SSL通信_MY CUP OF TEA的博客-CSDN博客基于Gmssl库静态编译&#xff0c;实现服务端和客…

基于GmSSL实现server服务端和client客户端之间SSL通信代码(升级优化公开版)

参考链接 工程搭建介绍 Ubuntu安装GmSSL库适用于ubuntu18和ubuntu20版本_MY CUP OF TEA的博客-CSDN博客CLion运行程序时添加命令行参数 即设置argv输入参数_MY CUP OF TEA的博客-CSDN博客基于SM2证书实现SSL通信_MY CUP OF TEA的博客-CSDN博客基于Gmssl库静态编译&#xff0c…

openssl 密码套件相关内容(OID|密码套件)

参考链接 SSL通信双方如何判断对方采用了国密 - Bigben - 博客园滑动验证页面 OpenSSL TLS1.2密码套件推荐安全的TLS协议 | Hexo OID OID是由ISO/IEC、ITU-T国际标准化组织上世纪80年代联合提出的标识机制&#xff0c;其野心很大&#xff0c;为任何类型的对象&#xff08;包…

Ubuntu配置gmssl和openssl,且均使用动态库,使用时根据需要进行动态切换

前情提要 openssl和gmssl如果想要共存&#xff0c;只能一个是动态库&#xff0c;一个是静态库配置openssl和gmssl无特定的编译顺序要求openssl3.x版本是未来趋势&#xff0c;openssl1.1.x等版本只是适用于基础软件包&#xff0c;后期将会删除配置文件 /etc/ld.so.conf文件只用…

thymeleaf动态选中select_一些LowPoly动态渐变效果实现

这篇文章根大家分享一些LowPoly动态效果的制作方法&#xff0c;由于使用的是uv采样方式效率很高&#xff0c;手机也可以随意使用&#xff0c;我们先来看一些效果的参考 本文将在Unity3D中还原这些效果,如果你学会后当然可以在你喜欢的引擎中实现~如果一篇太长有可能会分多篇&am…

使用Clion和gmssl动态库实现服务器server和客户端client之间的SSL通信

参考链接 Ubuntu配置gmssl和openssl&#xff0c;且均使用动态库&#xff0c;使用时根据需要进行动态切换_MY CUP OF TEA的博客-CSDN博客 编译gmssl动态库并关闭openssl配置&#xff0c;开启gmssl配置基于GmSSL实现server服务端和client客户端之间SSL通信代码&#xff08;升级…