diff options
author | Anton Khirnov <anton@khirnov.net> | 2013-04-30 08:36:20 +0200 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2013-05-03 08:32:35 +0200 |
commit | e3b225a4fe0ff1e64a220b757c6f0a5cf9258521 (patch) | |
tree | 952afdaae03b17159e8783431e75cbae1bb8534e | |
parent | 0574bc06d23a6690a16c5926dddc9be359a3d7bb (diff) | |
download | ffmpeg-e3b225a4fe0ff1e64a220b757c6f0a5cf9258521.tar.gz |
matroskaenc: add an option to put the index at the start of the file
-rw-r--r-- | Changelog | 1 | ||||
-rw-r--r-- | doc/muxers.texi | 21 | ||||
-rw-r--r-- | libavformat/matroskaenc.c | 64 | ||||
-rw-r--r-- | libavformat/version.h | 2 |
4 files changed, 86 insertions, 2 deletions
@@ -16,6 +16,7 @@ version 10: - new trim and atrim filters - avconv -t and -ss (output-only) options are now sample-accurate when transcoding audio +- Matroska muxer can now put the index at the beginning of the file. version 9: diff --git a/doc/muxers.texi b/doc/muxers.texi index 3f84450cfa..742e72aa02 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -373,6 +373,27 @@ For example a 3D WebM clip can be created using the following command line: avconv -i sample_left_right_clip.mpg -an -c:v libvpx -metadata STEREO_MODE=left_right -y stereo_clip.webm @end example +This muxer supports the following options: + +@table @option + +@item reserve_index_space +By default, this muxer writes the index for seeking (called cues in Matroska +terms) at the end of the file, because it cannot know in advance how much space +to leave for the index at the beginning of the file. However for some use cases +-- e.g. streaming where seeking is possible but slow -- it is useful to put the +index at the beginning of the file. + +If this option is set to a non-zero value, the muxer will reserve a given amount +of space in the file header and then try to write the cues there when the muxing +finishes. If the available space does not suffice, muxing will fail. A safe size +for most use cases should be about 50kB per hour of video. + +Note that cues are only written if the output is seekable and this option will +have no effect if it is not. + +@end table + @section segment Basic stream segmenter. diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index b0998d49c0..c521ed3926 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -34,6 +34,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/lfg.h" #include "libavutil/mathematics.h" +#include "libavutil/opt.h" #include "libavutil/random_seed.h" #include "libavutil/samplefmt.h" @@ -79,6 +80,7 @@ typedef struct { #define MODE_WEBM 0x02 typedef struct MatroskaMuxContext { + const AVClass *class; int mode; AVIOContext *dyn_bc; ebml_master segment; @@ -95,6 +97,9 @@ typedef struct MatroskaMuxContext { AVPacket cur_audio_pkt; int have_attachments; + + int reserve_cues_space; + int64_t cues_pos; } MatroskaMuxContext; @@ -968,6 +973,11 @@ static int mkv_write_header(AVFormatContext *s) if (mkv->cues == NULL) return AVERROR(ENOMEM); + if (pb->seekable && mkv->reserve_cues_space) { + mkv->cues_pos = avio_tell(pb); + put_ebml_void(pb, mkv->reserve_cues_space); + } + av_init_packet(&mkv->cur_audio_pkt); mkv->cur_audio_pkt.size = 0; @@ -1250,7 +1260,28 @@ static int mkv_write_trailer(AVFormatContext *s) if (pb->seekable) { if (mkv->cues->num_entries) { - cuespos = mkv_write_cues(pb, mkv->cues, s->nb_streams); + if (mkv->reserve_cues_space) { + int64_t cues_end; + + currentpos = avio_tell(pb); + avio_seek(pb, mkv->cues_pos, SEEK_SET); + + cuespos = mkv_write_cues(pb, mkv->cues, s->nb_streams); + cues_end = avio_tell(pb); + if (cues_end > cuespos + mkv->reserve_cues_space) { + av_log(s, AV_LOG_ERROR, "Insufficient space reserved for cues: %d " + "(needed: %"PRId64").\n", mkv->reserve_cues_space, + cues_end - cuespos); + return AVERROR(EINVAL); + } + + if (cues_end < cuespos + mkv->reserve_cues_space) + put_ebml_void(pb, mkv->reserve_cues_space - (cues_end - cuespos)); + + avio_seek(pb, currentpos, SEEK_SET); + } else { + cuespos = mkv_write_cues(pb, mkv->cues, s->nb_streams); + } ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_CUES, cuespos); if (ret < 0) return ret; @@ -1291,7 +1322,22 @@ static int mkv_query_codec(enum AVCodecID codec_id, int std_compliance) return 0; } +#define OFFSET(x) offsetof(MatroskaMuxContext, x) +#define FLAGS AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "reserve_index_space", "Reserve a given amount of space (in bytes) at the beginning " + "of the file for the index (cues).", OFFSET(reserve_cues_space), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, + { NULL }, +}; + #if CONFIG_MATROSKA_MUXER +static const AVClass matroska_class = { + .class_name = "matroska muxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVOutputFormat ff_matroska_muxer = { .name = "matroska", .long_name = NULL_IF_CONFIG_SMALL("Matroska"), @@ -1312,10 +1358,18 @@ AVOutputFormat ff_matroska_muxer = { }, .subtitle_codec = AV_CODEC_ID_SSA, .query_codec = mkv_query_codec, + .priv_class = &matroska_class, }; #endif #if CONFIG_WEBM_MUXER +static const AVClass webm_class = { + .class_name = "webm muxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVOutputFormat ff_webm_muxer = { .name = "webm", .long_name = NULL_IF_CONFIG_SMALL("WebM"), @@ -1329,10 +1383,17 @@ AVOutputFormat ff_webm_muxer = { .write_trailer = mkv_write_trailer, .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT, + .priv_class = &webm_class, }; #endif #if CONFIG_MATROSKA_AUDIO_MUXER +static const AVClass mka_class = { + .class_name = "matroska audio muxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; AVOutputFormat ff_matroska_audio_muxer = { .name = "matroska", .long_name = NULL_IF_CONFIG_SMALL("Matroska"), @@ -1347,5 +1408,6 @@ AVOutputFormat ff_matroska_audio_muxer = { .write_trailer = mkv_write_trailer, .flags = AVFMT_GLOBALHEADER | AVFMT_TS_NONSTRICT, .codec_tag = (const AVCodecTag* const []){ ff_codec_wav_tags, 0 }, + .priv_class = &mka_class, }; #endif diff --git a/libavformat/version.h b/libavformat/version.h index ea97eee993..4ebf0784e9 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -31,7 +31,7 @@ #define LIBAVFORMAT_VERSION_MAJOR 55 #define LIBAVFORMAT_VERSION_MINOR 0 -#define LIBAVFORMAT_VERSION_MICRO 0 +#define LIBAVFORMAT_VERSION_MICRO 1 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ |