]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/segment.c
avformat: remove deprecated AVStream.codec
[ffmpeg] / libavformat / segment.c
index 6e37707f9f07ba878fa4db2a9cf9ade7137d2724..74106445e6ef0a66dcf86ec49c50a3ff6bf2a3ac 100644 (file)
@@ -72,15 +72,15 @@ typedef struct SegmentContext {
     int segment_idx_wrap;  ///< number after which the index wraps
     int segment_idx_wrap_nb;  ///< number of time the index has wraped
     int segment_count;     ///< number of segment files already written
-    ff_const59 AVOutputFormat *oformat;
+    const AVOutputFormat *oformat;
     AVFormatContext *avf;
     char *format;              ///< format to use for output segment files
-    char *format_options_str;  ///< format options to use for output segment files
     AVDictionary *format_options;
     char *list;            ///< filename for the segment list file
     int   list_flags;      ///< flags affecting list generation
     int   list_size;       ///< number of entries for the segment list file
 
+    int is_nullctx;       ///< whether avf->pb is a nullctx
     int use_clocktime;    ///< flag to cut segments at regular clock time
     int64_t clocktime_offset; //< clock offset for cutting the segments at regular clock time
     int64_t clocktime_wrap_duration; //< wrapping duration considered for starting a new segment
@@ -91,7 +91,6 @@ typedef struct SegmentContext {
     char *entry_prefix;    ///< prefix to add to list entry filenames
     int 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
     int use_strftime;      ///< flag to expand filename with strftime
     int increment_tc;      ///< flag to increment timecode if found
@@ -163,14 +162,15 @@ static int segment_mux_init(AVFormatContext *s)
     oc->flags              = s->flags;
 
     for (i = 0; i < s->nb_streams; i++) {
-        AVStream *st;
-        AVCodecParameters *ipar, *opar;
+        AVStream *st, *ist = s->streams[i];
+        AVCodecParameters *ipar = ist->codecpar, *opar;
 
         if (!(st = avformat_new_stream(oc, NULL)))
             return AVERROR(ENOMEM);
-        ipar = s->streams[i]->codecpar;
+        ret = ff_stream_encode_params_copy(st, ist);
+        if (ret < 0)
+            return ret;
         opar = st->codecpar;
-        avcodec_parameters_copy(opar, ipar);
         if (!oc->oformat->codec_tag ||
             av_codec_get_id (oc->oformat->codec_tag, ipar->codec_tag) == opar->codec_id ||
             av_codec_get_tag(oc->oformat->codec_tag, ipar->codec_id) <= 0) {
@@ -178,9 +178,6 @@ static int segment_mux_init(AVFormatContext *s)
         } else {
             opar->codec_tag = 0;
         }
-        st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio;
-        st->time_base = s->streams[i]->time_base;
-        av_dict_copy(&st->metadata, s->streams[i]->metadata, 0);
     }
 
     return 0;
@@ -421,7 +418,7 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last)
                     rate = s->streams[i]->avg_frame_rate;/* Get fps from the video stream */
                     err = av_timecode_init_from_string(&tc, rate, tcr->value, s);
                     if (err < 0) {
-                        av_log(s, AV_LOG_WARNING, "Could not increment timecode, error occurred during timecode creation.");
+                        av_log(s, AV_LOG_WARNING, "Could not increment global timecode, error occurred during timecode creation.\n");
                         break;
                     }
                     tc.start += (int)((seg->cur_entry.end_time - seg->cur_entry.start_time) * av_q2d(rate));/* increment timecode */
@@ -431,7 +428,23 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last)
                 }
             }
         } else {
-            av_log(s, AV_LOG_WARNING, "Could not increment timecode, no timecode metadata found");
+            av_log(s, AV_LOG_WARNING, "Could not increment global timecode, no global timecode metadata found.\n");
+        }
+        for (i = 0; i < s->nb_streams; i++) {
+            if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
+                char st_buf[AV_TIMECODE_STR_SIZE];
+                AVTimecode st_tc;
+                AVRational st_rate = s->streams[i]->avg_frame_rate;
+                AVDictionaryEntry *st_tcr = av_dict_get(s->streams[i]->metadata, "timecode", NULL, 0);
+                if (st_tcr) {
+                    if ((av_timecode_init_from_string(&st_tc, st_rate, st_tcr->value, s) < 0)) {
+                        av_log(s, AV_LOG_WARNING, "Could not increment stream %d timecode, error occurred during timecode creation.\n", i);
+                        continue;
+                    }
+                st_tc.start += (int)((seg->cur_entry.end_time - seg->cur_entry.start_time) * av_q2d(st_rate));    // increment timecode
+                av_dict_set(&s->streams[i]->metadata, "timecode", av_timecode_make_string(&st_tc, st_buf, 0), 0);
+                }
+            }
         }
     }
 
@@ -488,7 +501,7 @@ static int parse_times(void *log_ctx, int64_t **times, int *nb_times,
         /* 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",
+                   "Specified time %f is smaller than the last time %f\n",
                    (float)((*times)[i])/1000000, (float)((*times)[i-1])/1000000);
             FAIL(AVERROR(EINVAL));
         }
@@ -502,60 +515,52 @@ end:
 static int parse_frames(void *log_ctx, int **frames, int *nb_frames,
                         const char *frames_str)
 {
-    char *p;
-    int i, ret = 0;
-    char *frames_str1 = av_strdup(frames_str);
-    char *saveptr = NULL;
-
-    if (!frames_str1)
-        return AVERROR(ENOMEM);
-
-#define FAIL(err) ret = err; goto end
+    const char *p;
+    int i;
 
     *nb_frames = 1;
-    for (p = frames_str1; *p; p++)
+    for (p = frames_str; *p; p++)
         if (*p == ',')
             (*nb_frames)++;
 
     *frames = av_malloc_array(*nb_frames, sizeof(**frames));
     if (!*frames) {
         av_log(log_ctx, AV_LOG_ERROR, "Could not allocate forced frames array\n");
-        FAIL(AVERROR(ENOMEM));
+        return AVERROR(ENOMEM);
     }
 
-    p = frames_str1;
+    p = frames_str;
     for (i = 0; i < *nb_frames; i++) {
         long int f;
         char *tailptr;
-        char *fstr = av_strtok(p, ",", &saveptr);
 
-        p = NULL;
-        if (!fstr) {
+        if (*p == '\0' || *p == ',') {
             av_log(log_ctx, AV_LOG_ERROR, "Empty frame specification in frame list %s\n",
                    frames_str);
-            FAIL(AVERROR(EINVAL));
+            return AVERROR(EINVAL);
         }
-        f = strtol(fstr, &tailptr, 10);
-        if (*tailptr || f <= 0 || f >= INT_MAX) {
+        f = strtol(p, &tailptr, 10);
+        if (*tailptr != '\0' && *tailptr != ',' || f <= 0 || f >= INT_MAX) {
             av_log(log_ctx, AV_LOG_ERROR,
-                   "Invalid argument '%s', must be a positive integer <= INT64_MAX\n",
-                   fstr);
-            FAIL(AVERROR(EINVAL));
+                   "Invalid argument '%s', must be a positive integer < INT_MAX\n",
+                   p);
+            return AVERROR(EINVAL);
         }
+        if (*tailptr == ',')
+            tailptr++;
+        p = tailptr;
         (*frames)[i] = f;
 
         /* check on monotonicity */
         if (i && (*frames)[i-1] > (*frames)[i]) {
             av_log(log_ctx, AV_LOG_ERROR,
-                   "Specified frame %d is greater than the following frame %d\n",
+                   "Specified frame %d is smaller than the last frame %d\n",
                    (*frames)[i], (*frames)[i-1]);
-            FAIL(AVERROR(EINVAL));
+            return AVERROR(EINVAL);
         }
     }
 
-end:
-    av_free(frames_str1);
-    return ret;
+    return 0;
 }
 
 static int open_null_ctx(AVIOContext **ctx)
@@ -638,9 +643,28 @@ static int select_reference_stream(AVFormatContext *s)
 static void seg_free(AVFormatContext *s)
 {
     SegmentContext *seg = s->priv_data;
-    ff_format_io_close(seg->avf, &seg->list_pb);
-    avformat_free_context(seg->avf);
-    seg->avf = NULL;
+    SegmentListEntry *cur;
+
+    ff_format_io_close(s, &seg->list_pb);
+    if (seg->avf) {
+        if (seg->is_nullctx)
+            close_null_ctxp(&seg->avf->pb);
+        else
+            ff_format_io_close(s, &seg->avf->pb);
+        avformat_free_context(seg->avf);
+        seg->avf = NULL;
+    }
+    av_freep(&seg->times);
+    av_freep(&seg->frames);
+    av_freep(&seg->cur_entry.filename);
+
+    cur = seg->segment_list_entries;
+    while (cur) {
+        SegmentListEntry *next = cur->next;
+        av_freep(&cur->filename);
+        av_free(cur);
+        cur = next;
+    }
 }
 
 static int seg_init(AVFormatContext *s)
@@ -665,7 +689,7 @@ static int seg_init(AVFormatContext *s)
                "you can use output_ts_offset instead of it\n");
     }
 
-    if (!!seg->time_str + !!seg->times_str + !!seg->frames_str > 1) {
+    if ((seg->time != 2000000) + !!seg->times_str + !!seg->frames_str > 1) {
         av_log(s, AV_LOG_ERROR,
                "segment_time, segment_times, and segment_frames options "
                "are mutually exclusive, select just one of them\n");
@@ -679,15 +703,6 @@ static int seg_init(AVFormatContext *s)
         if ((ret = parse_frames(s, &seg->frames, &seg->nb_frames, seg->frames_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->use_clocktime) {
             if (seg->time <= 0) {
                 av_log(s, AV_LOG_ERROR, "Invalid negative segment_time with segment_atclocktime option set\n");
@@ -697,15 +712,6 @@ static int seg_init(AVFormatContext *s)
         }
     }
 
-    if (seg->format_options_str) {
-        ret = av_dict_parse_string(&seg->format_options, seg->format_options_str, "=", ":", 0);
-        if (ret < 0) {
-            av_log(s, AV_LOG_ERROR, "Could not parse format options list '%s'\n",
-                   seg->format_options_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;
@@ -761,6 +767,7 @@ static int seg_init(AVFormatContext *s)
     } else {
         if ((ret = open_null_ctx(&oc->pb)) < 0)
             return ret;
+        seg->is_nullctx = 1;
     }
 
     av_dict_copy(&options, seg->format_options, 0);
@@ -768,14 +775,13 @@ static int seg_init(AVFormatContext *s)
     ret = avformat_init_output(oc, &options);
     if (av_dict_count(options)) {
         av_log(s, AV_LOG_ERROR,
-               "Some of the provided format options in '%s' are not recognized\n", seg->format_options_str);
+               "Some of the provided format options are not recognized\n");
         av_dict_free(&options);
         return AVERROR(EINVAL);
     }
     av_dict_free(&options);
 
     if (ret < 0) {
-        ff_format_io_close(oc, &oc->pb);
         return ret;
     }
     seg->segment_frame_count = 0;
@@ -804,26 +810,9 @@ static int seg_write_header(AVFormatContext *s)
 {
     SegmentContext *seg = s->priv_data;
     AVFormatContext *oc = seg->avf;
-    int ret, i;
+    int ret;
 
     if (!seg->header_written) {
-        for (i = 0; i < s->nb_streams; i++) {
-            AVStream *st = oc->streams[i];
-            AVCodecParameters *ipar, *opar;
-
-            ipar = s->streams[i]->codecpar;
-            opar = oc->streams[i]->codecpar;
-            avcodec_parameters_copy(opar, ipar);
-            if (!oc->oformat->codec_tag ||
-                av_codec_get_id (oc->oformat->codec_tag, ipar->codec_tag) == opar->codec_id ||
-                av_codec_get_tag(oc->oformat->codec_tag, ipar->codec_id) <= 0) {
-                opar->codec_tag = ipar->codec_tag;
-            } else {
-                opar->codec_tag = 0;
-            }
-            st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio;
-            st->time_base = s->streams[i]->time_base;
-        }
         ret = avformat_write_header(oc, NULL);
         if (ret < 0)
             return ret;
@@ -835,6 +824,7 @@ static int seg_write_header(AVFormatContext *s)
             ff_format_io_close(oc, &oc->pb);
         } else {
             close_null_ctxp(&oc->pb);
+            seg->is_nullctx = 0;
         }
         if ((ret = oc->io_open(oc, &oc->pb, oc->url, AVIO_FLAG_WRITE, NULL)) < 0)
             return ret;
@@ -860,7 +850,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
         return AVERROR(EINVAL);
 
     if (!st->codecpar->extradata_size) {
-        int pkt_extradata_size = 0;
+        size_t pkt_extradata_size;
         uint8_t *pkt_extradata = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &pkt_extradata_size);
         if (pkt_extradata && pkt_extradata_size > 0) {
             ret = ff_alloc_extradata(st->codecpar, pkt_extradata_size);
@@ -869,7 +859,6 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt)
                 goto calc_times;
             }
             memcpy(st->codecpar->extradata, pkt_extradata, pkt_extradata_size);
-            st->codecpar->extradata_size = pkt_extradata_size;
         }
     }
 
@@ -959,7 +948,8 @@ calc_times:
            av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base),
            av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, &st->time_base));
 
-    ret = ff_write_chained(seg->avf, pkt->stream_index, pkt, s, seg->initial_offset || seg->reset_timestamps);
+    ret = ff_write_chained(seg->avf, pkt->stream_index, pkt, s,
+                           seg->initial_offset || seg->reset_timestamps || seg->avf->oformat->interleave_packet);
 
 fail:
     if (pkt->stream_index == seg->reference_stream_index) {
@@ -974,42 +964,21 @@ static int seg_write_trailer(struct AVFormatContext *s)
 {
     SegmentContext *seg = s->priv_data;
     AVFormatContext *oc = seg->avf;
-    SegmentListEntry *cur, *next;
-    int ret = 0;
+    int ret;
 
     if (!oc)
-        goto fail;
+        return 0;
 
     if (!seg->write_header_trailer) {
         if ((ret = segment_end(s, 0, 1)) < 0)
-            goto fail;
+            return ret;
         if ((ret = open_null_ctx(&oc->pb)) < 0)
-            goto fail;
+            return ret;
+        seg->is_nullctx = 1;
         ret = av_write_trailer(oc);
-        close_null_ctxp(&oc->pb);
     } else {
         ret = segment_end(s, 1, 1);
     }
-fail:
-    if (seg->list)
-        ff_format_io_close(s, &seg->list_pb);
-
-    av_dict_free(&seg->format_options);
-    av_opt_free(seg);
-    av_freep(&seg->times);
-    av_freep(&seg->frames);
-    av_freep(&seg->cur_entry.filename);
-
-    cur = seg->segment_list_entries;
-    while (cur) {
-        next = cur->next;
-        av_freep(&cur->filename);
-        av_free(cur);
-        cur = next;
-    }
-
-    avformat_free_context(oc);
-    seg->avf = NULL;
     return ret;
 }
 
@@ -1022,10 +991,8 @@ static int seg_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt)
         if (ret == 1) {
             AVStream *st = s->streams[pkt->stream_index];
             AVStream *ost = oc->streams[pkt->stream_index];
-            st->internal->bsfcs = ost->internal->bsfcs;
-            st->internal->nb_bsfcs = ost->internal->nb_bsfcs;
-            ost->internal->bsfcs = NULL;
-            ost->internal->nb_bsfcs = 0;
+            st->internal->bsfc = ost->internal->bsfc;
+            ost->internal->bsfc = NULL;
         }
         return ret;
     }
@@ -1035,9 +1002,9 @@ static int seg_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt)
 #define OFFSET(x) offsetof(SegmentContext, x)
 #define E AV_OPT_FLAG_ENCODING_PARAM
 static const AVOption options[] = {
-    { "reference_stream",  "set reference stream", OFFSET(reference_stream_specifier), AV_OPT_TYPE_STRING, {.str = "auto"}, CHAR_MIN, CHAR_MAX, E },
+    { "reference_stream",  "set reference stream", OFFSET(reference_stream_specifier), AV_OPT_TYPE_STRING, {.str = "auto"}, 0, 0, E },
     { "segment_format",    "set container format used for the segments", OFFSET(format),  AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E },
-    { "segment_format_options", "set list of options for the container format used for the segments", OFFSET(format_options_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
+    { "segment_format_options", "set list of options for the container format used for the segments", OFFSET(format_options), AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, E },
     { "segment_list",      "set the segment list filename",              OFFSET(list),    AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E },
     { "segment_header_filename", "write a single file containing the header", OFFSET(header_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E },
 
@@ -1058,7 +1025,7 @@ static const AVOption options[] = {
     { "segment_atclocktime",      "set segment to be cut at clocktime",  OFFSET(use_clocktime), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, E},
     { "segment_clocktime_offset", "set segment clocktime offset",        OFFSET(clocktime_offset), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, 86400000000LL, E},
     { "segment_clocktime_wrap_duration", "set segment clocktime wrapping duration", OFFSET(clocktime_wrap_duration), AV_OPT_TYPE_DURATION, {.i64 = INT64_MAX}, 0, INT64_MAX, E},
-    { "segment_time",      "set segment duration",                       OFFSET(time_str),AV_OPT_TYPE_STRING, {.str = NULL},  0, 0,       E },
+    { "segment_time",      "set segment duration",                       OFFSET(time),AV_OPT_TYPE_DURATION, {.i64 = 2000000}, INT64_MIN, INT64_MAX,       E },
     { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, INT64_MAX, E },
     { "segment_times",     "set segment split time points",              OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL},  0, 0,       E },
     { "segment_frames",    "set segment split frame numbers",            OFFSET(frames_str),AV_OPT_TYPE_STRING,{.str = NULL},  0, 0,       E },