segment.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011, Luca Barbato
3  *
4  * This file is part of Libav.
5  *
6  * Libav 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  * Libav 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 Libav; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /**
22  * @file generic segmenter
23  * M3U8 specification can be find here:
24  * @url{http://tools.ietf.org/id/draft-pantos-http-live-streaming}
25  */
26 
27 /* #define DEBUG */
28 
29 #include <float.h>
30 
31 #include "avformat.h"
32 #include "internal.h"
33 
34 #include "libavutil/avassert.h"
35 #include "libavutil/log.h"
36 #include "libavutil/opt.h"
37 #include "libavutil/avstring.h"
38 #include "libavutil/parseutils.h"
39 #include "libavutil/mathematics.h"
40 #include "libavutil/timestamp.h"
41 
42 typedef struct SegmentListEntry {
43  int index;
45  int64_t start_pts;
46  char filename[1024];
49 
50 typedef enum {
55  LIST_TYPE_EXT, ///< deprecated
58 } ListType;
59 
60 #define SEGMENT_LIST_FLAG_CACHE 1
61 #define SEGMENT_LIST_FLAG_LIVE 2
62 
63 typedef struct {
64  const AVClass *class; /**< Class for private options. */
65  int segment_idx; ///< index of the segment file to write, starting from 0
66  int segment_idx_wrap; ///< number after which the index wraps
67  int segment_count; ///< number of segment files already written
70  char *format; ///< format to use for output segment files
71  char *list; ///< filename for the segment list file
72  int list_flags; ///< flags affecting list generation
73  int list_size; ///< number of entries for the segment list file
74  ListType list_type; ///< set the list type
75  AVIOContext *list_pb; ///< list file put-byte context
76  char *time_str; ///< segment duration specification string
77  int64_t time; ///< segment duration
78 
79  char *times_str; ///< segment times specification string
80  int64_t *times; ///< list of segment interval specification
81  int nb_times; ///< number of elments in the times array
82 
83  char *frames_str; ///< segment frame numbers specification string
84  int *frames; ///< list of frame number specification
85  int nb_frames; ///< number of elments in the frames array
87 
88  char *time_delta_str; ///< approximation value duration used for the segment times
89  int64_t time_delta;
90  int individual_header_trailer; /**< Set by a private option. */
91  int write_header_trailer; /**< Set by a private option. */
92 
93  int reset_timestamps; ///< reset timestamps at the begin of each segment
94  char *reference_stream_specifier; ///< reference stream specifier
96 
100 
101  int is_first_pkt; ///< tells if it is the first packet in the segment
103 
104 static void print_csv_escaped_str(AVIOContext *ctx, const char *str)
105 {
106  int needs_quoting = !!str[strcspn(str, "\",\n\r")];
107 
108  if (needs_quoting)
109  avio_w8(ctx, '"');
110 
111  for (; *str; str++) {
112  if (*str == '"')
113  avio_w8(ctx, '"');
114  avio_w8(ctx, *str);
115  }
116  if (needs_quoting)
117  avio_w8(ctx, '"');
118 }
119 
121 {
122  SegmentContext *seg = s->priv_data;
123  AVFormatContext *oc;
124  int i;
125 
126  seg->avf = oc = avformat_alloc_context();
127  if (!oc)
128  return AVERROR(ENOMEM);
129 
130  oc->oformat = seg->oformat;
132  av_dict_copy(&oc->metadata, s->metadata, 0);
133 
134  for (i = 0; i < s->nb_streams; i++) {
135  AVStream *st;
136  AVCodecContext *icodec, *ocodec;
137 
138  if (!(st = avformat_new_stream(oc, NULL)))
139  return AVERROR(ENOMEM);
140  icodec = s->streams[i]->codec;
141  ocodec = st->codec;
142  avcodec_copy_context(ocodec, icodec);
143  if (!oc->oformat->codec_tag ||
144  av_codec_get_id (oc->oformat->codec_tag, icodec->codec_tag) == ocodec->codec_id ||
145  av_codec_get_tag(oc->oformat->codec_tag, icodec->codec_id) <= 0) {
146  ocodec->codec_tag = icodec->codec_tag;
147  } else {
148  ocodec->codec_tag = 0;
149  }
151  }
152 
153  return 0;
154 }
155 
157 {
158  SegmentContext *seg = s->priv_data;
159  AVFormatContext *oc = seg->avf;
160 
161  if (seg->segment_idx_wrap)
162  seg->segment_idx %= seg->segment_idx_wrap;
163  if (av_get_frame_filename(oc->filename, sizeof(oc->filename),
164  s->filename, seg->segment_idx) < 0) {
165  av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", s->filename);
166  return AVERROR(EINVAL);
167  }
168  av_strlcpy(seg->cur_entry.filename, oc->filename, sizeof(seg->cur_entry.filename));
169  return 0;
170 }
171 
173 {
174  SegmentContext *seg = s->priv_data;
175  AVFormatContext *oc = seg->avf;
176  int err = 0;
177 
178  if (write_header) {
180  seg->avf = NULL;
181  if ((err = segment_mux_init(s)) < 0)
182  return err;
183  oc = seg->avf;
184  }
185 
186  seg->segment_idx++;
187  if ((err = set_segment_filename(s)) < 0)
188  return err;
189  seg->segment_count++;
190 
191  if ((err = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
192  &s->interrupt_callback, NULL)) < 0)
193  return err;
194 
195  if (oc->oformat->priv_class && oc->priv_data)
196  av_opt_set(oc->priv_data, "resend_headers", "1", 0); /* mpegts specific */
197 
198  if (write_header) {
199  if ((err = avformat_write_header(oc, NULL)) < 0)
200  return err;
201  }
202 
203  seg->is_first_pkt = 1;
204  return 0;
205 }
206 
208 {
209  SegmentContext *seg = s->priv_data;
210  int ret;
211 
212  ret = avio_open2(&seg->list_pb, seg->list, AVIO_FLAG_WRITE,
213  &s->interrupt_callback, NULL);
214  if (ret < 0)
215  return ret;
216 
217  if (seg->list_type == LIST_TYPE_M3U8 && seg->segment_list_entries) {
218  SegmentListEntry *entry;
219  double max_duration = 0;
220 
221  avio_printf(seg->list_pb, "#EXTM3U\n");
222  avio_printf(seg->list_pb, "#EXT-X-VERSION:3\n");
223  avio_printf(seg->list_pb, "#EXT-X-MEDIA-SEQUENCE:%d\n", seg->segment_list_entries->index);
224  avio_printf(seg->list_pb, "#EXT-X-ALLOW-CACHE:%s\n",
225  seg->list_flags & SEGMENT_LIST_FLAG_CACHE ? "YES" : "NO");
226 
227  for (entry = seg->segment_list_entries; entry; entry = entry->next)
228  max_duration = FFMAX(max_duration, entry->end_time - entry->start_time);
229  avio_printf(seg->list_pb, "#EXT-X-TARGETDURATION:%"PRId64"\n", (int64_t)ceil(max_duration));
230  } else if (seg->list_type == LIST_TYPE_FFCONCAT) {
231  avio_printf(seg->list_pb, "ffconcat version 1.0\n");
232  }
233 
234  return ret;
235 }
236 
237 static void segment_list_print_entry(AVIOContext *list_ioctx,
238  ListType list_type,
239  const SegmentListEntry *list_entry,
240  void *log_ctx)
241 {
242  switch (list_type) {
243  case LIST_TYPE_FLAT:
244  avio_printf(list_ioctx, "%s\n", list_entry->filename);
245  break;
246  case LIST_TYPE_CSV:
247  case LIST_TYPE_EXT:
248  print_csv_escaped_str(list_ioctx, list_entry->filename);
249  avio_printf(list_ioctx, ",%f,%f\n", list_entry->start_time, list_entry->end_time);
250  break;
251  case LIST_TYPE_M3U8:
252  avio_printf(list_ioctx, "#EXTINF:%f,\n%s\n",
253  list_entry->end_time - list_entry->start_time, list_entry->filename);
254  break;
255  case LIST_TYPE_FFCONCAT:
256  {
257  char *buf;
258  if (av_escape(&buf, list_entry->filename, NULL, AV_ESCAPE_MODE_AUTO, AV_ESCAPE_FLAG_WHITESPACE) < 0) {
259  av_log(log_ctx, AV_LOG_WARNING,
260  "Error writing list entry '%s' in list file\n", list_entry->filename);
261  return;
262  }
263  avio_printf(list_ioctx, "file %s\n", buf);
264  av_free(buf);
265  break;
266  }
267  default:
268  av_assert0(!"Invalid list type");
269  }
270 }
271 
272 static int segment_end(AVFormatContext *s, int write_trailer, int is_last)
273 {
274  SegmentContext *seg = s->priv_data;
275  AVFormatContext *oc = seg->avf;
276  int ret = 0;
277 
278  av_write_frame(oc, NULL); /* Flush any buffered data (fragmented mp4) */
279  if (write_trailer)
280  ret = av_write_trailer(oc);
281 
282  if (ret < 0)
283  av_log(s, AV_LOG_ERROR, "Failure occurred when ending segment '%s'\n",
284  oc->filename);
285 
286  if (seg->list) {
287  if (seg->list_size || seg->list_type == LIST_TYPE_M3U8) {
288  SegmentListEntry *entry = av_mallocz(sizeof(*entry));
289  if (!entry) {
290  ret = AVERROR(ENOMEM);
291  goto end;
292  }
293 
294  /* append new element */
295  memcpy(entry, &seg->cur_entry, sizeof(*entry));
296  if (!seg->segment_list_entries)
298  else
299  seg->segment_list_entries_end->next = entry;
300  seg->segment_list_entries_end = entry;
301 
302  /* drop first item */
303  if (seg->list_size && seg->segment_count > seg->list_size) {
304  entry = seg->segment_list_entries;
306  av_freep(&entry);
307  }
308 
309  avio_close(seg->list_pb);
310  if ((ret = segment_list_open(s)) < 0)
311  goto end;
312  for (entry = seg->segment_list_entries; entry; entry = entry->next)
313  segment_list_print_entry(seg->list_pb, seg->list_type, entry, s);
314  if (seg->list_type == LIST_TYPE_M3U8 && is_last)
315  avio_printf(seg->list_pb, "#EXT-X-ENDLIST\n");
316  } else {
317  segment_list_print_entry(seg->list_pb, seg->list_type, &seg->cur_entry, s);
318  }
319  avio_flush(seg->list_pb);
320  }
321 
322 end:
323  avio_close(oc->pb);
324 
325  return ret;
326 }
327 
328 static int parse_times(void *log_ctx, int64_t **times, int *nb_times,
329  const char *times_str)
330 {
331  char *p;
332  int i, ret = 0;
333  char *times_str1 = av_strdup(times_str);
334  char *saveptr = NULL;
335 
336  if (!times_str1)
337  return AVERROR(ENOMEM);
338 
339 #define FAIL(err) ret = err; goto end
340 
341  *nb_times = 1;
342  for (p = times_str1; *p; p++)
343  if (*p == ',')
344  (*nb_times)++;
345 
346  *times = av_malloc(sizeof(**times) * *nb_times);
347  if (!*times) {
348  av_log(log_ctx, AV_LOG_ERROR, "Could not allocate forced times array\n");
349  FAIL(AVERROR(ENOMEM));
350  }
351 
352  p = times_str1;
353  for (i = 0; i < *nb_times; i++) {
354  int64_t t;
355  char *tstr = av_strtok(p, ",", &saveptr);
356  p = NULL;
357 
358  if (!tstr || !tstr[0]) {
359  av_log(log_ctx, AV_LOG_ERROR, "Empty time specification in times list %s\n",
360  times_str);
361  FAIL(AVERROR(EINVAL));
362  }
363 
364  ret = av_parse_time(&t, tstr, 1);
365  if (ret < 0) {
366  av_log(log_ctx, AV_LOG_ERROR,
367  "Invalid time duration specification '%s' in times list %s\n", tstr, times_str);
368  FAIL(AVERROR(EINVAL));
369  }
370  (*times)[i] = t;
371 
372  /* check on monotonicity */
373  if (i && (*times)[i-1] > (*times)[i]) {
374  av_log(log_ctx, AV_LOG_ERROR,
375  "Specified time %f is greater than the following time %f\n",
376  (float)((*times)[i])/1000000, (float)((*times)[i-1])/1000000);
377  FAIL(AVERROR(EINVAL));
378  }
379  }
380 
381 end:
382  av_free(times_str1);
383  return ret;
384 }
385 
386 static int parse_frames(void *log_ctx, int **frames, int *nb_frames,
387  const char *frames_str)
388 {
389  char *p;
390  int i, ret = 0;
391  char *frames_str1 = av_strdup(frames_str);
392  char *saveptr = NULL;
393 
394  if (!frames_str1)
395  return AVERROR(ENOMEM);
396 
397 #define FAIL(err) ret = err; goto end
398 
399  *nb_frames = 1;
400  for (p = frames_str1; *p; p++)
401  if (*p == ',')
402  (*nb_frames)++;
403 
404  *frames = av_malloc(sizeof(**frames) * *nb_frames);
405  if (!*frames) {
406  av_log(log_ctx, AV_LOG_ERROR, "Could not allocate forced frames array\n");
407  FAIL(AVERROR(ENOMEM));
408  }
409 
410  p = frames_str1;
411  for (i = 0; i < *nb_frames; i++) {
412  long int f;
413  char *tailptr;
414  char *fstr = av_strtok(p, ",", &saveptr);
415 
416  p = NULL;
417  if (!fstr) {
418  av_log(log_ctx, AV_LOG_ERROR, "Empty frame specification in frame list %s\n",
419  frames_str);
420  FAIL(AVERROR(EINVAL));
421  }
422  f = strtol(fstr, &tailptr, 10);
423  if (*tailptr || f <= 0 || f >= INT_MAX) {
424  av_log(log_ctx, AV_LOG_ERROR,
425  "Invalid argument '%s', must be a positive integer <= INT64_MAX\n",
426  fstr);
427  FAIL(AVERROR(EINVAL));
428  }
429  (*frames)[i] = f;
430 
431  /* check on monotonicity */
432  if (i && (*frames)[i-1] > (*frames)[i]) {
433  av_log(log_ctx, AV_LOG_ERROR,
434  "Specified frame %d is greater than the following frame %d\n",
435  (*frames)[i], (*frames)[i-1]);
436  FAIL(AVERROR(EINVAL));
437  }
438  }
439 
440 end:
441  av_free(frames_str1);
442  return ret;
443 }
444 
445 static int open_null_ctx(AVIOContext **ctx)
446 {
447  int buf_size = 32768;
448  uint8_t *buf = av_malloc(buf_size);
449  if (!buf)
450  return AVERROR(ENOMEM);
451  *ctx = avio_alloc_context(buf, buf_size, AVIO_FLAG_WRITE, NULL, NULL, NULL, NULL);
452  if (!*ctx) {
453  av_free(buf);
454  return AVERROR(ENOMEM);
455  }
456  return 0;
457 }
458 
459 static void close_null_ctx(AVIOContext *pb)
460 {
461  av_free(pb->buffer);
462  av_free(pb);
463 }
464 
466 {
467  SegmentContext *seg = s->priv_data;
468  int ret, i;
469 
470  seg->reference_stream_index = -1;
471  if (!strcmp(seg->reference_stream_specifier, "auto")) {
472  /* select first index of type with highest priority */
473  int type_index_map[AVMEDIA_TYPE_NB];
474  static const enum AVMediaType type_priority_list[] = {
480  };
481  enum AVMediaType type;
482 
483  for (i = 0; i < AVMEDIA_TYPE_NB; i++)
484  type_index_map[i] = -1;
485 
486  /* select first index for each type */
487  for (i = 0; i < s->nb_streams; i++) {
488  type = s->streams[i]->codec->codec_type;
489  if ((unsigned)type < AVMEDIA_TYPE_NB && type_index_map[type] == -1
490  /* ignore attached pictures/cover art streams */
492  type_index_map[type] = i;
493  }
494 
495  for (i = 0; i < FF_ARRAY_ELEMS(type_priority_list); i++) {
496  type = type_priority_list[i];
497  if ((seg->reference_stream_index = type_index_map[type]) >= 0)
498  break;
499  }
500  } else {
501  for (i = 0; i < s->nb_streams; i++) {
504  if (ret < 0)
505  return ret;
506  if (ret > 0) {
507  seg->reference_stream_index = i;
508  break;
509  }
510  }
511  }
512 
513  if (seg->reference_stream_index < 0) {
514  av_log(s, AV_LOG_ERROR, "Could not select stream matching identifier '%s'\n",
516  return AVERROR(EINVAL);
517  }
518 
519  return 0;
520 }
521 
523 {
524  SegmentContext *seg = s->priv_data;
525  AVFormatContext *oc = NULL;
526  int ret;
527 
528  seg->segment_count = 0;
529  if (!seg->write_header_trailer)
530  seg->individual_header_trailer = 0;
531 
532  if (!!seg->time_str + !!seg->times_str + !!seg->frames_str > 1) {
533  av_log(s, AV_LOG_ERROR,
534  "segment_time, segment_times, and segment_frames options "
535  "are mutually exclusive, select just one of them\n");
536  return AVERROR(EINVAL);
537  }
538 
539  if (seg->times_str) {
540  if ((ret = parse_times(s, &seg->times, &seg->nb_times, seg->times_str)) < 0)
541  return ret;
542  } else if (seg->frames_str) {
543  if ((ret = parse_frames(s, &seg->frames, &seg->nb_frames, seg->frames_str)) < 0)
544  return ret;
545  } else {
546  /* set default value if not specified */
547  if (!seg->time_str)
548  seg->time_str = av_strdup("2");
549  if ((ret = av_parse_time(&seg->time, seg->time_str, 1)) < 0) {
550  av_log(s, AV_LOG_ERROR,
551  "Invalid time duration specification '%s' for segment_time option\n",
552  seg->time_str);
553  return ret;
554  }
555  }
556 
557  if (seg->time_delta_str) {
558  if ((ret = av_parse_time(&seg->time_delta, seg->time_delta_str, 1)) < 0) {
559  av_log(s, AV_LOG_ERROR,
560  "Invalid time duration specification '%s' for delta option\n",
561  seg->time_delta_str);
562  return ret;
563  }
564  }
565 
566  if (seg->list) {
567  if (seg->list_type == LIST_TYPE_UNDEFINED) {
568  if (av_match_ext(seg->list, "csv" )) seg->list_type = LIST_TYPE_CSV;
569  else if (av_match_ext(seg->list, "ext" )) seg->list_type = LIST_TYPE_EXT;
570  else if (av_match_ext(seg->list, "m3u8")) seg->list_type = LIST_TYPE_M3U8;
571  else if (av_match_ext(seg->list, "ffcat,ffconcat")) seg->list_type = LIST_TYPE_FFCONCAT;
572  else seg->list_type = LIST_TYPE_FLAT;
573  }
574  if ((ret = segment_list_open(s)) < 0)
575  goto fail;
576  }
577  if (seg->list_type == LIST_TYPE_EXT)
578  av_log(s, AV_LOG_WARNING, "'ext' list type option is deprecated in favor of 'csv'\n");
579 
580  if ((ret = select_reference_stream(s)) < 0)
581  goto fail;
582  av_log(s, AV_LOG_VERBOSE, "Selected stream id:%d type:%s\n",
585 
586  seg->oformat = av_guess_format(seg->format, s->filename, NULL);
587 
588  if (!seg->oformat) {
590  goto fail;
591  }
592  if (seg->oformat->flags & AVFMT_NOFILE) {
593  av_log(s, AV_LOG_ERROR, "format %s not supported.\n",
594  seg->oformat->name);
595  ret = AVERROR(EINVAL);
596  goto fail;
597  }
598 
599  if ((ret = segment_mux_init(s)) < 0)
600  goto fail;
601  oc = seg->avf;
602 
603  if ((ret = set_segment_filename(s)) < 0)
604  goto fail;
605  seg->segment_count++;
606 
607  if (seg->write_header_trailer) {
608  if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
609  &s->interrupt_callback, NULL)) < 0)
610  goto fail;
611  } else {
612  if ((ret = open_null_ctx(&oc->pb)) < 0)
613  goto fail;
614  }
615 
616  if ((ret = avformat_write_header(oc, NULL)) < 0) {
617  avio_close(oc->pb);
618  goto fail;
619  }
620  seg->is_first_pkt = 1;
621 
622  if (oc->avoid_negative_ts > 0 && s->avoid_negative_ts < 0)
623  s->avoid_negative_ts = 1;
624 
625  if (!seg->write_header_trailer) {
626  close_null_ctx(oc->pb);
627  if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
628  &s->interrupt_callback, NULL)) < 0)
629  goto fail;
630  }
631 
632 fail:
633  if (ret) {
634  if (seg->list)
635  avio_close(seg->list_pb);
636  if (seg->avf)
638  }
639  return ret;
640 }
641 
643 {
644  SegmentContext *seg = s->priv_data;
645  AVFormatContext *oc = seg->avf;
646  AVStream *st = s->streams[pkt->stream_index];
647  int64_t end_pts = INT64_MAX;
648  int start_frame = INT_MAX;
649  int ret;
650 
651  if (seg->times) {
652  end_pts = seg->segment_count <= seg->nb_times ?
653  seg->times[seg->segment_count-1] : INT64_MAX;
654  } else if (seg->frames) {
655  start_frame = seg->segment_count <= seg->nb_frames ?
656  seg->frames[seg->segment_count-1] : INT_MAX;
657  } else {
658  end_pts = seg->time * seg->segment_count;
659  }
660 
661  av_dlog(s, "packet stream:%d pts:%s pts_time:%s is_key:%d frame:%d\n",
662  pkt->stream_index, av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
663  pkt->flags & AV_PKT_FLAG_KEY,
664  pkt->stream_index == seg->reference_stream_index ? seg->frame_count : -1);
665 
666  if (pkt->stream_index == seg->reference_stream_index &&
667  pkt->flags & AV_PKT_FLAG_KEY &&
668  (seg->frame_count >= start_frame ||
669  (pkt->pts != AV_NOPTS_VALUE &&
670  av_compare_ts(pkt->pts, st->time_base,
671  end_pts-seg->time_delta, AV_TIME_BASE_Q) >= 0))) {
672  ret = segment_end(s, seg->individual_header_trailer, 0);
673 
674  if (!ret)
676 
677  if (ret)
678  goto fail;
679 
680  oc = seg->avf;
681 
682  seg->cur_entry.index = seg->segment_idx;
683  seg->cur_entry.start_time = (double)pkt->pts * av_q2d(st->time_base);
685  } else if (pkt->pts != AV_NOPTS_VALUE) {
686  seg->cur_entry.end_time =
687  FFMAX(seg->cur_entry.end_time, (double)(pkt->pts + pkt->duration) * av_q2d(st->time_base));
688  }
689 
690  if (seg->is_first_pkt) {
691  av_log(s, AV_LOG_DEBUG, "segment:'%s' starts with packet stream:%d pts:%s pts_time:%s frame:%d\n",
692  seg->avf->filename, pkt->stream_index,
693  av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), seg->frame_count);
694  seg->is_first_pkt = 0;
695  }
696 
697  if (seg->reset_timestamps) {
698  av_log(s, AV_LOG_DEBUG, "stream:%d start_pts_time:%s pts:%s pts_time:%s dts:%s dts_time:%s",
699  pkt->stream_index,
701  av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
702  av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
703 
704  /* compute new timestamps */
705  if (pkt->pts != AV_NOPTS_VALUE)
707  if (pkt->dts != AV_NOPTS_VALUE)
709 
710  av_log(s, AV_LOG_DEBUG, " -> pts:%s pts_time:%s dts:%s dts_time:%s\n",
711  av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
712  av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
713  }
714 
715  ret = ff_write_chained(oc, pkt->stream_index, pkt, s);
716 
717 fail:
718  if (pkt->stream_index == seg->reference_stream_index)
719  seg->frame_count++;
720 
721  if (ret < 0) {
722  if (seg->list)
723  avio_close(seg->list_pb);
725  }
726 
727  return ret;
728 }
729 
731 {
732  SegmentContext *seg = s->priv_data;
733  AVFormatContext *oc = seg->avf;
734  SegmentListEntry *cur, *next;
735 
736  int ret;
737  if (!seg->write_header_trailer) {
738  if ((ret = segment_end(s, 0, 1)) < 0)
739  goto fail;
740  open_null_ctx(&oc->pb);
741  ret = av_write_trailer(oc);
742  close_null_ctx(oc->pb);
743  } else {
744  ret = segment_end(s, 1, 1);
745  }
746 fail:
747  if (seg->list)
748  avio_close(seg->list_pb);
749 
750  av_opt_free(seg);
751  av_freep(&seg->times);
752  av_freep(&seg->frames);
753 
754  cur = seg->segment_list_entries;
755  while (cur) {
756  next = cur->next;
757  av_free(cur);
758  cur = next;
759  }
760 
762  return ret;
763 }
764 
765 #define OFFSET(x) offsetof(SegmentContext, x)
766 #define E AV_OPT_FLAG_ENCODING_PARAM
767 static const AVOption options[] = {
768  { "reference_stream", "set reference stream", OFFSET(reference_stream_specifier), AV_OPT_TYPE_STRING, {.str = "auto"}, CHAR_MIN, CHAR_MAX, E },
769  { "segment_format", "set container format used for the segments", OFFSET(format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
770  { "segment_list", "set the segment list filename", OFFSET(list), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
771 
772  { "segment_list_flags","set flags affecting segment list generation", OFFSET(list_flags), AV_OPT_TYPE_FLAGS, {.i64 = SEGMENT_LIST_FLAG_CACHE }, 0, UINT_MAX, E, "list_flags"},
773  { "cache", "allow list caching", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_LIST_FLAG_CACHE }, INT_MIN, INT_MAX, E, "list_flags"},
774  { "live", "enable live-friendly list generation (useful for HLS)", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_LIST_FLAG_LIVE }, INT_MIN, INT_MAX, E, "list_flags"},
775 
776  { "segment_list_size", "set the maximum number of playlist entries", OFFSET(list_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
777 
778  { "segment_list_type", "set the segment list type", OFFSET(list_type), AV_OPT_TYPE_INT, {.i64 = LIST_TYPE_UNDEFINED}, -1, LIST_TYPE_NB-1, E, "list_type" },
779  { "flat", "flat format", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_FLAT }, INT_MIN, INT_MAX, E, "list_type" },
780  { "csv", "csv format", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_CSV }, INT_MIN, INT_MAX, E, "list_type" },
781  { "ext", "extended format", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_EXT }, INT_MIN, INT_MAX, E, "list_type" },
782  { "ffconcat", "ffconcat format", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_FFCONCAT }, INT_MIN, INT_MAX, E, "list_type" },
783  { "m3u8", "M3U8 format", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_M3U8 }, INT_MIN, INT_MAX, E, "list_type" },
784  { "hls", "Apple HTTP Live Streaming compatible", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_M3U8 }, INT_MIN, INT_MAX, E, "list_type" },
785 
786  { "segment_time", "set segment duration", OFFSET(time_str),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
787  { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta_str), AV_OPT_TYPE_STRING, {.str = "0"}, 0, 0, E },
788  { "segment_times", "set segment split time points", OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E },
789  { "segment_frames", "set segment split frame numbers", OFFSET(frames_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E },
790  { "segment_wrap", "set number after which the index wraps", OFFSET(segment_idx_wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
791  { "segment_start_number", "set the sequence number of the first segment", OFFSET(segment_idx), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
792 
793  { "individual_header_trailer", "write header/trailer to each segment", OFFSET(individual_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E },
794  { "write_header_trailer", "write a header to the first segment and a trailer to the last one", OFFSET(write_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E },
795  { "reset_timestamps", "reset timestamps at the begin of each segment", OFFSET(reset_timestamps), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, E },
796  { NULL },
797 };
798 
799 static const AVClass seg_class = {
800  .class_name = "segment muxer",
801  .item_name = av_default_item_name,
802  .option = options,
803  .version = LIBAVUTIL_VERSION_INT,
804 };
805 
807  .name = "segment",
808  .long_name = NULL_IF_CONFIG_SMALL("segment"),
809  .priv_data_size = sizeof(SegmentContext),
814  .priv_class = &seg_class,
815 };
816 
817 static const AVClass sseg_class = {
818  .class_name = "stream_segment muxer",
819  .item_name = av_default_item_name,
820  .option = options,
821  .version = LIBAVUTIL_VERSION_INT,
822 };
823 
825  .name = "stream_segment,ssegment",
826  .long_name = NULL_IF_CONFIG_SMALL("streaming segment muxer"),
827  .priv_data_size = sizeof(SegmentContext),
828  .flags = AVFMT_NOFILE,
832  .priv_class = &sseg_class,
833 };
struct SegmentListEntry * next
Definition: segment.c:47
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:205
AVFormatContext * avf
Definition: segment.c:69
const char * s
Definition: avisynth_c.h:668
Bytestream IO Context.
Definition: avio.h:68
char * time_delta_str
approximation value duration used for the segment times
Definition: segment.c:88
AVIOInterruptCB interrupt_callback
Custom interrupt callbacks for the I/O layer.
Definition: avformat.h:1125
AVOption.
Definition: opt.h:251
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:383
int av_write_frame(AVFormatContext *s, AVPacket *pkt)
Write a packet to an output media file.
Definition: mux.c:504
av_default_item_name
int av_escape(char **dst, const char *src, const char *special_chars, enum AVEscapeMode mode, int flags)
Escape string in src, and put the escaped string in an allocated string in *dst, which must be freed ...
Definition: avstring.c:271
int av_parse_time(int64_t *timeval, const char *timestr, int duration)
Parse timestr and return in *time a corresponding number of microseconds.
Definition: parseutils.c:530
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:154
static int segment_start(AVFormatContext *s, int write_header)
Definition: segment.c:172
static int write_packet(AVFormatContext *s, AVPacket *pkt)
int segment_idx_wrap
number after which the index wraps
Definition: segment.c:66
#define FAIL(err)
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown)
Definition: avformat.h:709
Sinusoidal phase f
#define AVIO_FLAG_WRITE
write-only
Definition: avio.h:333
unsigned char * buffer
Start of the buffer.
Definition: avio.h:82
#define FF_ARRAY_ELEMS(a)
av_dlog(ac->avr,"%d samples - audio_convert: %s to %s (%s)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt), use_generic?ac->func_descr_generic:ac->func_descr)
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining list
int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src)
Copy the settings of the source AVCodecContext into the destination AVCodecContext.
char filename[1024]
Definition: segment.c:46
static int parse_frames(void *log_ctx, int **frames, int *nb_frames, const char *frames_str)
Definition: segment.c:386
static int seg_write_header(AVFormatContext *s)
Definition: segment.c:522
static int segment_end(AVFormatContext *s, int write_trailer, int is_last)
Definition: segment.c:272
int list_flags
flags affecting list generation
Definition: segment.c:72
static void close_null_ctx(AVIOContext *pb)
Definition: segment.c:459
static int segment_mux_init(AVFormatContext *s)
Definition: segment.c:120
void av_freep(void *arg)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc() and set the pointer ...
Definition: mem.c:198
Format I/O context.
Definition: avformat.h:944
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:55
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
int flags
can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_RAWPICTURE, AVFMT_GLOBALHEADER, AVFMT_NOTIMESTAMPS, AVFMT_VARIABLE_FPS, AVFMT_NODIMENSIONS, AVFMT_NOSTREAMS, AVFMT_ALLOW_FLUSH, AVFMT_TS_NONSTRICT
Definition: avformat.h:397
uint8_t
Opaque data information usually continuous.
Definition: avutil.h:145
AVOptions.
enum AVCodecID av_codec_get_id(const struct AVCodecTag *const *tags, unsigned int tag)
Get the AVCodecID for the given codec tag tag.
timestamp utils, mostly useful for debugging/logging purposes
static AVPacket pkt
Definition: demuxing.c:56
end end
int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec)
Check if the stream st contained in s is matched by the stream specifier spec.
static int seg_write_trailer(struct AVFormatContext *s)
Definition: segment.c:730
AVStream * avformat_new_stream(AVFormatContext *s, const AVCodec *c)
Add a new stream to a media file.
AVStream ** streams
Definition: avformat.h:992
AVFormatContext * avformat_alloc_context(void)
Allocate an AVFormatContext.
static double av_q2d(AVRational a)
Convert rational to double.
Definition: rational.h:69
int av_match_ext(const char *filename, const char *extensions)
Return a positive value if the given filename has one of the given extensions, 0 otherwise.
int duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
char * format
format to use for output segment files
Definition: segment.c:70
static int select_reference_stream(AVFormatContext *s)
Definition: segment.c:465
static int write_trailer(AVFormatContext *s)
struct AVOutputFormat * oformat
Definition: avformat.h:958
int64_t time_delta
Definition: segment.c:89
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:130
void av_dict_copy(AVDictionary **dst, AVDictionary *src, int flags)
Copy entries from one AVDictionary struct into another.
Definition: dict.c:176
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:109
AVDictionary * metadata
Definition: avformat.h:1092
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:183
int individual_header_trailer
Set by a private option.
Definition: segment.c:90
#define av_ts2timestr(ts, tb)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: timestamp.h:72
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
int avio_close(AVIOContext *s)
Close the resource accessed by the AVIOContext s and free it.
Definition: aviobuf.c:821
simple assert() macros that are a bit more flexible than ISO C assert().
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
int64_t * times
list of segment interval specification
Definition: segment.c:80
char * reference_stream_specifier
reference stream specifier
Definition: segment.c:94
#define FFMAX(a, b)
Definition: common.h:56
static int set_segment_filename(AVFormatContext *s)
Definition: segment.c:156
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:82
int reference_stream_index
Definition: segment.c:95
int nb_times
number of elments in the times array
Definition: segment.c:81
#define OFFSET(x)
Definition: segment.c:765
static int segment_list_open(AVFormatContext *s)
Definition: segment.c:207
int flags
A combination of AV_PKT_FLAG values.
int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b)
Compare 2 timestamps each in its own timebases.
Definition: mathematics.c:135
Use auto-selected escaping mode.
Definition: avstring.h:257
AVIOContext * list_pb
list file put-byte context
Definition: segment.c:75
AVCodecContext * codec
Codec context associated with this stream.
Definition: avformat.h:662
unsigned int nb_streams
A list of all streams in the file.
Definition: avformat.h:991
#define AV_LOG_VERBOSE
Definition: log.h:157
static void print_csv_escaped_str(AVIOContext *ctx, const char *str)
Definition: segment.c:104
int void avio_flush(AVIOContext *s)
Force flushing of buffered data to the output s.
Definition: aviobuf.c:193
char filename[1024]
input or output filename
Definition: avformat.h:994
ret
Definition: avfilter.c:821
#define AVFMT_GLOBALHEADER
Format wants global header.
Definition: avformat.h:351
static const AVClass sseg_class
Definition: segment.c:817
t
Definition: genspecsines3.m:6
const char * name
Definition: avformat.h:378
int reset_timestamps
reset timestamps at the begin of each segment
Definition: segment.c:93
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample format(the sample packing is implied by the sample format) and sample rate.The lists are not just lists
ListType
Definition: segment.c:50
struct SegmentListEntry SegmentListEntry
int avoid_negative_ts
Avoid negative timestamps during muxing.
Definition: avformat.h:1180
if it could not because there are no more frames
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...
Opaque data information usually sparse.
Definition: avutil.h:147
const AVClass * priv_class
AVClass for the private context.
Definition: avformat.h:406
LIBAVUTIL_VERSION_INT
Definition: eval.c:55
#define AV_DISPOSITION_ATTACHED_PIC
The stream is stored in the file as an attached picture/"cover art" (e.g.
Definition: avformat.h:627
int av_get_frame_filename(char *buf, int buf_size, const char *path, int number)
Return in &#39;buf&#39; the path with &#39;d&#39; replaced by a number.
static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
Definition: segment.c:642
Stream structure.
Definition: avformat.h:643
char * list
filename for the segment list file
Definition: segment.c:71
char * frames_str
segment frame numbers specification string
Definition: segment.c:83
NULL
Definition: eval.c:55
enum AVMediaType codec_type
enum AVCodecID codec_id
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition: avutil.h:202
char * av_strdup(const char *s)
Duplicate the string s.
Definition: mem.c:220
AVIOContext * pb
I/O context.
Definition: avformat.h:977
const struct AVCodecTag *const * codec_tag
List of supported codec_id-codec_tag pairs, ordered by "better choice first".
Definition: avformat.h:403
void avio_w8(AVIOContext *s, int b)
Definition: aviobuf.c:151
main external API structure.
int64_t time
segment duration
Definition: segment.c:77
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
unsigned int codec_tag
fourcc (LSB first, so "ABCD" -> (&#39;D&#39;<<24) + (&#39;C&#39;<<16) + (&#39;B&#39;<<8) + &#39;A&#39;).
void * buf
Definition: avisynth_c.h:594
AVOutputFormat ff_segment_muxer
Definition: segment.c:806
int segment_idx
index of the segment file to write, starting from 0
Definition: segment.c:65
void * av_malloc(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:73
Describe the class of an AVClass context structure.
Definition: log.h:50
int * frames
list of frame number specification
Definition: segment.c:84
int64_t start_pts
Definition: segment.c:45
synthesis window for stochastic i
char * time_str
segment duration specification string
Definition: segment.c:76
AVMediaType
Definition: avutil.h:141
int avio_open2(AVIOContext **s, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options)
Create and initialize a AVIOContext for accessing the resource indicated by url.
Definition: aviobuf.c:804
void avformat_free_context(AVFormatContext *s)
Free an AVFormatContext and all its streams.
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
misc parsing utilities
#define type
int is_first_pkt
tells if it is the first packet in the segment
Definition: segment.c:101
SegmentListEntry * segment_list_entries
Definition: segment.c:98
const char * av_get_media_type_string(enum AVMediaType media_type)
Return a string describing the media_type enum, NULL if media_type is unknown.
int nb_frames
number of elments in the frames array
Definition: segment.c:85
static int flags
Definition: cpu.c:23
int write_header_trailer
Set by a private option.
Definition: segment.c:91
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok()...
Definition: avstring.c:183
static void segment_list_print_entry(AVIOContext *list_ioctx, ListType list_type, const SegmentListEntry *list_entry, void *log_ctx)
Definition: segment.c:237
double end_time
Definition: segment.c:44
static const AVClass seg_class
Definition: segment.c:799
Main libavformat public API header.
void av_opt_free(void *obj)
Free all string and binary options in obj.
Definition: opt.c:1194
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:162
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition: avformat.h:345
int ff_write_chained(AVFormatContext *dst, int dst_stream, AVPacket *pkt, AVFormatContext *src)
Write a packet to another muxer than the one the user originally intended.
int disposition
AV_DISPOSITION_* bit field.
Definition: avformat.h:700
#define SEGMENT_LIST_FLAG_CACHE
Definition: segment.c:60
#define E
Definition: segment.c:766
static int parse_times(void *log_ctx, int64_t **times, int *nb_times, const char *times_str)
Definition: segment.c:328
double start_time
Definition: segment.c:44
#define av_ts2str(ts)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: timestamp.h:50
void * priv_data
Format private data.
Definition: avformat.h:964
static const AVOption options[]
Definition: segment.c:767
#define AV_ESCAPE_FLAG_WHITESPACE
Consider spaces special and escape them even in the middle of the string.
Definition: avstring.h:270
static void write_header(FFV1Context *f)
Definition: ffv1enc.c:470
AVOutputFormat ff_stream_segment_muxer
Definition: segment.c:824
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
int av_write_trailer(AVFormatContext *s)
Write the stream trailer to an output media file and free the file private data.
Definition: mux.c:769
static int open_null_ctx(AVIOContext **ctx)
Definition: segment.c:445
#define AVERROR_MUXER_NOT_FOUND
Muxer not found.
Definition: error.h:60
int segment_count
number of segment files already written
Definition: segment.c:67
char * times_str
segment times specification string
Definition: segment.c:79
ListType list_type
set the list type
Definition: segment.c:74
Note except for filters that can have queued request_frame does not push and as a the filter_frame method will be called and do the work Legacy the filter_frame method was it was made of start_frame
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
Definition: avformat.h:679
SegmentListEntry cur_entry
Definition: segment.c:97
unsigned int av_codec_get_tag(const struct AVCodecTag *const *tags, enum AVCodecID id)
Get the codec tag for the given codec id id.
int list_size
number of entries for the segment list file
Definition: segment.c:73
deprecated
Definition: segment.c:55
This structure stores compressed data.
int frame_count
Definition: segment.c:86
int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
Definition: opt.c:252
#define SEGMENT_LIST_FLAG_LIVE
Definition: segment.c:61
SegmentListEntry * segment_list_entries_end
Definition: segment.c:99
AVOutputFormat * oformat
Definition: segment.c:68
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:190
int avio_printf(AVIOContext *s, const char *fmt,...) av_printf_format(2