重要结构体

AVFormatContext

AVCodecContext
AVCodec

AVPacket
AVFrame

0.公共部分

av_register_all();
avfilter_register_all();
avformat_network_init();
avdevice_register_all();
av_log_set_level(AV_LOG_ERROR);

1.input部分

avformat_alloc_context
av_find_input_format
avformat_open_input avformat_find_stream_info avcodec_find_decoder
avcodec_open2 av_read_frame avcodec_decode_video2 avformat_close_input

2.output部分

avformat_alloc_output_context2

avio_open2

avcodec_find_encoder
avcodec_alloc_context3
avcodec_open2 avformat_new_stream
avcodec_copy_context ---> avcodec_find_decoder + avcodec_alloc_context3
               + avcodec_parameters_to_context + avcodec_parameters_from_context avformat_write_header avcodec_encode_video2 av_interleaved_write_frame av_write_trailer
avcodec_close
avformat_close_input

3.裁剪视频代码

  1 #include <stdlib.h>
2 #include <libavutil/timestamp.h>
3 #include <libavformat/avformat.h>
4
5 static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt, const char *tag)
6 {
7 AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;
8
9 printf("%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
10 tag,
11 av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
12 av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
13 av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
14 pkt->stream_index);
15 }
16
17 int cut_video(double from_seconds, double end_seconds, const char* in_filename, const char* out_filename) {
18 AVOutputFormat *ofmt = NULL;
19 AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
20 AVPacket pkt;
21 int ret, i;
22
23 av_register_all();
24
25 if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
26 fprintf(stderr, "Could not open input file '%s'", in_filename);
27 goto end;
28 }
29
30 if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
31 fprintf(stderr, "Failed to retrieve input stream information");
32 goto end;
33 }
34
35 av_dump_format(ifmt_ctx, 0, in_filename, 0);
36
37 avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
38 if (!ofmt_ctx) {
39 fprintf(stderr, "Could not create output context\n");
40 ret = AVERROR_UNKNOWN;
41 goto end;
42 }
43
44 ofmt = ofmt_ctx->oformat;
45
46 for (i = 0; i < ifmt_ctx->nb_streams; i++) {
47 /* AVStream *in_stream = ifmt_ctx->streams[i];
48 AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
49 if (!out_stream) {
50 fprintf(stderr, "Failed allocating output stream\n");
51 ret = AVERROR_UNKNOWN;
52 goto end;
53 }
54
55 ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
56 if (ret < 0) {
57 fprintf(stderr, "Failed to copy context from input to output stream codec context\n");
58 goto end;
59 }
60 out_stream->codec->codec_tag = 0;
61 if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
62 out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
63 */
64 AVStream *in_stream = ifmt_ctx->streams[i];
65 AVCodec * codec = avcodec_find_decoder(in_stream->codecpar->codec_id);
66 AVStream *out_stream = avformat_new_stream(ofmt_ctx, codec);
67 if (!out_stream) {
68 fprintf(stderr, "Failed allocating output stream\n");
69 ret = AVERROR_UNKNOWN;
70 goto end;
71 }
72
73 AVCodecContext * codec_ctx = avcodec_alloc_context3(codec);
74 ret = avcodec_parameters_to_context(codec_ctx, in_stream->codecpar);
75 if (ret < 0) {
76 fprintf(stderr, "Failed to copy in_stream codecpar to codec context\n");
77 goto end;
78 }
79
80 codec_ctx->codec_tag = 0;
81 if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
82 codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
83
84 ret = avcodec_parameters_from_context(out_stream->codecpar, codec_ctx);
85 if (ret < 0) {
86 fprintf(stderr, "Failed to copy codec context to out_stream codecpar context\n");
87 goto end;
88 }
89 }
90 av_dump_format(ofmt_ctx, 0, out_filename, 1);
91
92
93 if (!(ofmt->flags & AVFMT_NOFILE)) {
94 ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
95 if (ret < 0) {
96 fprintf(stderr, "Could not open output file '%s'", out_filename);
97 goto end;
98 }
99 }
100
101 ret = avformat_write_header(ofmt_ctx, NULL);
102 if (ret < 0) {
103 fprintf(stderr, "Error occurred when opening output file\n");
104 goto end;
105 }
106
107 // int64_t start_from = 8*AV_TIME_BASE;
108 ret = av_seek_frame(ifmt_ctx, -1, from_seconds*AV_TIME_BASE, AVSEEK_FLAG_ANY);
109 if (ret < 0) {
110 fprintf(stderr, "Error seek\n");
111 goto end;
112 }
113
114 int64_t *dts_start_from = malloc(sizeof(int64_t) * ifmt_ctx->nb_streams);
115 memset(dts_start_from, 0, sizeof(int64_t) * ifmt_ctx->nb_streams);
116 int64_t *pts_start_from = malloc(sizeof(int64_t) * ifmt_ctx->nb_streams);
117 memset(pts_start_from, 0, sizeof(int64_t) * ifmt_ctx->nb_streams);
118
119 while (1) {
120 AVStream *in_stream, *out_stream;
121
122 ret = av_read_frame(ifmt_ctx, &pkt);
123 if (ret < 0)
124 break;
125
126 in_stream = ifmt_ctx->streams[pkt.stream_index];
127 out_stream = ofmt_ctx->streams[pkt.stream_index];
128
129 log_packet(ifmt_ctx, &pkt, "in");
130
131 if (av_q2d(in_stream->time_base) * pkt.pts > end_seconds) {
132 av_free_packet(&pkt);
133 break;
134 }
135
136 if (dts_start_from[pkt.stream_index] == 0) {
137 dts_start_from[pkt.stream_index] = pkt.dts;
138 printf("dts_start_from: %s\n", av_ts2str(dts_start_from[pkt.stream_index]));
139 }
140 if (pts_start_from[pkt.stream_index] == 0) {
141 pts_start_from[pkt.stream_index] = pkt.pts;
142 printf("pts_start_from: %s\n", av_ts2str(pts_start_from[pkt.stream_index]));
143 }
144
145 /* copy packet */
146 pkt.pts = av_rescale_q_rnd(pkt.pts - pts_start_from[pkt.stream_index], in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
147 pkt.dts = av_rescale_q_rnd(pkt.dts - dts_start_from[pkt.stream_index], in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
148 if (pkt.pts < 0) {
149 pkt.pts = 0;
150 }
151 if (pkt.dts < 0) {
152 pkt.dts = 0;
153 }
154 pkt.duration = (int)av_rescale_q((int64_t)pkt.duration, in_stream->time_base, out_stream->time_base);
155 pkt.pos = -1;
156 log_packet(ofmt_ctx, &pkt, "out");
157 printf("\n");
158
159 ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
160 if (ret < 0) {
161 fprintf(stderr, "Error muxing packet\n");
162 //break; // 注释后,解决 错误 pts (6000) < dts (12000) in stream 0
163 }
164 av_free_packet(&pkt);
165 }
166 free(dts_start_from);
167 free(pts_start_from);
168
169 av_write_trailer(ofmt_ctx);
170 end:
171
172 avformat_close_input(&ifmt_ctx);
173
174 /* close output */
175 if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
176 avio_closep(&ofmt_ctx->pb);
177 avformat_free_context(ofmt_ctx);
178
179 if (ret < 0 && ret != AVERROR_EOF) {
180 fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
181 return 1;
182 }
183
184 return 0;
185 }
186
187 int main(int argc, char *argv[]){
188 if(argc < 5){
189 fprintf(stderr, "Usage: \
190 command startime, endtime, srcfile, outfile");
191 return -1;
192 }
193
194 double startime = atoi(argv[1]);
195 double endtime = atoi(argv[2]);
196 cut_video(startime, endtime, argv[3], argv[4]);
197
198 return 0;
199 }

4.问题

  问题分析:

  出现这种错误是由于视频pts大于dts。pts是视频播放时间,dts是送入解码器解码时间。所以一帧视频播放时间必须在解码时间点之后。

  产生错误的原因一般是对dts,pts操作不当。比如在进行视频分割时,常用的方法是视频截取后半段视频pts与dts减去前半段pts和dts。前半段pts可能比dts大(当解码的视频帧不是I帧时)后半段刚开始视频pts和dts刚好相等(当前帧为I帧时),两个一相减就会出现dts小于pts的情况。

  解决方法:

  1.进行判断:在av_interleaved_write_frame之前添加 if(packet.pts < packet.dts) continue; 把异常的帧简单跳过,异常帧只是极少数简单跳过不会有什么影响。这样会是的播放裁剪后的视频起始有黑屏。

  2.获取截取起始时间后的第一个I帧,从这个I帧开始。

  最好使用下面的方法。

FFmpeg input与output 函数流程的更多相关文章

  1. 让函数的input、output更"函数化"

    前言 我们都知道函数的基本形式为:output f(input),且先按这种形式进行input与output的分析,我们的input与output可以有更好的设计方式,而我们的output是选择使用r ...

  2. 给定一个字符串,把字符串内的字母转换成该字母的下一个字母,a换成b,z换成a,Z换成A,如aBf转换成bCg, 字符串内的其他字符不改变,给定函数,编写函数 void Stringchang(const char*input,char*output)其中input是输入字符串,output是输出字符串

    import java.util.Scanner; /*** * 1. 给定一个字符串,把字符串内的字母转换成该字母的下一个字母,a换成b,z换成a,Z换成A,如aBf转换成bCg, 字符串内的其他字 ...

  3. ffmpeg结构体以及函数介绍(一)

    本文对在使用ffmpeg进行音视频编解码时使用到的一些函数做一个简单介绍,我当前使用的ffmpeg版本为:0.8.5,因为本人发现在不同的版本中,有些函数名称会有点小改动,所以在此有必要说明下ffmp ...

  4. EPANET中读取INPUT文件的函数文件——INPUT3.C

    /* ********************************************************************** INPUT3.C -- Input data par ...

  5. EPANET中读取INPUT文件的函数文件——INPUT1.C/INPUT2.C/INPUT3.C

    首先介绍下这3个文件的关系:可以说INPUT1.C的函数粒度最大,它的函数getdata()就完成了整个INPUT文件数据的读入,该函数又调用了INPUT2.C中的部分函数,INPUT2.C文件中的函 ...

  6. Python Tutorial 学习(七)--Input and Output

    7. Input and Output Python里面有多种方式展示程序的输出.或是用便于人阅读的方式打印出来,或是存储到文件中以便将来使用.... 本章将对这些方法予以讨论. 两种将其他类型的值转 ...

  7. ffmpeg结构体以及函数介绍(三)

    1 AVPacket typedef struct AVPacket { /** * Presentation timestamp in AVStream->time_base units; t ...

  8. Linux input系统数据上报流程【转】

    转自:https://segmentfault.com/a/1190000017255939 作为鸡生蛋系列文章,这里主要关注Linux input系统,主要为触摸事件上报流程. 读该文章最好有对li ...

  9. Java中的IO流,Input和Output的用法,字节流和字符流的区别

    Java中的IO流:就是内存与设备之间的输入和输出操作就成为IO操作,也就是IO流.内存中的数据持久化到设备上-------->输出(Output).把 硬盘上的数据读取到内存中,这种操作 成为 ...

  10. angular 的 @Input、@Output 的一个用法

    angular 使用 @input.@Output 来进行父子组件之间数据的传递. 如下: 父元素: <child-root parent_value="this is parent ...

随机推荐

  1. apollo源码同时兼容mysql、postgresql、oracle解决思路

    本文摘录 apollo源码采用的是jpa规范 Hibernate 进行持久化的ORM框架 解决思路: 思路一:使用jpa配置文件persistence.xml文件,根据使用的数据库动态加载实体类与数据 ...

  2. Curl 命令举例

    curl是一个强大的网络请求lib,虽然强大,但是参数太多哈,不得不吐槽,下面列举一下常用使用方法,供大家CV POST 请求 入门: curl -X POST "http://localh ...

  3. C# 前台线程 后台线程区别

    前台线程 会随进程一起结束 不管是否完成,后台线程需要执行完毕,进程才能结束 例子: class Program { static void Main(string[] args) { Thread ...

  4. 20203412马畅若 实验三 《Python程序设计》Socket编程技术实验报告

    实验三 Socket编程技术 课程:<Python程序设计>班级: 2034姓名: 马畅若学号:20203412实验教师:王志强实验日期:2020年5月30日必修/选修: 公选课 ##1. ...

  5. (原创)odoo one2many字段以子列表形式显示

    模块详情

  6. 反射 1 加载指定的DLL

    我们通常 都是用反射来操作指定的程序集(dll,exe). 需要引用 System.Reflection 有三种加载方式 Assembly assembly = Assembly.Load(" ...

  7. (未完成)JAVAWEB学习——

    一.Servlet开发 1.sun公司提供的一种动态web资源开发技术,本质上就要是一段Java小程序,可以将Servlet加入到容器中运行Servlet. *servlet容器 -- 能够运行ser ...

  8. JSONObject没有parseObject方法

    一定是你引入的包不对,你把上面的import 删掉,重新导入包就可以了. 在这之前加入依赖: ` net.sf.json-lib json-lib 2.4 <dependency> < ...

  9. Java调试排错心得

    首先这里没有报错,但是打印了四行相同的数据,还都是最后一行的数据.然后调试了一下 这里是重点: 下面哪里account = {Account@1580}是一直用的一个对象,所有每一次调试那些什么rs. ...

  10. 遇到bug怎么分析,这篇文章值得一看

    博主总结的非常到位:https://mp.weixin.qq.com/s/UpaLWjix2tnfTqybx9dmoQ 为什么定位问题如此重要? 可以明确一个问题是不是真的"bug" ...