]> git.sesse.net Git - ffmpeg/commitdiff
Merge commit '65d12900432ac880d764edbbd36818431484a76e'
authorMichael Niedermayer <michaelni@gmx.at>
Fri, 5 Oct 2012 14:52:13 +0000 (16:52 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Fri, 5 Oct 2012 14:52:13 +0000 (16:52 +0200)
* commit '65d12900432ac880d764edbbd36818431484a76e':
  configure: add --enable-lto option
  x86: cpu: Break out test for cpuid capabilities into separate function
  x86: ff_get_cpu_flags_x86(): Avoid a pointless variable indirection
  build: Factor out mpegaudio dependencies to CONFIG_MPEGAUDIO
  segment: Add comments about calls that only are relevant for some muxers
  segment: Add an option for omitting the first header and final trailer

Conflicts:
configure
libavcodec/Makefile
libavformat/segment.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
1  2 
configure
libavcodec/Makefile
libavformat/segment.c
libavutil/x86/cpu.c

diff --cc configure
index 817c9cfac77d0d7ca13c11ad28ec11450ae36a35,4c3ebdb28120ce63e4baf0735b251090949a0041..449a46ecaeb95591f196a0be4d3d3a90145cd6b2
+++ b/configure
@@@ -1439,8 -1291,8 +1441,9 @@@ CMDLINE_SELECT=
      debug
      extra_warnings
      logging
+     lto
      optimizations
 +    stripping
  "
  
  PATHS_LIST='
@@@ -3847,22 -3447,32 +3851,37 @@@ void ff_foo(void) {
  EOF
  fi
  
- if [ -n "$optflags" ]; then
-     add_cflags $optflags
- elif enabled small; then
-     add_cflags $cflags_size
- elif enabled optimizations; then
-     add_cflags $cflags_speed
- else
-     add_cflags $cflags_noopt
+ if [ -z "$optflags" ]; then
+     if enabled small; then
+         optflags=$cflags_size
+     elif enabled optimizations; then
+         optflags=$cflags_speed
+     else
+         optflags=$cflags_noopt
+     fi
+ fi
+ check_optflags(){
+     check_cflags "$@"
+     enabled lto && check_ldflags "$@"
+ }
+ if enabled lto; then
+     test "$cc_type" != "$ld_type" && die "LTO requires same compiler and linker"
+     check_cflags  -flto
+     check_ldflags -flto $cpuflags
  fi
- check_cflags -fno-math-errno
- check_cflags -fno-signed-zeros
+ check_optflags $optflags
+ check_optflags -fno-math-errno
+ check_optflags -fno-signed-zeros
 +check_cc -mno-red-zone <<EOF && noredzone_flags="-mno-red-zone"
 +int x;
 +EOF
 +
 +
  if enabled icc; then
      # Just warnings, no remarks
      check_cflags -w1
@@@ -3896,9 -3506,10 +3915,9 @@@ elif enabled ccc; the
      add_cflags -msg_disable ptrmismatch1
      add_cflags -msg_disable unreachcode
  elif enabled gcc; then
-     check_cflags -fno-tree-vectorize
+     check_optflags -fno-tree-vectorize
      check_cflags -Werror=implicit-function-declaration
      check_cflags -Werror=missing-prototypes
 -    check_cflags -Werror=declaration-after-statement
  elif enabled llvm_gcc; then
      check_cflags -mllvm -stack-alignment=16
  elif enabled clang; then
index 8471b63f9de1a329fbd45e065257d70fff8953b4,bd6567eb526284071cb59174694b2ba340bcc535..5176f60d8f5ad5eee08412d939d08dea5aaa0921
@@@ -255,40 -225,23 +257,28 @@@ OBJS-$(CONFIG_MJPEGB_DECODER)          
  OBJS-$(CONFIG_MLP_DECODER)             += mlpdec.o mlpdsp.o
  OBJS-$(CONFIG_MMVIDEO_DECODER)         += mmvideo.o
  OBJS-$(CONFIG_MOTIONPIXELS_DECODER)    += motionpixels.o
- OBJS-$(CONFIG_MP1_DECODER)             += mpegaudiodec.o mpegaudiodecheader.o \
-                                           mpegaudio.o mpegaudiodata.o
- OBJS-$(CONFIG_MP1FLOAT_DECODER)        += mpegaudiodec_float.o mpegaudiodecheader.o \
-                                           mpegaudio.o mpegaudiodata.o
- OBJS-$(CONFIG_MP2_DECODER)             += mpegaudiodec.o mpegaudiodecheader.o \
-                                           mpegaudio.o mpegaudiodata.o
 +OBJS-$(CONFIG_MOVTEXT_DECODER)         += movtextdec.o ass.o
 +OBJS-$(CONFIG_MOVTEXT_ENCODER)         += movtextenc.o ass_split.o
+ OBJS-$(CONFIG_MP1_DECODER)             += mpegaudiodec.o
+ OBJS-$(CONFIG_MP1FLOAT_DECODER)        += mpegaudiodec_float.o
+ OBJS-$(CONFIG_MP2_DECODER)             += mpegaudiodec.o
  OBJS-$(CONFIG_MP2_ENCODER)             += mpegaudioenc.o mpegaudio.o \
                                            mpegaudiodata.o mpegaudiodsp_data.o
- OBJS-$(CONFIG_MP2FLOAT_DECODER)        += mpegaudiodec_float.o mpegaudiodecheader.o \
-                                           mpegaudio.o mpegaudiodata.o
- OBJS-$(CONFIG_MP3ADU_DECODER)          += mpegaudiodec.o mpegaudiodecheader.o \
-                                           mpegaudio.o mpegaudiodata.o
- OBJS-$(CONFIG_MP3ADUFLOAT_DECODER)     += mpegaudiodec_float.o mpegaudiodecheader.o \
-                                           mpegaudio.o mpegaudiodata.o
- OBJS-$(CONFIG_MP3ON4_DECODER)          += mpegaudiodec.o mpegaudiodecheader.o \
-                                           mpegaudio.o mpegaudiodata.o         \
-                                           mpeg4audio.o
- OBJS-$(CONFIG_MP3ON4FLOAT_DECODER)     += mpegaudiodec_float.o mpegaudiodecheader.o \
-                                           mpegaudio.o mpegaudiodata.o         \
-                                           mpeg4audio.o
- OBJS-$(CONFIG_MP3_DECODER)             += mpegaudiodec.o mpegaudiodecheader.o \
-                                           mpegaudio.o mpegaudiodata.o
- OBJS-$(CONFIG_MP3FLOAT_DECODER)        += mpegaudiodec_float.o mpegaudiodecheader.o \
-                                           mpegaudio.o mpegaudiodata.o
+ OBJS-$(CONFIG_MP2FLOAT_DECODER)        += mpegaudiodec_float.o
+ OBJS-$(CONFIG_MP3_DECODER)             += mpegaudiodec.o
+ OBJS-$(CONFIG_MP3ADU_DECODER)          += mpegaudiodec.o
+ OBJS-$(CONFIG_MP3ADUFLOAT_DECODER)     += mpegaudiodec_float.o
+ OBJS-$(CONFIG_MP3FLOAT_DECODER)        += mpegaudiodec_float.o
+ OBJS-$(CONFIG_MP3ON4_DECODER)          += mpegaudiodec.o mpeg4audio.o
+ OBJS-$(CONFIG_MP3ON4FLOAT_DECODER)     += mpegaudiodec_float.o mpeg4audio.o
  OBJS-$(CONFIG_MPC7_DECODER)            += mpc7.o mpc.o
  OBJS-$(CONFIG_MPC8_DECODER)            += mpc8.o mpc.o
 +OBJS-$(CONFIG_MPEGVIDEO_DECODER)       += mpeg12.o mpeg12data.o \
 +                                          mpegvideo.o error_resilience.o
  OBJS-$(CONFIG_MPEG_XVMC_DECODER)       += mpegvideo_xvmc.o
  OBJS-$(CONFIG_MPEG1VIDEO_DECODER)      += mpeg12.o mpeg12data.o
 -OBJS-$(CONFIG_MPEG1VIDEO_ENCODER)      += mpeg12enc.o mpeg12.o
 +OBJS-$(CONFIG_MPEG1VIDEO_ENCODER)      += mpeg12enc.o mpeg12.o          \
 +                                          timecode.o
  OBJS-$(CONFIG_MPEG2_DXVA2_HWACCEL)     += dxva2_mpeg2.o
  OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL)     += vaapi_mpeg2.o
  OBJS-$(CONFIG_MPEG2VIDEO_DECODER)      += mpeg12.o mpeg12data.o
index e49b93b89b856d17fa9ccee6d6b9677501884ad8,375df583967da892310b407ebee0284cbd261e6b..0284fac51e1ebc813b0d293aa5064ee21819d2d8
  #include "libavutil/parseutils.h"
  #include "libavutil/mathematics.h"
  
 +typedef enum {
 +    LIST_TYPE_UNDEFINED = -1,
 +    LIST_TYPE_FLAT = 0,
 +    LIST_TYPE_CSV,
 +    LIST_TYPE_M3U8,
 +    LIST_TYPE_EXT, ///< deprecated
 +    LIST_TYPE_NB,
 +} ListType;
 +
 +
 +#define SEGMENT_LIST_FLAG_CACHE 1
 +#define SEGMENT_LIST_FLAG_LIVE  2
 +
  typedef struct {
      const AVClass *class;  /**< Class for private options. */
 -    int number;
 +    int segment_idx;       ///< index of the segment file to write, starting from 0
 +    int segment_idx_wrap;  ///< number after which the index wraps
 +    int segment_count;     ///< number of segment files already written
      AVOutputFormat *oformat;
      AVFormatContext *avf;
 -    char *format;          /**< Set by a private option. */
 -    char *list;            /**< Set by a private option. */
 -    float time;            /**< Set by a private option. */
 -    int  size;             /**< Set by a private option. */
 -    int  wrap;             /**< Set by a private option. */
 +    char *format;          ///< format to use for output segment files
 +    char *list;            ///< filename for the segment list file
 +    int   list_count;      ///< list counter
 +    int   list_flags;      ///< flags affecting list generation
 +    int   list_size;       ///< number of entries for the segment list file
 +    double list_max_segment_time; ///< max segment time in the current list
 +    ListType list_type;    ///< set the list type
 +    AVIOContext *list_pb;  ///< list file put-byte context
 +    char *time_str;        ///< segment duration specification string
 +    int64_t time;          ///< segment duration
 +    char *times_str;       ///< segment times specification string
 +    int64_t *times;        ///< list of segment interval specification
 +    int nb_times;          ///< number of elments in the times array
 +    char *time_delta_str;  ///< approximation value duration used for the segment times
 +    int64_t time_delta;
      int  individual_header_trailer; /**< Set by a private option. */
 -    int64_t offset_time;
 -    int64_t recording_time;
+     int  write_header_trailer; /**< Set by a private option. */
      int has_video;
 -    AVIOContext *pb;
 +    double start_time, end_time;
  } SegmentContext;
  
 +static void print_csv_escaped_str(AVIOContext *ctx, const char *str)
 +{
 +    int needs_quoting = !!str[strcspn(str, "\",\n\r")];
 +
 +    if (needs_quoting)
 +        avio_w8(ctx, '"');
 +
 +    for (; *str; str++) {
 +        if (*str == '"')
 +            avio_w8(ctx, '"');
 +        avio_w8(ctx, *str);
 +    }
 +    if (needs_quoting)
 +        avio_w8(ctx, '"');
 +}
 +
  static int segment_mux_init(AVFormatContext *s)
  {
      SegmentContext *seg = s->priv_data;
@@@ -155,196 -108,54 +156,218 @@@ static int segment_start(AVFormatContex
      return 0;
  }
  
 -static int segment_end(AVFormatContext *oc, int write_trailer)
 +static int segment_list_open(AVFormatContext *s)
  {
 +    SegmentContext *seg = s->priv_data;
 +    int ret;
 +
 +    ret = avio_open2(&seg->list_pb, seg->list, AVIO_FLAG_WRITE,
 +                     &s->interrupt_callback, NULL);
 +    if (ret < 0)
 +        return ret;
 +    seg->list_max_segment_time = 0;
 +
 +    if (seg->list_type == LIST_TYPE_M3U8) {
 +        avio_printf(seg->list_pb, "#EXTM3U\n");
 +        avio_printf(seg->list_pb, "#EXT-X-VERSION:3\n");
 +        avio_printf(seg->list_pb, "#EXT-X-MEDIA-SEQUENCE:%d\n", seg->list_count);
 +        avio_printf(seg->list_pb, "#EXT-X-ALLOWCACHE:%d\n",
 +                    !!(seg->list_flags & SEGMENT_LIST_FLAG_CACHE));
 +        if (seg->list_flags & SEGMENT_LIST_FLAG_LIVE)
 +            avio_printf(seg->list_pb,
 +                        "#EXT-X-TARGETDURATION:%"PRId64"\n", seg->time / 1000000);
 +    }
 +
 +    return ret;
 +}
 +
 +static void segment_list_close(AVFormatContext *s)
 +{
 +    SegmentContext *seg = s->priv_data;
 +
 +    if (seg->list_type == LIST_TYPE_M3U8) {
 +        if (!(seg->list_flags & SEGMENT_LIST_FLAG_LIVE))
 +            avio_printf(seg->list_pb, "#EXT-X-TARGETDURATION:%d\n",
 +                        (int)ceil(seg->list_max_segment_time));
 +        avio_printf(seg->list_pb, "#EXT-X-ENDLIST\n");
 +    }
 +    seg->list_count++;
 +
 +    avio_close(seg->list_pb);
 +}
 +
 +static int segment_end(AVFormatContext *s, int write_trailer)
 +{
 +    SegmentContext *seg = s->priv_data;
 +    AVFormatContext *oc = seg->avf;
      int ret = 0;
  
-     av_write_frame(oc, NULL); /* Flush any buffered data */
+     av_write_frame(oc, NULL); /* Flush any buffered data (fragmented mp4) */
      if (write_trailer)
 -        av_write_trailer(oc);
 +        ret = av_write_trailer(oc);
 +
 +    if (ret < 0)
 +        av_log(s, AV_LOG_ERROR, "Failure occurred when ending segment '%s'\n",
 +               oc->filename);
 +
 +    if (seg->list) {
 +        if (seg->list_size && !(seg->segment_count % seg->list_size)) {
 +            segment_list_close(s);
 +            if ((ret = segment_list_open(s)) < 0)
 +                goto end;
 +        }
 +
 +        if (seg->list_type == LIST_TYPE_FLAT) {
 +            avio_printf(seg->list_pb, "%s\n", oc->filename);
 +        } else if (seg->list_type == LIST_TYPE_CSV || seg->list_type == LIST_TYPE_EXT) {
 +            print_csv_escaped_str(seg->list_pb, oc->filename);
 +            avio_printf(seg->list_pb, ",%f,%f\n", seg->start_time, seg->end_time);
 +        } else if (seg->list_type == LIST_TYPE_M3U8) {
 +            avio_printf(seg->list_pb, "#EXTINF:%f,\n%s\n",
 +                        seg->end_time - seg->start_time, oc->filename);
 +        }
 +        seg->list_max_segment_time = FFMAX(seg->end_time - seg->start_time, seg->list_max_segment_time);
 +        avio_flush(seg->list_pb);
 +    }
 +
 +end:
      avio_close(oc->pb);
  
      return ret;
  }
  
 +static int parse_times(void *log_ctx, int64_t **times, int *nb_times,
 +                       const char *times_str)
 +{
 +    char *p;
 +    int i, ret = 0;
 +    char *times_str1 = av_strdup(times_str);
 +    char *saveptr = NULL;
 +
 +    if (!times_str1)
 +        return AVERROR(ENOMEM);
 +
 +#define FAIL(err) ret = err; goto end
 +
 +    *nb_times = 1;
 +    for (p = times_str1; *p; p++)
 +        if (*p == ',')
 +            (*nb_times)++;
 +
 +    *times = av_malloc(sizeof(**times) * *nb_times);
 +    if (!*times) {
 +        av_log(log_ctx, AV_LOG_ERROR, "Could not allocate forced times array\n");
 +        FAIL(AVERROR(ENOMEM));
 +    }
 +
 +    p = times_str1;
 +    for (i = 0; i < *nb_times; i++) {
 +        int64_t t;
 +        char *tstr = av_strtok(p, ",", &saveptr);
 +        av_assert0(tstr);
 +        p = NULL;
 +
 +        ret = av_parse_time(&t, tstr, 1);
 +        if (ret < 0) {
 +            av_log(log_ctx, AV_LOG_ERROR,
 +                   "Invalid time duration specification in %s\n", p);
 +            FAIL(AVERROR(EINVAL));
 +        }
 +        (*times)[i] = t;
 +
 +        /* check on monotonicity */
 +        if (i && (*times)[i-1] > (*times)[i]) {
 +            av_log(log_ctx, AV_LOG_ERROR,
 +                   "Specified time %f is greater than the following time %f\n",
 +                   (float)((*times)[i])/1000000, (float)((*times)[i-1])/1000000);
 +            FAIL(AVERROR(EINVAL));
 +        }
 +    }
 +
 +end:
 +    av_free(times_str1);
 +    return ret;
 +}
 +
+ static int open_null_ctx(AVIOContext **ctx)
+ {
+     int buf_size = 32768;
+     uint8_t *buf = av_malloc(buf_size);
+     if (!buf)
+         return AVERROR(ENOMEM);
+     *ctx = avio_alloc_context(buf, buf_size, AVIO_FLAG_WRITE, NULL, NULL, NULL, NULL);
+     if (!*ctx) {
+         av_free(buf);
+         return AVERROR(ENOMEM);
+     }
+     return 0;
+ }
+ static void close_null_ctx(AVIOContext *pb)
+ {
+     av_free(pb->buffer);
+     av_free(pb);
+ }
  static int seg_write_header(AVFormatContext *s)
  {
      SegmentContext *seg = s->priv_data;
      AVFormatContext *oc = NULL;
      int ret, i;
  
 -    seg->number = 0;
 -    seg->offset_time = 0;
 -    seg->recording_time = seg->time * 1000000;
 +    seg->segment_count = 0;
+     if (!seg->write_header_trailer)
+         seg->individual_header_trailer = 0;
  
 -    if (seg->list)
 -        if ((ret = avio_open2(&seg->pb, seg->list, AVIO_FLAG_WRITE,
 -                              &s->interrupt_callback, NULL)) < 0)
 +    if (seg->time_str && seg->times_str) {
 +        av_log(s, AV_LOG_ERROR,
 +               "segment_time and segment_times options are mutually exclusive, select just one of them\n");
 +        return AVERROR(EINVAL);
 +    }
 +
 +    if ((seg->list_flags & SEGMENT_LIST_FLAG_LIVE) && seg->times_str) {
 +        av_log(s, AV_LOG_ERROR,
 +               "segment_flags +live and segment_times options are mutually exclusive:"
 +               "specify -segment_time if you want a live-friendly list\n");
 +        return AVERROR(EINVAL);
 +    }
 +
 +    if (seg->times_str) {
 +        if ((ret = parse_times(s, &seg->times, &seg->nb_times, seg->times_str)) < 0)
 +            return ret;
 +    } else {
 +        /* set default value if not specified */
 +        if (!seg->time_str)
 +            seg->time_str = av_strdup("2");
 +        if ((ret = av_parse_time(&seg->time, seg->time_str, 1)) < 0) {
 +            av_log(s, AV_LOG_ERROR,
 +                   "Invalid time duration specification '%s' for segment_time option\n",
 +                   seg->time_str);
 +            return ret;
 +        }
 +    }
 +
 +    if (seg->time_delta_str) {
 +        if ((ret = av_parse_time(&seg->time_delta, seg->time_delta_str, 1)) < 0) {
 +            av_log(s, AV_LOG_ERROR,
 +                   "Invalid time duration specification '%s' for delta option\n",
 +                   seg->time_delta_str);
 +            return ret;
 +        }
 +    }
 +
 +    if (seg->list) {
 +        if (seg->list_type == LIST_TYPE_UNDEFINED) {
 +            if      (av_match_ext(seg->list, "csv" )) seg->list_type = LIST_TYPE_CSV;
 +            else if (av_match_ext(seg->list, "ext" )) seg->list_type = LIST_TYPE_EXT;
 +            else if (av_match_ext(seg->list, "m3u8")) seg->list_type = LIST_TYPE_M3U8;
 +            else                                      seg->list_type = LIST_TYPE_FLAT;
 +        }
 +        if ((ret = segment_list_open(s)) < 0)
              goto fail;
 +    }
 +    if (seg->list_type == LIST_TYPE_EXT)
 +        av_log(s, AV_LOG_WARNING, "'ext' list type option is deprecated in favor of 'csv'\n");
  
      for (i = 0; i < s->nb_streams; i++)
          seg->has_video +=
          ret = AVERROR(EINVAL);
          goto fail;
      }
 +    seg->segment_count++;
  
-     if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
-                           &s->interrupt_callback, NULL)) < 0)
-         goto fail;
+     if (seg->write_header_trailer) {
+         if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
+                               &s->interrupt_callback, NULL)) < 0)
+             goto fail;
+     } else {
+         if ((ret = open_null_ctx(&oc->pb)) < 0)
+             goto fail;
+     }
  
      if ((ret = avformat_write_header(oc, NULL)) < 0) {
          avio_close(oc->pb);
          goto fail;
      }
  
 -    if (seg->list) {
 -        avio_printf(seg->pb, "%s\n", oc->filename);
 -        avio_flush(seg->pb);
 -    }
 -
+     if (!seg->write_header_trailer) {
+         close_null_ctx(oc->pb);
+         if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
+                               &s->interrupt_callback, NULL)) < 0)
+             goto fail;
+     }
  fail:
      if (ret) {
          if (seg->list)
@@@ -454,13 -279,17 +489,21 @@@ static int seg_write_trailer(struct AVF
  {
      SegmentContext *seg = s->priv_data;
      AVFormatContext *oc = seg->avf;
-     int ret = segment_end(s, 1);
+     int ret;
+     if (!seg->write_header_trailer) {
 -        ret = segment_end(oc, 0);
++        ret = segment_end(s, 0);
+         open_null_ctx(&oc->pb);
+         av_write_trailer(oc);
+         close_null_ctx(oc->pb);
+     } else {
 -        ret = segment_end(oc, 1);
++        ret = segment_end(s, 1);
+     }
      if (seg->list)
 -        avio_close(seg->pb);
 +        segment_list_close(s);
 +
 +    av_opt_free(seg);
 +    av_freep(&seg->times);
 +
      avformat_free_context(oc);
      return ret;
  }
  #define OFFSET(x) offsetof(SegmentContext, x)
  #define E AV_OPT_FLAG_ENCODING_PARAM
  static const AVOption options[] = {
 -    { "segment_format",    "container format used for the segments",  OFFSET(format),  AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E },
 -    { "segment_time",      "segment length in seconds",               OFFSET(time),    AV_OPT_TYPE_FLOAT,  {.dbl = 2},     0, FLT_MAX, E },
 -    { "segment_list",      "output the segment list",                 OFFSET(list),    AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E },
 -    { "segment_list_size", "maximum number of playlist entries",      OFFSET(size),    AV_OPT_TYPE_INT,    {.i64 = 5},     0, INT_MAX, E },
 -    { "segment_wrap",      "number after which the index wraps",      OFFSET(wrap),    AV_OPT_TYPE_INT,    {.i64 = 0},     0, INT_MAX, E },
 +    { "segment_format",    "set container format used for the segments", OFFSET(format),  AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E },
 +    { "segment_list",      "set the segment list filename",              OFFSET(list),    AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E },
 +
 +    { "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"},
 +    { "cache",             "allow list caching",                                    0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_LIST_FLAG_CACHE }, INT_MIN, INT_MAX,   E, "list_flags"},
 +    { "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"},
 +
 +    { "segment_list_size", "set the maximum number of playlist entries", OFFSET(list_size), AV_OPT_TYPE_INT,  {.i64 = 0},     0, INT_MAX, E },
 +    { "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" },
 +    { "flat", "flat format",     0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_FLAT }, INT_MIN, INT_MAX, 0, "list_type" },
 +    { "csv",  "csv format",      0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_CSV  }, INT_MIN, INT_MAX, 0, "list_type" },
 +    { "ext",  "extended format", 0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_EXT  }, INT_MIN, INT_MAX, 0, "list_type" },
 +    { "m3u8", "M3U8 format",     0, AV_OPT_TYPE_CONST, {.i64=LIST_TYPE_M3U8 }, INT_MIN, INT_MAX, 0, "list_type" },
 +    { "segment_time",      "set segment duration",                       OFFSET(time_str),AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E },
 +    { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta_str), AV_OPT_TYPE_STRING, {.str = "0"}, 0, 0, E },
 +    { "segment_times",     "set segment split time points",              OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL},  0, 0,       E },
 +    { "segment_wrap",      "set number after which the index wraps",     OFFSET(segment_idx_wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E },
      { "individual_header_trailer", "write header/trailer to each segment", OFFSET(individual_header_trailer), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, E },
+     { "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 },
      { NULL },
  };
  
Simple merge