Browse code

lavf/segment: add reference_stream option

Stefano Sabatini authored on 2012/12/23 05:49:06
Showing 3 changed files
... ...
@@ -493,7 +493,9 @@ streaming output formats, i.e. which do not require global headers,
493 493
 and is recommended for outputting e.g. to MPEG transport stream segments.
494 494
 @code{ssegment} is a shorter alias for @code{stream_segment}.
495 495
 
496
-Every segment starts with a video keyframe, if a video stream is present.
496
+Every segment starts with a keyframe of the selected reference stream,
497
+which is set through the @option{reference_stream} option.
498
+
497 499
 Note that if you want accurate splitting for a video file, you need to
498 500
 make the input key frames correspond to the exact splitting times
499 501
 expected by the segmenter, or the segment muxer will start the new
... ...
@@ -509,6 +511,13 @@ the option @var{segment_list}. The list type is specified by the
509 509
 The segment muxer supports the following options:
510 510
 
511 511
 @table @option
512
+@item reference_stream @var{specifier}
513
+Set the reference stream, as specified by the string @var{specifier}.
514
+If @var{specifier} is set to @code{auto}, the reference is choosen
515
+automatically. Otherwise it must a stream specifier (see the ``Stream
516
+specifiers'' chapter in the ffmpeg manual) which specifies the
517
+reference stream. The default value is ``auto''.
518
+
512 519
 @item segment_format @var{format}
513 520
 Override the inner container format, by default it is guessed by the filename
514 521
 extension.
... ...
@@ -74,7 +74,9 @@ typedef struct {
74 74
     int  write_header_trailer; /**< Set by a private option. */
75 75
 
76 76
     int reset_timestamps;  ///< reset timestamps at the begin of each segment
77
-    int has_video;
77
+    char *reference_stream_specifier; ///< reference stream specifier
78
+    int   reference_stream_index;
79
+
78 80
     double start_time, end_time;
79 81
     int64_t start_pts, start_dts;
80 82
     int is_first_pkt;      ///< tells if it is the first packet in the segment
... ...
@@ -398,14 +400,57 @@ static int seg_write_header(AVFormatContext *s)
398 398
     if (seg->list_type == LIST_TYPE_EXT)
399 399
         av_log(s, AV_LOG_WARNING, "'ext' list type option is deprecated in favor of 'csv'\n");
400 400
 
401
-    for (i = 0; i < s->nb_streams; i++)
402
-        seg->has_video +=
403
-            (s->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO);
401
+    seg->reference_stream_index = -1;
402
+    if (!strcmp(seg->reference_stream_specifier, "auto")) {
403
+        /* select first index of type with highest priority */
404
+        int type_index_map[AVMEDIA_TYPE_NB];
405
+        static const enum AVMediaType type_priority_list[] = {
406
+            AVMEDIA_TYPE_VIDEO,
407
+            AVMEDIA_TYPE_AUDIO,
408
+            AVMEDIA_TYPE_SUBTITLE,
409
+            AVMEDIA_TYPE_DATA,
410
+            AVMEDIA_TYPE_ATTACHMENT
411
+        };
412
+        enum AVMediaType type;
413
+
414
+        for (i = 0; i < AVMEDIA_TYPE_NB; i++)
415
+            type_index_map[i] = -1;
416
+
417
+        /* select first index for each type */
418
+        for (i = 0; i < s->nb_streams; i++) {
419
+            type = s->streams[i]->codec->codec_type;
420
+            if ((unsigned)type < AVMEDIA_TYPE_NB && type_index_map[type] == -1)
421
+                type_index_map[type] = i;
422
+        }
423
+
424
+        for (i = 0; i < FF_ARRAY_ELEMS(type_priority_list); i++) {
425
+            type = type_priority_list[i];
426
+            if ((seg->reference_stream_index = type_index_map[type]) >= 0)
427
+                break;
428
+        }
429
+    } else {
430
+        for (i = 0; i < s->nb_streams; i++) {
431
+            ret = avformat_match_stream_specifier(s, s->streams[i],
432
+                                                  seg->reference_stream_specifier);
433
+            if (ret < 0)
434
+                goto fail;
435
+            if (ret > 0) {
436
+                seg->reference_stream_index = i;
437
+                break;
438
+            }
439
+        }
440
+    }
441
+
442
+    if (seg->reference_stream_index < 0) {
443
+        av_log(s, AV_LOG_ERROR, "Could not select stream matching identifier '%s'\n",
444
+               seg->reference_stream_specifier);
445
+        ret = AVERROR(EINVAL);
446
+        goto fail;
447
+    }
404 448
 
405
-    if (seg->has_video > 1)
406
-        av_log(s, AV_LOG_WARNING,
407
-               "More than a single video stream present, "
408
-               "expect issues decoding it.\n");
449
+    av_log(s, AV_LOG_VERBOSE, "Selected stream id:%d type:%s\n",
450
+           seg->reference_stream_index,
451
+           av_get_media_type_string(s->streams[seg->reference_stream_index]->codec->codec_type));
409 452
 
410 453
     seg->oformat = av_guess_format(seg->format, s->filename, NULL);
411 454
 
... ...
@@ -478,8 +523,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
478 478
         end_pts = seg->time * seg->segment_count;
479 479
     }
480 480
 
481
-    /* if the segment has video, start a new segment *only* with a key video frame */
482
-    if ((st->codec->codec_type == AVMEDIA_TYPE_VIDEO || !seg->has_video) &&
481
+    if (pkt->stream_index == seg->reference_stream_index &&
483 482
         pkt->pts != AV_NOPTS_VALUE &&
484 483
         av_compare_ts(pkt->pts, st->time_base,
485 484
                       end_pts-seg->time_delta, AV_TIME_BASE_Q) >= 0 &&
... ...
@@ -565,6 +609,7 @@ fail:
565 565
 #define OFFSET(x) offsetof(SegmentContext, x)
566 566
 #define E AV_OPT_FLAG_ENCODING_PARAM
567 567
 static const AVOption options[] = {
568
+    { "reference_stream",  "set reference stream", OFFSET(reference_stream_specifier), AV_OPT_TYPE_STRING, {.str = "auto"}, CHAR_MIN, CHAR_MAX, E },
568 569
     { "segment_format",    "set container format used for the segments", OFFSET(format),  AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E },
569 570
     { "segment_list",      "set the segment list filename",              OFFSET(list),    AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E },
570 571
 
... ...
@@ -31,7 +31,7 @@
31 31
 
32 32
 #define LIBAVFORMAT_VERSION_MAJOR 54
33 33
 #define LIBAVFORMAT_VERSION_MINOR 50
34
-#define LIBAVFORMAT_VERSION_MICRO 102
34
+#define LIBAVFORMAT_VERSION_MICRO 103
35 35
 
36 36
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
37 37
                                                LIBAVFORMAT_VERSION_MINOR, \