FFmpeg
movenc.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Martin Storsjo
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include "config.h"
22 
23 #include "libavutil/intreadwrite.h"
24 #include "libavutil/mathematics.h"
25 #include "libavutil/md5.h"
26 
27 #include "libavformat/avformat.h"
28 
29 #if HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 
33 #if !HAVE_GETOPT
34 #include "compat/getopt.c"
35 #endif
36 
37 #define HASH_SIZE 16
38 
39 static const uint8_t h264_extradata[] = {
40  0x01, 0x4d, 0x40, 0x1e, 0xff, 0xe1, 0x00, 0x02, 0x67, 0x4d, 0x01, 0x00, 0x02, 0x68, 0xef
41 };
42 static const uint8_t aac_extradata[] = {
43  0x12, 0x10
44 };
45 
46 
47 static const char *format = "mp4";
49 uint8_t iobuf[32768];
51 
53 const char *cur_name;
54 FILE* out;
56 struct AVMD5* md5;
58 
61 
62 int bframes;
63 int64_t duration;
65 int frames;
67 int64_t next_p_pts;
75 
77 
79 
80 
81 static void count_warnings(void *avcl, int level, const char *fmt, va_list vl)
82 {
83  if (level == AV_LOG_WARNING)
84  num_warnings++;
85 }
86 
87 static void init_count_warnings(void)
88 {
90  num_warnings = 0;
91 }
92 
93 static void reset_count_warnings(void)
94 {
96 }
97 
98 static int io_write(void *opaque, uint8_t *buf, int size)
99 {
100  out_size += size;
101  av_md5_update(md5, buf, size);
102  if (out)
103  fwrite(buf, 1, size, out);
104  return size;
105 }
106 
107 static int io_write_data_type(void *opaque, uint8_t *buf, int size,
108  enum AVIODataMarkerType type, int64_t time)
109 {
110  char timebuf[30], content[5] = { 0 };
111  const char *str;
112  switch (type) {
113  case AVIO_DATA_MARKER_HEADER: str = "header"; break;
114  case AVIO_DATA_MARKER_SYNC_POINT: str = "sync"; break;
115  case AVIO_DATA_MARKER_BOUNDARY_POINT: str = "boundary"; break;
116  case AVIO_DATA_MARKER_UNKNOWN: str = "unknown"; break;
117  case AVIO_DATA_MARKER_TRAILER: str = "trailer"; break;
118  default: str = "unknown"; break;
119  }
120  if (time == AV_NOPTS_VALUE)
121  snprintf(timebuf, sizeof(timebuf), "nopts");
122  else
123  snprintf(timebuf, sizeof(timebuf), "%"PRId64, time);
124  // There can be multiple header/trailer callbacks, only log the box type
125  // for header at out_size == 0
126  if (type != AVIO_DATA_MARKER_UNKNOWN &&
127  type != AVIO_DATA_MARKER_TRAILER &&
128  (type != AVIO_DATA_MARKER_HEADER || out_size == 0) &&
129  size >= 8)
130  memcpy(content, &buf[4], 4);
131  else
132  snprintf(content, sizeof(content), "-");
133  printf("write_data len %d, time %s, type %s atom %s\n", size, timebuf, str, content);
134  return io_write(opaque, buf, size);
135 }
136 
137 static void init_out(const char *name)
138 {
139  char buf[100];
140  cur_name = name;
141  snprintf(buf, sizeof(buf), "%s.%s", cur_name, format);
142 
143  av_md5_init(md5);
144  if (write_file) {
145  out = fopen(buf, "wb");
146  if (!out)
147  perror(buf);
148  }
149  out_size = 0;
150 }
151 
152 static void close_out(void)
153 {
154  int i;
155  av_md5_final(md5, hash);
156  for (i = 0; i < HASH_SIZE; i++)
157  printf("%02x", hash[i]);
158  printf(" %d %s\n", out_size, cur_name);
159  if (out)
160  fclose(out);
161  out = NULL;
162 }
163 
164 static void check_func(int value, int line, const char *msg, ...)
165 {
166  if (!value) {
167  va_list ap;
168  va_start(ap, msg);
169  printf("%d: ", line);
170  vprintf(msg, ap);
171  printf("\n");
172  check_faults++;
173  va_end(ap);
174  }
175 }
176 #define check(value, ...) check_func(value, __LINE__, __VA_ARGS__)
177 
178 static void init_fps(int bf, int audio_preroll, int fps)
179 {
180  AVStream *st;
181  int iobuf_size = force_iobuf_size ? force_iobuf_size : sizeof(iobuf);
182  ctx = avformat_alloc_context();
183  if (!ctx)
184  exit(1);
186  if (!ctx->oformat)
187  exit(1);
188  ctx->pb = avio_alloc_context(iobuf, iobuf_size, AVIO_FLAG_WRITE, NULL, NULL, io_write, NULL);
189  if (!ctx->pb)
190  exit(1);
192  ctx->flags |= AVFMT_FLAG_BITEXACT;
193 
194  st = avformat_new_stream(ctx, NULL);
195  if (!st)
196  exit(1);
199  st->codecpar->width = 640;
200  st->codecpar->height = 480;
201  st->time_base.num = 1;
202  st->time_base.den = 30;
203  st->codecpar->extradata_size = sizeof(h264_extradata);
205  if (!st->codecpar->extradata)
206  exit(1);
207  memcpy(st->codecpar->extradata, h264_extradata, sizeof(h264_extradata));
208  video_st = st;
209 
210  st = avformat_new_stream(ctx, NULL);
211  if (!st)
212  exit(1);
215  st->codecpar->sample_rate = 44100;
216  st->codecpar->channels = 2;
217  st->time_base.num = 1;
218  st->time_base.den = 44100;
219  st->codecpar->extradata_size = sizeof(aac_extradata);
221  if (!st->codecpar->extradata)
222  exit(1);
223  memcpy(st->codecpar->extradata, aac_extradata, sizeof(aac_extradata));
224  audio_st = st;
225 
226  if (avformat_write_header(ctx, &opts) < 0)
227  exit(1);
228  av_dict_free(&opts);
229 
230  frames = 0;
231  gop_size = 30;
232  duration = video_st->time_base.den / fps;
233  audio_duration = 1024LL * audio_st->time_base.den / audio_st->codecpar->sample_rate;
234  if (audio_preroll)
235  audio_preroll = 2048LL * audio_st->time_base.den / audio_st->codecpar->sample_rate;
236 
237  bframes = bf;
238  video_dts = bframes ? -duration : 0;
239  audio_dts = -audio_preroll;
240 }
241 
242 static void init(int bf, int audio_preroll)
243 {
244  init_fps(bf, audio_preroll, 30);
245 }
246 
247 static void mux_frames(int n, int c)
248 {
249  int end_frames = frames + n;
250  while (1) {
251  AVPacket pkt;
252  uint8_t pktdata[8] = { 0 };
253  av_init_packet(&pkt);
254 
255  if (av_compare_ts(audio_dts, audio_st->time_base, video_dts, video_st->time_base) < 0) {
256  pkt.dts = pkt.pts = audio_dts;
257  pkt.stream_index = 1;
258  pkt.duration = audio_duration;
260  } else {
261  if (frames == end_frames)
262  break;
263  pkt.dts = video_dts;
264  pkt.stream_index = 0;
265  pkt.duration = duration;
266  if ((frames % gop_size) == 0) {
267  pkt.flags |= AV_PKT_FLAG_KEY;
269  pkt.pts = pkt.dts + duration;
270  video_dts = pkt.pts;
271  } else {
274  pkt.pts = pkt.dts;
276  } else {
278  if (((frames + 1) % gop_size) == 0) {
279  pkt.pts = pkt.dts + duration;
280  video_dts = pkt.pts;
281  } else {
282  next_p_pts = pkt.pts = pkt.dts + 2 * duration;
283  video_dts += duration;
284  }
285  }
286  }
287  if (!bframes)
288  pkt.pts = pkt.dts;
289  if (fake_pkt_duration)
291  frames++;
292  }
293 
294  if (clear_duration)
295  pkt.duration = 0;
296  AV_WB32(pktdata + 4, pkt.pts);
297  pkt.data = pktdata;
298  pkt.size = 8;
299  if (skip_write)
300  continue;
301  if (skip_write_audio && pkt.stream_index == 1)
302  continue;
303 
304  if (c) {
305  pkt.pts += (1LL<<32);
306  pkt.dts += (1LL<<32);
307  }
308 
309  if (do_interleave)
310  av_interleaved_write_frame(ctx, &pkt);
311  else
312  av_write_frame(ctx, &pkt);
313  }
314 }
315 
316 static void mux_gops(int n)
317 {
318  mux_frames(gop_size * n, 0);
319 }
320 
321 static void skip_gops(int n)
322 {
323  skip_write = 1;
324  mux_gops(n);
325  skip_write = 0;
326 }
327 
328 static void signal_init_ts(void)
329 {
330  AVPacket pkt;
331  av_init_packet(&pkt);
332  pkt.size = 0;
333  pkt.data = NULL;
334 
335  pkt.stream_index = 0;
336  pkt.dts = video_dts;
337  pkt.pts = 0;
338  av_write_frame(ctx, &pkt);
339 
340  pkt.stream_index = 1;
341  pkt.dts = pkt.pts = audio_dts;
342  av_write_frame(ctx, &pkt);
343 }
344 
345 static void finish(void)
346 {
347  av_write_trailer(ctx);
348  avio_context_free(&ctx->pb);
350  ctx = NULL;
351 }
352 
353 static void help(void)
354 {
355  printf("movenc-test [-w]\n"
356  "-w write output into files\n");
357 }
358 
359 int main(int argc, char **argv)
360 {
361  int c;
363  uint8_t content[HASH_SIZE];
364  int empty_moov_pos;
365  int prev_pos;
366 
367  for (;;) {
368  c = getopt(argc, argv, "wh");
369  if (c == -1)
370  break;
371  switch (c) {
372  case 'w':
373  write_file = 1;
374  break;
375  default:
376  case 'h':
377  help();
378  return 0;
379  }
380  }
381 
382  md5 = av_md5_alloc();
383  if (!md5)
384  return 1;
385 
386  // Write a fragmented file with an initial moov that actually contains some
387  // samples. One moov+mdat with 1 second of data and one moof+mdat with 1
388  // second of data.
389  init_out("non-empty-moov");
390  av_dict_set(&opts, "movflags", "frag_keyframe", 0);
391  init(0, 0);
392  mux_gops(2);
393  finish();
394  close_out();
395 
396  // Write a similar file, but with B-frames and audio preroll, handled
397  // via an edit list.
398  init_out("non-empty-moov-elst");
399  av_dict_set(&opts, "movflags", "frag_keyframe", 0);
400  av_dict_set(&opts, "use_editlist", "1", 0);
401  init(1, 1);
402  mux_gops(2);
403  finish();
404  close_out();
405 
406  // Use B-frames but no audio-preroll, but without an edit list.
407  // Due to avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO, the dts
408  // of the first audio packet is > 0, but it is set to zero since edit
409  // lists aren't used, increasing the duration of the first packet instead.
410  init_out("non-empty-moov-no-elst");
411  av_dict_set(&opts, "movflags", "frag_keyframe", 0);
412  av_dict_set(&opts, "use_editlist", "0", 0);
413  init(1, 0);
414  mux_gops(2);
415  finish();
416  close_out();
417 
418  format = "ismv";
419  // Write an ISMV, with B-frames and audio preroll.
420  init_out("ismv");
421  av_dict_set(&opts, "movflags", "frag_keyframe", 0);
422  init(1, 1);
423  mux_gops(2);
424  finish();
425  close_out();
426  format = "mp4";
427 
428  // An initial moov that doesn't contain any samples, followed by two
429  // moof+mdat pairs.
430  init_out("empty-moov");
431  av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
432  av_dict_set(&opts, "use_editlist", "0", 0);
433  init(0, 0);
434  mux_gops(2);
435  finish();
436  close_out();
437  memcpy(content, hash, HASH_SIZE);
438 
439  // Similar to the previous one, but with input that doesn't start at
440  // pts/dts 0. avoid_negative_ts behaves in the same way as
441  // in non-empty-moov-no-elst above.
442  init_out("empty-moov-no-elst");
443  av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
444  init(1, 0);
445  mux_gops(2);
446  finish();
447  close_out();
448 
449  // Same as the previous one, but disable avoid_negative_ts (which
450  // would require using an edit list, but with empty_moov, one can't
451  // write a sensible edit list, when the start timestamps aren't known).
452  // This should trigger a warning - we check that the warning is produced.
454  init_out("empty-moov-no-elst-no-adjust");
455  av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
456  av_dict_set(&opts, "avoid_negative_ts", "0", 0);
457  init(1, 0);
458  mux_gops(2);
459  finish();
460  close_out();
461 
463  check(num_warnings > 0, "No warnings printed for unhandled start offset");
464 
465  // Verify that delay_moov produces the same as empty_moov for
466  // simple input
467  init_out("delay-moov");
468  av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov", 0);
469  av_dict_set(&opts, "use_editlist", "0", 0);
470  init(0, 0);
471  mux_gops(2);
472  finish();
473  close_out();
474  check(!memcmp(hash, content, HASH_SIZE), "delay_moov differs from empty_moov");
475 
476  // Test writing content that requires an edit list using delay_moov
477  init_out("delay-moov-elst");
478  av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov", 0);
479  init(1, 1);
480  mux_gops(2);
481  finish();
482  close_out();
483 
484  // Test writing a file with one track lacking packets, with delay_moov.
485  skip_write_audio = 1;
486  init_out("delay-moov-empty-track");
487  av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov", 0);
488  init(0, 0);
489  mux_gops(2);
490  // The automatic flushing shouldn't output anything, since we're still
491  // waiting for data for some tracks
492  check(out_size == 0, "delay_moov flushed prematurely");
493  // When closed (or manually flushed), all the written data should still
494  // be output.
495  finish();
496  close_out();
497  check(out_size > 0, "delay_moov didn't output anything");
498 
499  // Check that manually flushing still outputs things as expected. This
500  // produces two fragments, while the one above produces only one.
501  init_out("delay-moov-empty-track-flush");
502  av_dict_set(&opts, "movflags", "frag_custom+delay_moov", 0);
503  init(0, 0);
504  mux_gops(1);
505  av_write_frame(ctx, NULL); // Force writing the moov
506  check(out_size > 0, "No moov written");
507  av_write_frame(ctx, NULL);
508  mux_gops(1);
509  av_write_frame(ctx, NULL);
510  finish();
511  close_out();
512 
513  skip_write_audio = 0;
514 
515 
516 
517  // Verify that the header written by delay_moov when manually flushed
518  // is identical to the one by empty_moov.
519  init_out("empty-moov-header");
520  av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
521  av_dict_set(&opts, "use_editlist", "0", 0);
522  init(0, 0);
523  close_out();
524  memcpy(header, hash, HASH_SIZE);
525  init_out("empty-moov-content");
526  mux_gops(2);
527  // Written 2 seconds of content, with an automatic flush after 1 second.
528  check(out_size > 0, "No automatic flush?");
529  empty_moov_pos = prev_pos = out_size;
530  // Manually flush the second fragment
531  av_write_frame(ctx, NULL);
532  check(out_size > prev_pos, "No second fragment flushed?");
533  prev_pos = out_size;
534  // Check that an extra flush doesn't output any more data
535  av_write_frame(ctx, NULL);
536  check(out_size == prev_pos, "More data written?");
537  close_out();
538  memcpy(content, hash, HASH_SIZE);
539  // Ignore the trailer written here
540  finish();
541 
542  init_out("delay-moov-header");
543  av_dict_set(&opts, "movflags", "frag_custom+delay_moov", 0);
544  av_dict_set(&opts, "use_editlist", "0", 0);
545  init(0, 0);
546  check(out_size == 0, "Output written during init with delay_moov");
547  mux_gops(1); // Write 1 second of content
548  av_write_frame(ctx, NULL); // Force writing the moov
549  close_out();
550  check(!memcmp(hash, header, HASH_SIZE), "delay_moov header differs from empty_moov");
551  init_out("delay-moov-content");
552  av_write_frame(ctx, NULL); // Flush the first fragment
553  check(out_size == empty_moov_pos, "Manually flushed content differs from automatically flushed, %d vs %d", out_size, empty_moov_pos);
554  mux_gops(1); // Write the rest of the content
555  av_write_frame(ctx, NULL); // Flush the second fragment
556  close_out();
557  check(!memcmp(hash, content, HASH_SIZE), "delay_moov content differs from empty_moov");
558  finish();
559 
560 
561  // Verify that we can produce an identical second fragment without
562  // writing the first one. First write the reference fragments that
563  // we want to reproduce.
564  av_dict_set(&opts, "movflags", "frag_custom+empty_moov+dash", 0);
565  init(0, 0);
566  mux_gops(1);
567  av_write_frame(ctx, NULL); // Output the first fragment
568  init_out("empty-moov-second-frag");
569  mux_gops(1);
570  av_write_frame(ctx, NULL); // Output the second fragment
571  close_out();
572  memcpy(content, hash, HASH_SIZE);
573  finish();
574 
575  // Produce the same second fragment without actually writing the first
576  // one before.
577  av_dict_set(&opts, "movflags", "frag_custom+empty_moov+dash+frag_discont", 0);
578  av_dict_set(&opts, "fragment_index", "2", 0);
579  av_dict_set(&opts, "avoid_negative_ts", "0", 0);
580  av_dict_set(&opts, "use_editlist", "0", 0);
581  init(0, 0);
582  skip_gops(1);
583  init_out("empty-moov-second-frag-discont");
584  mux_gops(1);
585  av_write_frame(ctx, NULL); // Output the second fragment
586  close_out();
587  check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
588  finish();
589 
590  // Produce the same thing by using delay_moov, which requires a slightly
591  // different call sequence.
592  av_dict_set(&opts, "movflags", "frag_custom+delay_moov+dash+frag_discont", 0);
593  av_dict_set(&opts, "fragment_index", "2", 0);
594  init(0, 0);
595  skip_gops(1);
596  mux_gops(1);
597  av_write_frame(ctx, NULL); // Output the moov
598  init_out("delay-moov-second-frag-discont");
599  av_write_frame(ctx, NULL); // Output the second fragment
600  close_out();
601  check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
602  finish();
603 
604 
605  // Test discontinuously written fragments with B-frames (where the
606  // assumption of starting at pts=0 works) but not with audio preroll
607  // (which can't be guessed).
608  av_dict_set(&opts, "movflags", "frag_custom+delay_moov+dash", 0);
609  init(1, 0);
610  mux_gops(1);
611  init_out("delay-moov-elst-init");
612  av_write_frame(ctx, NULL); // Output the moov
613  close_out();
614  memcpy(header, hash, HASH_SIZE);
615  av_write_frame(ctx, NULL); // Output the first fragment
616  init_out("delay-moov-elst-second-frag");
617  mux_gops(1);
618  av_write_frame(ctx, NULL); // Output the second fragment
619  close_out();
620  memcpy(content, hash, HASH_SIZE);
621  finish();
622 
623  av_dict_set(&opts, "movflags", "frag_custom+delay_moov+dash+frag_discont", 0);
624  av_dict_set(&opts, "fragment_index", "2", 0);
625  init(1, 0);
626  skip_gops(1);
627  mux_gops(1); // Write the second fragment
628  init_out("delay-moov-elst-init-discont");
629  av_write_frame(ctx, NULL); // Output the moov
630  close_out();
631  check(!memcmp(hash, header, HASH_SIZE), "discontinuously written header differs");
632  init_out("delay-moov-elst-second-frag-discont");
633  av_write_frame(ctx, NULL); // Output the second fragment
634  close_out();
635  check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
636  finish();
637 
638 
639  // Test discontinuously written fragments with B-frames and audio preroll,
640  // properly signaled.
641  av_dict_set(&opts, "movflags", "frag_custom+delay_moov+dash", 0);
642  init(1, 1);
643  mux_gops(1);
644  init_out("delay-moov-elst-signal-init");
645  av_write_frame(ctx, NULL); // Output the moov
646  close_out();
647  memcpy(header, hash, HASH_SIZE);
648  av_write_frame(ctx, NULL); // Output the first fragment
649  init_out("delay-moov-elst-signal-second-frag");
650  mux_gops(1);
651  av_write_frame(ctx, NULL); // Output the second fragment
652  close_out();
653  memcpy(content, hash, HASH_SIZE);
654  finish();
655 
656  av_dict_set(&opts, "movflags", "frag_custom+delay_moov+dash+frag_discont", 0);
657  av_dict_set(&opts, "fragment_index", "2", 0);
658  init(1, 1);
659  signal_init_ts();
660  skip_gops(1);
661  mux_gops(1); // Write the second fragment
662  init_out("delay-moov-elst-signal-init-discont");
663  av_write_frame(ctx, NULL); // Output the moov
664  close_out();
665  check(!memcmp(hash, header, HASH_SIZE), "discontinuously written header differs");
666  init_out("delay-moov-elst-signal-second-frag-discont");
667  av_write_frame(ctx, NULL); // Output the second fragment
668  close_out();
669  check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
670  finish();
671 
672 
673  // Test muxing discontinuous fragments with very large (> (1<<31)) timestamps.
674  av_dict_set(&opts, "movflags", "frag_custom+delay_moov+dash+frag_discont", 0);
675  av_dict_set(&opts, "fragment_index", "2", 0);
676  init(1, 1);
677  signal_init_ts();
678  skip_gops(1);
679  mux_frames(gop_size, 1); // Write the second fragment
680  init_out("delay-moov-elst-signal-init-discont-largets");
681  av_write_frame(ctx, NULL); // Output the moov
682  close_out();
683  init_out("delay-moov-elst-signal-second-frag-discont-largets");
684  av_write_frame(ctx, NULL); // Output the second fragment
685  close_out();
686  finish();
687 
688  // Test VFR content, with sidx atoms (which declare the pts duration
689  // of a fragment, forcing overriding the start pts of the next one).
690  // Here, the fragment duration in pts is significantly different from
691  // the duration in dts. The video stream starts at dts=-10,pts=0, and
692  // the second fragment starts at dts=155,pts=156. The trun duration sum
693  // of the first fragment is 165, which also is written as
694  // baseMediaDecodeTime in the tfdt in the second fragment. The sidx for
695  // the first fragment says earliest_presentation_time = 0 and
696  // subsegment_duration = 156, which also matches the sidx in the second
697  // fragment. For the audio stream, the pts and dts durations also don't
698  // match - the input stream starts at pts=-2048, but that part is excluded
699  // by the edit list.
700  init_out("vfr");
701  av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov+dash", 0);
702  init_fps(1, 1, 3);
703  mux_frames(gop_size/2, 0);
704  duration /= 10;
705  mux_frames(gop_size/2, 0);
706  mux_gops(1);
707  finish();
708  close_out();
709 
710  // Test VFR content, with cleared duration fields. In these cases,
711  // the muxer must guess the duration of the last packet of each
712  // fragment. As long as the framerate doesn't vary (too much) at the
713  // fragment edge, it works just fine. Additionally, when automatically
714  // cutting fragments, the muxer already know the timestamps of the next
715  // packet for one stream (in most cases the video stream), avoiding
716  // having to use guesses for that one.
718  clear_duration = 1;
719  init_out("vfr-noduration");
720  av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov+dash", 0);
721  init_fps(1, 1, 3);
722  mux_frames(gop_size/2, 0);
723  duration /= 10;
724  mux_frames(gop_size/2, 0);
725  mux_gops(1);
726  finish();
727  close_out();
728  clear_duration = 0;
730  check(num_warnings > 0, "No warnings printed for filled in durations");
731 
732  // Test with an IO buffer size that is too small to hold a full fragment;
733  // this will cause write_data_type to be called with the type unknown.
734  force_iobuf_size = 1500;
735  init_out("large_frag");
736  av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov", 0);
737  init_fps(1, 1, 3);
738  mux_gops(2);
739  finish();
740  close_out();
741  force_iobuf_size = 0;
742 
743  // Test VFR content with bframes with interleaving.
744  // Here, using av_interleaved_write_frame allows the muxer to get the
745  // fragment end durations right. We always set the packet duration to
746  // the expected, but we simulate dropped frames at one point.
747  do_interleave = 1;
748  init_out("vfr-noduration-interleave");
749  av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov", 0);
750  av_dict_set(&opts, "frag_duration", "650000", 0);
751  init_fps(1, 1, 30);
752  mux_frames(gop_size/2, 0);
753  // Pretend that the packet duration is the normal, even if
754  // we actually skip a bunch of frames. (I.e., simulate that
755  // we don't know of the framedrop in advance.)
757  duration *= 10;
758  mux_frames(1, 0);
759  fake_pkt_duration = 0;
760  duration /= 10;
761  mux_frames(gop_size/2 - 1, 0);
762  mux_gops(1);
763  finish();
764  close_out();
765  clear_duration = 0;
766  do_interleave = 0;
767 
768  // Write a fragmented file with b-frames and audio preroll,
769  // with negative cts values, removing the edit list for the
770  // video track.
771  init_out("delay-moov-elst-neg-cts");
772  av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov+negative_cts_offsets", 0);
773  init(1, 1);
774  mux_gops(2);
775  finish();
776  close_out();
777 
778  // Write a fragmented file with b-frames without audio preroll,
779  // with negative cts values, avoiding any edit lists, allowing
780  // to use empty_moov instead of delay_moov.
781  init_out("empty-moov-neg-cts");
782  av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov+negative_cts_offsets", 0);
783  init(1, 0);
784  mux_gops(2);
785  finish();
786  close_out();
787 
788  av_free(md5);
789 
790  return check_faults > 0 ? 1 : 0;
791 }
#define NULL
Definition: coverity.c:32
int64_t video_dts
Definition: movenc.c:60
int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file ensuring correct interleaving.
Definition: mux.c:1192
int skip_write
Definition: movenc.c:69
static const uint8_t h264_extradata[]
Definition: movenc.c:39
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file.
Definition: mux.c:878
const char * fmt
Definition: avisynth_c.h:861
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
int bframes
Definition: movenc.c:62
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: avcodec.h:3957
int num
Numerator.
Definition: rational.h:59
static void count_warnings(void *avcl, int level, const char *fmt, va_list vl)
Definition: movenc.c:81
int size
Definition: avcodec.h:1478
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:675
GLint GLenum type
Definition: opengl_enc.c:104
int out_size
Definition: movenc.c:55
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:236
static AVPacket pkt
int num_warnings
Definition: movenc.c:76
static void mux_frames(int n, int c)
Definition: movenc.c:247
int fake_pkt_duration
Definition: movenc.c:74
enum AVPictureType last_picture
Definition: movenc.c:68
static int io_write_data_type(void *opaque, uint8_t *buf, int size, enum AVIODataMarkerType type, int64_t time)
Definition: movenc.c:107
void av_md5_update(AVMD5 *ctx, const uint8_t *src, int len)
Update hash value.
Definition: md5.c:154
Trailer data, which doesn&#39;t contain actual content, but only for finalizing the output file...
Definition: avio.h:140
Format I/O context.
Definition: avformat.h:1358
const char * cur_name
Definition: movenc.c:53
int64_t audio_dts
Definition: movenc.c:60
struct AVMD5 * av_md5_alloc(void)
Allocate an AVMD5 context.
Definition: md5.c:48
uint8_t
int width
Video only.
Definition: avcodec.h:4023
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: avcodec.h:1495
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
GLsizei GLboolean const GLfloat * value
Definition: opengl_enc.c:108
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
Definition: utils.c:4465
int64_t duration
Definition: movenc.c:63
A point in the output bytestream where a demuxer can start parsing (for non self synchronizing bytest...
Definition: avio.h:128
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
Definition: options.c:144
struct AVMD5 * md5
Definition: movenc.c:56
static void finish(void)
Definition: movenc.c:345
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1489
uint8_t * data
Definition: avcodec.h:1477
static void reset_count_warnings(void)
Definition: movenc.c:93
ptrdiff_t size
Definition: opengl_enc.c:100
static const uint8_t header[24]
Definition: sdr2.c:67
Definition: md5.c:40
#define AVFMT_FLAG_BITEXACT
When muxing, try to avoid writing any random/volatile data to the output.
Definition: avformat.h:1506
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: avcodec.h:1509
uint8_t hash[HASH_SIZE]
Definition: movenc.c:57
uint8_t iobuf[32768]
Definition: movenc.c:49
AVIOContext * avio_alloc_context(unsigned char *buffer, int buffer_size, int write_flag, void *opaque, int(*read_packet)(void *opaque, uint8_t *buf, int buf_size), int(*write_packet)(void *opaque, uint8_t *buf, int buf_size), int64_t(*seek)(void *opaque, int64_t offset, int whence))
Allocate and initialize an AVIOContext for buffered I/O.
Definition: aviobuf.c:131
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
AVStream * video_st
Definition: movenc.c:59
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values. ...
Definition: dict.c:203
enum AVMediaType codec_type
General type of the encoded data.
Definition: avcodec.h:3953
Definition: graph2dot.c:48
void av_log_default_callback(void *ptr, int level, const char *fmt, va_list vl)
Default logging callback.
Definition: log.c:300
int flags
A combination of AV_PKT_FLAG values.
Definition: avcodec.h:1483
int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b)
Compare two timestamps each in its own time base.
Definition: mathematics.c:147
int extradata_size
Size of the extradata content in bytes.
Definition: avcodec.h:3975
int gop_size
Definition: movenc.c:66
static void init_fps(int bf, int audio_preroll, int fps)
Definition: movenc.c:178
AVDictionary * opts
Definition: movenc.c:50
#define HASH_SIZE
Definition: movenc.c:37
This is any, unlabelled data.
Definition: avio.h:135
av_warn_unused_result int avformat_write_header(AVFormatContext *s, AVDictionary **options)
Allocate the stream private data and write the stream header to an output media file.
Definition: mux.c:508
void av_log_set_callback(void(*callback)(void *, int, const char *, va_list))
Set the logging callback.
Definition: log.c:400
AVIODataMarkerType
Different data types that can be returned via the AVIO write_data_type callback.
Definition: avio.h:111
AVFormatContext * ctx
Definition: movenc.c:48
int n
Definition: avisynth_c.h:760
int force_iobuf_size
Definition: movenc.c:72
int frames
Definition: movenc.c:65
int write_file
Definition: movenc.c:52
int64_t next_p_pts
Definition: movenc.c:67
static void mux_gops(int n)
Definition: movenc.c:316
int64_t audio_duration
Definition: movenc.c:64
ff_const59 struct AVOutputFormat * oformat
The output container format.
Definition: avformat.h:1377
static void help(void)
Definition: movenc.c:353
Stream structure.
Definition: avformat.h:881
AVIOContext * pb
I/O context.
Definition: avformat.h:1400
AVStream * audio_st
Definition: movenc.c:59
static void close_out(void)
Definition: movenc.c:152
static int getopt(int argc, char *argv[], char *opts)
Definition: getopt.c:41
void av_md5_init(AVMD5 *ctx)
Initialize MD5 hashing.
Definition: md5.c:143
void * buf
Definition: avisynth_c.h:766
int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags)
Set the given entry in *pm, overwriting an existing entry.
Definition: dict.c:70
static const char * format
Definition: movenc.c:47
#define AV_WB32(p, v)
Definition: intreadwrite.h:419
ff_const59 AVOutputFormat * av_guess_format(const char *short_name, const char *filename, const char *mime_type)
Return the output format in the list of registered output formats which best matches the provided par...
Definition: format.c:51
AVPictureType
Definition: avutil.h:272
#define snprintf
Definition: snprintf.h:34
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition: utils.c:4399
void av_md5_final(AVMD5 *ctx, uint8_t *dst)
Finish hashing and output digest value.
Definition: md5.c:192
static void init_out(const char *name)
Definition: movenc.c:137
#define check(value,...)
Definition: movenc.c:176
int skip_write_audio
Definition: movenc.c:70
int do_interleave
Definition: movenc.c:73
uint8_t level
Definition: svq3.c:207
static void init_count_warnings(void)
Definition: movenc.c:87
int check_faults
Definition: movenc.c:78
int sample_rate
Audio only.
Definition: avcodec.h:4067
Main libavformat public API header.
int clear_duration
Definition: movenc.c:71
int(* write_data_type)(void *opaque, uint8_t *buf, int buf_size, enum AVIODataMarkerType type, int64_t time)
A callback that is used instead of write_packet.
Definition: avio.h:319
void avio_context_free(AVIOContext **s)
Free the supplied IO context and everything associated with it.
Definition: aviobuf.c:148
int main(int argc, char **argv)
Definition: movenc.c:359
Bi-dir predicted.
Definition: avutil.h:276
static void init(int bf, int audio_preroll)
Definition: movenc.c:242
void av_init_packet(AVPacket *pkt)
Initialize optional fields of a packet with default values.
Definition: avpacket.c:33
static void signal_init_ts(void)
Definition: movenc.c:328
int den
Denominator.
Definition: rational.h:60
#define AV_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding...
Definition: avcodec.h:790
static void skip_gops(int n)
Definition: movenc.c:321
A point in the output bytestream where a decoder can start decoding (i.e.
Definition: avio.h:122
#define av_free(p)
printf("static const uint8_t my_array[100] = {\n")
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: avcodec.h:3971
int channels
Audio only.
Definition: avcodec.h:4063
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
Definition: avcodec.h:1476
int av_write_trailer(AVFormatContext *s)
Write the stream trailer to an output media file and free the file private data.
Definition: mux.c:1254
static int io_write(void *opaque, uint8_t *buf, int size)
Definition: movenc.c:98
FILE * out
Definition: movenc.c:54
Public header for MD5 hash function implementation.
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1028
static const uint8_t aac_extradata[]
Definition: movenc.c:42
int stream_index
Definition: avcodec.h:1479
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
Definition: avformat.h:910
This structure stores compressed data.
Definition: avcodec.h:1454
static void check_func(int value, int line, const char *msg,...)
Definition: movenc.c:164
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: avcodec.h:1470
Header data; this needs to be present for the stream to be decodeable.
Definition: avio.h:115
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
Predicted.
Definition: avutil.h:275
const char * name
Definition: opengl_enc.c:102