ffmpeg 之ffmpeg 整理流程分析
这个篇文档主要对ffmpeg 命令分析:主要分析ffmpeg 程序主要流程:
1. 分析命令行函数,解析出输入文件及输出文件
ffmpeg_parse_option
int ffmpeg_parse_options(int argc, char **argv)
{OptionParseContext octx;uint8_t error[128];int ret;memset(&octx, 0, sizeof(octx));/* split the commandline into an internal representation */ret = split_commandline(&octx, argc, argv, options, groups,FF_ARRAY_ELEMS(groups));if (ret < 0) {av_log(NULL, AV_LOG_FATAL, "Error splitting the argument list: ");goto fail;}/* apply global options */ret = parse_optgroup(NULL, &octx.global_opts);if (ret < 0) {av_log(NULL, AV_LOG_FATAL, "Error parsing global options: ");goto fail;}/* configure terminal and setup signal handlers */term_init();/* open input files */ret = open_files(&octx.groups[GROUP_INFILE], "input", open_input_file);if (ret < 0) {av_log(NULL, AV_LOG_FATAL, "Error opening input files: ");goto fail;}/* create the complex filtergraphs */ret = init_complex_filters();if (ret < 0) {av_log(NULL, AV_LOG_FATAL, "Error initializing complex filters.\n");goto fail;}/* open output files */ret = open_files(&octx.groups[GROUP_OUTFILE], "output", open_output_file);if (ret < 0) {av_log(NULL, AV_LOG_FATAL, "Error opening output files: ");goto fail;}check_filter_outputs();fail:uninit_parse_context(&octx);if (ret < 0) {av_strerror(ret, error, sizeof(error));av_log(NULL, AV_LOG_FATAL, "%s\n", error);}return ret;
}
2. transcode 转码处理
static int transcode(void)
{int ret, i;AVFormatContext *os;OutputStream *ost;InputStream *ist;int64_t timer_start;int64_t total_packets_written = 0;ret = transcode_init(); // 转码初始化if (ret < 0)goto fail;if (stdin_interaction) {av_log(NULL, AV_LOG_INFO, "Press [q] to stop, [?] for help\n");}timer_start = av_gettime_relative();#if HAVE_THREADSif ((ret = init_input_threads()) < 0)goto fail;
#endifwhile (!received_sigterm) {int64_t cur_time= av_gettime_relative();/* if 'q' pressed, exits */if (stdin_interaction)if (check_keyboard_interaction(cur_time) < 0)break;/* check if there's any stream where output is still needed */if (!need_output()) {av_log(NULL, AV_LOG_VERBOSE, "No more output streams to write to, finishing.\n");break;}ret = transcode_step();if (ret < 0 && ret != AVERROR_EOF) {av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", av_err2str(ret));break;}/* dump report by using the output first video and audio streams */print_report(0, timer_start, cur_time);}
#if HAVE_THREADSfree_input_threads();
#endif/* at the end of stream, we must flush the decoder buffers */for (i = 0; i < nb_input_streams; i++) {ist = input_streams[i];if (!input_files[ist->file_index]->eof_reached) {process_input_packet(ist, NULL, 0);}}flush_encoders();term_exit();/* write the trailer if needed and close file */for (i = 0; i < nb_output_files; i++) {os = output_files[i]->ctx;if (!output_files[i]->header_written) {av_log(NULL, AV_LOG_ERROR,"Nothing was written into output file %d (%s), because ""at least one of its streams received no packets.\n",i, os->url);continue;}if ((ret = av_write_trailer(os)) < 0) {av_log(NULL, AV_LOG_ERROR, "Error writing trailer of %s: %s\n", os->url, av_err2str(ret));if (exit_on_error)exit_program(1);}}/* dump report by using the first video and audio streams */print_report(1, timer_start, av_gettime_relative());/* close each encoder */for (i = 0; i < nb_output_streams; i++) {ost = output_streams[i];if (ost->encoding_needed) {av_freep(&ost->enc_ctx->stats_in);}total_packets_written += ost->packets_written;if (!ost->packets_written && (abort_on_flags & ABORT_ON_FLAG_EMPTY_OUTPUT_STREAM)) {av_log(NULL, AV_LOG_FATAL, "Empty output on stream %d.\n", i);exit_program(1);}}if (!total_packets_written && (abort_on_flags & ABORT_ON_FLAG_EMPTY_OUTPUT)) {av_log(NULL, AV_LOG_FATAL, "Empty output\n");exit_program(1);}/* close each decoder */for (i = 0; i < nb_input_streams; i++) {ist = input_streams[i];if (ist->decoding_needed) {avcodec_close(ist->dec_ctx);if (ist->hwaccel_uninit)ist->hwaccel_uninit(ist->dec_ctx);}}hw_device_free_all();/* finished ! */ret = 0;fail:
#if HAVE_THREADSfree_input_threads();
#endifif (output_streams) {for (i = 0; i < nb_output_streams; i++) {ost = output_streams[i];if (ost) {if (ost->logfile) {if (fclose(ost->logfile))av_log(NULL, AV_LOG_ERROR,"Error closing logfile, loss of information possible: %s\n",av_err2str(AVERROR(errno)));ost->logfile = NULL;}av_freep(&ost->forced_kf_pts);av_freep(&ost->apad);av_freep(&ost->disposition);av_dict_free(&ost->encoder_opts);av_dict_free(&ost->sws_dict);av_dict_free(&ost->swr_opts);av_dict_free(&ost->resample_opts);}}}return ret;
}
2.1 transcode_step // 转换流程。
process_input
process_input_packet
/* pkt = NULL means EOF (needed to flush decoder buffers) */
static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
{int ret = 0, i;int repeating = 0;int eof_reached = 0;AVPacket avpkt;if (!ist->saw_first_ts) {ist->dts = ist->st->avg_frame_rate.num ? - ist->dec_ctx->has_b_frames * AV_TIME_BASE / av_q2d(ist->st->avg_frame_rate) : 0;ist->pts = 0;if (pkt && pkt->pts != AV_NOPTS_VALUE && !ist->decoding_needed) {ist->dts += av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q);ist->pts = ist->dts; //unused but better to set it to a value thats not totally wrong}ist->saw_first_ts = 1;}if (ist->next_dts == AV_NOPTS_VALUE)ist->next_dts = ist->dts;if (ist->next_pts == AV_NOPTS_VALUE)ist->next_pts = ist->pts;if (!pkt) {/* EOF handling */av_init_packet(&avpkt);avpkt.data = NULL;avpkt.size = 0;} else {avpkt = *pkt;}if (pkt && pkt->dts != AV_NOPTS_VALUE) {ist->next_dts = ist->dts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);if (ist->dec_ctx->codec_type != AVMEDIA_TYPE_VIDEO || !ist->decoding_needed)ist->next_pts = ist->pts = ist->dts;}// while we have more to decode or while the decoder did output something on EOFwhile (ist->decoding_needed) {int64_t duration_dts = 0;int64_t duration_pts = 0;int got_output = 0;int decode_failed = 0;ist->pts = ist->next_pts;ist->dts = ist->next_dts;switch (ist->dec_ctx->codec_type) {case AVMEDIA_TYPE_AUDIO:ret = decode_audio (ist, repeating ? NULL : &avpkt, &got_output,&decode_failed);break;case AVMEDIA_TYPE_VIDEO:ret = decode_video (ist, repeating ? NULL : &avpkt, &got_output, &duration_pts, !pkt,&decode_failed);if (!repeating || !pkt || got_output) {if (pkt && pkt->duration) {duration_dts = av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q);} else if(ist->dec_ctx->framerate.num != 0 && ist->dec_ctx->framerate.den != 0) {int ticks= av_stream_get_parser(ist->st) ? av_stream_get_parser(ist->st)->repeat_pict+1 : ist->dec_ctx->ticks_per_frame;duration_dts = ((int64_t)AV_TIME_BASE *ist->dec_ctx->framerate.den * ticks) /ist->dec_ctx->framerate.num / ist->dec_ctx->ticks_per_frame;}if(ist->dts != AV_NOPTS_VALUE && duration_dts) {ist->next_dts += duration_dts;}elseist->next_dts = AV_NOPTS_VALUE;}if (got_output) {if (duration_pts > 0) {ist->next_pts += av_rescale_q(duration_pts, ist->st->time_base, AV_TIME_BASE_Q);} else {ist->next_pts += duration_dts;}}break;case AVMEDIA_TYPE_SUBTITLE:if (repeating)break;ret = transcode_subtitles(ist, &avpkt, &got_output, &decode_failed);if (!pkt && ret >= 0)ret = AVERROR_EOF;break;default:return -1;}if (ret == AVERROR_EOF) {eof_reached = 1;break;}if (ret < 0) {if (decode_failed) {av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d: %s\n",ist->file_index, ist->st->index, av_err2str(ret));} else {av_log(NULL, AV_LOG_FATAL, "Error while processing the decoded ""data for stream #%d:%d\n", ist->file_index, ist->st->index);}if (!decode_failed || exit_on_error)exit_program(1);break;}if (got_output)ist->got_output = 1;if (!got_output)break;// During draining, we might get multiple output frames in this loop.// ffmpeg.c does not drain the filter chain on configuration changes,// which means if we send multiple frames at once to the filters, and// one of those frames changes configuration, the buffered frames will// be lost. This can upset certain FATE tests.// Decode only 1 frame per call on EOF to appease these FATE tests.// The ideal solution would be to rewrite decoding to use the new// decoding API in a better way.if (!pkt)break;repeating = 1;}/* after flushing, send an EOF on all the filter inputs attached to the stream *//* except when looping we need to flush but not to send an EOF */if (!pkt && ist->decoding_needed && eof_reached && !no_eof) {int ret = send_filter_eof(ist);if (ret < 0) {av_log(NULL, AV_LOG_FATAL, "Error marking filters as finished\n");exit_program(1);}}/* handle stream copy */if (!ist->decoding_needed && pkt) {ist->dts = ist->next_dts;switch (ist->dec_ctx->codec_type) {case AVMEDIA_TYPE_AUDIO:av_assert1(pkt->duration >= 0);if (ist->dec_ctx->sample_rate) {ist->next_dts += ((int64_t)AV_TIME_BASE * ist->dec_ctx->frame_size) /ist->dec_ctx->sample_rate;} else {ist->next_dts += av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q);}break;case AVMEDIA_TYPE_VIDEO:if (ist->framerate.num) {// TODO: Remove work-around for c99-to-c89 issue 7AVRational time_base_q = AV_TIME_BASE_Q;int64_t next_dts = av_rescale_q(ist->next_dts, time_base_q, av_inv_q(ist->framerate));ist->next_dts = av_rescale_q(next_dts + 1, av_inv_q(ist->framerate), time_base_q);} else if (pkt->duration) {ist->next_dts += av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q);} else if(ist->dec_ctx->framerate.num != 0) {int ticks= av_stream_get_parser(ist->st) ? av_stream_get_parser(ist->st)->repeat_pict + 1 : ist->dec_ctx->ticks_per_frame;ist->next_dts += ((int64_t)AV_TIME_BASE *ist->dec_ctx->framerate.den * ticks) /ist->dec_ctx->framerate.num / ist->dec_ctx->ticks_per_frame;}break;}ist->pts = ist->dts;ist->next_pts = ist->next_dts;}for (i = 0; i < nb_output_streams; i++) {OutputStream *ost = output_streams[i];if (!check_output_constraints(ist, ost) || ost->encoding_needed)continue;do_streamcopy(ist, ost, pkt); // packet 拷贝到输出文件}return !eof_reached;
}
3. do_streamcopy
do_streamcopy
output_packet
write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue)
av_interleaved_write_frame
write_packets_common
write_packet(AVFormatContext *s, AVPacket *pkt)
s->oformat->write_packet
AVOutputFormat *oformat; mux 中函数:
ffmpeg 之ffmpeg 整理流程分析相关推荐
- ffmpeg.c学习-1-框架分析及命令行解析
ffmpeg.c学习-1-框架分析及命令行解析 目录 掌握ffmpeg.c的意义 ffmpeg框架分析 ffmpeg对应的⽂件 ffmpeg程序框架流程 命令行解析 1. 掌握ffmpeg.c的意义 ...
- FFmpeg简述,源码分析,录制/压缩/水印/剪切/旋转/滤镜/美颜/上传视频等(CPU软编码和解码)
> ffmpeg源码分析 ffmpeg源码简析(一)结构总览- https://blog.csdn.net/Louis_815/article/details/79621056 FFmpeg的库 ...
- FFMpeg中apiexample.c例子分析——编码分析
FFMpeg中apiexample.c例子分析--编码分析apiexample.c例子教我们如何去利用ffmpeg库中的api函数来自己编写编解码程序. (1)首先,main函数中一开始会去调用avc ...
- FFMpeg中apiexample.c例子分析——解码分析
FFMpeg中apiexample.c例子分析--解码分析 收藏 我们直接从 video_decode_example() 函数开始讲,该函数实现了如何去解码一个视频文件,以 .mpeg 文 件为例. ...
- 利用ffmpeg对视频文件进行分析几例
1.将视频文件转换为jpg图片文件序列: ffmpeg -i /home/czl/WorkSpace/ffmpeg/H264_REC.raw -r 1 -q:v 2 -f image2 pic-%03 ...
- FFmpeg播放视频文件流程
一.FFmpeg解码播放主要流程,如图1-1所示: 使用播放一个媒体文件时,通常需要经过以下几个步骤: 图1-1 FFmpeg 播放视频文件流程 1.解封装(Demuxing):就是将输入的封装 ...
- FFmpeg 使用命令整理 – 提取音频或视频、提取图片、格式转换等
提取声音的软件网上搜索有不少,不过最有名最专业的似乎是一个命令行工具:ffmpeg.这个工具功能十分丰富且强大,我所需要的从视频中提取 mp3 的功能只是其中包含的一个.感觉使用起来很复杂因为是命令行 ...
- WebRTC视频数据流程分析
本文来自<WebRTC Native开发实战>书籍作者许建林在LiveVideoStack线上分享中的内容,详细分析总结 WebRTC 的视频数据流程,并对大型项目如何快速上手:分析方法, ...
- Android流媒体处理流程分析
文章目录 1. WiFiDisplay简介 2.RTSP协议流程分析 3. 流媒体协议简介 4. RTP.RTCP协议简介 4.1 RTP协议 4.1 RTP载荷H264码流 4.2 RTP载荷PS码 ...
最新文章
- 讲一讲什么是 MMAP
- 你真的了解实时计算吗?
- java环境教程_window下Java环境配置图文教程
- Ubuntu 16.04 安装mysql5.7
- 5月7日MySQL 学习
- CentOS 7运维管理笔记(5)----源代码安装Apache 2.4,搭建LAMP服务器
- phpstudy mysql升级5.7
- 维基解密:科技公司获得安全漏洞信息须答应几个条件
- 1、mysql创建用户和授权总结
- 精益创业实战 - 第3章 制作自己的精益画布
- 教你快速制作多张图片、多段视频的画中画特效
- 电脑变wifi 用电脑建立无线网
- triplets 、triplet Loss和 hard triplets
- OC基础--对象做参数在方法间传递
- 更改分辨率时banner图片变形解决方案
- commons-poll、jedis-2.7.0、jedis.properties资源分享
- 使用NAT打造FTP服务新法
- html如何制作正方体手工图,怎么用卡纸做正方体(做长方体的步骤图纸)
- iReport制作报表
- 【原创】开源OpenIM:轻量、高效、实时、可靠、低成本的消息模型
热门文章
- web前端HTML_1(简单页面的实现)
- 使用Guardium大数据智能解决方案释放Guardium数据的价值
- excel高级筛选怎么用_Excel表格中高级筛选的优点以及常用方法介绍
- deepin标题栏边框美化
- 京东价格api,京东商品详情接口,京东api,京东优惠券接口,京东到手价api接口,京东app详情接口,接口代码对接实现价格监控接口,品牌维权接口,行业分析api接口代码分享
- C#中Trim的功能介绍
- 渐进式复杂度分析-学习笔记
- 最新最全移动端界面设计UI尺寸规范-2018年初版
- friends第九季看完了,经典对白记录--gt;对婚姻有阴影的男人
- 初识IndexedDB本地存储