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 #include "libavutil/mem.h"
27 
28 #include "libavformat/avformat.h"
29 
30 #if HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 
34 #if !HAVE_GETOPT
35 #include "compat/getopt.c"
36 #endif
37 
38 #define HASH_SIZE 16
39 
40 static const uint8_t h264_extradata[] = {
41  0x01, 0x4d, 0x40, 0x1e, 0xff, 0xe1, 0x00, 0x02, 0x67, 0x4d, 0x01, 0x00, 0x02, 0x68, 0xef
42 };
43 static const uint8_t aac_extradata[] = {
44  0x12, 0x10
45 };
46 
47 
48 static const char *format = "mp4";
50 uint8_t iobuf[32768];
52 
54 const char *cur_name;
55 FILE* out;
57 struct AVMD5* md5;
58 uint8_t hash[HASH_SIZE];
59 
63 
64 int bframes;
65 int64_t duration;
67 int frames;
69 int64_t next_p_pts;
77 
79 
81 
82 
83 static void count_warnings(void *avcl, int level, const char *fmt, va_list vl)
84 {
85  if (level == AV_LOG_WARNING)
86  num_warnings++;
87 }
88 
89 static void init_count_warnings(void)
90 {
92  num_warnings = 0;
93 }
94 
95 static void reset_count_warnings(void)
96 {
98 }
99 
100 static int io_write(void *opaque, const uint8_t *buf, int size)
101 {
102  out_size += size;
103  av_md5_update(md5, buf, size);
104  if (out)
105  fwrite(buf, 1, size, out);
106  return size;
107 }
108 
109 static int io_write_data_type(void *opaque, const uint8_t *buf, int size,
110  enum AVIODataMarkerType type, int64_t time)
111 {
112  char timebuf[30], content[5] = { 0 };
113  const char *str;
114  switch (type) {
115  case AVIO_DATA_MARKER_HEADER: str = "header"; break;
116  case AVIO_DATA_MARKER_SYNC_POINT: str = "sync"; break;
117  case AVIO_DATA_MARKER_BOUNDARY_POINT: str = "boundary"; break;
118  case AVIO_DATA_MARKER_UNKNOWN: str = "unknown"; break;
119  case AVIO_DATA_MARKER_TRAILER: str = "trailer"; break;
120  default: str = "unknown"; break;
121  }
122  if (time == AV_NOPTS_VALUE)
123  snprintf(timebuf, sizeof(timebuf), "nopts");
124  else
125  snprintf(timebuf, sizeof(timebuf), "%"PRId64, time);
126  // There can be multiple header/trailer callbacks, only log the box type
127  // for header at out_size == 0
130  (type != AVIO_DATA_MARKER_HEADER || out_size == 0) &&
131  size >= 8)
132  memcpy(content, &buf[4], 4);
133  else
134  snprintf(content, sizeof(content), "-");
135  printf("write_data len %d, time %s, type %s atom %s\n", size, timebuf, str, content);
136  return io_write(opaque, buf, size);
137 }
138 
139 static void init_out(const char *name)
140 {
141  char buf[100];
142  cur_name = name;
143  snprintf(buf, sizeof(buf), "%s.%s", cur_name, format);
144 
145  av_md5_init(md5);
146  if (write_file) {
147  out = fopen(buf, "wb");
148  if (!out)
149  perror(buf);
150  }
151  out_size = 0;
152 }
153 
154 static void close_out(void)
155 {
156  int i;
158  for (i = 0; i < HASH_SIZE; i++)
159  printf("%02x", hash[i]);
160  printf(" %d %s\n", out_size, cur_name);
161  if (out)
162  fclose(out);
163  out = NULL;
164 }
165 
166 static void check_func(int value, int line, const char *msg, ...)
167 {
168  if (!value) {
169  va_list ap;
170  va_start(ap, msg);
171  printf("%d: ", line);
172  vprintf(msg, ap);
173  printf("\n");
174  check_faults++;
175  va_end(ap);
176  }
177 }
178 #define check(value, ...) check_func(value, __LINE__, __VA_ARGS__)
179 
180 static void init_fps(int bf, int audio_preroll, int fps, int id3)
181 {
182  AVStream *st;
183  int iobuf_size = force_iobuf_size ? force_iobuf_size : sizeof(iobuf);
185  if (!ctx)
186  exit(1);
188  if (!ctx->oformat)
189  exit(1);
190  ctx->pb = avio_alloc_context(iobuf, iobuf_size, 1, NULL, NULL, io_write, NULL);
191  if (!ctx->pb)
192  exit(1);
195 
197  if (!st)
198  exit(1);
201  st->codecpar->width = 640;
202  st->codecpar->height = 480;
203  st->time_base.num = 1;
204  st->time_base.den = 30;
205  st->codecpar->extradata_size = sizeof(h264_extradata);
207  if (!st->codecpar->extradata)
208  exit(1);
209  memcpy(st->codecpar->extradata, h264_extradata, sizeof(h264_extradata));
210  video_st = st;
211 
213  if (!st)
214  exit(1);
217  st->codecpar->sample_rate = 44100;
218  st->codecpar->frame_size = 1024;
220  st->time_base.num = 1;
221  st->time_base.den = 44100;
222  st->codecpar->extradata_size = sizeof(aac_extradata);
224  if (!st->codecpar->extradata)
225  exit(1);
226  memcpy(st->codecpar->extradata, aac_extradata, sizeof(aac_extradata));
227  audio_st = st;
228 
229  if (id3) {
231  if (!st)
232  exit(1);
235  st->time_base.num = 1;
236  st->time_base.den = 1000;
237  id3_st = st;
238  }
239 
240  if (avformat_write_header(ctx, &opts) < 0)
241  exit(1);
242  av_dict_free(&opts);
243 
244  frames = 0;
245  gop_size = 30;
246  duration = video_st->time_base.den / fps;
247  audio_duration = (long long)audio_st->codecpar->frame_size *
249  if (audio_preroll)
250  audio_preroll = 2 * audio_duration;
251 
252  bframes = bf;
253  video_dts = bframes ? -duration : 0;
254  audio_dts = -audio_preroll;
255 }
256 
257 static void init(int bf, int audio_preroll)
258 {
259  init_fps(bf, audio_preroll, 30, 0);
260 }
261 
262 static void mux_frames(int n, int c)
263 {
264  int end_frames = frames + n;
265  while (1) {
266  uint8_t pktdata[8] = { 0 };
268 
270  pkt->dts = pkt->pts = audio_dts;
271  pkt->stream_index = 1;
274  } else {
275  if (frames == end_frames)
276  break;
277  pkt->dts = video_dts;
278  pkt->stream_index = 0;
279  pkt->duration = duration;
280  if ((frames % gop_size) == 0) {
283  pkt->pts = pkt->dts + duration;
284  video_dts = pkt->pts;
285  } else {
288  pkt->pts = pkt->dts;
290  } else {
292  if (((frames + 1) % gop_size) == 0) {
293  pkt->pts = pkt->dts + duration;
294  video_dts = pkt->pts;
295  } else {
296  next_p_pts = pkt->pts = pkt->dts + 2 * duration;
297  video_dts += duration;
298  }
299  }
300  }
301  if (!bframes)
302  pkt->pts = pkt->dts;
303  if (fake_pkt_duration)
305  frames++;
306  }
307 
308  if (clear_duration)
309  pkt->duration = 0;
310  AV_WB32(pktdata + 4, pkt->pts);
311  pkt->data = pktdata;
312  pkt->size = 8;
313  if (skip_write)
314  continue;
315  if (skip_write_audio && pkt->stream_index == 1)
316  continue;
317 
318  if (c) {
319  pkt->pts += (1LL<<32);
320  pkt->dts += (1LL<<32);
321  }
322 
323  if (do_interleave)
325  else
327  }
328 }
329 
330 static void mux_id3(void)
331 {
332  uint8_t pktdata[8] = { 0 };
334 
338  pkt->duration = 0;
339 
340  AV_WB32(pktdata + 4, pkt->pts);
341  pkt->data = pktdata;
342  pkt->size = 8;
343 
345 }
346 
347 static void mux_gops(int n)
348 {
349  mux_frames(gop_size * n, 0);
350 }
351 
352 static void skip_gops(int n)
353 {
354  skip_write = 1;
355  mux_gops(n);
356  skip_write = 0;
357 }
358 
359 static void signal_init_ts(void)
360 {
362 
363  pkt->stream_index = 0;
364  pkt->dts = video_dts;
365  pkt->pts = 0;
367 
368  pkt->stream_index = 1;
369  pkt->dts = pkt->pts = audio_dts;
371 }
372 
373 static void finish(void)
374 {
378  ctx = NULL;
379 }
380 
381 static void help(void)
382 {
383  printf("movenc-test [-w]\n"
384  "-w write output into files\n");
385 }
386 
387 int main(int argc, char **argv)
388 {
389  int c;
390  uint8_t header[HASH_SIZE];
391  uint8_t content[HASH_SIZE];
392  int empty_moov_pos;
393  int prev_pos;
394 
395  for (;;) {
396  c = getopt(argc, argv, "wh");
397  if (c == -1)
398  break;
399  switch (c) {
400  case 'w':
401  write_file = 1;
402  break;
403  default:
404  case 'h':
405  help();
406  return 0;
407  }
408  }
409 
410  md5 = av_md5_alloc();
411  if (!md5)
412  return 1;
413  pkt = av_packet_alloc();
414  if (!pkt) {
415  av_free(md5);
416  return 1;
417  }
418 
419  // Write a fragmented file with an initial moov that actually contains some
420  // samples. One moov+mdat with 1 second of data and one moof+mdat with 1
421  // second of data.
422  init_out("non-empty-moov");
423  av_dict_set(&opts, "movflags", "+frag_keyframe", 0);
424  init(0, 0);
425  mux_gops(2);
426  finish();
427  close_out();
428 
429  // Write a similar file, but with B-frames and audio preroll, handled
430  // via an edit list.
431  init_out("non-empty-moov-elst");
432  av_dict_set(&opts, "movflags", "+frag_keyframe", 0);
433  av_dict_set(&opts, "use_editlist", "1", 0);
434  init(1, 1);
435  mux_gops(2);
436  finish();
437  close_out();
438 
439  // Use B-frames but no audio-preroll, but without an edit list.
440  // Due to avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO, the dts
441  // of the first audio packet is > 0, but it is set to zero since edit
442  // lists aren't used, increasing the duration of the first packet instead.
443  init_out("non-empty-moov-no-elst");
444  av_dict_set(&opts, "movflags", "+frag_keyframe", 0);
445  av_dict_set(&opts, "use_editlist", "0", 0);
446  init(1, 0);
447  mux_gops(2);
448  finish();
449  close_out();
450 
451  format = "ismv";
452  // Write an ISMV, with B-frames and audio preroll.
453  init_out("ismv");
454  av_dict_set(&opts, "movflags", "+frag_keyframe", 0);
455  init(1, 1);
456  mux_gops(2);
457  finish();
458  close_out();
459  format = "mp4";
460 
461  // An initial moov that doesn't contain any samples, followed by two
462  // moof+mdat pairs.
463  init_out("empty-moov");
464  av_dict_set(&opts, "movflags", "+frag_keyframe+empty_moov", 0);
465  av_dict_set(&opts, "use_editlist", "0", 0);
466  init(0, 0);
467  mux_gops(2);
468  finish();
469  close_out();
470  memcpy(content, hash, HASH_SIZE);
471 
472  // Similar to the previous one, but with input that doesn't start at
473  // pts/dts 0. avoid_negative_ts behaves in the same way as
474  // in non-empty-moov-no-elst above.
476  init_out("empty-moov-no-elst");
477  av_dict_set(&opts, "movflags", "+frag_keyframe+empty_moov", 0);
478  init(1, 0);
479  mux_gops(2);
480  finish();
481  close_out();
482 
484  check(num_warnings == 0, "Unexpected warnings printed");
485 
486  // Same as the previous one, but disable avoid_negative_ts (which
487  // would require using an edit list, but with empty_moov, one can't
488  // write a sensible edit list, when the start timestamps aren't known).
489  // This should trigger a warning - we check that the warning is produced.
491  init_out("empty-moov-no-elst-no-adjust");
492  av_dict_set(&opts, "movflags", "+frag_keyframe+empty_moov", 0);
493  av_dict_set(&opts, "avoid_negative_ts", "disabled", 0);
494  init(1, 0);
495  mux_gops(2);
496  finish();
497  close_out();
498 
500  check(num_warnings > 0, "No warnings printed for unhandled start offset");
501 
502  // Verify that delay_moov produces the same as empty_moov for
503  // simple input
504  init_out("delay-moov");
505  av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov", 0);
506  av_dict_set(&opts, "use_editlist", "0", 0);
507  init(0, 0);
508  mux_gops(2);
509  finish();
510  close_out();
511  check(!memcmp(hash, content, HASH_SIZE), "delay_moov differs from empty_moov");
512 
513  // Test writing content that requires an edit list using delay_moov
514  init_out("delay-moov-elst");
515  av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov", 0);
516  init(1, 1);
517  mux_gops(2);
518  finish();
519  close_out();
520 
521  // Test writing a file with one track lacking packets, with delay_moov.
522  skip_write_audio = 1;
523  init_out("delay-moov-empty-track");
524  av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov", 0);
525  init(0, 0);
526  mux_gops(2);
527  // The automatic flushing shouldn't output anything, since we're still
528  // waiting for data for some tracks
529  check(out_size == 0, "delay_moov flushed prematurely");
530  // When closed (or manually flushed), all the written data should still
531  // be output.
532  finish();
533  close_out();
534  check(out_size > 0, "delay_moov didn't output anything");
535 
536  // Check that manually flushing still outputs things as expected. This
537  // produces two fragments, while the one above produces only one.
538  init_out("delay-moov-empty-track-flush");
539  av_dict_set(&opts, "movflags", "+frag_custom+delay_moov", 0);
540  init(0, 0);
541  mux_gops(1);
542  av_write_frame(ctx, NULL); // Force writing the moov
543  check(out_size > 0, "No moov written");
545  mux_gops(1);
547  finish();
548  close_out();
549 
550  skip_write_audio = 0;
551 
552 
553 
554  // Verify that the header written by delay_moov when manually flushed
555  // is identical to the one by empty_moov.
556  init_out("empty-moov-header");
557  av_dict_set(&opts, "movflags", "+frag_keyframe+empty_moov", 0);
558  av_dict_set(&opts, "use_editlist", "0", 0);
559  init(0, 0);
560  close_out();
561  memcpy(header, hash, HASH_SIZE);
562  init_out("empty-moov-content");
563  mux_gops(2);
564  // Written 2 seconds of content, with an automatic flush after 1 second.
565  check(out_size > 0, "No automatic flush?");
566  empty_moov_pos = prev_pos = out_size;
567  // Manually flush the second fragment
569  check(out_size > prev_pos, "No second fragment flushed?");
570  prev_pos = out_size;
571  // Check that an extra flush doesn't output any more data
573  check(out_size == prev_pos, "More data written?");
574  close_out();
575  memcpy(content, hash, HASH_SIZE);
576  // Ignore the trailer written here
577  finish();
578 
579  init_out("delay-moov-header");
580  av_dict_set(&opts, "movflags", "+frag_custom+delay_moov", 0);
581  av_dict_set(&opts, "use_editlist", "0", 0);
582  init(0, 0);
583  check(out_size == 0, "Output written during init with delay_moov");
584  mux_gops(1); // Write 1 second of content
585  av_write_frame(ctx, NULL); // Force writing the moov
586  close_out();
587  check(!memcmp(hash, header, HASH_SIZE), "delay_moov header differs from empty_moov");
588  init_out("delay-moov-content");
589  av_write_frame(ctx, NULL); // Flush the first fragment
590  check(out_size == empty_moov_pos, "Manually flushed content differs from automatically flushed, %d vs %d", out_size, empty_moov_pos);
591  mux_gops(1); // Write the rest of the content
592  av_write_frame(ctx, NULL); // Flush the second fragment
593  close_out();
594  check(!memcmp(hash, content, HASH_SIZE), "delay_moov content differs from empty_moov");
595  finish();
596 
597 
598  // Verify that we can produce an identical second fragment without
599  // writing the first one. First write the reference fragments that
600  // we want to reproduce.
601  av_dict_set(&opts, "movflags", "+frag_custom+empty_moov+dash", 0);
602  init(0, 0);
603  mux_gops(1);
604  av_write_frame(ctx, NULL); // Output the first fragment
605  init_out("empty-moov-second-frag");
606  mux_gops(1);
607  av_write_frame(ctx, NULL); // Output the second fragment
608  close_out();
609  memcpy(content, hash, HASH_SIZE);
610  finish();
611 
612  // Produce the same second fragment without actually writing the first
613  // one before.
614  av_dict_set(&opts, "movflags", "+frag_custom+empty_moov+dash+frag_discont", 0);
615  av_dict_set(&opts, "fragment_index", "2", 0);
616  av_dict_set(&opts, "avoid_negative_ts", "disabled", 0);
617  av_dict_set(&opts, "use_editlist", "0", 0);
618  init(0, 0);
619  skip_gops(1);
620  init_out("empty-moov-second-frag-discont");
621  mux_gops(1);
622  av_write_frame(ctx, NULL); // Output the second fragment
623  close_out();
624  check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
625  finish();
626 
627  // Produce the same thing by using delay_moov, which requires a slightly
628  // different call sequence.
629  av_dict_set(&opts, "movflags", "+frag_custom+delay_moov+dash+frag_discont", 0);
630  av_dict_set(&opts, "fragment_index", "2", 0);
631  init(0, 0);
632  skip_gops(1);
633  mux_gops(1);
634  av_write_frame(ctx, NULL); // Output the moov
635  init_out("delay-moov-second-frag-discont");
636  av_write_frame(ctx, NULL); // Output the second fragment
637  close_out();
638  check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
639  finish();
640 
641 
642  // Test discontinuously written fragments with B-frames (where the
643  // assumption of starting at pts=0 works) but not with audio preroll
644  // (which can't be guessed).
645  av_dict_set(&opts, "movflags", "+frag_custom+delay_moov+dash", 0);
646  init(1, 0);
647  mux_gops(1);
648  init_out("delay-moov-elst-init");
649  av_write_frame(ctx, NULL); // Output the moov
650  close_out();
651  memcpy(header, hash, HASH_SIZE);
652  av_write_frame(ctx, NULL); // Output the first fragment
653  init_out("delay-moov-elst-second-frag");
654  mux_gops(1);
655  av_write_frame(ctx, NULL); // Output the second fragment
656  close_out();
657  memcpy(content, hash, HASH_SIZE);
658  finish();
659 
660  av_dict_set(&opts, "movflags", "+frag_custom+delay_moov+dash+frag_discont", 0);
661  av_dict_set(&opts, "fragment_index", "2", 0);
662  init(1, 0);
663  skip_gops(1);
664  mux_gops(1); // Write the second fragment
665  init_out("delay-moov-elst-init-discont");
666  av_write_frame(ctx, NULL); // Output the moov
667  close_out();
668  check(!memcmp(hash, header, HASH_SIZE), "discontinuously written header differs");
669  init_out("delay-moov-elst-second-frag-discont");
670  av_write_frame(ctx, NULL); // Output the second fragment
671  close_out();
672  check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
673  finish();
674 
675 
676  // Test discontinuously written fragments with B-frames and audio preroll,
677  // properly signaled.
678  av_dict_set(&opts, "movflags", "+frag_custom+delay_moov+dash", 0);
679  init(1, 1);
680  mux_gops(1);
681  init_out("delay-moov-elst-signal-init");
682  av_write_frame(ctx, NULL); // Output the moov
683  close_out();
684  memcpy(header, hash, HASH_SIZE);
685  av_write_frame(ctx, NULL); // Output the first fragment
686  init_out("delay-moov-elst-signal-second-frag");
687  mux_gops(1);
688  av_write_frame(ctx, NULL); // Output the second fragment
689  close_out();
690  memcpy(content, hash, HASH_SIZE);
691  finish();
692 
693  av_dict_set(&opts, "movflags", "+frag_custom+delay_moov+dash+frag_discont", 0);
694  av_dict_set(&opts, "fragment_index", "2", 0);
695  init(1, 1);
696  signal_init_ts();
697  skip_gops(1);
698  mux_gops(1); // Write the second fragment
699  init_out("delay-moov-elst-signal-init-discont");
700  av_write_frame(ctx, NULL); // Output the moov
701  close_out();
702  check(!memcmp(hash, header, HASH_SIZE), "discontinuously written header differs");
703  init_out("delay-moov-elst-signal-second-frag-discont");
704  av_write_frame(ctx, NULL); // Output the second fragment
705  close_out();
706  check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
707  finish();
708 
709 
710  // Test muxing discontinuous fragments with very large (> (1<<31)) timestamps.
711  av_dict_set(&opts, "movflags", "+frag_custom+delay_moov+dash+frag_discont", 0);
712  av_dict_set(&opts, "fragment_index", "2", 0);
713  init(1, 1);
714  signal_init_ts();
715  skip_gops(1);
716  mux_frames(gop_size, 1); // Write the second fragment
717  init_out("delay-moov-elst-signal-init-discont-largets");
718  av_write_frame(ctx, NULL); // Output the moov
719  close_out();
720  init_out("delay-moov-elst-signal-second-frag-discont-largets");
721  av_write_frame(ctx, NULL); // Output the second fragment
722  close_out();
723  finish();
724 
725  // Test VFR content, with sidx atoms (which declare the pts duration
726  // of a fragment, forcing overriding the start pts of the next one).
727  // Here, the fragment duration in pts is significantly different from
728  // the duration in dts. The video stream starts at dts=-10,pts=0, and
729  // the second fragment starts at dts=155,pts=156. The trun duration sum
730  // of the first fragment is 165, which also is written as
731  // baseMediaDecodeTime in the tfdt in the second fragment. The sidx for
732  // the first fragment says earliest_presentation_time = 0 and
733  // subsegment_duration = 156, which also matches the sidx in the second
734  // fragment. For the audio stream, the pts and dts durations also don't
735  // match - the input stream starts at pts=-2048, but that part is excluded
736  // by the edit list.
737  init_out("vfr");
738  av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov+dash", 0);
739  init_fps(1, 1, 3, 0);
740  mux_frames(gop_size/2, 0);
741  duration /= 10;
742  mux_frames(gop_size/2, 0);
743  mux_gops(1);
744  finish();
745  close_out();
746 
747  // Test VFR content, with cleared duration fields. In these cases,
748  // the muxer must guess the duration of the last packet of each
749  // fragment. As long as the framerate doesn't vary (too much) at the
750  // fragment edge, it works just fine. Additionally, when automatically
751  // cutting fragments, the muxer already know the timestamps of the next
752  // packet for one stream (in most cases the video stream), avoiding
753  // having to use guesses for that one.
755  clear_duration = 1;
756  init_out("vfr-noduration");
757  av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov+dash", 0);
758  init_fps(1, 1, 3, 0);
759  mux_frames(gop_size/2, 0);
760  duration /= 10;
761  mux_frames(gop_size/2, 0);
762  mux_gops(1);
763  finish();
764  close_out();
765  clear_duration = 0;
767  check(num_warnings > 0, "No warnings printed for filled in durations");
768 
769  // Test with an IO buffer size that is too small to hold a full fragment;
770  // this will cause write_data_type to be called with the type unknown.
771  force_iobuf_size = 1500;
772  init_out("large_frag");
773  av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov", 0);
774  init_fps(1, 1, 3, 0);
775  mux_gops(2);
776  finish();
777  close_out();
778  force_iobuf_size = 0;
779 
780  // Test VFR content with bframes with interleaving.
781  // Here, using av_interleaved_write_frame allows the muxer to get the
782  // fragment end durations right. We always set the packet duration to
783  // the expected, but we simulate dropped frames at one point.
784  do_interleave = 1;
785  init_out("vfr-noduration-interleave");
786  av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov", 0);
787  av_dict_set(&opts, "frag_duration", "650000", 0);
788  init_fps(1, 1, 30, 0);
789  mux_frames(gop_size/2, 0);
790  // Pretend that the packet duration is the normal, even if
791  // we actually skip a bunch of frames. (I.e., simulate that
792  // we don't know of the framedrop in advance.)
794  duration *= 10;
795  mux_frames(1, 0);
796  fake_pkt_duration = 0;
797  duration /= 10;
798  mux_frames(gop_size/2 - 1, 0);
799  mux_gops(1);
800  finish();
801  close_out();
802  clear_duration = 0;
803  do_interleave = 0;
804 
805  // Write a fragmented file with b-frames and audio preroll,
806  // with negative cts values, removing the edit list for the
807  // video track.
808  init_out("delay-moov-elst-neg-cts");
809  av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov+negative_cts_offsets", 0);
810  init(1, 1);
811  mux_gops(2);
812  finish();
813  close_out();
814 
815  // Write a fragmented file with b-frames without audio preroll,
816  // with negative cts values, avoiding any edit lists, allowing
817  // to use empty_moov instead of delay_moov.
818  init_out("empty-moov-neg-cts");
819  av_dict_set(&opts, "movflags", "+frag_keyframe+empty_moov+negative_cts_offsets", 0);
820  init(1, 0);
821  mux_gops(2);
822  finish();
823  close_out();
824 
825  // Write a manually fragmented file, with timed ID3 packets at the head
826  // of each fragment.
827  init_out("emsg");
828  av_dict_set(&opts, "movflags", "+frag_custom+cmaf", 0);
829  init_fps(1, 0, 30, 1);
830  mux_id3();
831  mux_gops(2);
832  av_write_frame(ctx, NULL); // Flush fragment.
833  mux_id3();
834  mux_gops(2);
835  finish();
836  close_out();
837 
838  av_free(md5);
840 
841  return check_faults > 0 ? 1 : 0;
842 }
aac_extradata
static const uint8_t aac_extradata[]
Definition: movenc.c:43
av_packet_unref
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: packet.c:427
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
skip_write
int skip_write
Definition: movenc.c:71
AVCodecParameters::extradata
uint8_t * extradata
Extra binary data needed for initializing the decoder, codec-dependent.
Definition: codec_par.h:69
name
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
level
uint8_t level
Definition: svq3.c:205
AVIO_DATA_MARKER_BOUNDARY_POINT
@ AVIO_DATA_MARKER_BOUNDARY_POINT
A point in the output bytestream where a demuxer can start parsing (for non self synchronizing bytest...
Definition: avio.h:127
cur_name
const char * cur_name
Definition: movenc.c:54
AVCodecParameters::codec_type
enum AVMediaType codec_type
General type of the encoded data.
Definition: codec_par.h:51
av_compare_ts
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
out
FILE * out
Definition: movenc.c:55
AV_CHANNEL_LAYOUT_STEREO
#define AV_CHANNEL_LAYOUT_STEREO
Definition: channel_layout.h:379
avformat_new_stream
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
h264_extradata
static const uint8_t h264_extradata[]
Definition: movenc.c:40
avio_context_free
void avio_context_free(AVIOContext **s)
Free the supplied IO context and everything associated with it.
Definition: aviobuf.c:126
AVPictureType
AVPictureType
Definition: avutil.h:277
audio_dts
int64_t audio_dts
Definition: movenc.c:62
out_size
int out_size
Definition: movenc.c:56
AVPacket::data
uint8_t * data
Definition: packet.h:524
avio_alloc_context
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, const 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:109
num_warnings
int num_warnings
Definition: movenc.c:78
last_picture
enum AVPictureType last_picture
Definition: movenc.c:70
check_func
static void check_func(int value, int line, const char *msg,...)
Definition: movenc.c:166
AVPacket::duration
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: packet.h:542
bframes
int bframes
Definition: movenc.c:64
mathematics.h
AVDictionary
Definition: dict.c:34
AVIODataMarkerType
AVIODataMarkerType
Different data types that can be returned via the AVIO write_data_type callback.
Definition: avio.h:110
hash
uint8_t hash[HASH_SIZE]
Definition: movenc.c:58
AV_PKT_FLAG_KEY
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: packet.h:579
av_packet_free
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition: packet.c:74
video_dts
int64_t video_dts
Definition: movenc.c:62
finish
static void finish(void)
Definition: movenc.c:373
fake_pkt_duration
int fake_pkt_duration
Definition: movenc.c:76
md5
struct AVMD5 * md5
Definition: movenc.c:57
AVIOContext::write_data_type
int(* write_data_type)(void *opaque, const uint8_t *buf, int buf_size, enum AVIODataMarkerType type, int64_t time)
A callback that is used instead of write_packet.
Definition: avio.h:283
type
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf type
Definition: writing_filters.txt:86
AVMD5
Definition: md5.c:42
AVRational::num
int num
Numerator.
Definition: rational.h:59
gop_size
int gop_size
Definition: movenc.c:68
pkt
AVPacket * pkt
Definition: movenc.c:60
mux_frames
static void mux_frames(int n, int c)
Definition: movenc.c:262
getopt
static int getopt(int argc, char *argv[], char *opts)
Definition: getopt.c:41
duration
int64_t duration
Definition: movenc.c:65
AVCodecParameters::frame_size
int frame_size
Audio only.
Definition: codec_par.h:195
intreadwrite.h
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1406
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
AVCodecParameters::width
int width
Video only.
Definition: codec_par.h:134
reset_count_warnings
static void reset_count_warnings(void)
Definition: movenc.c:95
ctx
AVFormatContext * ctx
Definition: movenc.c:49
av_rescale_q
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:142
force_iobuf_size
int force_iobuf_size
Definition: movenc.c:74
AVMEDIA_TYPE_DATA
@ AVMEDIA_TYPE_DATA
Opaque data information usually continuous.
Definition: avutil.h:203
mux_gops
static void mux_gops(int n)
Definition: movenc.c:347
AV_CODEC_ID_H264
@ AV_CODEC_ID_H264
Definition: codec_id.h:79
avformat_write_header
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:487
iobuf
uint8_t iobuf[32768]
Definition: movenc.c:50
if
if(ret)
Definition: filter_design.txt:179
AVFormatContext
Format I/O context.
Definition: avformat.h:1255
io_write_data_type
static int io_write_data_type(void *opaque, const uint8_t *buf, int size, enum AVIODataMarkerType type, int64_t time)
Definition: movenc.c:109
opts
AVDictionary * opts
Definition: movenc.c:51
AVStream::codecpar
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:766
AVStream::time_base
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented.
Definition: avformat.h:782
NULL
#define NULL
Definition: coverity.c:32
AV_CODEC_ID_TIMED_ID3
@ AV_CODEC_ID_TIMED_ID3
Definition: codec_id.h:589
AVIO_DATA_MARKER_TRAILER
@ AVIO_DATA_MARKER_TRAILER
Trailer data, which doesn't contain actual content, but only for finalizing the output file.
Definition: avio.h:139
AV_PICTURE_TYPE_I
@ AV_PICTURE_TYPE_I
Intra.
Definition: avutil.h:279
AVFormatContext::pb
AVIOContext * pb
I/O context.
Definition: avformat.h:1297
av_write_frame
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file.
Definition: mux.c:1233
AVCodecParameters::ch_layout
AVChannelLayout ch_layout
Audio only.
Definition: codec_par.h:180
audio_st
AVStream * audio_st
Definition: movenc.c:61
c
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
AVCodecParameters::sample_rate
int sample_rate
Audio only.
Definition: codec_par.h:184
AVCodecParameters::extradata_size
int extradata_size
Size of the extradata content in bytes.
Definition: codec_par.h:73
AV_WB32
#define AV_WB32(p, v)
Definition: intreadwrite.h:417
AV_CODEC_ID_AAC
@ AV_CODEC_ID_AAC
Definition: codec_id.h:442
mux_id3
static void mux_id3(void)
Definition: movenc.c:330
audio_duration
int64_t audio_duration
Definition: movenc.c:66
av_log_set_callback
void av_log_set_callback(void(*callback)(void *, int, const char *, va_list))
Set the logging callback.
Definition: log.c:462
AVPacket::size
int size
Definition: packet.h:525
avformat_alloc_context
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
Definition: options.c:161
AVChannelLayout
An AVChannelLayout holds information about the channel layout of audio data.
Definition: channel_layout.h:303
size
int size
Definition: twinvq_data.h:10344
video_st
AVStream * video_st
Definition: movenc.c:61
AV_NOPTS_VALUE
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:248
frames
int frames
Definition: movenc.c:67
printf
printf("static const uint8_t my_array[100] = {\n")
skip_write_audio
int skip_write_audio
Definition: movenc.c:72
init_out
static void init_out(const char *name)
Definition: movenc.c:139
AVIO_DATA_MARKER_SYNC_POINT
@ AVIO_DATA_MARKER_SYNC_POINT
A point in the output bytestream where a decoder can start decoding (i.e.
Definition: avio.h:121
header
static const uint8_t header[24]
Definition: sdr2.c:68
AVPacket::dts
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed.
Definition: packet.h:523
next_p_pts
int64_t next_p_pts
Definition: movenc.c:69
check
#define check(value,...)
Definition: movenc.c:178
line
Definition: graph2dot.c:48
AVPacket::flags
int flags
A combination of AV_PKT_FLAG values.
Definition: packet.h:530
av_packet_alloc
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition: packet.c:63
av_dict_free
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition: dict.c:223
HASH_SIZE
#define HASH_SIZE
Definition: movenc.c:38
write_file
int write_file
Definition: movenc.c:53
check_faults
int check_faults
Definition: movenc.c:80
init
static void init(int bf, int audio_preroll)
Definition: movenc.c:257
av_write_trailer
int av_write_trailer(AVFormatContext *s)
Write the stream trailer to an output media file and free the file private data.
Definition: mux.c:1295
av_md5_init
void av_md5_init(AVMD5 *ctx)
Initialize MD5 hashing.
Definition: md5.c:143
skip_gops
static void skip_gops(int n)
Definition: movenc.c:352
help
static void help(void)
Definition: movenc.c:381
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
AVPacket::pts
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: packet.h:517
AVCodecParameters::height
int height
Definition: codec_par.h:135
md5.h
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:256
av_md5_final
void av_md5_final(AVMD5 *ctx, uint8_t *dst)
Finish hashing and output digest value.
Definition: md5.c:188
format
static const char * format
Definition: movenc.c:48
AVIO_DATA_MARKER_UNKNOWN
@ AVIO_DATA_MARKER_UNKNOWN
This is any, unlabelled data.
Definition: avio.h:134
AVFMT_FLAG_BITEXACT
#define AVFMT_FLAG_BITEXACT
When muxing, try to avoid writing any random/volatile data to the output.
Definition: avformat.h:1423
AVStream
Stream structure.
Definition: avformat.h:743
AVFormatContext::oformat
const struct AVOutputFormat * oformat
The output container format.
Definition: avformat.h:1274
main
int main(int argc, char **argv)
Definition: movenc.c:387
avformat.h
getopt.c
AV_INPUT_BUFFER_PADDING_SIZE
#define AV_INPUT_BUFFER_PADDING_SIZE
Definition: defs.h:40
AVStream::index
int index
stream index in AVFormatContext
Definition: avformat.h:749
close_out
static void close_out(void)
Definition: movenc.c:154
AV_PICTURE_TYPE_B
@ AV_PICTURE_TYPE_B
Bi-dir predicted.
Definition: avutil.h:281
av_md5_alloc
struct AVMD5 * av_md5_alloc(void)
Allocate an AVMD5 context.
Definition: md5.c:50
AVRational::den
int den
Denominator.
Definition: rational.h:60
AVIO_DATA_MARKER_HEADER
@ AVIO_DATA_MARKER_HEADER
Header data; this needs to be present for the stream to be decodeable.
Definition: avio.h:114
avformat_free_context
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Definition: avformat.c:141
init_fps
static void init_fps(int bf, int audio_preroll, int fps, int id3)
Definition: movenc.c:180
init_count_warnings
static void init_count_warnings(void)
Definition: movenc.c:89
clear_duration
int clear_duration
Definition: movenc.c:73
AVPacket::stream_index
int stream_index
Definition: packet.h:526
av_md5_update
void av_md5_update(AVMD5 *ctx, const uint8_t *src, size_t len)
Update hash value.
Definition: md5.c:153
AV_PICTURE_TYPE_P
@ AV_PICTURE_TYPE_P
Predicted.
Definition: avutil.h:280
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
av_log_default_callback
void av_log_default_callback(void *ptr, int level, const char *fmt, va_list vl)
Default logging callback.
Definition: log.c:353
av_guess_format
const 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:79
mem.h
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
AVCodecParameters::codec_id
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: codec_par.h:55
AVPacket
This structure stores compressed data.
Definition: packet.h:501
av_interleaved_write_frame
int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file ensuring correct interleaving.
Definition: mux.c:1280
av_dict_set
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:88
signal_init_ts
static void signal_init_ts(void)
Definition: movenc.c:359
io_write
static int io_write(void *opaque, const uint8_t *buf, int size)
Definition: movenc.c:100
do_interleave
int do_interleave
Definition: movenc.c:75
id3_st
AVStream * id3_st
Definition: movenc.c:61
count_warnings
static void count_warnings(void *avcl, int level, const char *fmt, va_list vl)
Definition: movenc.c:83
snprintf
#define snprintf
Definition: snprintf.h:34