重要结构体

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帧开始。

  最好使用下面的方法。

最新文章

  1. [R语言]R语言使用多线程对数据库进行大批量访问时出现无法连接问题
  2. 继续SecureString
  3. huffman编码压缩算法(转)
  4. CSS包含块containing block详解
  5. AWR报告-数据库概要信息(一)
  6. C++指针内存
  7. Multi-Device Hybrid Apps for Visual Studio CTP2.0
  8. php错误消息捕获
  9. 深度优先搜索(DFS)递归形式改为非递归形式
  10. 如何在高并发的分布式系统中产生UUID
  11. Linux学习 -- Shell编程 -- 正则表达式
  12. Eclipse设置问题:字体大小、修改注释内容、修改快捷键
  13. 《算法导论》学习总结 — XX.第23章 最小生成树
  14. Vue生命周期-手动挂载理解
  15. maven项目的配置
  16. Java——@SupressWarnings
  17. 用dos命令导出一个文件夹里面所有文件的名字(装逼利器)
  18. IntelliJ IDEA 创建Web项目(全教程)
  19. 一个判断I2C总线通信异常原因的方法
  20. 1. Tensorflow高效流水线Pipeline

热门文章

  1. git如何把本地文件夹和远程仓库关联
  2. 初学银河麒麟linux笔记 第四章 windows中开发的QT程序适配linux的修改——error: ‘QT_WARNING_DISABLE_DEPRECATED’ does not name a type
  3. HIVE- 各年逐月累加函数
  4. HTML&amp;CSS学习总结
  5. [Docker-2]排查基于docker部署mysql主从过程中遇到“Slave_IO_Running: Connecting”这个疑难杂症
  6. [工作]IT连和IT恋产品已完成第一版,准备上线运营
  7. VMware Workstation Ubuntu 20.04 LTS无法连接网络问题
  8. thunar文件管理器修改默认的关联的终端
  9. vue打包添加时间戳,实现更新项目自动清除缓存
  10. Windows系统运行selenium