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;
67 int frames;
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;
275  } else {
276  if (frames == end_frames)
277  break;
278  pkt->dts = video_dts;
279  pkt->stream_index = 0;
280  pkt->duration = duration;
281  if ((frames % gop_size) == 0) {
284  pkt->pts = pkt->dts + duration;
285  video_dts = pkt->pts;
286  } else {
289  pkt->pts = pkt->dts;
291  } else {
293  if (((frames + 1) % gop_size) == 0) {
294  pkt->pts = pkt->dts + duration;
295  video_dts = pkt->pts;
296  } else {
297  next_p_pts = pkt->pts = pkt->dts + 2 * duration;
298  video_dts += duration;
299  }
300  }
301  }
302  if (!bframes)
303  pkt->pts = pkt->dts;
304  if (fake_pkt_duration)
306  frames++;
307  }
308 
309  if (clear_duration)
310  pkt->duration = 0;
311  AV_WB32(pktdata + 4, pkt->pts);
312  pkt->data = pktdata;
313  pkt->size = 8;
314  if (skip_write)
315  continue;
316  if (skip_write_audio && pkt->stream_index == 1)
317  continue;
318 
319  if (c) {
320  pkt->pts += (1LL<<32);
321  pkt->dts += (1LL<<32);
322  }
323 
324  if (do_interleave)
326  else
328  }
329 }
330 
331 static void mux_id3(void)
332 {
333  uint8_t pktdata[8] = { 0 };
335 
339  pkt->duration = 0;
340 
341  AV_WB32(pktdata + 4, pkt->pts);
342  pkt->data = pktdata;
343  pkt->size = 8;
344 
346 }
347 
348 static void mux_gops(int n)
349 {
350  mux_frames(gop_size * n, 0);
351 }
352 
353 static void skip_gops(int n)
354 {
355  skip_write = 1;
356  mux_gops(n);
357  skip_write = 0;
358 }
359 
360 static void signal_init_ts(void)
361 {
363 
364  pkt->stream_index = 0;
365  pkt->dts = video_dts;
366  pkt->pts = 0;
368 
369  pkt->stream_index = 1;
370  pkt->dts = pkt->pts = audio_dts;
372 }
373 
374 static void finish(void)
375 {
379  ctx = NULL;
380 }
381 
382 static void help(void)
383 {
384  printf("movenc-test [-w]\n"
385  "-w write output into files\n");
386 }
387 
388 int main(int argc, char **argv)
389 {
390  int c;
391  uint8_t header[HASH_SIZE];
392  uint8_t content[HASH_SIZE];
393  int empty_moov_pos;
394  int prev_pos;
395 
396  for (;;) {
397  c = getopt(argc, argv, "wh");
398  if (c == -1)
399  break;
400  switch (c) {
401  case 'w':
402  write_file = 1;
403  break;
404  default:
405  case 'h':
406  help();
407  return 0;
408  }
409  }
410 
411  md5 = av_md5_alloc();
412  if (!md5)
413  return 1;
414  pkt = av_packet_alloc();
415  if (!pkt) {
416  av_free(md5);
417  return 1;
418  }
419 
420  // Write a fragmented file with an initial moov that actually contains some
421  // samples. One moov+mdat with 1 second of data and one moof+mdat with 1
422  // second of data.
423  init_out("non-empty-moov");
424  av_dict_set(&opts, "movflags", "+frag_keyframe", 0);
425  init(0, 0);
426  mux_gops(2);
427  finish();
428  close_out();
429 
430  // Write a similar file, but with B-frames and audio preroll, handled
431  // via an edit list.
432  init_out("non-empty-moov-elst");
433  av_dict_set(&opts, "movflags", "+frag_keyframe", 0);
434  av_dict_set(&opts, "use_editlist", "1", 0);
435  init(1, 1);
436  mux_gops(2);
437  finish();
438  close_out();
439 
440  // Use B-frames but no audio-preroll, but without an edit list.
441  // Due to avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO, the dts
442  // of the first audio packet is > 0, but it is set to zero since edit
443  // lists aren't used, increasing the duration of the first packet instead.
444  init_out("non-empty-moov-no-elst");
445  av_dict_set(&opts, "movflags", "+frag_keyframe", 0);
446  av_dict_set(&opts, "use_editlist", "0", 0);
447  init(1, 0);
448  mux_gops(2);
449  finish();
450  close_out();
451 
452  format = "ismv";
453  // Write an ISMV, with B-frames and audio preroll.
454  init_out("ismv");
455  av_dict_set(&opts, "movflags", "+frag_keyframe", 0);
456  init(1, 1);
457  mux_gops(2);
458  finish();
459  close_out();
460  format = "mp4";
461 
462  // An initial moov that doesn't contain any samples, followed by two
463  // moof+mdat pairs.
464  init_out("empty-moov");
465  av_dict_set(&opts, "movflags", "+frag_keyframe+empty_moov", 0);
466  av_dict_set(&opts, "use_editlist", "0", 0);
467  init(0, 0);
468  mux_gops(2);
469  finish();
470  close_out();
471  memcpy(content, hash, HASH_SIZE);
472 
473  // Similar to the previous one, but with input that doesn't start at
474  // pts/dts 0. avoid_negative_ts behaves in the same way as
475  // in non-empty-moov-no-elst above.
477  init_out("empty-moov-no-elst");
478  av_dict_set(&opts, "movflags", "+frag_keyframe+empty_moov", 0);
479  init(1, 0);
480  mux_gops(2);
481  finish();
482  close_out();
483 
485  check(num_warnings == 0, "Unexpected warnings printed");
486 
487  // Same as the previous one, but disable avoid_negative_ts (which
488  // would require using an edit list, but with empty_moov, one can't
489  // write a sensible edit list, when the start timestamps aren't known).
490  // This should trigger a warning - we check that the warning is produced.
492  init_out("empty-moov-no-elst-no-adjust");
493  av_dict_set(&opts, "movflags", "+frag_keyframe+empty_moov", 0);
494  av_dict_set(&opts, "avoid_negative_ts", "disabled", 0);
495  init(1, 0);
496  mux_gops(2);
497  finish();
498  close_out();
499 
501  check(num_warnings > 0, "No warnings printed for unhandled start offset");
502 
503  // Verify that delay_moov produces the same as empty_moov for
504  // simple input
505  init_out("delay-moov");
506  av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov", 0);
507  av_dict_set(&opts, "use_editlist", "0", 0);
508  init(0, 0);
509  mux_gops(2);
510  finish();
511  close_out();
512  check(!memcmp(hash, content, HASH_SIZE), "delay_moov differs from empty_moov");
513 
514  // Test writing content that requires an edit list using delay_moov
515  init_out("delay-moov-elst");
516  av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov", 0);
517  init(1, 1);
518  mux_gops(2);
519  finish();
520  close_out();
521 
522  // Test writing a file with one track lacking packets, with delay_moov.
523  skip_write_audio = 1;
524  init_out("delay-moov-empty-track");
525  av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov", 0);
526  init(0, 0);
527  mux_gops(2);
528  // The automatic flushing shouldn't output anything, since we're still
529  // waiting for data for some tracks
530  check(out_size == 0, "delay_moov flushed prematurely");
531  // When closed (or manually flushed), all the written data should still
532  // be output.
533  finish();
534  close_out();
535  check(out_size > 0, "delay_moov didn't output anything");
536 
537  // Check that manually flushing still outputs things as expected. This
538  // produces two fragments, while the one above produces only one.
539  init_out("delay-moov-empty-track-flush");
540  av_dict_set(&opts, "movflags", "+frag_custom+delay_moov", 0);
541  init(0, 0);
542  mux_gops(1);
543  av_write_frame(ctx, NULL); // Force writing the moov
544  check(out_size > 0, "No moov written");
546  mux_gops(1);
548  finish();
549  close_out();
550 
551  skip_write_audio = 0;
552 
553 
554 
555  // Verify that the header written by delay_moov when manually flushed
556  // is identical to the one by empty_moov.
557  init_out("empty-moov-header");
558  av_dict_set(&opts, "movflags", "+frag_keyframe+empty_moov", 0);
559  av_dict_set(&opts, "use_editlist", "0", 0);
560  init(0, 0);
561  close_out();
562  memcpy(header, hash, HASH_SIZE);
563  init_out("empty-moov-content");
564  mux_gops(2);
565  // Written 2 seconds of content, with an automatic flush after 1 second.
566  check(out_size > 0, "No automatic flush?");
567  empty_moov_pos = prev_pos = out_size;
568  // Manually flush the second fragment
570  check(out_size > prev_pos, "No second fragment flushed?");
571  prev_pos = out_size;
572  // Check that an extra flush doesn't output any more data
574  check(out_size == prev_pos, "More data written?");
575  close_out();
576  memcpy(content, hash, HASH_SIZE);
577  // Ignore the trailer written here
578  finish();
579 
580  init_out("delay-moov-header");
581  av_dict_set(&opts, "movflags", "+frag_custom+delay_moov", 0);
582  av_dict_set(&opts, "use_editlist", "0", 0);
583  init(0, 0);
584  check(out_size == 0, "Output written during init with delay_moov");
585  mux_gops(1); // Write 1 second of content
586  av_write_frame(ctx, NULL); // Force writing the moov
587  close_out();
588  check(!memcmp(hash, header, HASH_SIZE), "delay_moov header differs from empty_moov");
589  init_out("delay-moov-content");
590  av_write_frame(ctx, NULL); // Flush the first fragment
591  check(out_size == empty_moov_pos, "Manually flushed content differs from automatically flushed, %d vs %d", out_size, empty_moov_pos);
592  mux_gops(1); // Write the rest of the content
593  av_write_frame(ctx, NULL); // Flush the second fragment
594  close_out();
595  check(!memcmp(hash, content, HASH_SIZE), "delay_moov content differs from empty_moov");
596  finish();
597 
598 
599  // Verify that we can produce an identical second fragment without
600  // writing the first one. First write the reference fragments that
601  // we want to reproduce.
602  av_dict_set(&opts, "movflags", "+frag_custom+empty_moov+dash", 0);
603  init(0, 0);
604  mux_gops(1);
605  av_write_frame(ctx, NULL); // Output the first fragment
606  init_out("empty-moov-second-frag");
607  mux_gops(1);
608  av_write_frame(ctx, NULL); // Output the second fragment
609  close_out();
610  memcpy(content, hash, HASH_SIZE);
611  finish();
612 
613  // Produce the same second fragment without actually writing the first
614  // one before.
615  av_dict_set(&opts, "movflags", "+frag_custom+empty_moov+dash+frag_discont", 0);
616  av_dict_set(&opts, "fragment_index", "2", 0);
617  av_dict_set(&opts, "avoid_negative_ts", "disabled", 0);
618  av_dict_set(&opts, "use_editlist", "0", 0);
619  init(0, 0);
620  skip_gops(1);
621  init_out("empty-moov-second-frag-discont");
622  mux_gops(1);
623  av_write_frame(ctx, NULL); // Output the second fragment
624  close_out();
625  check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
626  finish();
627 
628  // Produce the same thing by using delay_moov, which requires a slightly
629  // different call sequence.
630  av_dict_set(&opts, "movflags", "+frag_custom+delay_moov+dash+frag_discont", 0);
631  av_dict_set(&opts, "fragment_index", "2", 0);
632  init(0, 0);
633  skip_gops(1);
634  mux_gops(1);
635  av_write_frame(ctx, NULL); // Output the moov
636  init_out("delay-moov-second-frag-discont");
637  av_write_frame(ctx, NULL); // Output the second fragment
638  close_out();
639  check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
640  finish();
641 
642 
643  // Test discontinuously written fragments with B-frames (where the
644  // assumption of starting at pts=0 works) but not with audio preroll
645  // (which can't be guessed).
646  av_dict_set(&opts, "movflags", "+frag_custom+delay_moov+dash", 0);
647  init(1, 0);
648  mux_gops(1);
649  init_out("delay-moov-elst-init");
650  av_write_frame(ctx, NULL); // Output the moov
651  close_out();
652  memcpy(header, hash, HASH_SIZE);
653  av_write_frame(ctx, NULL); // Output the first fragment
654  init_out("delay-moov-elst-second-frag");
655  mux_gops(1);
656  av_write_frame(ctx, NULL); // Output the second fragment
657  close_out();
658  memcpy(content, hash, HASH_SIZE);
659  finish();
660 
661  av_dict_set(&opts, "movflags", "+frag_custom+delay_moov+dash+frag_discont", 0);
662  av_dict_set(&opts, "fragment_index", "2", 0);
663  init(1, 0);
664  skip_gops(1);
665  mux_gops(1); // Write the second fragment
666  init_out("delay-moov-elst-init-discont");
667  av_write_frame(ctx, NULL); // Output the moov
668  close_out();
669  check(!memcmp(hash, header, HASH_SIZE), "discontinuously written header differs");
670  init_out("delay-moov-elst-second-frag-discont");
671  av_write_frame(ctx, NULL); // Output the second fragment
672  close_out();
673  check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
674  finish();
675 
676 
677  // Test discontinuously written fragments with B-frames and audio preroll,
678  // properly signaled.
679  av_dict_set(&opts, "movflags", "+frag_custom+delay_moov+dash", 0);
680  init(1, 1);
681  mux_gops(1);
682  init_out("delay-moov-elst-signal-init");
683  av_write_frame(ctx, NULL); // Output the moov
684  close_out();
685  memcpy(header, hash, HASH_SIZE);
686  av_write_frame(ctx, NULL); // Output the first fragment
687  init_out("delay-moov-elst-signal-second-frag");
688  mux_gops(1);
689  av_write_frame(ctx, NULL); // Output the second fragment
690  close_out();
691  memcpy(content, hash, HASH_SIZE);
692  finish();
693 
694  av_dict_set(&opts, "movflags", "+frag_custom+delay_moov+dash+frag_discont", 0);
695  av_dict_set(&opts, "fragment_index", "2", 0);
696  init(1, 1);
697  signal_init_ts();
698  skip_gops(1);
699  mux_gops(1); // Write the second fragment
700  init_out("delay-moov-elst-signal-init-discont");
701  av_write_frame(ctx, NULL); // Output the moov
702  close_out();
703  check(!memcmp(hash, header, HASH_SIZE), "discontinuously written header differs");
704  init_out("delay-moov-elst-signal-second-frag-discont");
705  av_write_frame(ctx, NULL); // Output the second fragment
706  close_out();
707  check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
708  finish();
709 
710 
711  // Test muxing discontinuous fragments with very large (> (1<<31)) timestamps.
712  av_dict_set(&opts, "movflags", "+frag_custom+delay_moov+dash+frag_discont", 0);
713  av_dict_set(&opts, "fragment_index", "2", 0);
714  init(1, 1);
715  signal_init_ts();
716  skip_gops(1);
717  mux_frames(gop_size, 1); // Write the second fragment
718  init_out("delay-moov-elst-signal-init-discont-largets");
719  av_write_frame(ctx, NULL); // Output the moov
720  close_out();
721  init_out("delay-moov-elst-signal-second-frag-discont-largets");
722  av_write_frame(ctx, NULL); // Output the second fragment
723  close_out();
724  finish();
725 
726  // Test VFR content, with sidx atoms (which declare the pts duration
727  // of a fragment, forcing overriding the start pts of the next one).
728  // Here, the fragment duration in pts is significantly different from
729  // the duration in dts. The video stream starts at dts=-10,pts=0, and
730  // the second fragment starts at dts=155,pts=156. The trun duration sum
731  // of the first fragment is 165, which also is written as
732  // baseMediaDecodeTime in the tfdt in the second fragment. The sidx for
733  // the first fragment says earliest_presentation_time = 0 and
734  // subsegment_duration = 156, which also matches the sidx in the second
735  // fragment. For the audio stream, the pts and dts durations also don't
736  // match - the input stream starts at pts=-2048, but that part is excluded
737  // by the edit list.
738  init_out("vfr");
739  av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov+dash", 0);
740  init_fps(1, 1, 3, 0);
741  mux_frames(gop_size/2, 0);
742  duration /= 10;
743  mux_frames(gop_size/2, 0);
744  mux_gops(1);
745  finish();
746  close_out();
747 
748  // Test VFR content, with cleared duration fields. In these cases,
749  // the muxer must guess the duration of the last packet of each
750  // fragment. As long as the framerate doesn't vary (too much) at the
751  // fragment edge, it works just fine. Additionally, when automatically
752  // cutting fragments, the muxer already know the timestamps of the next
753  // packet for one stream (in most cases the video stream), avoiding
754  // having to use guesses for that one.
756  clear_duration = 1;
757  init_out("vfr-noduration");
758  av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov+dash", 0);
759  init_fps(1, 1, 3, 0);
760  mux_frames(gop_size/2, 0);
761  duration /= 10;
762  mux_frames(gop_size/2, 0);
763  mux_gops(1);
764  finish();
765  close_out();
766  clear_duration = 0;
768  check(num_warnings > 0, "No warnings printed for filled in durations");
769 
770  // Test with an IO buffer size that is too small to hold a full fragment;
771  // this will cause write_data_type to be called with the type unknown.
772  force_iobuf_size = 1500;
773  init_out("large_frag");
774  av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov", 0);
775  init_fps(1, 1, 3, 0);
776  mux_gops(2);
777  finish();
778  close_out();
779  force_iobuf_size = 0;
780 
781  // Test VFR content with bframes with interleaving.
782  // Here, using av_interleaved_write_frame allows the muxer to get the
783  // fragment end durations right. We always set the packet duration to
784  // the expected, but we simulate dropped frames at one point.
785  do_interleave = 1;
786  init_out("vfr-noduration-interleave");
787  av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov", 0);
788  av_dict_set(&opts, "frag_duration", "650000", 0);
789  init_fps(1, 1, 30, 0);
790  mux_frames(gop_size/2, 0);
791  // Pretend that the packet duration is the normal, even if
792  // we actually skip a bunch of frames. (I.e., simulate that
793  // we don't know of the framedrop in advance.)
795  duration *= 10;
796  mux_frames(1, 0);
797  fake_pkt_duration = 0;
798  duration /= 10;
799  mux_frames(gop_size/2 - 1, 0);
800  mux_gops(1);
801  finish();
802  close_out();
803  clear_duration = 0;
804  do_interleave = 0;
805 
806  // Write a fragmented file with b-frames and audio preroll,
807  // with negative cts values, removing the edit list for the
808  // video track.
809  init_out("delay-moov-elst-neg-cts");
810  av_dict_set(&opts, "movflags", "+frag_keyframe+delay_moov+negative_cts_offsets", 0);
811  init(1, 1);
812  mux_gops(2);
813  finish();
814  close_out();
815 
816  // Write a fragmented file with b-frames without audio preroll,
817  // with negative cts values, avoiding any edit lists, allowing
818  // to use empty_moov instead of delay_moov.
819  init_out("empty-moov-neg-cts");
820  av_dict_set(&opts, "movflags", "+frag_keyframe+empty_moov+negative_cts_offsets", 0);
821  init(1, 0);
822  mux_gops(2);
823  finish();
824  close_out();
825 
826  // Write a manually fragmented file, with timed ID3 packets at the head
827  // of each fragment.
828  init_out("emsg");
829  av_dict_set(&opts, "movflags", "+frag_custom+cmaf", 0);
830  init_fps(1, 0, 30, 1);
831  mux_id3();
832  mux_gops(2);
833  av_write_frame(ctx, NULL); // Flush fragment.
834  mux_id3();
835  mux_gops(2);
836  finish();
837  close_out();
838 
839  av_free(md5);
841 
842  return check_faults > 0 ? 1 : 0;
843 }
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:429
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:215
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:393
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
int64_t
long long int64_t
Definition: coverity.c:34
out_size
int out_size
Definition: movenc.c:56
AVPacket::data
uint8_t * data
Definition: packet.h:539
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:557
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:594
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:374
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
bf
#define bf(fn, bd, opt)
Definition: vvcdsp_init.c:28
intreadwrite.h
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1451
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:348
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:488
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:1300
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:771
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:787
NULL
#define NULL
Definition: coverity.c:32
AV_CODEC_ID_TIMED_ID3
@ AV_CODEC_ID_TIMED_ID3
Definition: codec_id.h:595
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:1342
av_write_frame
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file.
Definition: mux.c:1236
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:415
AV_CODEC_ID_AAC
@ AV_CODEC_ID_AAC
Definition: codec_id.h:448
mux_id3
static void mux_id3(void)
Definition: movenc.c:331
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:540
avformat_alloc_context
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
Definition: options.c:162
AVChannelLayout
An AVChannelLayout holds information about the channel layout of audio data.
Definition: channel_layout.h:317
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:538
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:545
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:1298
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:353
help
static void help(void)
Definition: movenc.c:382
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:532
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:1468
AVStream
Stream structure.
Definition: avformat.h:748
AVFormatContext::oformat
const struct AVOutputFormat * oformat
The output container format.
Definition: avformat.h:1319
main
int main(int argc, char **argv)
Definition: movenc.c:388
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:754
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:149
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:541
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:516
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:1283
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:360
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