mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-11-26 19:01:44 +02:00
libavformat/segment: add an option to write the header to a separate file
This permits some interesting segmenting techniques with formats like Matroska, where you can concatenate the header and segments [N, nb_segments) and get a working file that starts at segment N's start time. Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
parent
481f0f153a
commit
7b060a96ad
@ -105,6 +105,7 @@ typedef struct SegmentContext {
|
|||||||
int64_t time_delta;
|
int64_t time_delta;
|
||||||
int individual_header_trailer; /**< Set by a private option. */
|
int individual_header_trailer; /**< Set by a private option. */
|
||||||
int write_header_trailer; /**< Set by a private option. */
|
int write_header_trailer; /**< Set by a private option. */
|
||||||
|
char *header_filename; ///< filename to write the output header to
|
||||||
|
|
||||||
int reset_timestamps; ///< reset timestamps at the begin of each segment
|
int reset_timestamps; ///< reset timestamps at the begin of each segment
|
||||||
int64_t initial_offset; ///< initial timestamps offset, expressed in microseconds
|
int64_t initial_offset; ///< initial timestamps offset, expressed in microseconds
|
||||||
@ -593,6 +594,11 @@ static int seg_write_header(AVFormatContext *s)
|
|||||||
if (!seg->write_header_trailer)
|
if (!seg->write_header_trailer)
|
||||||
seg->individual_header_trailer = 0;
|
seg->individual_header_trailer = 0;
|
||||||
|
|
||||||
|
if (seg->header_filename) {
|
||||||
|
seg->write_header_trailer = 1;
|
||||||
|
seg->individual_header_trailer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!!seg->time_str + !!seg->times_str + !!seg->frames_str > 1) {
|
if (!!seg->time_str + !!seg->times_str + !!seg->frames_str > 1) {
|
||||||
av_log(s, AV_LOG_ERROR,
|
av_log(s, AV_LOG_ERROR,
|
||||||
"segment_time, segment_times, and segment_frames options "
|
"segment_time, segment_times, and segment_frames options "
|
||||||
@ -669,7 +675,7 @@ static int seg_write_header(AVFormatContext *s)
|
|||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (seg->write_header_trailer) {
|
if (seg->write_header_trailer) {
|
||||||
if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
|
if ((ret = avio_open2(&oc->pb, seg->header_filename ? seg->header_filename : oc->filename, AVIO_FLAG_WRITE,
|
||||||
&s->interrupt_callback, NULL)) < 0) {
|
&s->interrupt_callback, NULL)) < 0) {
|
||||||
av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->filename);
|
av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->filename);
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -704,8 +710,13 @@ static int seg_write_header(AVFormatContext *s)
|
|||||||
if (oc->avoid_negative_ts > 0 && s->avoid_negative_ts < 0)
|
if (oc->avoid_negative_ts > 0 && s->avoid_negative_ts < 0)
|
||||||
s->avoid_negative_ts = 1;
|
s->avoid_negative_ts = 1;
|
||||||
|
|
||||||
if (!seg->write_header_trailer) {
|
if (!seg->write_header_trailer || seg->header_filename) {
|
||||||
|
if (seg->header_filename) {
|
||||||
|
av_write_frame(oc, NULL);
|
||||||
|
avio_closep(&oc->pb);
|
||||||
|
} else {
|
||||||
close_null_ctxp(&oc->pb);
|
close_null_ctxp(&oc->pb);
|
||||||
|
}
|
||||||
if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
|
if ((ret = avio_open2(&oc->pb, oc->filename, AVIO_FLAG_WRITE,
|
||||||
&s->interrupt_callback, NULL)) < 0)
|
&s->interrupt_callback, NULL)) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -877,6 +888,7 @@ static const AVOption options[] = {
|
|||||||
{ "segment_format", "set container format used for the segments", OFFSET(format), AV_OPT_TYPE_STRING, {.str = NULL}, 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_str), 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", "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 },
|
||||||
|
|
||||||
{ "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"},
|
{ "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"},
|
{ "cache", "allow list caching", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_LIST_FLAG_CACHE }, INT_MIN, INT_MAX, E, "list_flags"},
|
||||||
|
Loading…
Reference in New Issue
Block a user