From 6e57a02b9f639af53acfa9fc742c1341400818f8 Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Fri, 17 Feb 2012 12:21:22 -0800 Subject: [PATCH 01/58] asf: error out on ridiculously large minpktsize values. They cause various issues further down in demuxing. Found-by: Mateusz "j00ru" Jurczyk and Gynvael Coldwind CC: libav-stable@libav.org --- libavformat/asfdec.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libavformat/asfdec.c b/libavformat/asfdec.c index 2922ecf515..01411faf5a 100644 --- a/libavformat/asfdec.c +++ b/libavformat/asfdec.c @@ -202,6 +202,8 @@ static int asf_read_file_properties(AVFormatContext *s, int64_t size) asf->hdr.flags = avio_rl32(pb); asf->hdr.min_pktsize = avio_rl32(pb); asf->hdr.max_pktsize = avio_rl32(pb); + if (asf->hdr.min_pktsize >= (1U<<29)) + return AVERROR_INVALIDDATA; asf->hdr.max_bitrate = avio_rl32(pb); s->packet_size = asf->hdr.max_pktsize; @@ -616,7 +618,9 @@ static int asf_read_header(AVFormatContext *s) if (gsize < 24) return -1; if (!ff_guidcmp(&g, &ff_asf_file_header)) { - asf_read_file_properties(s, gsize); + int ret = asf_read_file_properties(s, gsize); + if (ret < 0) + return ret; } else if (!ff_guidcmp(&g, &ff_asf_stream_header)) { asf_read_stream_properties(s, gsize); } else if (!ff_guidcmp(&g, &ff_asf_comment_header)) { From bb6d5411e1e1a8e0608b1af1c4addee654dcbac5 Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Tue, 28 Feb 2012 16:13:46 -0800 Subject: [PATCH 02/58] asf: don't seek back on EOF. Seeking back on EOF will reset the EOF flag, causing us to re-enter the loop to find the next marker in the ASF file, thus potentially causing an infinite loop. Found-by: Mateusz "j00ru" Jurczyk and Gynvael Coldwind CC: libav-stable@libav.org --- libavformat/asfdec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavformat/asfdec.c b/libavformat/asfdec.c index 01411faf5a..8828eb583c 100644 --- a/libavformat/asfdec.c +++ b/libavformat/asfdec.c @@ -761,7 +761,7 @@ static int ff_asf_get_packet(AVFormatContext *s, AVIOContext *pb) c= avio_r8(pb); d= avio_r8(pb); rsize+=3; - }else{ + } else if (!pb->eof_reached) { avio_seek(pb, -1, SEEK_CUR); //FIXME } From 8bc396fc0e8769a056375c1c211f389ce0e3ecc5 Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Thu, 23 Feb 2012 11:19:33 -0800 Subject: [PATCH 03/58] vp56: error out on invalid stream dimensions. Prevents crashes when playing corrupt vp5/6 streams. Found-by: Mateusz "j00ru" Jurczyk and Gynvael Coldwind CC: libav-stable@libav.org --- libavcodec/vp5.c | 5 +++++ libavcodec/vp6.c | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/libavcodec/vp5.c b/libavcodec/vp5.c index 999b183c7f..19079ffd0d 100644 --- a/libavcodec/vp5.c +++ b/libavcodec/vp5.c @@ -57,6 +57,11 @@ static int vp5_parse_header(VP56Context *s, const uint8_t *buf, int buf_size, } rows = vp56_rac_gets(c, 8); /* number of stored macroblock rows */ cols = vp56_rac_gets(c, 8); /* number of stored macroblock cols */ + if (!rows || !cols) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid size %dx%d\n", + cols << 4, rows << 4); + return 0; + } vp56_rac_gets(c, 8); /* number of displayed macroblock rows */ vp56_rac_gets(c, 8); /* number of displayed macroblock cols */ vp56_rac_gets(c, 2); diff --git a/libavcodec/vp6.c b/libavcodec/vp6.c index 75863a9b67..f6c7761f9d 100644 --- a/libavcodec/vp6.c +++ b/libavcodec/vp6.c @@ -77,6 +77,10 @@ static int vp6_parse_header(VP56Context *s, const uint8_t *buf, int buf_size, cols = buf[3]; /* number of stored macroblock cols */ /* buf[4] is number of displayed macroblock rows */ /* buf[5] is number of displayed macroblock cols */ + if (!rows || !cols) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid size %dx%d\n", cols << 4, rows << 4); + return 0; + } if (!s->macroblocks || /* first frame */ 16*cols != s->avctx->coded_width || @@ -97,7 +101,7 @@ static int vp6_parse_header(VP56Context *s, const uint8_t *buf, int buf_size, vrt_shift = 5; s->sub_version = sub_version; } else { - if (!s->sub_version) + if (!s->sub_version || !s->avctx->coded_width || !s->avctx->coded_height) return 0; if (separated_coeff || !s->filter_header) { From 2564f6e6d433ec9907dc4bf2f9e8ea252e83a635 Mon Sep 17 00:00:00 2001 From: Alex Converse Date: Tue, 28 Feb 2012 10:36:29 -0800 Subject: [PATCH 04/58] aacdec: Reshuffle functions so get_che() can call set_default_channel_config() and output_configure(). --- libavcodec/aacdec.c | 140 ++++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/libavcodec/aacdec.c b/libavcodec/aacdec.c index 811ec0bd9d..340052e0c0 100644 --- a/libavcodec/aacdec.c +++ b/libavcodec/aacdec.c @@ -114,55 +114,6 @@ static VLC vlc_spectral[11]; static const char overread_err[] = "Input buffer exhausted before END element found\n"; -static ChannelElement *get_che(AACContext *ac, int type, int elem_id) -{ - // For PCE based channel configurations map the channels solely based on tags. - if (!ac->m4ac.chan_config) { - return ac->tag_che_map[type][elem_id]; - } - // For indexed channel configurations map the channels solely based on position. - switch (ac->m4ac.chan_config) { - case 7: - if (ac->tags_mapped == 3 && type == TYPE_CPE) { - ac->tags_mapped++; - return ac->tag_che_map[TYPE_CPE][elem_id] = ac->che[TYPE_CPE][2]; - } - case 6: - /* Some streams incorrectly code 5.1 audio as SCE[0] CPE[0] CPE[1] SCE[1] - instead of SCE[0] CPE[0] CPE[1] LFE[0]. If we seem to have - encountered such a stream, transfer the LFE[0] element to the SCE[1]'s mapping */ - if (ac->tags_mapped == tags_per_config[ac->m4ac.chan_config] - 1 && (type == TYPE_LFE || type == TYPE_SCE)) { - ac->tags_mapped++; - return ac->tag_che_map[type][elem_id] = ac->che[TYPE_LFE][0]; - } - case 5: - if (ac->tags_mapped == 2 && type == TYPE_CPE) { - ac->tags_mapped++; - return ac->tag_che_map[TYPE_CPE][elem_id] = ac->che[TYPE_CPE][1]; - } - case 4: - if (ac->tags_mapped == 2 && ac->m4ac.chan_config == 4 && type == TYPE_SCE) { - ac->tags_mapped++; - return ac->tag_che_map[TYPE_SCE][elem_id] = ac->che[TYPE_SCE][1]; - } - case 3: - case 2: - if (ac->tags_mapped == (ac->m4ac.chan_config != 2) && type == TYPE_CPE) { - ac->tags_mapped++; - return ac->tag_che_map[TYPE_CPE][elem_id] = ac->che[TYPE_CPE][0]; - } else if (ac->m4ac.chan_config == 2) { - return NULL; - } - case 1: - if (!ac->tags_mapped && type == TYPE_SCE) { - ac->tags_mapped++; - return ac->tag_che_map[TYPE_SCE][elem_id] = ac->che[TYPE_SCE][0]; - } - default: - return NULL; - } -} - static int count_channels(uint8_t (*layout)[3], int tags) { int i, sum = 0; @@ -437,6 +388,76 @@ static av_cold int output_configure(AACContext *ac, return 0; } +/** + * Set up channel positions based on a default channel configuration + * as specified in table 1.17. + * + * @return Returns error status. 0 - OK, !0 - error + */ +static av_cold int set_default_channel_config(AVCodecContext *avctx, + uint8_t (*layout_map)[3], + int *tags, + int channel_config) +{ + if (channel_config < 1 || channel_config > 7) { + av_log(avctx, AV_LOG_ERROR, "invalid default channel configuration (%d)\n", + channel_config); + return -1; + } + *tags = tags_per_config[channel_config]; + memcpy(layout_map, aac_channel_layout_map[channel_config-1], *tags * sizeof(*layout_map)); + return 0; +} + +static ChannelElement *get_che(AACContext *ac, int type, int elem_id) +{ + // For PCE based channel configurations map the channels solely based on tags. + if (!ac->m4ac.chan_config) { + return ac->tag_che_map[type][elem_id]; + } + // For indexed channel configurations map the channels solely based on position. + switch (ac->m4ac.chan_config) { + case 7: + if (ac->tags_mapped == 3 && type == TYPE_CPE) { + ac->tags_mapped++; + return ac->tag_che_map[TYPE_CPE][elem_id] = ac->che[TYPE_CPE][2]; + } + case 6: + /* Some streams incorrectly code 5.1 audio as SCE[0] CPE[0] CPE[1] SCE[1] + instead of SCE[0] CPE[0] CPE[1] LFE[0]. If we seem to have + encountered such a stream, transfer the LFE[0] element to the SCE[1]'s mapping */ + if (ac->tags_mapped == tags_per_config[ac->m4ac.chan_config] - 1 && (type == TYPE_LFE || type == TYPE_SCE)) { + ac->tags_mapped++; + return ac->tag_che_map[type][elem_id] = ac->che[TYPE_LFE][0]; + } + case 5: + if (ac->tags_mapped == 2 && type == TYPE_CPE) { + ac->tags_mapped++; + return ac->tag_che_map[TYPE_CPE][elem_id] = ac->che[TYPE_CPE][1]; + } + case 4: + if (ac->tags_mapped == 2 && ac->m4ac.chan_config == 4 && type == TYPE_SCE) { + ac->tags_mapped++; + return ac->tag_che_map[TYPE_SCE][elem_id] = ac->che[TYPE_SCE][1]; + } + case 3: + case 2: + if (ac->tags_mapped == (ac->m4ac.chan_config != 2) && type == TYPE_CPE) { + ac->tags_mapped++; + return ac->tag_che_map[TYPE_CPE][elem_id] = ac->che[TYPE_CPE][0]; + } else if (ac->m4ac.chan_config == 2) { + return NULL; + } + case 1: + if (!ac->tags_mapped && type == TYPE_SCE) { + ac->tags_mapped++; + return ac->tag_che_map[TYPE_SCE][elem_id] = ac->che[TYPE_SCE][0]; + } + default: + return NULL; + } +} + /** * Decode an array of 4 bit element IDs, optionally interleaved with a stereo/mono switching bit. * @@ -529,27 +550,6 @@ static int decode_pce(AVCodecContext *avctx, MPEG4AudioConfig *m4ac, return tags; } -/** - * Set up channel positions based on a default channel configuration - * as specified in table 1.17. - * - * @return Returns error status. 0 - OK, !0 - error - */ -static av_cold int set_default_channel_config(AVCodecContext *avctx, - uint8_t (*layout_map)[3], - int *tags, - int channel_config) -{ - if (channel_config < 1 || channel_config > 7) { - av_log(avctx, AV_LOG_ERROR, "invalid default channel configuration (%d)\n", - channel_config); - return -1; - } - *tags = tags_per_config[channel_config]; - memcpy(layout_map, aac_channel_layout_map[channel_config-1], *tags * sizeof(*layout_map)); - return 0; -} - /** * Decode GA "General Audio" specific configuration; reference: table 4.1. * From 956fb91e0333634aa25dcb5632c6e4e3769d05ee Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Fri, 21 Oct 2011 09:41:40 +0000 Subject: [PATCH 05/58] aacdec: Support stereo streams that erroneously signal predefined channel configuration 1 (mono). [alex.converse@mgail.com] Move code to get_che() Update for AAC new channel configuration interface Only set chan_config if output_configure succeeds. Signed-off-by: Alex Converse --- libavcodec/aacdec.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libavcodec/aacdec.c b/libavcodec/aacdec.c index 340052e0c0..4f94f5f5c9 100644 --- a/libavcodec/aacdec.c +++ b/libavcodec/aacdec.c @@ -415,6 +415,20 @@ static ChannelElement *get_che(AACContext *ac, int type, int elem_id) if (!ac->m4ac.chan_config) { return ac->tag_che_map[type][elem_id]; } + // Allow single CPE stereo files to be signalled with mono configuration. + if (!ac->tags_mapped && type == TYPE_CPE && ac->m4ac.chan_config == 1) { + uint8_t layout_map[MAX_ELEM_ID*4][3]; + int layout_map_tags; + + if (set_default_channel_config(ac->avctx, layout_map, &layout_map_tags, + 2) < 0) + return NULL; + if (output_configure(ac, layout_map, layout_map_tags, + 2, OC_TRIAL_FRAME) < 0) + return NULL; + + ac->m4ac.chan_config = 2; + } // For indexed channel configurations map the channels solely based on position. switch (ac->m4ac.chan_config) { case 7: From ed019b8e5bfefe59e307ce01f2860777e037b94b Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 27 Feb 2012 12:12:19 +0100 Subject: [PATCH 06/58] lavc: add -mpv_flags to mpegvideo_enc-based encoders. Deprecate CODEC_FLAG2_SKIP_RD in favor of the corresponding mpv_flags flag. --- libavcodec/avcodec.h | 2 ++ libavcodec/flvenc.c | 3 +++ libavcodec/h261enc.c | 3 +++ libavcodec/mpeg12enc.c | 2 ++ libavcodec/mpeg4videoenc.c | 1 + libavcodec/mpegvideo.h | 23 +++++++++++++++++++++++ libavcodec/mpegvideo_enc.c | 23 ++++++++++++++++++++++- libavcodec/options.c | 4 +++- libavcodec/rv10enc.c | 3 +++ libavcodec/rv20enc.c | 3 +++ libavcodec/version.h | 3 +++ 11 files changed, 68 insertions(+), 2 deletions(-) diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index cd86856d32..0623c1cb01 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -570,7 +570,9 @@ typedef struct RcOverride{ #define CODEC_FLAG2_STRICT_GOP 0x00000002 ///< Strictly enforce GOP size. #define CODEC_FLAG2_NO_OUTPUT 0x00000004 ///< Skip bitstream encoding. #define CODEC_FLAG2_LOCAL_HEADER 0x00000008 ///< Place global headers at every keyframe instead of in extradata. +#if FF_API_MPV_GLOBAL_OPTS #define CODEC_FLAG2_SKIP_RD 0x00004000 ///< RD optimal MB level residual skipping +#endif #define CODEC_FLAG2_CHUNKS 0x00008000 ///< Input bitstream might be truncated at a packet boundaries instead of only at frame boundaries. /* Unsupported options : diff --git a/libavcodec/flvenc.c b/libavcodec/flvenc.c index 332592d623..121aaf548d 100644 --- a/libavcodec/flvenc.c +++ b/libavcodec/flvenc.c @@ -84,6 +84,8 @@ void ff_flv2_encode_ac_esc(PutBitContext *pb, int slevel, int level, int run, in } } +FF_MPV_GENERIC_CLASS(flv) + AVCodec ff_flv_encoder = { .name = "flv", .type = AVMEDIA_TYPE_VIDEO, @@ -94,4 +96,5 @@ AVCodec ff_flv_encoder = { .close = ff_MPV_encode_end, .pix_fmts= (const enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE}, .long_name= NULL_IF_CONFIG_SMALL("Flash Video (FLV) / Sorenson Spark / Sorenson H.263"), + .priv_class = &flv_class, }; diff --git a/libavcodec/h261enc.c b/libavcodec/h261enc.c index 0ae48ca092..1f3cf714f1 100644 --- a/libavcodec/h261enc.c +++ b/libavcodec/h261enc.c @@ -321,6 +321,8 @@ static void h261_encode_block(H261Context * h, DCTELEM * block, int n){ } } +FF_MPV_GENERIC_CLASS(h261) + AVCodec ff_h261_encoder = { .name = "h261", .type = AVMEDIA_TYPE_VIDEO, @@ -331,4 +333,5 @@ AVCodec ff_h261_encoder = { .close = ff_MPV_encode_end, .pix_fmts= (const enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE}, .long_name= NULL_IF_CONFIG_SMALL("H.261"), + .priv_class = &h261_class, }; diff --git a/libavcodec/mpeg12enc.c b/libavcodec/mpeg12enc.c index c53d99b1b5..b6cbbbc2d2 100644 --- a/libavcodec/mpeg12enc.c +++ b/libavcodec/mpeg12enc.c @@ -927,6 +927,7 @@ static void mpeg1_encode_block(MpegEncContext *s, static const AVOption mpeg1_options[] = { COMMON_OPTS + FF_MPV_COMMON_OPTS { NULL }, }; @@ -934,6 +935,7 @@ static const AVOption mpeg2_options[] = { COMMON_OPTS { "non_linear_quant", "Use nonlinear quantizer.", OFFSET(q_scale_type), AV_OPT_TYPE_INT, { 0 }, 0, 1, VE }, { "alternate_scan", "Enable alternate scantable.", OFFSET(alternate_scan), AV_OPT_TYPE_INT, { 0 }, 0, 1, VE }, + FF_MPV_COMMON_OPTS { NULL }, }; diff --git a/libavcodec/mpeg4videoenc.c b/libavcodec/mpeg4videoenc.c index d512daa1fa..c2d4626dad 100644 --- a/libavcodec/mpeg4videoenc.c +++ b/libavcodec/mpeg4videoenc.c @@ -1320,6 +1320,7 @@ void ff_mpeg4_encode_video_packet_header(MpegEncContext *s) static const AVOption options[] = { { "data_partitioning", "Use data partitioning.", OFFSET(data_partitioning), AV_OPT_TYPE_INT, { 0 }, 0, 1, VE }, { "alternate_scan", "Enable alternate scantable.", OFFSET(alternate_scan), AV_OPT_TYPE_INT, { 0 }, 0, 1, VE }, + FF_MPV_COMMON_OPTS { NULL }, }; diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index 9753d1064c..7e157fdfff 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -37,6 +37,8 @@ #include "mpeg12data.h" #include "rl.h" +#include "libavutil/opt.h" + #define FRAME_SKIPPED 100 ///< return value for header parsers if frame is not coded enum OutputFormat { @@ -687,6 +689,8 @@ typedef struct MpegEncContext { int (*dct_quantize)(struct MpegEncContext *s, DCTELEM *block/*align 16*/, int n, int qscale, int *overflow); int (*fast_dct_quantize)(struct MpegEncContext *s, DCTELEM *block/*align 16*/, int n, int qscale, int *overflow); void (*denoise_dct)(struct MpegEncContext *s, DCTELEM *block); + + int mpv_flags; ///< flags set by private options } MpegEncContext; #define REBASE_PICTURE(pic, new_ctx, old_ctx) (pic ? \ @@ -694,6 +698,25 @@ typedef struct MpegEncContext { &new_ctx->picture[pic - old_ctx->picture] : pic - (Picture*)old_ctx + (Picture*)new_ctx)\ : NULL) +/* mpegvideo_enc common options */ +#define FF_MPV_FLAG_SKIP_RD 0x0001 + +#define FF_MPV_OFFSET(x) offsetof(MpegEncContext, x) +#define FF_MPV_OPT_FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) +#define FF_MPV_COMMON_OPTS \ +{ "mpv_flags", "Flags common for all mpegvideo-based encoders.", FF_MPV_OFFSET(mpv_flags), AV_OPT_TYPE_FLAGS, { 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "mpv_flags" },\ +{ "skip_rd", "RD optimal MB level residual skipping", 0, AV_OPT_TYPE_CONST, { FF_MPV_FLAG_SKIP_RD }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" },\ + +extern const AVOption ff_mpv_generic_options[]; + +#define FF_MPV_GENERIC_CLASS(name) \ +static const AVClass name ## _class = {\ + .class_name = #name " encoder",\ + .item_name = av_default_item_name,\ + .option = ff_mpv_generic_options,\ + .version = LIBAVUTIL_VERSION_INT,\ +}; + void ff_MPV_decode_defaults(MpegEncContext *s); int ff_MPV_common_init(MpegEncContext *s); void ff_MPV_common_end(MpegEncContext *s); diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index 6f4df59517..8e502ed62c 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -62,6 +62,11 @@ static int dct_quantize_trellis_c(MpegEncContext *s, DCTELEM *block, int n, int static uint8_t default_mv_penalty[MAX_FCODE + 1][MAX_MV * 2 + 1]; static uint8_t default_fcode_tab[MAX_MV * 2 + 1]; +const AVOption ff_mpv_generic_options[] = { + FF_MPV_COMMON_OPTS + { NULL }, +}; + void ff_convert_matrix(DSPContext *dsp, int (*qmat)[64], uint16_t (*qmat16)[2][64], const uint16_t *quant_matrix, @@ -606,6 +611,11 @@ av_cold int ff_MPV_encode_init(AVCodecContext *avctx) } s->time_increment_bits = av_log2(s->avctx->time_base.den - 1) + 1; +#if FF_API_MPV_GLOBAL_OPTS + if (avctx->flags2 & CODEC_FLAG2_SKIP_RD) + s->mpv_flags |= FF_MPV_FLAG_SKIP_RD; +#endif + switch (avctx->codec->id) { case CODEC_ID_MPEG1VIDEO: s->out_format = FMT_MPEG1; @@ -2698,7 +2708,7 @@ static int encode_thread(AVCodecContext *c, void *arg){ encode_mb_hq(s, &backup_s, &best_s, CANDIDATE_MB_TYPE_DIRECT, pb, pb2, tex_pb, &dmin, &next_block, 0, 0); } - if(!best_s.mb_intra && s->flags2&CODEC_FLAG2_SKIP_RD){ + if (!best_s.mb_intra && s->mpv_flags & FF_MPV_FLAG_SKIP_RD) { int coded=0; for(i=0; i<6; i++) coded |= s->block_last_index[i]; @@ -4046,6 +4056,7 @@ int ff_dct_quantize_c(MpegEncContext *s, static const AVOption h263_options[] = { { "obmc", "use overlapped block motion compensation.", OFFSET(obmc), AV_OPT_TYPE_INT, { 0 }, 0, 1, VE }, { "structured_slices","Write slice start position at every GOB header instead of just GOB number.", OFFSET(h263_slice_structured), AV_OPT_TYPE_INT, { 0 }, 0, 1, VE}, + FF_MPV_COMMON_OPTS { NULL }, }; @@ -4074,6 +4085,7 @@ static const AVOption h263p_options[] = { { "aiv", "Use alternative inter VLC.", OFFSET(alt_inter_vlc), AV_OPT_TYPE_INT, { 0 }, 0, 1, VE }, { "obmc", "use overlapped block motion compensation.", OFFSET(obmc), AV_OPT_TYPE_INT, { 0 }, 0, 1, VE }, { "structured_slices", "Write slice start position at every GOB header instead of just GOB number.", OFFSET(h263_slice_structured), AV_OPT_TYPE_INT, { 0 }, 0, 1, VE}, + FF_MPV_COMMON_OPTS { NULL }, }; static const AVClass h263p_class = { @@ -4097,6 +4109,8 @@ AVCodec ff_h263p_encoder = { .priv_class = &h263p_class, }; +FF_MPV_GENERIC_CLASS(msmpeg4v2) + AVCodec ff_msmpeg4v2_encoder = { .name = "msmpeg4v2", .type = AVMEDIA_TYPE_VIDEO, @@ -4107,8 +4121,11 @@ AVCodec ff_msmpeg4v2_encoder = { .close = ff_MPV_encode_end, .pix_fmts= (const enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE}, .long_name= NULL_IF_CONFIG_SMALL("MPEG-4 part 2 Microsoft variant version 2"), + .priv_class = &msmpeg4v2_class, }; +FF_MPV_GENERIC_CLASS(msmpeg4v3) + AVCodec ff_msmpeg4v3_encoder = { .name = "msmpeg4", .type = AVMEDIA_TYPE_VIDEO, @@ -4119,8 +4136,11 @@ AVCodec ff_msmpeg4v3_encoder = { .close = ff_MPV_encode_end, .pix_fmts= (const enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE}, .long_name= NULL_IF_CONFIG_SMALL("MPEG-4 part 2 Microsoft variant version 3"), + .priv_class = &msmpeg4v3_class, }; +FF_MPV_GENERIC_CLASS(wmv1) + AVCodec ff_wmv1_encoder = { .name = "wmv1", .type = AVMEDIA_TYPE_VIDEO, @@ -4131,4 +4151,5 @@ AVCodec ff_wmv1_encoder = { .close = ff_MPV_encode_end, .pix_fmts= (const enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE}, .long_name= NULL_IF_CONFIG_SMALL("Windows Media Video 7"), + .priv_class = &wmv1_class, }; diff --git a/libavcodec/options.c b/libavcodec/options.c index 81e910cb7e..fb48030ebc 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -361,7 +361,9 @@ static const AVOption options[]={ {"refs", "reference frames to consider for motion compensation (Snow)", OFFSET(refs), AV_OPT_TYPE_INT, {.dbl = 1 }, INT_MIN, INT_MAX, V|E}, {"chromaoffset", "chroma qp offset from luma", OFFSET(chromaoffset), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|E}, {"trellis", "rate-distortion optimal quantization", OFFSET(trellis), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|A|E}, -{"skiprd", "RD optimal MB level residual skipping", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG2_SKIP_RD }, INT_MIN, INT_MAX, V|E, "flags2"}, +#if FF_API_MPV_GLOBAL_OPTS +{"skiprd", "Deprecated, use mpegvideo private options instead", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG2_SKIP_RD }, INT_MIN, INT_MAX, V|E, "flags2"}, +#endif {"sc_factor", "multiplied by qscale for each frame and added to scene_change_score", OFFSET(scenechange_factor), AV_OPT_TYPE_INT, {.dbl = 6 }, 0, INT_MAX, V|E}, {"mv0_threshold", NULL, OFFSET(mv0_threshold), AV_OPT_TYPE_INT, {.dbl = 256 }, 0, INT_MAX, V|E}, {"b_sensitivity", "adjusts sensitivity of b_frame_strategy 1", OFFSET(b_sensitivity), AV_OPT_TYPE_INT, {.dbl = 40 }, 1, INT_MAX, V|E}, diff --git a/libavcodec/rv10enc.c b/libavcodec/rv10enc.c index 47fb2225e4..1b4694c502 100644 --- a/libavcodec/rv10enc.c +++ b/libavcodec/rv10enc.c @@ -56,6 +56,8 @@ void ff_rv10_encode_picture_header(MpegEncContext *s, int picture_number) put_bits(&s->pb, 3, 0); /* ignored */ } +FF_MPV_GENERIC_CLASS(rv10) + AVCodec ff_rv10_encoder = { .name = "rv10", .type = AVMEDIA_TYPE_VIDEO, @@ -66,4 +68,5 @@ AVCodec ff_rv10_encoder = { .close = ff_MPV_encode_end, .pix_fmts= (const enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE}, .long_name= NULL_IF_CONFIG_SMALL("RealVideo 1.0"), + .priv_class = &rv10_class, }; diff --git a/libavcodec/rv20enc.c b/libavcodec/rv20enc.c index ace70d180b..8b50baf52f 100644 --- a/libavcodec/rv20enc.c +++ b/libavcodec/rv20enc.c @@ -57,6 +57,8 @@ void ff_rv20_encode_picture_header(MpegEncContext *s, int picture_number){ } } +FF_MPV_GENERIC_CLASS(rv20) + AVCodec ff_rv20_encoder = { .name = "rv20", .type = AVMEDIA_TYPE_VIDEO, @@ -67,4 +69,5 @@ AVCodec ff_rv20_encoder = { .close = ff_MPV_encode_end, .pix_fmts= (const enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE}, .long_name= NULL_IF_CONFIG_SMALL("RealVideo 2.0"), + .priv_class = &rv20_class, }; diff --git a/libavcodec/version.h b/libavcodec/version.h index bf2848d4b2..ffce89588d 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -50,5 +50,8 @@ #ifndef FF_API_OLD_ENCODE_VIDEO #define FF_API_OLD_ENCODE_VIDEO (LIBAVCODEC_VERSION_MAJOR < 55) #endif +#ifndef FF_API_MPV_GLOBAL_OPTS +#define FF_API_MPV_GLOBAL_OPTS (LIBAVCODEC_VERSION_MAJOR < 55) +#endif #endif /* AVCODEC_VERSION_H */ From a249f0cc23457bc73a249e1b1ca22adcfe5b0894 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 27 Feb 2012 12:23:19 +0100 Subject: [PATCH 07/58] mpegvideo_enc: add strict_gop flag to mpv_flags. Deprecate CODEC_FLAG2_STRICT_GOP. --- libavcodec/avcodec.h | 2 +- libavcodec/mpegvideo.h | 2 ++ libavcodec/mpegvideo_enc.c | 4 +++- libavcodec/options.c | 4 +++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 0623c1cb01..fdbb1ab6c3 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -567,10 +567,10 @@ typedef struct RcOverride{ #define CODEC_FLAG_INTERLACED_ME 0x20000000 ///< interlaced motion estimation #define CODEC_FLAG_CLOSED_GOP 0x80000000 #define CODEC_FLAG2_FAST 0x00000001 ///< Allow non spec compliant speedup tricks. -#define CODEC_FLAG2_STRICT_GOP 0x00000002 ///< Strictly enforce GOP size. #define CODEC_FLAG2_NO_OUTPUT 0x00000004 ///< Skip bitstream encoding. #define CODEC_FLAG2_LOCAL_HEADER 0x00000008 ///< Place global headers at every keyframe instead of in extradata. #if FF_API_MPV_GLOBAL_OPTS +#define CODEC_FLAG2_STRICT_GOP 0x00000002 ///< Strictly enforce GOP size. #define CODEC_FLAG2_SKIP_RD 0x00004000 ///< RD optimal MB level residual skipping #endif #define CODEC_FLAG2_CHUNKS 0x00008000 ///< Input bitstream might be truncated at a packet boundaries instead of only at frame boundaries. diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index 7e157fdfff..b780331a9c 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -700,12 +700,14 @@ typedef struct MpegEncContext { /* mpegvideo_enc common options */ #define FF_MPV_FLAG_SKIP_RD 0x0001 +#define FF_MPV_FLAG_STRICT_GOP 0x0002 #define FF_MPV_OFFSET(x) offsetof(MpegEncContext, x) #define FF_MPV_OPT_FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) #define FF_MPV_COMMON_OPTS \ { "mpv_flags", "Flags common for all mpegvideo-based encoders.", FF_MPV_OFFSET(mpv_flags), AV_OPT_TYPE_FLAGS, { 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "mpv_flags" },\ { "skip_rd", "RD optimal MB level residual skipping", 0, AV_OPT_TYPE_CONST, { FF_MPV_FLAG_SKIP_RD }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" },\ +{ "strict_gop", "Strictly enforce gop size", 0, AV_OPT_TYPE_CONST, { FF_MPV_FLAG_STRICT_GOP }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" }, extern const AVOption ff_mpv_generic_options[]; diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index 8e502ed62c..d21ced7d59 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -614,6 +614,8 @@ av_cold int ff_MPV_encode_init(AVCodecContext *avctx) #if FF_API_MPV_GLOBAL_OPTS if (avctx->flags2 & CODEC_FLAG2_SKIP_RD) s->mpv_flags |= FF_MPV_FLAG_SKIP_RD; + if (avctx->flags2 & CODEC_FLAG2_STRICT_GOP) + s->mpv_flags |= FF_MPV_FLAG_STRICT_GOP; #endif switch (avctx->codec->id) { @@ -1300,7 +1302,7 @@ static int select_input_picture(MpegEncContext *s) } if (s->picture_in_gop_number + b_frames >= s->gop_size) { - if ((s->flags2 & CODEC_FLAG2_STRICT_GOP) && + if ((s->mpv_flags & FF_MPV_FLAG_STRICT_GOP) && s->gop_size > s->picture_in_gop_number) { b_frames = s->gop_size - s->picture_in_gop_number - 1; } else { diff --git a/libavcodec/options.c b/libavcodec/options.c index fb48030ebc..8374f9d487 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -102,7 +102,9 @@ static const AVOption options[]={ {"ilme", "interlaced motion estimation", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG_INTERLACED_ME }, INT_MIN, INT_MAX, V|E, "flags"}, {"cgop", "closed gop", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG_CLOSED_GOP }, INT_MIN, INT_MAX, V|E, "flags"}, {"fast", "allow non spec compliant speedup tricks", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG2_FAST }, INT_MIN, INT_MAX, V|E, "flags2"}, -{"sgop", "strictly enforce gop size", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG2_STRICT_GOP }, INT_MIN, INT_MAX, V|E, "flags2"}, +#if FF_API_MPV_GLOBAL_OPTS +{"sgop", "Deprecated, use mpegvideo private options instead", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG2_STRICT_GOP }, INT_MIN, INT_MAX, V|E, "flags2"}, +#endif {"noout", "skip bitstream encoding", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG2_NO_OUTPUT }, INT_MIN, INT_MAX, V|E, "flags2"}, {"local_header", "place global headers at every keyframe instead of in extradata", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG2_LOCAL_HEADER }, INT_MIN, INT_MAX, V|E, "flags2"}, {"sub_id", NULL, OFFSET(sub_id), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX}, From ff71a383ac884706903b2613d6f885021b69e552 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 27 Feb 2012 12:23:19 +0100 Subject: [PATCH 08/58] mpegvideo_enc: add qp_rd flag to mpv_flags. Deprecate CODEC_FLAG_QP_RD. --- libavcodec/avcodec.h | 2 +- libavcodec/mpegvideo.h | 4 +++- libavcodec/mpegvideo_enc.c | 17 +++++++++++------ libavcodec/options.c | 4 +++- tests/codec-regression.sh | 6 +++--- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index fdbb1ab6c3..2a27d8d53b 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -562,7 +562,6 @@ typedef struct RcOverride{ /* Fx : Flag for h263+ extra options */ #define CODEC_FLAG_AC_PRED 0x01000000 ///< H.263 advanced intra coding / MPEG-4 AC prediction #define CODEC_FLAG_CBP_RD 0x04000000 ///< Use rate distortion optimization for cbp. -#define CODEC_FLAG_QP_RD 0x08000000 ///< Use rate distortion optimization for qp selectioon. #define CODEC_FLAG_LOOP_FILTER 0x00000800 ///< loop filter #define CODEC_FLAG_INTERLACED_ME 0x20000000 ///< interlaced motion estimation #define CODEC_FLAG_CLOSED_GOP 0x80000000 @@ -570,6 +569,7 @@ typedef struct RcOverride{ #define CODEC_FLAG2_NO_OUTPUT 0x00000004 ///< Skip bitstream encoding. #define CODEC_FLAG2_LOCAL_HEADER 0x00000008 ///< Place global headers at every keyframe instead of in extradata. #if FF_API_MPV_GLOBAL_OPTS +#define CODEC_FLAG_QP_RD 0x08000000 ///< Use rate distortion optimization for qp selectioon. #define CODEC_FLAG2_STRICT_GOP 0x00000002 ///< Strictly enforce GOP size. #define CODEC_FLAG2_SKIP_RD 0x00004000 ///< RD optimal MB level residual skipping #endif diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index b780331a9c..26c88b000c 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -701,13 +701,15 @@ typedef struct MpegEncContext { /* mpegvideo_enc common options */ #define FF_MPV_FLAG_SKIP_RD 0x0001 #define FF_MPV_FLAG_STRICT_GOP 0x0002 +#define FF_MPV_FLAG_QP_RD 0x0004 #define FF_MPV_OFFSET(x) offsetof(MpegEncContext, x) #define FF_MPV_OPT_FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) #define FF_MPV_COMMON_OPTS \ { "mpv_flags", "Flags common for all mpegvideo-based encoders.", FF_MPV_OFFSET(mpv_flags), AV_OPT_TYPE_FLAGS, { 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "mpv_flags" },\ { "skip_rd", "RD optimal MB level residual skipping", 0, AV_OPT_TYPE_CONST, { FF_MPV_FLAG_SKIP_RD }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" },\ -{ "strict_gop", "Strictly enforce gop size", 0, AV_OPT_TYPE_CONST, { FF_MPV_FLAG_STRICT_GOP }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" }, +{ "strict_gop", "Strictly enforce gop size", 0, AV_OPT_TYPE_CONST, { FF_MPV_FLAG_STRICT_GOP }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" },\ +{ "qp_rd", "Use rate distortion optimization for qp selection", 0, AV_OPT_TYPE_CONST, { FF_MPV_FLAG_QP_RD }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" }, extern const AVOption ff_mpv_generic_options[]; diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index d21ced7d59..bb348137aa 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -374,13 +374,18 @@ av_cold int ff_MPV_encode_init(AVCodecContext *avctx) /* Fixed QSCALE */ s->fixed_qscale = !!(avctx->flags & CODEC_FLAG_QSCALE); +#if FF_API_MPV_GLOBAL_OPTS + if (s->flags & CODEC_FLAG_QP_RD) + s->mpv_flags |= FF_MPV_FLAG_QP_RD; +#endif + s->adaptive_quant = (s->avctx->lumi_masking || s->avctx->dark_masking || s->avctx->temporal_cplx_masking || s->avctx->spatial_cplx_masking || s->avctx->p_masking || s->avctx->border_masking || - (s->flags & CODEC_FLAG_QP_RD)) && + (s->mpv_flags & FF_MPV_FLAG_QP_RD)) && !s->fixed_qscale; s->loop_filter = !!(s->flags & CODEC_FLAG_LOOP_FILTER); @@ -495,7 +500,7 @@ av_cold int ff_MPV_encode_init(AVCodecContext *avctx) return -1; } - if ((s->flags & CODEC_FLAG_QP_RD) && + if ((s->mpv_flags & FF_MPV_FLAG_QP_RD) && s->avctx->mb_decision != FF_MB_DECISION_RD) { av_log(avctx, AV_LOG_ERROR, "QP RD needs mbd=2\n"); return -1; @@ -1727,7 +1732,7 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, s->lambda = s->lambda_table[mb_xy]; update_qscale(s); - if (!(s->flags & CODEC_FLAG_QP_RD)) { + if (!(s->mpv_flags & FF_MPV_FLAG_QP_RD)) { s->qscale = s->current_picture_ptr->f.qscale_table[mb_xy]; s->dquant = s->qscale - last_qp; @@ -1747,7 +1752,7 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, } } ff_set_qscale(s, last_qp + s->dquant); - } else if (s->flags & CODEC_FLAG_QP_RD) + } else if (s->mpv_flags & FF_MPV_FLAG_QP_RD) ff_set_qscale(s, s->qscale + s->dquant); wrap_y = s->linesize; @@ -2508,7 +2513,7 @@ static int encode_thread(AVCodecContext *c, void *arg){ s->mb_skipped=0; s->dquant=0; //only for QP_RD - if(mb_type & (mb_type-1) || (s->flags & CODEC_FLAG_QP_RD)){ // more than 1 MB type possible or CODEC_FLAG_QP_RD + if (mb_type & (mb_type-1) || (s->mpv_flags & FF_MPV_FLAG_QP_RD)) { // more than 1 MB type possible or FF_MPV_FLAG_QP_RD int next_block=0; int pb_bits_count, pb2_bits_count, tex_pb_bits_count; @@ -2645,7 +2650,7 @@ static int encode_thread(AVCodecContext *c, void *arg){ } } - if((s->flags & CODEC_FLAG_QP_RD) && dmin < INT_MAX){ + if ((s->mpv_flags & FF_MPV_FLAG_QP_RD) && dmin < INT_MAX) { if(best_s.mv_type==MV_TYPE_16X16){ //FIXME move 4mv after QPRD const int last_qp= backup_s.qscale; int qpi, qp, dc[6]; diff --git a/libavcodec/options.c b/libavcodec/options.c index 8374f9d487..de5b42a147 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -98,7 +98,9 @@ static const AVOption options[]={ {"bitexact", "use only bitexact stuff (except (i)dct)", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG_BITEXACT }, INT_MIN, INT_MAX, A|V|S|D|E, "flags"}, {"aic", "h263 advanced intra coding / mpeg4 ac prediction", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG_AC_PRED }, INT_MIN, INT_MAX, V|E, "flags"}, {"cbp", "use rate distortion optimization for cbp", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG_CBP_RD }, INT_MIN, INT_MAX, V|E, "flags"}, -{"qprd", "use rate distortion optimization for qp selection", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG_QP_RD }, INT_MIN, INT_MAX, V|E, "flags"}, +#if FF_API_MPV_GLOBAL_OPTS +{"qprd", "Deprecated, use mpegvideo private options instead", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG_QP_RD }, INT_MIN, INT_MAX, V|E, "flags"}, +#endif {"ilme", "interlaced motion estimation", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG_INTERLACED_ME }, INT_MIN, INT_MAX, V|E, "flags"}, {"cgop", "closed gop", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG_CLOSED_GOP }, INT_MIN, INT_MAX, V|E, "flags"}, {"fast", "allow non spec compliant speedup tricks", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG2_FAST }, INT_MIN, INT_MAX, V|E, "flags2"}, diff --git a/tests/codec-regression.sh b/tests/codec-regression.sh index d59ce07b35..6a1dee6e2d 100755 --- a/tests/codec-regression.sh +++ b/tests/codec-regression.sh @@ -38,13 +38,13 @@ fi if [ -n "$do_mpeg2_ivlc_qprd" ]; then # mpeg2 encoding intra vlc qprd -do_video_encoding mpeg2ivlc-qprd.mpg "-vb 500k -bf 2 -trellis 1 -flags +qprd+mv0 -intra_vlc 1 -cmp 2 -subcmp 2 -mbd rd -vcodec mpeg2video -f mpeg2video" +do_video_encoding mpeg2ivlc-qprd.mpg "-vb 500k -bf 2 -trellis 1 -flags +mv0 -mpv_flags +qp_rd -intra_vlc 1 -cmp 2 -subcmp 2 -mbd rd -vcodec mpeg2video -f mpeg2video" do_video_decoding fi if [ -n "$do_mpeg2_422" ]; then #mpeg2 4:2:2 encoding -do_video_encoding mpeg2_422.mpg "-vb 1000k -bf 2 -trellis 1 -flags +qprd+mv0+ildct+ilme -intra_vlc 1 -mbd rd -vcodec mpeg2video -pix_fmt yuv422p -f mpeg2video" +do_video_encoding mpeg2_422.mpg "-vb 1000k -bf 2 -trellis 1 -flags +mv0+ildct+ilme -mpv_flags +qp_rd -intra_vlc 1 -mbd rd -vcodec mpeg2video -pix_fmt yuv422p -f mpeg2video" do_video_decoding fi @@ -128,7 +128,7 @@ do_video_decoding fi if [ -n "$do_mpeg4_qprd" ]; then -do_video_encoding mpeg4-qprd.avi "-b 450k -bf 2 -trellis 1 -flags +mv4+qprd+mv0 -cmp 2 -subcmp 2 -mbd rd -an -vcodec mpeg4" +do_video_encoding mpeg4-qprd.avi "-b 450k -bf 2 -trellis 1 -flags +mv4+mv0 -mpv_flags +qp_rd -cmp 2 -subcmp 2 -mbd rd -an -vcodec mpeg4" do_video_decoding fi From af3d804f9feebe34ad3815c501fba795b801cdd0 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 27 Feb 2012 12:23:19 +0100 Subject: [PATCH 09/58] mpegvideo_enc: add cbp_rd flag to mpv_flags. Deprecate CODEC_FLAG_CBP_RD. --- libavcodec/avcodec.h | 2 +- libavcodec/h263.h | 2 +- libavcodec/mpeg4videoenc.c | 2 +- libavcodec/mpegvideo.h | 4 +++- libavcodec/mpegvideo_enc.c | 9 +++++++-- libavcodec/options.c | 2 +- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 2a27d8d53b..5677c0bce5 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -561,7 +561,6 @@ typedef struct RcOverride{ #define CODEC_FLAG_BITEXACT 0x00800000 ///< Use only bitexact stuff (except (I)DCT). /* Fx : Flag for h263+ extra options */ #define CODEC_FLAG_AC_PRED 0x01000000 ///< H.263 advanced intra coding / MPEG-4 AC prediction -#define CODEC_FLAG_CBP_RD 0x04000000 ///< Use rate distortion optimization for cbp. #define CODEC_FLAG_LOOP_FILTER 0x00000800 ///< loop filter #define CODEC_FLAG_INTERLACED_ME 0x20000000 ///< interlaced motion estimation #define CODEC_FLAG_CLOSED_GOP 0x80000000 @@ -569,6 +568,7 @@ typedef struct RcOverride{ #define CODEC_FLAG2_NO_OUTPUT 0x00000004 ///< Skip bitstream encoding. #define CODEC_FLAG2_LOCAL_HEADER 0x00000008 ///< Place global headers at every keyframe instead of in extradata. #if FF_API_MPV_GLOBAL_OPTS +#define CODEC_FLAG_CBP_RD 0x04000000 ///< Use rate distortion optimization for cbp. #define CODEC_FLAG_QP_RD 0x08000000 ///< Use rate distortion optimization for qp selectioon. #define CODEC_FLAG2_STRICT_GOP 0x00000002 ///< Strictly enforce GOP size. #define CODEC_FLAG2_SKIP_RD 0x00004000 ///< RD optimal MB level residual skipping diff --git a/libavcodec/h263.h b/libavcodec/h263.h index d26cf636eb..2a1ae4839d 100644 --- a/libavcodec/h263.h +++ b/libavcodec/h263.h @@ -148,7 +148,7 @@ static inline int get_p_cbp(MpegEncContext * s, int motion_x, int motion_y){ int cbp, i; - if(s->flags & CODEC_FLAG_CBP_RD){ + if (s->mpv_flags & FF_MPV_FLAG_CBP_RD) { int best_cbpy_score= INT_MAX; int best_cbpc_score= INT_MAX; int cbpc = (-1), cbpy= (-1); diff --git a/libavcodec/mpeg4videoenc.c b/libavcodec/mpeg4videoenc.c index c2d4626dad..e6b015a431 100644 --- a/libavcodec/mpeg4videoenc.c +++ b/libavcodec/mpeg4videoenc.c @@ -430,7 +430,7 @@ static inline int get_b_cbp(MpegEncContext * s, DCTELEM block[6][64], { int cbp = 0, i; - if (s->flags & CODEC_FLAG_CBP_RD) { + if (s->mpv_flags & FF_MPV_FLAG_CBP_RD) { int score = 0; const int lambda = s->lambda2 >> (FF_LAMBDA_SHIFT - 6); diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index 26c88b000c..4ec419034f 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -702,6 +702,7 @@ typedef struct MpegEncContext { #define FF_MPV_FLAG_SKIP_RD 0x0001 #define FF_MPV_FLAG_STRICT_GOP 0x0002 #define FF_MPV_FLAG_QP_RD 0x0004 +#define FF_MPV_FLAG_CBP_RD 0x0008 #define FF_MPV_OFFSET(x) offsetof(MpegEncContext, x) #define FF_MPV_OPT_FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) @@ -709,7 +710,8 @@ typedef struct MpegEncContext { { "mpv_flags", "Flags common for all mpegvideo-based encoders.", FF_MPV_OFFSET(mpv_flags), AV_OPT_TYPE_FLAGS, { 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "mpv_flags" },\ { "skip_rd", "RD optimal MB level residual skipping", 0, AV_OPT_TYPE_CONST, { FF_MPV_FLAG_SKIP_RD }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" },\ { "strict_gop", "Strictly enforce gop size", 0, AV_OPT_TYPE_CONST, { FF_MPV_FLAG_STRICT_GOP }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" },\ -{ "qp_rd", "Use rate distortion optimization for qp selection", 0, AV_OPT_TYPE_CONST, { FF_MPV_FLAG_QP_RD }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" }, +{ "qp_rd", "Use rate distortion optimization for qp selection", 0, AV_OPT_TYPE_CONST, { FF_MPV_FLAG_QP_RD }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" },\ +{ "cbp_rd", "use rate distortion optimization for CBP", 0, AV_OPT_TYPE_CONST, { FF_MPV_FLAG_CBP_RD }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" }, extern const AVOption ff_mpv_generic_options[]; diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index bb348137aa..e6e6a95b48 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -495,7 +495,12 @@ av_cold int ff_MPV_encode_init(AVCodecContext *avctx) return -1; } - if ((s->flags & CODEC_FLAG_CBP_RD) && !avctx->trellis) { +#if FF_API_MPV_GLOBAL_OPTS + if (s->flags & CODEC_FLAG_CBP_RD) + s->mpv_flags |= FF_MPV_FLAG_CBP_RD; +#endif + + if ((s->mpv_flags & FF_MPV_FLAG_CBP_RD) && !avctx->trellis) { av_log(avctx, AV_LOG_ERROR, "CBP RD needs trellis quant\n"); return -1; } @@ -1998,7 +2003,7 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, for (i = 4; i < mb_block_count; i++) dct_single_coeff_elimination(s, i, s->chroma_elim_threshold); - if (s->flags & CODEC_FLAG_CBP_RD) { + if (s->mpv_flags & FF_MPV_FLAG_CBP_RD) { for (i = 0; i < mb_block_count; i++) { if (s->block_last_index[i] == -1) s->coded_score[i] = INT_MAX / 256; diff --git a/libavcodec/options.c b/libavcodec/options.c index de5b42a147..6b5b148516 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -97,8 +97,8 @@ static const AVOption options[]={ {"global_header", "place global headers in extradata instead of every keyframe", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG_GLOBAL_HEADER }, INT_MIN, INT_MAX, V|A|E, "flags"}, {"bitexact", "use only bitexact stuff (except (i)dct)", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG_BITEXACT }, INT_MIN, INT_MAX, A|V|S|D|E, "flags"}, {"aic", "h263 advanced intra coding / mpeg4 ac prediction", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG_AC_PRED }, INT_MIN, INT_MAX, V|E, "flags"}, -{"cbp", "use rate distortion optimization for cbp", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG_CBP_RD }, INT_MIN, INT_MAX, V|E, "flags"}, #if FF_API_MPV_GLOBAL_OPTS +{"cbp", "Deprecated, use mpegvideo private options instead", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG_CBP_RD }, INT_MIN, INT_MAX, V|E, "flags"}, {"qprd", "Deprecated, use mpegvideo private options instead", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG_QP_RD }, INT_MIN, INT_MAX, V|E, "flags"}, #endif {"ilme", "interlaced motion estimation", 0, AV_OPT_TYPE_CONST, {.dbl = CODEC_FLAG_INTERLACED_ME }, INT_MIN, INT_MAX, V|E, "flags"}, From 63efd83ae10a158e3ae0823e3527f3845dda397a Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 27 Feb 2012 19:09:49 +0100 Subject: [PATCH 10/58] mpegvideo_enc: add chroma/luma_elim_threshold private options. Deprecate corresponding AVCodecContext fields. --- libavcodec/avcodec.h | 6 ++++-- libavcodec/mpegvideo.h | 6 +++++- libavcodec/mpegvideo_enc.c | 8 ++++++-- libavcodec/options.c | 2 ++ libavformat/ffmdec.c | 2 -- libavformat/ffmenc.c | 2 -- tests/ref/lavf/ffm | 2 +- 7 files changed, 18 insertions(+), 10 deletions(-) diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 5677c0bce5..01da5a6258 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -1439,19 +1439,21 @@ typedef struct AVCodecContext { int b_frame_strategy; +#if FF_API_MPV_GLOBAL_OPTS /** * luma single coefficient elimination threshold * - encoding: Set by user. * - decoding: unused */ - int luma_elim_threshold; + attribute_deprecated int luma_elim_threshold; /** * chroma single coeff elimination threshold * - encoding: Set by user. * - decoding: unused */ - int chroma_elim_threshold; + attribute_deprecated int chroma_elim_threshold; +#endif /** * qscale offset between IP and B-frames diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index 4ec419034f..084f4be769 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -711,7 +711,11 @@ typedef struct MpegEncContext { { "skip_rd", "RD optimal MB level residual skipping", 0, AV_OPT_TYPE_CONST, { FF_MPV_FLAG_SKIP_RD }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" },\ { "strict_gop", "Strictly enforce gop size", 0, AV_OPT_TYPE_CONST, { FF_MPV_FLAG_STRICT_GOP }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" },\ { "qp_rd", "Use rate distortion optimization for qp selection", 0, AV_OPT_TYPE_CONST, { FF_MPV_FLAG_QP_RD }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" },\ -{ "cbp_rd", "use rate distortion optimization for CBP", 0, AV_OPT_TYPE_CONST, { FF_MPV_FLAG_CBP_RD }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" }, +{ "cbp_rd", "use rate distortion optimization for CBP", 0, AV_OPT_TYPE_CONST, { FF_MPV_FLAG_CBP_RD }, 0, 0, FF_MPV_OPT_FLAGS, "mpv_flags" },\ +{ "luma_elim_threshold", "single coefficient elimination threshold for luminance (negative values also consider dc coefficient)",\ + FF_MPV_OFFSET(luma_elim_threshold), AV_OPT_TYPE_INT, { 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS },\ +{ "chroma_elim_threshold", "single coefficient elimination threshold for chrominance (negative values also consider dc coefficient)",\ + FF_MPV_OFFSET(chroma_elim_threshold), AV_OPT_TYPE_INT, { 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, extern const AVOption ff_mpv_generic_options[]; diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index e6e6a95b48..8a516b3016 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -353,8 +353,12 @@ av_cold int ff_MPV_encode_init(AVCodecContext *avctx) s->flags2 = avctx->flags2; s->max_b_frames = avctx->max_b_frames; s->codec_id = avctx->codec->id; - s->luma_elim_threshold = avctx->luma_elim_threshold; - s->chroma_elim_threshold = avctx->chroma_elim_threshold; +#if FF_API_MPV_GLOBAL_OPTS + if (avctx->luma_elim_threshold) + s->luma_elim_threshold = avctx->luma_elim_threshold; + if (avctx->chroma_elim_threshold) + s->chroma_elim_threshold = avctx->chroma_elim_threshold; +#endif s->strict_std_compliance = avctx->strict_std_compliance; s->quarter_sample = (avctx->flags & CODEC_FLAG_QPEL) != 0; s->mpeg_quant = avctx->mpeg_quant; diff --git a/libavcodec/options.c b/libavcodec/options.c index 6b5b148516..9aa02a9c05 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -169,8 +169,10 @@ static const AVOption options[]={ {"dc_clip", NULL, 0, AV_OPT_TYPE_CONST, {.dbl = FF_BUG_DC_CLIP }, INT_MIN, INT_MAX, V|D, "bug"}, {"ms", "workaround various bugs in microsofts broken decoders", 0, AV_OPT_TYPE_CONST, {.dbl = FF_BUG_MS }, INT_MIN, INT_MAX, V|D, "bug"}, {"trunc", "trancated frames", 0, AV_OPT_TYPE_CONST, {.dbl = FF_BUG_TRUNCATED}, INT_MIN, INT_MAX, V|D, "bug"}, +#if FF_API_MPV_GLOBAL_OPTS {"lelim", "single coefficient elimination threshold for luminance (negative values also consider dc coefficient)", OFFSET(luma_elim_threshold), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|E}, {"celim", "single coefficient elimination threshold for chrominance (negative values also consider dc coefficient)", OFFSET(chroma_elim_threshold), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|E}, +#endif {"strict", "how strictly to follow the standards", OFFSET(strict_std_compliance), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, A|V|D|E, "strict"}, {"very", "strictly conform to a older more strict version of the spec or reference software", 0, AV_OPT_TYPE_CONST, {.dbl = FF_COMPLIANCE_VERY_STRICT }, INT_MIN, INT_MAX, V|D|E, "strict"}, {"strict", "strictly conform to all the things in the spec no matter what consequences", 0, AV_OPT_TYPE_CONST, {.dbl = FF_COMPLIANCE_STRICT }, INT_MIN, INT_MAX, V|D|E, "strict"}, diff --git a/libavformat/ffmdec.c b/libavformat/ffmdec.c index 089609f3ee..2149c8cdd7 100644 --- a/libavformat/ffmdec.c +++ b/libavformat/ffmdec.c @@ -332,8 +332,6 @@ static int ffm_read_header(AVFormatContext *s) codec->dct_algo = avio_rb32(pb); codec->strict_std_compliance = avio_rb32(pb); codec->max_b_frames = avio_rb32(pb); - codec->luma_elim_threshold = avio_rb32(pb); - codec->chroma_elim_threshold = avio_rb32(pb); codec->mpeg_quant = avio_rb32(pb); codec->intra_dc_precision = avio_rb32(pb); codec->me_method = avio_rb32(pb); diff --git a/libavformat/ffmenc.c b/libavformat/ffmenc.c index b8d3d315bd..500ae0bf50 100644 --- a/libavformat/ffmenc.c +++ b/libavformat/ffmenc.c @@ -144,8 +144,6 @@ static int ffm_write_header(AVFormatContext *s) avio_wb32(pb, codec->dct_algo); avio_wb32(pb, codec->strict_std_compliance); avio_wb32(pb, codec->max_b_frames); - avio_wb32(pb, codec->luma_elim_threshold); - avio_wb32(pb, codec->chroma_elim_threshold); avio_wb32(pb, codec->mpeg_quant); avio_wb32(pb, codec->intra_dc_precision); avio_wb32(pb, codec->me_method); diff --git a/tests/ref/lavf/ffm b/tests/ref/lavf/ffm index 0ae40f59d9..afef176a9b 100644 --- a/tests/ref/lavf/ffm +++ b/tests/ref/lavf/ffm @@ -1,3 +1,3 @@ -c963591a7f9a08d48e0f988640795690 *./tests/data/lavf/lavf.ffm +8a95fa3db8e6082ed24e963e40ec1526 *./tests/data/lavf/lavf.ffm 376832 ./tests/data/lavf/lavf.ffm ./tests/data/lavf/lavf.ffm CRC=0x88f58ba1 From e0f68413ddd06a0290b812599e3af98a90fd5ca1 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 27 Feb 2012 19:44:41 +0100 Subject: [PATCH 11/58] avplay: remove an unused variable. --- avplay.c | 1 - 1 file changed, 1 deletion(-) diff --git a/avplay.c b/avplay.c index 836647a215..beb8dd152e 100644 --- a/avplay.c +++ b/avplay.c @@ -137,7 +137,6 @@ typedef struct VideoState { int64_t seek_rel; int read_pause_return; AVFormatContext *ic; - int dtg_active_format; int audio_stream; From 4f07f8196c23cf49cc074eef65ab50134085018f Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 27 Feb 2012 19:53:21 +0100 Subject: [PATCH 12/58] lavc: deprecate AVCodecContext.color_table_id. It's currently only used as temporary storage by the mov demuxer. Make it use a local variable instead. --- libavcodec/avcodec.h | 4 +++- libavcodec/options.c | 2 ++ libavcodec/version.h | 3 +++ libavformat/mov.c | 7 ++++--- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 01da5a6258..d8c7416be9 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -1684,13 +1684,15 @@ typedef struct AVCodecContext { */ int inter_quant_bias; +#if FF_API_COLOR_TABLE_ID /** * color table ID * - encoding: unused * - decoding: Which clrtable should be used for 8bit RGB images. * Tables have to be stored somewhere. FIXME */ - int color_table_id; + attribute_deprecated int color_table_id; +#endif /** * slice flags diff --git a/libavcodec/options.c b/libavcodec/options.c index 9aa02a9c05..bfd4b8988f 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -297,7 +297,9 @@ static const AVOption options[]={ {"me_range", "limit motion vectors range (1023 for DivX player)", OFFSET(me_range), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|E}, {"ibias", "intra quant bias", OFFSET(intra_quant_bias), AV_OPT_TYPE_INT, {.dbl = FF_DEFAULT_QUANT_BIAS }, INT_MIN, INT_MAX, V|E}, {"pbias", "inter quant bias", OFFSET(inter_quant_bias), AV_OPT_TYPE_INT, {.dbl = FF_DEFAULT_QUANT_BIAS }, INT_MIN, INT_MAX, V|E}, +#if FF_API_COLOR_TABLE_ID {"color_table_id", NULL, OFFSET(color_table_id), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX}, +#endif {"global_quality", NULL, OFFSET(global_quality), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|A|E}, {"coder", NULL, OFFSET(coder_type), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|E, "coder"}, {"vlc", "variable length coder / huffman coder", 0, AV_OPT_TYPE_CONST, {.dbl = FF_CODER_TYPE_VLC }, INT_MIN, INT_MAX, V|E, "coder"}, diff --git a/libavcodec/version.h b/libavcodec/version.h index ffce89588d..618e92b3e2 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -53,5 +53,8 @@ #ifndef FF_API_MPV_GLOBAL_OPTS #define FF_API_MPV_GLOBAL_OPTS (LIBAVCODEC_VERSION_MAJOR < 55) #endif +#ifndef FF_API_COLOR_TABLE_ID +#define FF_API_COLOR_TABLE_ID (LIBAVCODEC_VERSION_MAJOR < 55) +#endif #endif /* AVCODEC_VERSION_H */ diff --git a/libavformat/mov.c b/libavformat/mov.c index b11e0bfef7..0c51eac05c 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -1180,6 +1180,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) if (st->codec->codec_type==AVMEDIA_TYPE_VIDEO) { unsigned int color_depth, len; int color_greyscale; + int color_table_id; st->codec->codec_id = id; avio_rb16(pb); /* version */ @@ -1207,9 +1208,9 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) st->codec->codec_tag=MKTAG('I', '4', '2', '0'); st->codec->bits_per_coded_sample = avio_rb16(pb); /* depth */ - st->codec->color_table_id = avio_rb16(pb); /* colortable id */ + color_table_id = avio_rb16(pb); /* colortable id */ av_dlog(c->fc, "depth %d, ctab id %d\n", - st->codec->bits_per_coded_sample, st->codec->color_table_id); + st->codec->bits_per_coded_sample, color_table_id); /* figure out the palette situation */ color_depth = st->codec->bits_per_coded_sample & 0x1F; color_greyscale = st->codec->bits_per_coded_sample & 0x20; @@ -1236,7 +1237,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) if (color_index < 0) color_index = 0; } - } else if (st->codec->color_table_id) { + } else if (color_table_id) { const uint8_t *color_table; /* if flag bit 3 is set, use the default palette */ color_count = 1 << color_depth; From 16b7557b794c6cd47c5a256a246f8c930c01eef7 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 27 Feb 2012 19:58:41 +0100 Subject: [PATCH 13/58] lavc: deprecate AVCodecContext.inter_threshold. It's unused. --- libavcodec/avcodec.h | 8 ++++---- libavcodec/options.c | 2 ++ libavcodec/version.h | 3 +++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index d8c7416be9..a9fc31e900 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -1750,12 +1750,12 @@ typedef struct AVCodecContext { */ int noise_reduction; +#if FF_API_INTER_THRESHOLD /** - * - * - encoding: Set by user. - * - decoding: unused + * @deprecated this field is unused */ - int inter_threshold; + attribute_deprecated int inter_threshold; +#endif /** * quantizer noise shaping diff --git a/libavcodec/options.c b/libavcodec/options.c index bfd4b8988f..dbf3427d91 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -320,7 +320,9 @@ static const AVOption options[]={ {"lmax", "max lagrange factor (VBR)", OFFSET(lmax), AV_OPT_TYPE_INT, {.dbl = 31*FF_QP2LAMBDA }, 0, INT_MAX, V|E}, {"nr", "noise reduction", OFFSET(noise_reduction), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|E}, {"rc_init_occupancy", "number of bits which should be loaded into the rc buffer before decoding starts", OFFSET(rc_initial_buffer_occupancy), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|E}, +#if FF_API_INTER_THRESHOLD {"inter_threshold", NULL, OFFSET(inter_threshold), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|E}, +#endif {"flags2", NULL, OFFSET(flags2), AV_OPT_TYPE_FLAGS, {.dbl = DEFAULT}, 0, UINT_MAX, V|A|E|D, "flags2"}, {"error", NULL, OFFSET(error_rate), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|E}, {"qns", "quantizer noise shaping", OFFSET(quantizer_noise_shaping), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|E}, diff --git a/libavcodec/version.h b/libavcodec/version.h index 618e92b3e2..2f11a29d92 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -56,5 +56,8 @@ #ifndef FF_API_COLOR_TABLE_ID #define FF_API_COLOR_TABLE_ID (LIBAVCODEC_VERSION_MAJOR < 55) #endif +#ifndef FF_API_INTER_THRESHOLD +#define FF_API_INTER_THRESHOLD (LIBAVCODEC_VERSION_MAJOR < 55) +#endif #endif /* AVCODEC_VERSION_H */ From 23bfcc066d468e2ec6159be2f5af3d5a59f40d79 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 27 Feb 2012 20:06:23 +0100 Subject: [PATCH 14/58] mpegvideo_enc: add quantizer_noise_shaping private option. Deprecate corresponding AVCodecContext field. --- libavcodec/avcodec.h | 8 ++++---- libavcodec/mpegvideo.h | 4 +++- libavcodec/mpegvideo_enc.c | 12 +++++++----- libavcodec/options.c | 4 +++- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index a9fc31e900..f4db08335a 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -1757,12 +1757,12 @@ typedef struct AVCodecContext { attribute_deprecated int inter_threshold; #endif +#if FF_API_MPV_GLOBAL_OPTS /** - * quantizer noise shaping - * - encoding: Set by user. - * - decoding: unused + * @deprecated use mpegvideo private options instead */ - int quantizer_noise_shaping; + attribute_deprecated int quantizer_noise_shaping; +#endif /** * Motion estimation threshold below which no motion estimation is diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index 084f4be769..ad0bd3a164 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -691,6 +691,7 @@ typedef struct MpegEncContext { void (*denoise_dct)(struct MpegEncContext *s, DCTELEM *block); int mpv_flags; ///< flags set by private options + int quantizer_noise_shaping; } MpegEncContext; #define REBASE_PICTURE(pic, new_ctx, old_ctx) (pic ? \ @@ -715,7 +716,8 @@ typedef struct MpegEncContext { { "luma_elim_threshold", "single coefficient elimination threshold for luminance (negative values also consider dc coefficient)",\ FF_MPV_OFFSET(luma_elim_threshold), AV_OPT_TYPE_INT, { 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS },\ { "chroma_elim_threshold", "single coefficient elimination threshold for chrominance (negative values also consider dc coefficient)",\ - FF_MPV_OFFSET(chroma_elim_threshold), AV_OPT_TYPE_INT, { 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, + FF_MPV_OFFSET(chroma_elim_threshold), AV_OPT_TYPE_INT, { 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS },\ +{ "quantizer_noise_shaping", NULL, FF_MPV_OFFSET(quantizer_noise_shaping), AV_OPT_TYPE_INT, { 0 }, 0, INT_MAX, FF_MPV_OPT_FLAGS }, extern const AVOption ff_mpv_generic_options[]; diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index 8a516b3016..0940eeda2f 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -630,6 +630,8 @@ av_cold int ff_MPV_encode_init(AVCodecContext *avctx) s->mpv_flags |= FF_MPV_FLAG_SKIP_RD; if (avctx->flags2 & CODEC_FLAG2_STRICT_GOP) s->mpv_flags |= FF_MPV_FLAG_STRICT_GOP; + if (avctx->quantizer_noise_shaping) + s->quantizer_noise_shaping = avctx->quantizer_noise_shaping; #endif switch (avctx->codec->id) { @@ -1949,7 +1951,7 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, } } - if (s->avctx->quantizer_noise_shaping) { + if (s->quantizer_noise_shaping) { if (!skip_dct[0]) get_visual_weight(weight[0], ptr_y , wrap_y); if (!skip_dct[1]) @@ -1990,7 +1992,7 @@ static av_always_inline void encode_mb_internal(MpegEncContext *s, } else s->block_last_index[i] = -1; } - if (s->avctx->quantizer_noise_shaping) { + if (s->quantizer_noise_shaping) { for (i = 0; i < mb_block_count; i++) { if (!skip_dct[i]) { s->block_last_index[i] = @@ -3738,7 +3740,7 @@ STOP_TIMER("init rem[]") #ifdef REFINE_STATS {START_TIMER #endif - analyze_gradient = last_non_zero > 2 || s->avctx->quantizer_noise_shaping >= 3; + analyze_gradient = last_non_zero > 2 || s->quantizer_noise_shaping >= 3; if(analyze_gradient){ #ifdef REFINE_STATS @@ -3796,7 +3798,7 @@ STOP_TIMER("dct")} const int level= block[j]; int change, old_coeff; - if(s->avctx->quantizer_noise_shaping < 3 && i > last_non_zero + 1) + if(s->quantizer_noise_shaping < 3 && i > last_non_zero + 1) break; if(level){ @@ -3814,7 +3816,7 @@ STOP_TIMER("dct")} int score, new_coeff, unquant_change; score=0; - if(s->avctx->quantizer_noise_shaping < 2 && FFABS(new_level) > FFABS(level)) + if(s->quantizer_noise_shaping < 2 && FFABS(new_level) > FFABS(level)) continue; if(new_level){ diff --git a/libavcodec/options.c b/libavcodec/options.c index dbf3427d91..288c75437a 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -325,7 +325,9 @@ static const AVOption options[]={ #endif {"flags2", NULL, OFFSET(flags2), AV_OPT_TYPE_FLAGS, {.dbl = DEFAULT}, 0, UINT_MAX, V|A|E|D, "flags2"}, {"error", NULL, OFFSET(error_rate), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|E}, -{"qns", "quantizer noise shaping", OFFSET(quantizer_noise_shaping), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|E}, +#if FF_API_MPV_GLOBAL_OPTS +{"qns", "deprecated, use mpegvideo private options instead", OFFSET(quantizer_noise_shaping), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|E}, +#endif {"threads", NULL, OFFSET(thread_count), AV_OPT_TYPE_INT, {.dbl = 1 }, 0, INT_MAX, V|E|D, "threads"}, {"auto", "detect a good number of threads", 0, AV_OPT_TYPE_CONST, {.dbl = 0 }, INT_MIN, INT_MAX, V|E|D, "threads"}, {"me_threshold", "motion estimaton threshold", OFFSET(me_threshold), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|E}, From 235d6932865fcfa686e5614ca609acefa8fed5c1 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Tue, 28 Feb 2012 19:03:09 +0100 Subject: [PATCH 15/58] prores: handle 444 chroma in right order ProRes codes chroma blocks in 444 mode in different order than luma blocks, so make both decoder and encoder read/write chroma blocks in right order. Reported by Phil Barrett --- libavcodec/proresdec.c | 41 +++++++++++++++++++++++++------------ libavcodec/proresenc.c | 37 ++++++++++++++++++++++----------- tests/ref/fate/prores-alpha | 4 ++-- 3 files changed, 55 insertions(+), 27 deletions(-) diff --git a/libavcodec/proresdec.c b/libavcodec/proresdec.c index 8ca5f3d632..da90912031 100644 --- a/libavcodec/proresdec.c +++ b/libavcodec/proresdec.c @@ -411,7 +411,7 @@ static void decode_slice_plane(ProresContext *ctx, ProresThreadData *td, int data_size, uint16_t *out_ptr, int linesize, int mbs_per_slice, int blocks_per_mb, int plane_size_factor, - const int16_t *qmat) + const int16_t *qmat, int is_chroma) { GetBitContext gb; DCTELEM *block_ptr; @@ -431,18 +431,33 @@ static void decode_slice_plane(ProresContext *ctx, ProresThreadData *td, /* inverse quantization, inverse transform and output */ block_ptr = td->blocks; - for (mb_num = 0; mb_num < mbs_per_slice; mb_num++, out_ptr += blocks_per_mb * 4) { - ctx->dsp.idct_put(out_ptr, linesize, block_ptr, qmat); - block_ptr += 64; - if (blocks_per_mb > 2) { - ctx->dsp.idct_put(out_ptr + 8, linesize, block_ptr, qmat); + if (!is_chroma) { + for (mb_num = 0; mb_num < mbs_per_slice; mb_num++, out_ptr += blocks_per_mb * 4) { + ctx->dsp.idct_put(out_ptr, linesize, block_ptr, qmat); block_ptr += 64; + if (blocks_per_mb > 2) { + ctx->dsp.idct_put(out_ptr + 8, linesize, block_ptr, qmat); + block_ptr += 64; + } + ctx->dsp.idct_put(out_ptr + linesize * 4, linesize, block_ptr, qmat); + block_ptr += 64; + if (blocks_per_mb > 2) { + ctx->dsp.idct_put(out_ptr + linesize * 4 + 8, linesize, block_ptr, qmat); + block_ptr += 64; + } } - ctx->dsp.idct_put(out_ptr + linesize * 4, linesize, block_ptr, qmat); - block_ptr += 64; - if (blocks_per_mb > 2) { - ctx->dsp.idct_put(out_ptr + linesize * 4 + 8, linesize, block_ptr, qmat); + } else { + for (mb_num = 0; mb_num < mbs_per_slice; mb_num++, out_ptr += blocks_per_mb * 4) { + ctx->dsp.idct_put(out_ptr, linesize, block_ptr, qmat); block_ptr += 64; + ctx->dsp.idct_put(out_ptr + linesize * 4, linesize, block_ptr, qmat); + block_ptr += 64; + if (blocks_per_mb > 2) { + ctx->dsp.idct_put(out_ptr + 8, linesize, block_ptr, qmat); + block_ptr += 64; + ctx->dsp.idct_put(out_ptr + linesize * 4 + 8, linesize, block_ptr, qmat); + block_ptr += 64; + } } } } @@ -523,7 +538,7 @@ static int decode_slice(AVCodecContext *avctx, void *tdata) (uint16_t*) (y_data + (mb_y_pos << 4) * y_linesize + (mb_x_pos << 5)), y_linesize, mbs_per_slice, 4, slice_width_factor + 2, - td->qmat_luma_scaled); + td->qmat_luma_scaled, 0); /* decode U chroma plane */ decode_slice_plane(ctx, td, buf + hdr_size + y_data_size, u_data_size, @@ -531,7 +546,7 @@ static int decode_slice(AVCodecContext *avctx, void *tdata) (mb_x_pos << ctx->mb_chroma_factor)), u_linesize, mbs_per_slice, ctx->num_chroma_blocks, slice_width_factor + ctx->chroma_factor - 1, - td->qmat_chroma_scaled); + td->qmat_chroma_scaled, 1); /* decode V chroma plane */ decode_slice_plane(ctx, td, buf + hdr_size + y_data_size + u_data_size, @@ -540,7 +555,7 @@ static int decode_slice(AVCodecContext *avctx, void *tdata) (mb_x_pos << ctx->mb_chroma_factor)), v_linesize, mbs_per_slice, ctx->num_chroma_blocks, slice_width_factor + ctx->chroma_factor - 1, - td->qmat_chroma_scaled); + td->qmat_chroma_scaled, 1); return 0; } diff --git a/libavcodec/proresenc.c b/libavcodec/proresenc.c index aa96b35e75..552fa7c14a 100644 --- a/libavcodec/proresenc.c +++ b/libavcodec/proresenc.c @@ -171,7 +171,7 @@ typedef struct ProresContext { static void get_slice_data(ProresContext *ctx, const uint16_t *src, int linesize, int x, int y, int w, int h, DCTELEM *blocks, - int mbs_per_slice, int blocks_per_mb) + int mbs_per_slice, int blocks_per_mb, int is_chroma) { const uint16_t *esrc; const int mb_width = 4 * blocks_per_mb; @@ -209,17 +209,30 @@ static void get_slice_data(ProresContext *ctx, const uint16_t *src, ctx->emu_buf + (bh - 1) * estride, mb_width * sizeof(*ctx->emu_buf)); } - ctx->dsp.fdct(esrc, elinesize, blocks); - blocks += 64; - if (blocks_per_mb > 2) { - ctx->dsp.fdct(src + 8, linesize, blocks); + if (!is_chroma) { + ctx->dsp.fdct(esrc, elinesize, blocks); blocks += 64; - } - ctx->dsp.fdct(src + linesize * 4, linesize, blocks); - blocks += 64; - if (blocks_per_mb > 2) { - ctx->dsp.fdct(src + linesize * 4 + 8, linesize, blocks); + if (blocks_per_mb > 2) { + ctx->dsp.fdct(src + 8, linesize, blocks); + blocks += 64; + } + ctx->dsp.fdct(src + linesize * 4, linesize, blocks); blocks += 64; + if (blocks_per_mb > 2) { + ctx->dsp.fdct(src + linesize * 4 + 8, linesize, blocks); + blocks += 64; + } + } else { + ctx->dsp.fdct(esrc, elinesize, blocks); + blocks += 64; + ctx->dsp.fdct(src + linesize * 4, linesize, blocks); + blocks += 64; + if (blocks_per_mb > 2) { + ctx->dsp.fdct(src + 8, linesize, blocks); + blocks += 64; + ctx->dsp.fdct(src + linesize * 4 + 8, linesize, blocks); + blocks += 64; + } } x += mb_width; @@ -383,7 +396,7 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic, get_slice_data(ctx, src, pic->linesize[i], xp, yp, pwidth, avctx->height, ctx->blocks[0], - mbs_per_slice, num_cblocks); + mbs_per_slice, num_cblocks, is_chroma); sizes[i] = encode_slice_plane(ctx, pb, src, pic->linesize[i], mbs_per_slice, ctx->blocks[0], num_cblocks, plane_factor, @@ -539,7 +552,7 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic, get_slice_data(ctx, src, pic->linesize[i], xp, yp, pwidth, avctx->height, ctx->blocks[i], - mbs_per_slice, num_cblocks[i]); + mbs_per_slice, num_cblocks[i], is_chroma[i]); } for (q = min_quant; q < max_quant + 2; q++) { diff --git a/tests/ref/fate/prores-alpha b/tests/ref/fate/prores-alpha index 9aa916013b..80442fe7b5 100644 --- a/tests/ref/fate/prores-alpha +++ b/tests/ref/fate/prores-alpha @@ -1,3 +1,3 @@ #tb 0: 1/2997 -0, 0, 0, 0, 12441600, 0x9d3dc525 -0, 100, 100, 0, 12441600, 0x9d3dc525 +0, 0, 0, 0, 12441600, 0x254d8f95 +0, 100, 100, 0, 12441600, 0x254d8f95 From c7084182e85eaa437899df58fd1ae57426d3c7f7 Mon Sep 17 00:00:00 2001 From: Phil Barrett Date: Tue, 28 Feb 2012 19:26:11 +0100 Subject: [PATCH 16/58] proresenc: correct edge emulation Signed-off-by: Kostya Shishkov --- libavcodec/proresenc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libavcodec/proresenc.c b/libavcodec/proresenc.c index 552fa7c14a..c10f599f27 100644 --- a/libavcodec/proresenc.c +++ b/libavcodec/proresenc.c @@ -189,24 +189,24 @@ static void get_slice_data(ProresContext *ctx, const uint16_t *src, elinesize = linesize; } else { int bw, bh, pix; - const int estride = 16 / sizeof(*ctx->emu_buf); esrc = ctx->emu_buf; - elinesize = 16; + elinesize = 16 * sizeof(*ctx->emu_buf); bw = FFMIN(w - x, mb_width); bh = FFMIN(h - y, 16); for (j = 0; j < bh; j++) { - memcpy(ctx->emu_buf + j * estride, src + j * linesize, + memcpy(ctx->emu_buf + j * 16, + (const uint8_t*)src + j * linesize, bw * sizeof(*src)); - pix = ctx->emu_buf[j * estride + bw - 1]; + pix = ctx->emu_buf[j * 16 + bw - 1]; for (k = bw; k < mb_width; k++) - ctx->emu_buf[j * estride + k] = pix; + ctx->emu_buf[j * 16 + k] = pix; } for (; j < 16; j++) - memcpy(ctx->emu_buf + j * estride, - ctx->emu_buf + (bh - 1) * estride, + memcpy(ctx->emu_buf + j * 16, + ctx->emu_buf + (bh - 1) * 16, mb_width * sizeof(*ctx->emu_buf)); } if (!is_chroma) { From 12b812d2e5dcc7c80b19b7c01713be31389120d5 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Tue, 28 Feb 2012 19:44:07 +0100 Subject: [PATCH 17/58] prores: store and retrieve extended colourspace information Based on the patch by Phil Barrett. --- libavcodec/proresdec.c | 4 ++++ libavcodec/proresenc.c | 6 +++--- tests/ref/vsynth1/prores | 2 +- tests/ref/vsynth2/prores | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/libavcodec/proresdec.c b/libavcodec/proresdec.c index da90912031..a399576179 100644 --- a/libavcodec/proresdec.c +++ b/libavcodec/proresdec.c @@ -165,6 +165,10 @@ static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, ctx->picture.top_field_first = ctx->frame_type & 1; } + avctx->color_primaries = buf[14]; + avctx->color_trc = buf[15]; + avctx->colorspace = buf[16]; + ctx->alpha_info = buf[17] & 0xf; if (ctx->alpha_info) av_log_missing_feature(avctx, "alpha channel", 0); diff --git a/libavcodec/proresenc.c b/libavcodec/proresenc.c index c10f599f27..8e6f93fe2b 100644 --- a/libavcodec/proresenc.c +++ b/libavcodec/proresenc.c @@ -689,9 +689,9 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, bytestream_put_be16 (&buf, avctx->height); bytestream_put_byte (&buf, ctx->chroma_factor << 6); // frame flags bytestream_put_byte (&buf, 0); // reserved - bytestream_put_byte (&buf, 0); // primaries - bytestream_put_byte (&buf, 0); // transfer function - bytestream_put_byte (&buf, 6); // colour matrix - ITU-R BT.601-4 + bytestream_put_byte (&buf, avctx->color_primaries); + bytestream_put_byte (&buf, avctx->color_trc); + bytestream_put_byte (&buf, avctx->colorspace); bytestream_put_byte (&buf, 0x40); // source format and alpha information bytestream_put_byte (&buf, 0); // reserved bytestream_put_byte (&buf, 0x03); // matrix flags - both matrices are present diff --git a/tests/ref/vsynth1/prores b/tests/ref/vsynth1/prores index b496d99e93..67ae0dcfd6 100644 --- a/tests/ref/vsynth1/prores +++ b/tests/ref/vsynth1/prores @@ -1,4 +1,4 @@ -c050b1a4905175211ead9979562366ff *./tests/data/vsynth1/prores.mov +2566517b15c62887bd94daaab1b1a85b *./tests/data/vsynth1/prores.mov 3859037 ./tests/data/vsynth1/prores.mov 0a4153637d0cc0a88a8bcbf04cfaf8c6 *./tests/data/prores.vsynth1.out.yuv stddev: 3.17 PSNR: 38.09 MAXDIFF: 39 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth2/prores b/tests/ref/vsynth2/prores index da5a97e7b3..44bd405d6f 100644 --- a/tests/ref/vsynth2/prores +++ b/tests/ref/vsynth2/prores @@ -1,4 +1,4 @@ -ecd11fa69712902143c0c54b193c9313 *./tests/data/vsynth2/prores.mov +28755ce05e812adbb8b7c180318ffba8 *./tests/data/vsynth2/prores.mov 3884722 ./tests/data/vsynth2/prores.mov ca2f6c1162635dedfa468c90f1fdc0ef *./tests/data/prores.vsynth2.out.yuv stddev: 0.92 PSNR: 48.77 MAXDIFF: 10 bytes: 7603200/ 7603200 From eaea76d72ce56f0c9ae4b15dbb6629ef1b027de7 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 29 Feb 2012 08:07:57 +0100 Subject: [PATCH 18/58] swfdec: do not set codec timebase. It is not supposed to be set outside of lavc. Fixes a divide by zero when the stored framerate is 0. --- libavformat/swfdec.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/libavformat/swfdec.c b/libavformat/swfdec.c index c194310a37..71346de05c 100644 --- a/libavformat/swfdec.c +++ b/libavformat/swfdec.c @@ -113,7 +113,6 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt) vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; vst->codec->codec_id = ff_codec_get_id(swf_codec_tags, avio_r8(pb)); avpriv_set_pts_info(vst, 16, 256, swf->frame_rate); - vst->codec->time_base = (AVRational){ 256, swf->frame_rate }; len -= 8; } else if (tag == TAG_STREAMHEAD || tag == TAG_STREAMHEAD2) { /* streaming found */ @@ -186,7 +185,6 @@ static int swf_read_packet(AVFormatContext *s, AVPacket *pkt) vst->codec->codec_type = AVMEDIA_TYPE_VIDEO; vst->codec->codec_id = CODEC_ID_MJPEG; avpriv_set_pts_info(vst, 64, 256, swf->frame_rate); - vst->codec->time_base = (AVRational){ 256, swf->frame_rate }; st = vst; } avio_rl16(pb); /* BITMAP_ID */ From b73ad746606e193aa3e2dde20ce8afeeb8fa7e0e Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 19 Jan 2011 10:21:29 +0100 Subject: [PATCH 19/58] lavf: move CodecMime from matroska.h to internal.h it will be useful for attached pictures in ID3v2 --- libavformat/internal.h | 5 +++++ libavformat/matroska.h | 6 +----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/libavformat/internal.h b/libavformat/internal.h index fb298539b6..c30deb7732 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -37,6 +37,11 @@ typedef struct AVCodecTag { unsigned int tag; } AVCodecTag; +typedef struct CodecMime{ + char str[32]; + enum CodecID id; +} CodecMime; + void ff_dynarray_add(intptr_t **tab_ptr, int *nb_ptr, intptr_t elem); #ifdef __GNUC__ diff --git a/libavformat/matroska.h b/libavformat/matroska.h index 8e747e6a9c..ada735f172 100644 --- a/libavformat/matroska.h +++ b/libavformat/matroska.h @@ -24,6 +24,7 @@ #include "libavcodec/avcodec.h" #include "metadata.h" +#include "internal.h" /* EBML version supported */ #define EBML_VERSION 1 @@ -245,11 +246,6 @@ typedef struct CodecTags{ enum CodecID id; }CodecTags; -typedef struct CodecMime{ - char str[32]; - enum CodecID id; -}CodecMime; - /* max. depth in the EBML tree structure */ #define EBML_MAX_DEPTH 16 From a93b09cb45b86427d6e81fa51c660877d8d5fd17 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 25 Feb 2012 09:45:38 +0100 Subject: [PATCH 20/58] id3v2: read attached pictures and export them in ID3v2ExtraMeta. --- libavformat/id3v2.c | 112 ++++++++++++++++++++++++++++++++++++++++++++ libavformat/id3v2.h | 13 +++++ 2 files changed, 125 insertions(+) diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c index deb652d60c..853a04c78e 100644 --- a/libavformat/id3v2.c +++ b/libavformat/id3v2.c @@ -25,6 +25,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/dict.h" #include "avio_internal.h" +#include "internal.h" const AVMetadataConv ff_id3v2_34_metadata_conv[] = { { "TALB", "album"}, @@ -86,6 +87,38 @@ const char ff_id3v2_3_tags[][4] = { { 0 }, }; +const char *ff_id3v2_picture_types[21] = { + "Other", + "32x32 pixels 'file icon'", + "Other file icon", + "Cover (front)", + "Cover (back)", + "Leaflet page", + "Media (e.g. label side of CD)", + "Lead artist/lead performer/soloist", + "Artist/performer", + "Conductor", + "Band/Orchestra", + "Composer", + "Lyricist/text writer", + "Recording Location", + "During recording", + "During performance", + "Movie/video screen capture", + "A bright coloured fish", + "Illustration", + "Band/artist logotype", + "Publisher/Studio logotype", +}; + +const CodecMime ff_id3v2_mime_tags[] = { + {"image/gif" , CODEC_ID_GIF}, + {"image/jpeg", CODEC_ID_MJPEG}, + {"image/png" , CODEC_ID_PNG}, + {"image/tiff", CODEC_ID_TIFF}, + {"", CODEC_ID_NONE}, +}; + int ff_id3v2_match(const uint8_t *buf, const char * magic) { return buf[0] == magic[0] && @@ -381,6 +414,84 @@ finish: av_dict_set(m, "date", date, 0); } +static void free_apic(void *obj) +{ + ID3v2ExtraMetaAPIC *apic = obj; + av_freep(&apic->data); + av_freep(&apic->description); + av_freep(&apic); +} + +static void read_apic(AVFormatContext *s, AVIOContext *pb, int taglen, char *tag, ID3v2ExtraMeta **extra_meta) +{ + int enc, pic_type; + char mimetype[64]; + const CodecMime *mime = ff_id3v2_mime_tags; + enum CodecID id = CODEC_ID_NONE; + ID3v2ExtraMetaAPIC *apic = NULL; + ID3v2ExtraMeta *new_extra = NULL; + int64_t end = avio_tell(pb) + taglen; + + if (taglen <= 4) + goto fail; + + new_extra = av_mallocz(sizeof(*new_extra)); + apic = av_mallocz(sizeof(*apic)); + if (!new_extra || !apic) + goto fail; + + enc = avio_r8(pb); + taglen--; + + /* mimetype */ + taglen -= avio_get_str(pb, taglen, mimetype, sizeof(mimetype)); + while (mime->id != CODEC_ID_NONE) { + if (!strncmp(mime->str, mimetype, sizeof(mimetype))) { + id = mime->id; + break; + } + mime++; + } + if (id == CODEC_ID_NONE) { + av_log(s, AV_LOG_WARNING, "Unknown attached picture mimetype: %s, skipping.\n", mimetype); + goto fail; + } + apic->id = id; + + /* picture type */ + pic_type = avio_r8(pb); + taglen--; + if (pic_type < 0 || pic_type >= FF_ARRAY_ELEMS(ff_id3v2_picture_types)) { + av_log(s, AV_LOG_WARNING, "Unknown attached picture type %d.\n", pic_type); + pic_type = 0; + } + apic->type = ff_id3v2_picture_types[pic_type]; + + /* description and picture data */ + if (decode_str(s, pb, enc, &apic->description, &taglen) < 0) { + av_log(s, AV_LOG_ERROR, "Error decoding attached picture description.\n"); + goto fail; + } + + apic->len = taglen; + apic->data = av_malloc(taglen); + if (!apic->data || avio_read(pb, apic->data, taglen) != taglen) + goto fail; + + new_extra->tag = "APIC"; + new_extra->data = apic; + new_extra->next = *extra_meta; + *extra_meta = new_extra; + + return; + +fail: + if (apic) + free_apic(apic); + av_freep(&new_extra); + avio_seek(pb, end, SEEK_SET); +} + typedef struct ID3v2EMFunc { const char *tag3; const char *tag4; @@ -390,6 +501,7 @@ typedef struct ID3v2EMFunc { static const ID3v2EMFunc id3v2_extra_meta_funcs[] = { { "GEO", "GEOB", read_geobtag, free_geobtag }, + { "PIC", "APIC", read_apic, free_apic }, { NULL } }; diff --git a/libavformat/id3v2.h b/libavformat/id3v2.h index a296e0315b..f358d02892 100644 --- a/libavformat/id3v2.h +++ b/libavformat/id3v2.h @@ -24,6 +24,7 @@ #include #include "avformat.h" +#include "internal.h" #include "metadata.h" #define ID3v2_HEADER_SIZE 10 @@ -59,6 +60,14 @@ typedef struct ID3v2ExtraMetaGEOB { uint8_t *data; } ID3v2ExtraMetaGEOB; +typedef struct ID3v2ExtraMetaAPIC { + uint8_t *data; + int len; + const char *type; + uint8_t *description; + enum CodecID id; +} ID3v2ExtraMetaAPIC; + /** * Detect ID3v2 Header. * @param buf must be ID3v2_HEADER_SIZE byte long @@ -120,4 +129,8 @@ extern const char ff_id3v2_4_tags[][4]; */ extern const char ff_id3v2_3_tags[][4]; +extern const CodecMime ff_id3v2_mime_tags[]; + +extern const char *ff_id3v2_picture_types[21]; + #endif /* AVFORMAT_ID3V2_H */ From dd2a4bcfd72eee85710142943a1c68ac02520771 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 25 Feb 2012 18:05:55 +0100 Subject: [PATCH 21/58] lavf: generic code for exporting attached pictures. --- libavformat/avformat.h | 16 +++++++++++++++ libavformat/utils.c | 46 +++++++++++++++++++++++++----------------- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 1aa18d8213..65ed376c89 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -530,6 +530,13 @@ typedef struct AVIndexEntry { #define AV_DISPOSITION_HEARING_IMPAIRED 0x0080 /**< stream for hearing impaired audiences */ #define AV_DISPOSITION_VISUAL_IMPAIRED 0x0100 /**< stream for visual impaired audiences */ #define AV_DISPOSITION_CLEAN_EFFECTS 0x0200 /**< stream without voice */ +/** + * The stream is stored in the file as an attached picture/"cover art" (e.g. + * APIC frame in ID3v2). The single packet associated with it will be returned + * among the first few packets read from the file unless seeking takes place. + * It can also be accessed at any time in AVStream.attached_pic. + */ +#define AV_DISPOSITION_ATTACHED_PIC 0x0400 /** * Stream structure. @@ -602,6 +609,15 @@ typedef struct AVStream { */ AVRational avg_frame_rate; + /** + * For streams with AV_DISPOSITION_ATTACHED_PIC disposition, this packet + * will contain the attached picture. + * + * decoding: set by libavformat, must not be modified by the caller. + * encoding: unused + */ + AVPacket attached_pic; + /***************************************************************** * All fields below this line are not part of the public API. They * may not be used outside of libavformat and can be changed and diff --git a/libavformat/utils.c b/libavformat/utils.c index 0f9c8b6293..c8dd7f5868 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -498,10 +498,27 @@ static int init_input(AVFormatContext *s, const char *filename, AVDictionary **o return av_probe_input_buffer(s->pb, &s->iformat, filename, s, 0, 0); } +static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt, + AVPacketList **plast_pktl){ + AVPacketList *pktl = av_mallocz(sizeof(AVPacketList)); + if (!pktl) + return NULL; + + if (*packet_buffer) + (*plast_pktl)->next = pktl; + else + *packet_buffer = pktl; + + /* add the packet in the buffered packet list */ + *plast_pktl = pktl; + pktl->pkt= *pkt; + return &pktl->pkt; +} + int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options) { AVFormatContext *s = *ps; - int ret = 0; + int i, ret = 0; AVDictionary *tmp = NULL; if (!s && !(s = avformat_alloc_context())) @@ -551,6 +568,14 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma if ((ret = s->iformat->read_header(s)) < 0) goto fail; + /* queue attached pictures */ + for (i = 0; i < s->nb_streams; i++) + if (s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC) { + AVPacket copy = s->streams[i]->attached_pic; + copy.destruct = NULL; + add_to_pktbuf(&s->raw_packet_buffer, ©, &s->raw_packet_buffer_end); + } + if (s->pb && !s->data_offset) s->data_offset = avio_tell(s->pb); @@ -574,23 +599,6 @@ fail: /*******************************************************/ -static AVPacket *add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt, - AVPacketList **plast_pktl){ - AVPacketList *pktl = av_mallocz(sizeof(AVPacketList)); - if (!pktl) - return NULL; - - if (*packet_buffer) - (*plast_pktl)->next = pktl; - else - *packet_buffer = pktl; - - /* add the packet in the buffered packet list */ - *plast_pktl = pktl; - pktl->pkt= *pkt; - return &pktl->pkt; -} - int av_read_packet(AVFormatContext *s, AVPacket *pkt) { int ret, i; @@ -2547,6 +2555,8 @@ void avformat_free_context(AVFormatContext *s) av_parser_close(st->parser); av_free_packet(&st->cur_pkt); } + if (st->attached_pic.data) + av_free_packet(&st->attached_pic); av_dict_free(&st->metadata); av_free(st->index_entries); av_free(st->codec->extradata); From 079ea6ca5f8f108ec328d3c2c1792e676fc30b9c Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 25 Feb 2012 09:53:35 +0100 Subject: [PATCH 22/58] lavf: export id3v2 attached pictures as streams. --- libavformat/id3v2.c | 34 ++++++++++++++++++++++++++++++++++ libavformat/id3v2.h | 6 ++++++ libavformat/utils.c | 9 ++++++++- 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c index 853a04c78e..4170c853a6 100644 --- a/libavformat/id3v2.c +++ b/libavformat/id3v2.c @@ -702,3 +702,37 @@ void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta) current = next; } } + +int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta) +{ + ID3v2ExtraMeta *cur; + + for (cur = *extra_meta; cur; cur = cur->next) { + ID3v2ExtraMetaAPIC *apic; + AVStream *st; + + if (strcmp(cur->tag, "APIC")) + continue; + apic = cur->data; + + if (!(st = avformat_new_stream(s, NULL))) + return AVERROR(ENOMEM); + + st->disposition |= AV_DISPOSITION_ATTACHED_PIC; + st->codec->codec_type = AVMEDIA_TYPE_VIDEO; + st->codec->codec_id = apic->id; + av_dict_set(&st->metadata, "title", apic->description, 0); + av_dict_set(&st->metadata, "comment", apic->type, 0); + + av_init_packet(&st->attached_pic); + st->attached_pic.data = apic->data; + st->attached_pic.size = apic->len; + st->attached_pic.destruct = av_destruct_packet; + st->attached_pic.stream_index = st->index; + + apic->data = NULL; + apic->len = 0; + } + + return 0; +} diff --git a/libavformat/id3v2.h b/libavformat/id3v2.h index f358d02892..c3f08f5875 100644 --- a/libavformat/id3v2.h +++ b/libavformat/id3v2.h @@ -109,6 +109,12 @@ int ff_id3v2_write(struct AVFormatContext *s, int id3v2_version, const char *mag */ void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta); +/** + * Create a stream for each APIC (attached picture) extracted from the + * ID3v2 header. + */ +int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta); + extern const AVMetadataConv ff_id3v2_34_metadata_conv[]; extern const AVMetadataConv ff_id3v2_4_metadata_conv[]; diff --git a/libavformat/utils.c b/libavformat/utils.c index c8dd7f5868..e657362a38 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -520,6 +520,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma AVFormatContext *s = *ps; int i, ret = 0; AVDictionary *tmp = NULL; + ID3v2ExtraMeta *id3v2_extra_meta = NULL; if (!s && !(s = avformat_alloc_context())) return AVERROR(ENOMEM); @@ -562,12 +563,17 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma /* e.g. AVFMT_NOFILE formats will not have a AVIOContext */ if (s->pb) - ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC); + ff_id3v2_read_all(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); if (s->iformat->read_header) if ((ret = s->iformat->read_header(s)) < 0) goto fail; + if (id3v2_extra_meta && + (ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) + goto fail; + ff_id3v2_free_extra_meta(&id3v2_extra_meta); + /* queue attached pictures */ for (i = 0; i < s->nb_streams; i++) if (s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC) { @@ -589,6 +595,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma return 0; fail: + ff_id3v2_free_extra_meta(&id3v2_extra_meta); av_dict_free(&tmp); if (s->pb && !(s->flags & AVFMT_FLAG_CUSTOM_IO)) avio_close(s->pb); From 393fd0d89e6d0a1cf5bd39f309f6f10e0f1f8ac7 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 25 Feb 2012 09:53:59 +0100 Subject: [PATCH 23/58] id3v2: remove unused ff_id3v2_read(). Rename ff_id3v2_read_all to ff_id3v2_read(). --- libavformat/id3v2.c | 7 +------ libavformat/id3v2.h | 9 ++------- libavformat/omadec.c | 2 +- libavformat/utils.c | 2 +- 4 files changed, 5 insertions(+), 15 deletions(-) diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c index 4170c853a6..1f2c3d5437 100644 --- a/libavformat/id3v2.c +++ b/libavformat/id3v2.c @@ -653,7 +653,7 @@ seek: return; } -void ff_id3v2_read_all(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta) +void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta) { int len, ret; uint8_t buf[ID3v2_HEADER_SIZE]; @@ -684,11 +684,6 @@ void ff_id3v2_read_all(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **e merge_date(&s->metadata); } -void ff_id3v2_read(AVFormatContext *s, const char *magic) -{ - ff_id3v2_read_all(s, magic, NULL); -} - void ff_id3v2_free_extra_meta(ID3v2ExtraMeta **extra_meta) { ID3v2ExtraMeta *current = *extra_meta, *next; diff --git a/libavformat/id3v2.h b/libavformat/id3v2.h index c3f08f5875..5f3ec1b3ca 100644 --- a/libavformat/id3v2.h +++ b/libavformat/id3v2.h @@ -84,16 +84,11 @@ int ff_id3v2_match(const uint8_t *buf, const char *magic); int ff_id3v2_tag_len(const uint8_t *buf); /** - * Read an ID3v2 tag (text tags only) - */ -void ff_id3v2_read(AVFormatContext *s, const char *magic); - -/** - * Read an ID3v2 tag, including supported extra metadata (currently only GEOB) + * Read an ID3v2 tag, including supported extra metadata * @param extra_meta If not NULL, extra metadata is parsed into a list of * ID3v2ExtraMeta structs and *extra_meta points to the head of the list */ -void ff_id3v2_read_all(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta); +void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta); /** * Write an ID3v2 tag. diff --git a/libavformat/omadec.c b/libavformat/omadec.c index 7c54ffbc97..810e970c11 100644 --- a/libavformat/omadec.c +++ b/libavformat/omadec.c @@ -267,7 +267,7 @@ static int oma_read_header(AVFormatContext *s) ID3v2ExtraMeta *extra_meta = NULL; OMAContext *oc = s->priv_data; - ff_id3v2_read_all(s, ID3v2_EA3_MAGIC, &extra_meta); + ff_id3v2_read(s, ID3v2_EA3_MAGIC, &extra_meta); ret = avio_read(s->pb, buf, EA3_HEADER_SIZE); if (ret < EA3_HEADER_SIZE) return -1; diff --git a/libavformat/utils.c b/libavformat/utils.c index e657362a38..cf4392b581 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -563,7 +563,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputForma /* e.g. AVFMT_NOFILE formats will not have a AVIOContext */ if (s->pb) - ff_id3v2_read_all(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); + ff_id3v2_read(s, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); if (s->iformat->read_header) if ((ret = s->iformat->read_header(s)) < 0) From c19981774880919c7f9417014bdcb1fb63f69231 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 27 Feb 2012 21:48:37 +0100 Subject: [PATCH 24/58] id3v2enc: make id3v2_put_size take only an AVIOContext. It has no need of full AVFormatContext. --- libavformat/id3v2enc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libavformat/id3v2enc.c b/libavformat/id3v2enc.c index 36c73bfecb..3a4d229232 100644 --- a/libavformat/id3v2enc.c +++ b/libavformat/id3v2enc.c @@ -26,12 +26,12 @@ #include "avio.h" #include "id3v2.h" -static void id3v2_put_size(AVFormatContext *s, int size) +static void id3v2_put_size(AVIOContext *pb, int size) { - avio_w8(s->pb, size >> 21 & 0x7f); - avio_w8(s->pb, size >> 14 & 0x7f); - avio_w8(s->pb, size >> 7 & 0x7f); - avio_w8(s->pb, size & 0x7f); + avio_w8(pb, size >> 21 & 0x7f); + avio_w8(pb, size >> 14 & 0x7f); + avio_w8(pb, size >> 7 & 0x7f); + avio_w8(pb, size & 0x7f); } static int string_is_ascii(const uint8_t *str) @@ -74,7 +74,7 @@ static int id3v2_put_ttag(AVFormatContext *s, const char *str1, const char *str2 len = avio_close_dyn_buf(dyn_buf, &pb); avio_wb32(s->pb, tag); - id3v2_put_size(s, len); + id3v2_put_size(s->pb, len); avio_wb16(s->pb, 0); avio_write(s->pb, pb, len); @@ -140,7 +140,7 @@ int ff_id3v2_write(struct AVFormatContext *s, int id3v2_version, cur_pos = avio_tell(s->pb); avio_seek(s->pb, size_pos, SEEK_SET); - id3v2_put_size(s, totlen); + id3v2_put_size(s->pb, totlen); avio_seek(s->pb, cur_pos, SEEK_SET); return 0; } From 411225aabce57411d1544a7bbc6f6bee6d8ef638 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 27 Feb 2012 22:08:50 +0100 Subject: [PATCH 25/58] id3v2enc: split ff_id3v2_write(). This will allow writing the tag in several steps, needed for writing attached pictures. --- libavformat/id3v2.h | 26 +++++++++++++++-- libavformat/id3v2enc.c | 64 +++++++++++++++++++++++++++--------------- libavformat/mp3enc.c | 2 +- libavformat/omaenc.c | 2 +- 4 files changed, 68 insertions(+), 26 deletions(-) diff --git a/libavformat/id3v2.h b/libavformat/id3v2.h index 5f3ec1b3ca..f47abe9d25 100644 --- a/libavformat/id3v2.h +++ b/libavformat/id3v2.h @@ -46,6 +46,12 @@ enum ID3v2Encoding { ID3v2_ENCODING_UTF8 = 3, }; +typedef struct ID3v2EncContext { + int version; ///< ID3v2 minor version, either 3 or 4 + int64_t size_pos; ///< offset of the tag total size + int len; ///< size of the tag written so far +} ID3v2EncContext; + typedef struct ID3v2ExtraMeta { const char *tag; void *data; @@ -91,12 +97,28 @@ int ff_id3v2_tag_len(const uint8_t *buf); void ff_id3v2_read(AVFormatContext *s, const char *magic, ID3v2ExtraMeta **extra_meta); /** - * Write an ID3v2 tag. + * Initialize an ID3v2 tag. + */ +void ff_id3v2_start(ID3v2EncContext *id3, AVIOContext *pb, int id3v2_version, + const char *magic); + +/** + * Convert and write all global metadata from s into an ID3v2 tag. + */ +int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3); + +/** + * Finalize an opened ID3v2 tag. + */ +void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb); + +/** + * Write an ID3v2 tag containing all global metadata from s. * @param id3v2_version Subversion of ID3v2; supported values are 3 and 4 * @param magic magic bytes to identify the header * If in doubt, use ID3v2_DEFAULT_MAGIC. */ -int ff_id3v2_write(struct AVFormatContext *s, int id3v2_version, const char *magic); +int ff_id3v2_write_simple(struct AVFormatContext *s, int id3v2_version, const char *magic); /** * Free memory allocated parsing special (non-text) metadata. diff --git a/libavformat/id3v2enc.c b/libavformat/id3v2enc.c index 3a4d229232..8666818128 100644 --- a/libavformat/id3v2enc.c +++ b/libavformat/id3v2enc.c @@ -97,50 +97,70 @@ static int id3v2_check_write_tag(AVFormatContext *s, AVDictionaryEntry *t, const return -1; } -int ff_id3v2_write(struct AVFormatContext *s, int id3v2_version, - const char *magic) +void ff_id3v2_start(ID3v2EncContext *id3, AVIOContext *pb, int id3v2_version, + const char *magic) { - int64_t size_pos, cur_pos; - AVDictionaryEntry *t = NULL; + id3->version = id3v2_version; - int totlen = 0, enc = id3v2_version == 3 ? ID3v2_ENCODING_UTF16BOM : - ID3v2_ENCODING_UTF8; - - - avio_wb32(s->pb, MKBETAG(magic[0], magic[1], magic[2], id3v2_version)); - avio_w8(s->pb, 0); - avio_w8(s->pb, 0); /* flags */ + avio_wb32(pb, MKBETAG(magic[0], magic[1], magic[2], id3v2_version)); + avio_w8(pb, 0); + avio_w8(pb, 0); /* flags */ /* reserve space for size */ - size_pos = avio_tell(s->pb); - avio_wb32(s->pb, 0); + id3->size_pos = avio_tell(pb); + avio_wb32(pb, 0); +} + +int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3) +{ + AVDictionaryEntry *t = NULL; + int enc = id3->version == 3 ? ID3v2_ENCODING_UTF16BOM : + ID3v2_ENCODING_UTF8; ff_metadata_conv(&s->metadata, ff_id3v2_34_metadata_conv, NULL); - if (id3v2_version == 4) + if (id3->version == 4) ff_metadata_conv(&s->metadata, ff_id3v2_4_metadata_conv, NULL); while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) { int ret; if ((ret = id3v2_check_write_tag(s, t, ff_id3v2_tags, enc)) > 0) { - totlen += ret; + id3->len += ret; continue; } - if ((ret = id3v2_check_write_tag(s, t, id3v2_version == 3 ? + if ((ret = id3v2_check_write_tag(s, t, id3->version == 3 ? ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) { - totlen += ret; + id3->len += ret; continue; } /* unknown tag, write as TXXX frame */ if ((ret = id3v2_put_ttag(s, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0) return ret; - totlen += ret; + id3->len += ret; } - cur_pos = avio_tell(s->pb); - avio_seek(s->pb, size_pos, SEEK_SET); - id3v2_put_size(s->pb, totlen); - avio_seek(s->pb, cur_pos, SEEK_SET); + return 0; +} + +void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb) +{ + int64_t cur_pos = avio_tell(pb); + avio_seek(pb, id3->size_pos, SEEK_SET); + id3v2_put_size(pb, id3->len); + avio_seek(pb, cur_pos, SEEK_SET); +} + +int ff_id3v2_write_simple(struct AVFormatContext *s, int id3v2_version, + const char *magic) +{ + ID3v2EncContext id3 = { 0 }; + int ret; + + ff_id3v2_start(&id3, s->pb, id3v2_version, magic); + if ((ret = ff_id3v2_write_metadata(s, &id3)) < 0) + return ret; + ff_id3v2_finish(&id3, s->pb); + return 0; } diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c index ce547ead38..ab20c299fe 100644 --- a/libavformat/mp3enc.c +++ b/libavformat/mp3enc.c @@ -187,7 +187,7 @@ static int mp3_write_header(struct AVFormatContext *s) MP3Context *mp3 = s->priv_data; int ret; - ret = ff_id3v2_write(s, mp3->id3v2_version, ID3v2_DEFAULT_MAGIC); + ret = ff_id3v2_write_simple(s, mp3->id3v2_version, ID3v2_DEFAULT_MAGIC); if (ret < 0) return ret; diff --git a/libavformat/omaenc.c b/libavformat/omaenc.c index e932b4bbc1..c3ee0e8de1 100644 --- a/libavformat/omaenc.c +++ b/libavformat/omaenc.c @@ -49,7 +49,7 @@ static av_cold int oma_write_header(AVFormatContext *s) } /* Metadata; OpenMG does not support ID3v2.4 */ - ff_id3v2_write(s, 3, ID3v2_EA3_MAGIC); + ff_id3v2_write_simple(s, 3, ID3v2_EA3_MAGIC); ffio_wfourcc(s->pb, "EA3\0"); avio_w8(s->pb, EA3_HEADER_SIZE >> 7); From 24fe1a3b1662652df076804fdbfd8b2fd089497e Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 28 Feb 2012 11:45:07 +0100 Subject: [PATCH 26/58] id3v2enc: fix writing frame sizes for ID3v2.3 Frame sizes in ID3v2.3 are not synchsafe, they are simply 32be numbers. In practice this bug is not noticeable unless the frame size takes more than 7 bits (which is almost never for text frames). --- libavformat/id3v2enc.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/libavformat/id3v2enc.c b/libavformat/id3v2enc.c index 8666818128..58f77970ef 100644 --- a/libavformat/id3v2enc.c +++ b/libavformat/id3v2enc.c @@ -45,7 +45,7 @@ static int string_is_ascii(const uint8_t *str) * according to encoding (only UTF-8 or UTF-16+BOM supported). * @return number of bytes written or a negative error code. */ -static int id3v2_put_ttag(AVFormatContext *s, const char *str1, const char *str2, +static int id3v2_put_ttag(ID3v2EncContext *id3, AVIOContext *avioc, const char *str1, const char *str2, uint32_t tag, enum ID3v2Encoding enc) { int len; @@ -73,17 +73,21 @@ static int id3v2_put_ttag(AVFormatContext *s, const char *str1, const char *str2 put(dyn_buf, str2); len = avio_close_dyn_buf(dyn_buf, &pb); - avio_wb32(s->pb, tag); - id3v2_put_size(s->pb, len); - avio_wb16(s->pb, 0); - avio_write(s->pb, pb, len); + avio_wb32(avioc, tag); + /* ID3v2.3 frame size is not synchsafe */ + if (id3->version == 3) + avio_wb32(avioc, len); + else + id3v2_put_size(avioc, len); + avio_wb16(avioc, 0); + avio_write(avioc, pb, len); av_freep(&pb); return len + ID3v2_HEADER_SIZE; } -static int id3v2_check_write_tag(AVFormatContext *s, AVDictionaryEntry *t, const char table[][4], - enum ID3v2Encoding enc) +static int id3v2_check_write_tag(ID3v2EncContext *id3, AVIOContext *pb, AVDictionaryEntry *t, + const char table[][4], enum ID3v2Encoding enc) { uint32_t tag; int i; @@ -93,7 +97,7 @@ static int id3v2_check_write_tag(AVFormatContext *s, AVDictionaryEntry *t, const tag = AV_RB32(t->key); for (i = 0; *table[i]; i++) if (tag == AV_RB32(table[i])) - return id3v2_put_ttag(s, t->value, NULL, tag, enc); + return id3v2_put_ttag(id3, pb, t->value, NULL, tag, enc); return -1; } @@ -124,18 +128,18 @@ int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3) while ((t = av_dict_get(s->metadata, "", t, AV_DICT_IGNORE_SUFFIX))) { int ret; - if ((ret = id3v2_check_write_tag(s, t, ff_id3v2_tags, enc)) > 0) { + if ((ret = id3v2_check_write_tag(id3, s->pb, t, ff_id3v2_tags, enc)) > 0) { id3->len += ret; continue; } - if ((ret = id3v2_check_write_tag(s, t, id3->version == 3 ? + if ((ret = id3v2_check_write_tag(id3, s->pb, t, id3->version == 3 ? ff_id3v2_3_tags : ff_id3v2_4_tags, enc)) > 0) { id3->len += ret; continue; } /* unknown tag, write as TXXX frame */ - if ((ret = id3v2_put_ttag(s, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0) + if ((ret = id3v2_put_ttag(id3, s->pb, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0) return ret; id3->len += ret; } From ba445f5557bf16aeb807bb6c83d7de264f98f375 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 27 Feb 2012 22:51:28 +0100 Subject: [PATCH 27/58] id3v2enc: add a function for writing attached pictures. Unused so far. --- libavformat/id3v2.h | 5 +++ libavformat/id3v2enc.c | 91 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 87 insertions(+), 9 deletions(-) diff --git a/libavformat/id3v2.h b/libavformat/id3v2.h index f47abe9d25..88dcbdb812 100644 --- a/libavformat/id3v2.h +++ b/libavformat/id3v2.h @@ -107,6 +107,11 @@ void ff_id3v2_start(ID3v2EncContext *id3, AVIOContext *pb, int id3v2_version, */ int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3); +/** + * Write an attached picture from pkt into an ID3v2 tag. + */ +int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt); + /** * Finalize an opened ID3v2 tag. */ diff --git a/libavformat/id3v2enc.c b/libavformat/id3v2enc.c index 58f77970ef..624333609b 100644 --- a/libavformat/id3v2enc.c +++ b/libavformat/id3v2enc.c @@ -19,6 +19,7 @@ */ #include +#include #include "libavutil/dict.h" #include "libavutil/intreadwrite.h" @@ -40,6 +41,20 @@ static int string_is_ascii(const uint8_t *str) return !*str; } +static void id3v2_encode_string(AVIOContext *pb, const uint8_t *str, + enum ID3v2Encoding enc) +{ + int (*put)(AVIOContext*, const char*); + + if (enc == ID3v2_ENCODING_UTF16BOM) { + avio_wl16(pb, 0xFEFF); /* BOM */ + put = avio_put_str16le; + } else + put = avio_put_str; + + put(pb, str); +} + /** * Write a text frame with one (normal frames) or two (TXXX frames) strings * according to encoding (only UTF-8 or UTF-16+BOM supported). @@ -50,7 +65,6 @@ static int id3v2_put_ttag(ID3v2EncContext *id3, AVIOContext *avioc, const char * { int len; uint8_t *pb; - int (*put)(AVIOContext*, const char*); AVIOContext *dyn_buf; if (avio_open_dyn_buf(&dyn_buf) < 0) return AVERROR(ENOMEM); @@ -62,15 +76,9 @@ static int id3v2_put_ttag(ID3v2EncContext *id3, AVIOContext *avioc, const char * enc = ID3v2_ENCODING_ISO8859; avio_w8(dyn_buf, enc); - if (enc == ID3v2_ENCODING_UTF16BOM) { - avio_wl16(dyn_buf, 0xFEFF); /* BOM */ - put = avio_put_str16le; - } else - put = avio_put_str; - - put(dyn_buf, str1); + id3v2_encode_string(dyn_buf, str1, enc); if (str2) - put(dyn_buf, str2); + id3v2_encode_string(dyn_buf, str2, enc); len = avio_close_dyn_buf(dyn_buf, &pb); avio_wb32(avioc, tag); @@ -147,6 +155,71 @@ int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3) return 0; } +int ff_id3v2_write_apic(AVFormatContext *s, ID3v2EncContext *id3, AVPacket *pkt) +{ + AVStream *st = s->streams[pkt->stream_index]; + AVDictionaryEntry *e; + + AVIOContext *dyn_buf; + uint8_t *buf; + const CodecMime *mime = ff_id3v2_mime_tags; + const char *mimetype = NULL, *desc = ""; + int enc = id3->version == 3 ? ID3v2_ENCODING_UTF16BOM : + ID3v2_ENCODING_UTF8; + int i, len, type = 0; + + /* get the mimetype*/ + while (mime->id != CODEC_ID_NONE) { + if (mime->id == st->codec->codec_id) { + mimetype = mime->str; + break; + } + mime++; + } + if (!mimetype) { + av_log(s, AV_LOG_ERROR, "No mimetype is known for stream %d, cannot " + "write an attached picture.\n", st->index); + return AVERROR(EINVAL); + } + + /* get the picture type */ + e = av_dict_get(st->metadata, "comment", NULL, 0); + for (i = 0; e && i < FF_ARRAY_ELEMS(ff_id3v2_picture_types); i++) { + if (strstr(ff_id3v2_picture_types[i], e->value) == ff_id3v2_picture_types[i]) { + type = i; + break; + } + } + + /* get the description */ + if ((e = av_dict_get(st->metadata, "title", NULL, 0))) + desc = e->value; + + /* start writing */ + if (avio_open_dyn_buf(&dyn_buf) < 0) + return AVERROR(ENOMEM); + + avio_w8(dyn_buf, enc); + avio_put_str(dyn_buf, mimetype); + avio_w8(dyn_buf, type); + id3v2_encode_string(dyn_buf, desc, enc); + avio_write(dyn_buf, pkt->data, pkt->size); + len = avio_close_dyn_buf(dyn_buf, &buf); + + avio_wb32(s->pb, MKBETAG('A', 'P', 'I', 'C')); + if (id3->version == 3) + avio_wb32(s->pb, len); + else + id3v2_put_size(s->pb, len); + avio_wb16(s->pb, 0); + avio_write(s->pb, buf, len); + av_freep(&buf); + + id3->len += len + ID3v2_HEADER_SIZE; + + return 0; +} + void ff_id3v2_finish(ID3v2EncContext *id3, AVIOContext *pb) { int64_t cur_pos = avio_tell(pb); From c68148b1ea8130454bc98b897051d4677e1dfd5d Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 29 Feb 2012 09:11:26 +0100 Subject: [PATCH 28/58] mp3enc: move mp3_write_xing() further up in the file. It will be need by new functions called from mp3_write_trailer(). --- libavformat/mp3enc.c | 94 +++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c index ab20c299fe..90d7b4df6a 100644 --- a/libavformat/mp3enc.c +++ b/libavformat/mp3enc.c @@ -80,6 +80,55 @@ typedef struct MP3Context { int64_t nb_frames_offset; } MP3Context; +/* insert a dummy frame containing number of frames */ +static void mp3_write_xing(AVFormatContext *s) +{ + MP3Context *mp3 = s->priv_data; + AVCodecContext *codec = s->streams[0]->codec; + int bitrate_idx = 1; // 32 kbps + int64_t xing_offset = (codec->channels == 2) ? 32 : 17; + int32_t header; + MPADecodeHeader mpah; + int srate_idx, i, channels; + + if (!s->pb->seekable) + return; + + for (i = 0; i < FF_ARRAY_ELEMS(avpriv_mpa_freq_tab); i++) + if (avpriv_mpa_freq_tab[i] == codec->sample_rate) { + srate_idx = i; + break; + } + if (i == FF_ARRAY_ELEMS(avpriv_mpa_freq_tab)) { + av_log(s, AV_LOG_ERROR, "Unsupported sample rate.\n"); + return; + } + + switch (codec->channels) { + case 1: channels = MPA_MONO; break; + case 2: channels = MPA_STEREO; break; + default: av_log(s, AV_LOG_ERROR, "Unsupported number of channels.\n"); return; + } + + /* dummy MPEG audio header */ + header = 0xff << 24; // sync + header |= (0x7 << 5 | 0x3 << 3 | 0x1 << 1 | 0x1) << 16; // sync/mpeg-1/layer 3/no crc*/ + header |= (bitrate_idx << 4 | srate_idx << 2) << 8; + header |= channels << 6; + avio_wb32(s->pb, header); + + avpriv_mpegaudio_decode_header(&mpah, header); + + ffio_fill(s->pb, 0, xing_offset); + ffio_wfourcc(s->pb, "Xing"); + avio_wb32(s->pb, 0x1); // only number of frames + mp3->nb_frames_offset = avio_tell(s->pb); + avio_wb32(s->pb, 0); + + mpah.frame_size -= 4 + xing_offset + 4 + 4 + 4; + ffio_fill(s->pb, 0, mpah.frame_size); +} + static int mp3_write_trailer(struct AVFormatContext *s) { uint8_t buf[ID3v1_TAG_SIZE]; @@ -132,51 +181,6 @@ static const AVClass mp3_muxer_class = { .version = LIBAVUTIL_VERSION_INT, }; -/* insert a dummy frame containing number of frames */ -static void mp3_write_xing(AVFormatContext *s) -{ - AVCodecContext *codec = s->streams[0]->codec; - MP3Context *mp3 = s->priv_data; - int bitrate_idx = 1; // 32 kbps - int64_t xing_offset = (codec->channels == 2) ? 32 : 17; - int32_t header; - MPADecodeHeader mpah; - int srate_idx, i, channels; - - for (i = 0; i < FF_ARRAY_ELEMS(avpriv_mpa_freq_tab); i++) - if (avpriv_mpa_freq_tab[i] == codec->sample_rate) { - srate_idx = i; - break; - } - if (i == FF_ARRAY_ELEMS(avpriv_mpa_freq_tab)) { - av_log(s, AV_LOG_ERROR, "Unsupported sample rate.\n"); - return; - } - - switch (codec->channels) { - case 1: channels = MPA_MONO; break; - case 2: channels = MPA_STEREO; break; - default: av_log(s, AV_LOG_ERROR, "Unsupported number of channels.\n"); return; - } - - /* dummy MPEG audio header */ - header = 0xff << 24; // sync - header |= (0x7 << 5 | 0x3 << 3 | 0x1 << 1 | 0x1) << 16; // sync/mpeg-1/layer 3/no crc*/ - header |= (bitrate_idx << 4 | srate_idx << 2) << 8; - header |= channels << 6; - avio_wb32(s->pb, header); - - avpriv_mpegaudio_decode_header(&mpah, header); - - ffio_fill(s->pb, 0, xing_offset); - ffio_wfourcc(s->pb, "Xing"); - avio_wb32(s->pb, 0x1); // only number of frames - mp3->nb_frames_offset = avio_tell(s->pb); - avio_wb32(s->pb, 0); - - mpah.frame_size -= 4 + xing_offset + 4 + 4 + 4; - ffio_fill(s->pb, 0, mpah.frame_size); -} /** * Write an ID3v2 header at beginning of stream From 2dfea1205870c298461f08fc323c652be41888f8 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 28 Feb 2012 09:52:05 +0100 Subject: [PATCH 29/58] mp3enc: write attached pictures (APIC). --- libavformat/mp3enc.c | 120 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 113 insertions(+), 7 deletions(-) diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c index 90d7b4df6a..fb46ac94ca 100644 --- a/libavformat/mp3enc.c +++ b/libavformat/mp3enc.c @@ -31,6 +31,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/opt.h" #include "libavutil/dict.h" +#include "libavutil/avassert.h" static int id3v1_set_string(AVFormatContext *s, const char *key, uint8_t *buf, int buf_size) @@ -75,16 +76,25 @@ static int id3v1_create_tag(AVFormatContext *s, uint8_t *buf) typedef struct MP3Context { const AVClass *class; + ID3v2EncContext id3; int id3v2_version; int write_id3v1; int64_t nb_frames_offset; + + /* index of the audio stream */ + int audio_stream_idx; + /* number of attached pictures we still need to write */ + int pics_to_write; + + /* audio packets are queued here until we get all the attached pictures */ + AVPacketList *queue, *queue_end; } MP3Context; /* insert a dummy frame containing number of frames */ static void mp3_write_xing(AVFormatContext *s) { MP3Context *mp3 = s->priv_data; - AVCodecContext *codec = s->streams[0]->codec; + AVCodecContext *codec = s->streams[mp3->audio_stream_idx]->codec; int bitrate_idx = 1; // 32 kbps int64_t xing_offset = (codec->channels == 2) ? 32 : 17; int32_t header; @@ -129,11 +139,37 @@ static void mp3_write_xing(AVFormatContext *s) ffio_fill(s->pb, 0, mpah.frame_size); } +static int mp3_queue_flush(AVFormatContext *s) +{ + MP3Context *mp3 = s->priv_data; + AVPacketList *pktl; + int ret = 0, write = 1; + + ff_id3v2_finish(&mp3->id3, s->pb); + mp3_write_xing(s); + + while ((pktl = mp3->queue)) { + if (write && (ret = ff_raw_write_packet(s, &pktl->pkt)) < 0) + write = 0; + av_free_packet(&pktl->pkt); + mp3->queue = pktl->next; + av_freep(&pktl); + } + mp3->queue_end = NULL; + return ret; +} + static int mp3_write_trailer(struct AVFormatContext *s) { uint8_t buf[ID3v1_TAG_SIZE]; MP3Context *mp3 = s->priv_data; + if (mp3 && mp3->pics_to_write) { + av_log(s, AV_LOG_WARNING, "No packets were sent for some of the " + "attached pictures.\n"); + mp3_queue_flush(s); + } + /* write the id3v1 tag */ if (mp3 && mp3->write_id3v1 && id3v1_create_tag(s, buf) > 0) { avio_write(s->pb, buf, ID3v1_TAG_SIZE); @@ -142,7 +178,7 @@ static int mp3_write_trailer(struct AVFormatContext *s) /* write number of frames */ if (mp3 && mp3->nb_frames_offset) { avio_seek(s->pb, mp3->nb_frames_offset, SEEK_SET); - avio_wb32(s->pb, s->streams[0]->nb_frames); + avio_wb32(s->pb, s->streams[mp3->audio_stream_idx]->nb_frames); avio_seek(s->pb, 0, SEEK_END); } @@ -181,6 +217,50 @@ static const AVClass mp3_muxer_class = { .version = LIBAVUTIL_VERSION_INT, }; +static int mp3_write_packet(AVFormatContext *s, AVPacket *pkt) +{ + MP3Context *mp3 = s->priv_data; + + if (pkt->stream_index == mp3->audio_stream_idx) { + if (mp3->pics_to_write) { + /* buffer audio packets until we get all the pictures */ + AVPacketList *pktl = av_mallocz(sizeof(*pktl)); + if (!pktl) + return AVERROR(ENOMEM); + + pktl->pkt = *pkt; + pkt->destruct = NULL; + + if (mp3->queue_end) + mp3->queue_end->next = pktl; + else + mp3->queue = pktl; + mp3->queue_end = pktl; + } else + return ff_raw_write_packet(s, pkt); + } else { + int ret; + + /* warn only once for each stream */ + if (s->streams[pkt->stream_index]->nb_frames == 1) { + av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d," + " ignoring.\n", pkt->stream_index); + } + if (!mp3->pics_to_write || s->streams[pkt->stream_index]->nb_frames >= 1) + return 0; + + if ((ret = ff_id3v2_write_apic(s, &mp3->id3, pkt)) < 0) + return ret; + mp3->pics_to_write--; + + /* flush the buffered audio packets */ + if (!mp3->pics_to_write && + (ret = mp3_queue_flush(s)) < 0) + return ret; + } + + return 0; +} /** * Write an ID3v2 header at beginning of stream @@ -189,14 +269,40 @@ static const AVClass mp3_muxer_class = { static int mp3_write_header(struct AVFormatContext *s) { MP3Context *mp3 = s->priv_data; - int ret; + int ret, i; - ret = ff_id3v2_write_simple(s, mp3->id3v2_version, ID3v2_DEFAULT_MAGIC); + /* check the streams -- we want exactly one audio and arbitrary number of + * video (attached pictures) */ + mp3->audio_stream_idx = -1; + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { + if (mp3->audio_stream_idx >= 0 || st->codec->codec_id != CODEC_ID_MP3) { + av_log(s, AV_LOG_ERROR, "Invalid audio stream. Exactly one MP3 " + "audio stream is required.\n"); + return AVERROR(EINVAL); + } + mp3->audio_stream_idx = i; + } else if (st->codec->codec_type != AVMEDIA_TYPE_VIDEO) { + av_log(s, AV_LOG_ERROR, "Only audio streams and pictures are allowed in MP3.\n"); + return AVERROR(EINVAL); + } + } + if (mp3->audio_stream_idx < 0) { + av_log(s, AV_LOG_ERROR, "No audio stream present.\n"); + return AVERROR(EINVAL); + } + mp3->pics_to_write = s->nb_streams - 1; + + ff_id3v2_start(&mp3->id3, s->pb, mp3->id3v2_version, ID3v2_DEFAULT_MAGIC); + ret = ff_id3v2_write_metadata(s, &mp3->id3); if (ret < 0) return ret; - if (s->pb->seekable) + if (!mp3->pics_to_write) { + ff_id3v2_finish(&mp3->id3, s->pb); mp3_write_xing(s); + } return 0; } @@ -208,9 +314,9 @@ AVOutputFormat ff_mp3_muxer = { .extensions = "mp3", .priv_data_size = sizeof(MP3Context), .audio_codec = CODEC_ID_MP3, - .video_codec = CODEC_ID_NONE, + .video_codec = CODEC_ID_PNG, .write_header = mp3_write_header, - .write_packet = ff_raw_write_packet, + .write_packet = mp3_write_packet, .write_trailer = mp3_write_trailer, .flags = AVFMT_NOTIMESTAMPS, .priv_class = &mp3_muxer_class, From 322537478b63c6bc01e640643550ff539864d790 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 28 Feb 2012 12:07:53 +0100 Subject: [PATCH 30/58] Add a minor bump, changelog/APIchanges entry and some documentation for APIC support. --- Changelog | 1 + doc/APIchanges | 4 ++++ doc/muxers.texi | 34 ++++++++++++++++++++++++++++++++++ libavformat/version.h | 2 +- 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/Changelog b/Changelog index 65accca721..9dc2ae951c 100644 --- a/Changelog +++ b/Changelog @@ -10,6 +10,7 @@ version : - Apple ProRes encoder - Sun Rasterfile Encoder - remove libpostproc +- ID3v2 attached pictures reading and writing version 0.8: diff --git a/doc/APIchanges b/doc/APIchanges index 8b12de0bad..de57b2e69c 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -12,6 +12,10 @@ libavutil: 2011-04-18 API changes, most recent first: +2012-xx-xx - xxxxxxx - lavf 54.2.0 - avformat.h + Add AVStream.attached_pic and AV_DISPOSITION_ATTACHED_PIC, + used for dealing with attached pictures/cover art. + 2012-02-25 - c9bca80 - lavu 51.24.0 - error.h Add AVERROR_UNKNOWN diff --git a/doc/muxers.texi b/doc/muxers.texi index 4878e7630e..82ea99a17e 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -361,5 +361,39 @@ Wrap around segment index once it reaches @var{limit}. avconv -i in.mkv -c copy -map 0 -f segment -list out.list out%03d.nut @end example +@section mp3 + +The MP3 muxer writes a raw MP3 stream with an ID3v2 header at the beginning and +optionally an ID3v1 tag at the end. ID3v2.3 and ID3v2.4 are supported, the +@code{id3v2_version} option controls which one is used. The legacy ID3v1 tag is +not written by default, but may be enabled with the @code{write_id3v1} option. + +For seekable output the muxer also writes a Xing frame at the beginning, which +contains the number of frames in the file. It is useful for computing duration +of VBR files. + +The muxer supports writing ID3v2 attached pictures (APIC frames). The pictures +are supplied to the muxer in form of a video stream with a single packet. There +can be any number of those streams, each will correspond to a single APIC frame. +The stream metadata tags @var{title} and @var{comment} map to APIC +@var{description} and @var{picture type} respectively. See +@url{http://id3.org/id3v2.4.0-frames} for allowed picture types. + +Note that the APIC frames must be written at the beginning, so the muxer will +buffer the audio frames until it gets all the pictures. It is therefore advised +to provide the pictures as soon as possible to avoid excessive buffering. + +Examples: + +Write an mp3 with an ID3v2.3 header and an ID3v1 footer: +@example +avconv -i INPUT -id3v2_version 3 -write_id3v1 1 out.mp3 +@end example + +Attach a picture to an mp3: +@example +avconv -i input.mp3 -i cover.png -c copy -metadata:s:v title="Album cover" +-metadata:s:v comment="Cover (Front)" out.mp3 +@end example @c man end MUXERS diff --git a/libavformat/version.h b/libavformat/version.h index b944589e2f..bcc8c4dca5 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -30,7 +30,7 @@ #include "libavutil/avutil.h" #define LIBAVFORMAT_VERSION_MAJOR 54 -#define LIBAVFORMAT_VERSION_MINOR 1 +#define LIBAVFORMAT_VERSION_MINOR 2 #define LIBAVFORMAT_VERSION_MICRO 0 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ From 07ec1f21404e2b97d18f1b1b9324ca0ec5ea81e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Wed, 29 Feb 2012 14:50:06 +0200 Subject: [PATCH 31/58] rtpenc: Fix setting the max packet size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes cases where the user had specified one desired MTU via an option, and the protocol indicates another one. Signed-off-by: Martin Storsjö --- libavformat/rtpenc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.c index e4ef0fc92b..cb0e241329 100644 --- a/libavformat/rtpenc.c +++ b/libavformat/rtpenc.c @@ -112,7 +112,7 @@ static int rtp_write_header(AVFormatContext *s1) if (s->max_packet_size) { if (s1->pb->max_packet_size) - s->max_packet_size = FFMIN(s->max_payload_size, + s->max_packet_size = FFMIN(s->max_packet_size, s1->pb->max_packet_size); } else s->max_packet_size = s1->pb->max_packet_size; From 85b221e4d3e7f42cfcf4a491b357b137f731e9d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Wed, 29 Feb 2012 17:35:00 +0200 Subject: [PATCH 32/58] dpxenc: Don't include the libavcodec ident if bitexact mode is enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids breaking fate every time the lavc version is bumped. Signed-off-by: Martin Storsjö --- libavcodec/dpxenc.c | 3 ++- tests/ref/lavf/dpx | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libavcodec/dpxenc.c b/libavcodec/dpxenc.c index c731bb44c5..89548ba0c3 100644 --- a/libavcodec/dpxenc.c +++ b/libavcodec/dpxenc.c @@ -126,7 +126,8 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, memcpy (buf + 8, "V1.0", 4); write32(buf + 20, 1); /* new image */ write32(buf + 24, HEADER_SIZE); - memcpy (buf + 160, LIBAVCODEC_IDENT, FFMIN(sizeof(LIBAVCODEC_IDENT), 100)); + if (!(avctx->flags & CODEC_FLAG_BITEXACT)) + memcpy (buf + 160, LIBAVCODEC_IDENT, FFMIN(sizeof(LIBAVCODEC_IDENT), 100)); write32(buf + 660, 0xFFFFFFFF); /* unencrypted */ /* Image information header */ diff --git a/tests/ref/lavf/dpx b/tests/ref/lavf/dpx index 61c462a60e..a852ae058e 100644 --- a/tests/ref/lavf/dpx +++ b/tests/ref/lavf/dpx @@ -1,3 +1,3 @@ -5bb43eae2d80da95d26f7fe4669d6166 *./tests/data/images/dpx/02.dpx +808ea110635774252439722a48329d61 *./tests/data/images/dpx/02.dpx ./tests/data/images/dpx/%02d.dpx CRC=0x6da01946 305792 ./tests/data/images/dpx/02.dpx From 791de61bbb0d2bceb1037597b310e2a4a94494fd Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Tue, 28 Feb 2012 18:21:31 -0800 Subject: [PATCH 33/58] swscale: fix another integer overflow. Found-by: Mateusz "j00ru" Jurczyk and Gynvael Coldwind CC: libav-stable@libav.org --- libswscale/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libswscale/utils.c b/libswscale/utils.c index 3b488ca44f..7c89a70953 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -1014,7 +1014,7 @@ int sws_init_context(SwsContext *c, SwsFilter *srcFilter, SwsFilter *dstFilter) c->vLumBufSize= c->vLumFilterSize; c->vChrBufSize= c->vChrFilterSize; for (i=0; ichrDstH / dstH; + int chrI = (int64_t) i * c->chrDstH / dstH; int nextSlice= FFMAX(c->vLumFilterPos[i ] + c->vLumFilterSize - 1, ((c->vChrFilterPos[chrI] + c->vChrFilterSize - 1)<chrSrcVSubSample)); From e54ae60e46f737b8e9a96548971091f7ab6b8f7c Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Tue, 28 Feb 2012 19:00:39 -0800 Subject: [PATCH 34/58] qtrle: return error on decode_init() failure. Found-by: Mateusz "j00ru" Jurczyk and Gynvael Coldwind CC: libav-stable@libav.org --- libavcodec/qtrle.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavcodec/qtrle.c b/libavcodec/qtrle.c index e96e2788c9..613dcaea49 100644 --- a/libavcodec/qtrle.c +++ b/libavcodec/qtrle.c @@ -407,7 +407,7 @@ static av_cold int qtrle_decode_init(AVCodecContext *avctx) default: av_log (avctx, AV_LOG_ERROR, "Unsupported colorspace: %d bits/sample?\n", avctx->bits_per_coded_sample); - break; + return AVERROR_INVALIDDATA; } s->frame.data[0] = NULL; From 78e9852a2e3b198ecd69ffa0deab3fa22a8e5378 Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Tue, 28 Feb 2012 17:04:33 -0800 Subject: [PATCH 35/58] rpza: error out on buffer overreads. Found-by: Mateusz "j00ru" Jurczyk and Gynvael Coldwind CC: libav-stable@libav.org --- libavcodec/rpza.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libavcodec/rpza.c b/libavcodec/rpza.c index 7350ef2c4a..59c3a7b3a7 100644 --- a/libavcodec/rpza.c +++ b/libavcodec/rpza.c @@ -183,6 +183,8 @@ static void rpza_decode_stream(RpzaContext *s) color4[1] |= ((11 * ta + 21 * tb) >> 5); color4[2] |= ((21 * ta + 11 * tb) >> 5); + if (s->size - stream_ptr < n_blocks * 4) + return; while (n_blocks--) { block_ptr = row_ptr + pixel_ptr; for (pixel_y = 0; pixel_y < 4; pixel_y++) { @@ -200,6 +202,8 @@ static void rpza_decode_stream(RpzaContext *s) /* Fill block with 16 colors */ case 0x00: + if (s->size - stream_ptr < 16) + return; block_ptr = row_ptr + pixel_ptr; for (pixel_y = 0; pixel_y < 4; pixel_y++) { for (pixel_x = 0; pixel_x < 4; pixel_x++){ From 6aeea1dfb2f21de959701ee7dfaab59b4634e570 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Wed, 22 Feb 2012 21:26:09 -0500 Subject: [PATCH 36/58] ac3enc: choose the closest bit rate to the one requested instead of failing --- libavcodec/ac3enc.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/libavcodec/ac3enc.c b/libavcodec/ac3enc.c index c577c87dda..669be23a05 100644 --- a/libavcodec/ac3enc.c +++ b/libavcodec/ac3enc.c @@ -2189,15 +2189,20 @@ static av_cold int validate_options(AC3EncodeContext *s) wpf--; s->frame_size_min = 2 * wpf; } else { + int best_br = 0, best_code = 0, best_diff = INT_MAX; for (i = 0; i < 19; i++) { - if ((ff_ac3_bitrate_tab[i] >> s->bit_alloc.sr_shift)*1000 == avctx->bit_rate) + int br = (ff_ac3_bitrate_tab[i] >> s->bit_alloc.sr_shift) * 1000; + int diff = abs(br - avctx->bit_rate); + if (diff < best_diff) { + best_br = br; + best_code = i; + best_diff = diff; + } + if (!best_diff) break; } - if (i == 19) { - av_log(avctx, AV_LOG_ERROR, "invalid bit rate\n"); - return AVERROR(EINVAL); - } - s->frame_size_code = i << 1; + avctx->bit_rate = best_br; + s->frame_size_code = best_code << 1; s->frame_size_min = 2 * ff_ac3_frame_size_tab[s->frame_size_code][s->bit_alloc.sr_code]; s->num_blks_code = 0x3; s->num_blocks = 6; From 4e99501f629f6baebac0414d92d841b64ead30fe Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Wed, 22 Feb 2012 21:45:06 -0500 Subject: [PATCH 37/58] (e)ac3enc: select a default bit rate based on the channel layout --- libavcodec/ac3enc.c | 11 +++++++++++ libavcodec/ac3enc_fixed.c | 1 + libavcodec/ac3enc_float.c | 1 + libavcodec/ac3enc_opts_template.c | 6 ++++++ libavcodec/eac3enc.c | 1 + 5 files changed, 20 insertions(+) diff --git a/libavcodec/ac3enc.c b/libavcodec/ac3enc.c index 669be23a05..967c1bd8d3 100644 --- a/libavcodec/ac3enc.c +++ b/libavcodec/ac3enc.c @@ -2141,6 +2141,17 @@ static av_cold int validate_options(AC3EncodeContext *s) s->bit_alloc.sr_code = i % 3; s->bitstream_id = s->eac3 ? 16 : 8 + s->bit_alloc.sr_shift; + /* select a default bit rate if not set by the user */ + if (!avctx->bit_rate) { + switch (s->fbw_channels) { + case 1: avctx->bit_rate = 96000; break; + case 2: avctx->bit_rate = 192000; break; + case 3: avctx->bit_rate = 320000; break; + case 4: avctx->bit_rate = 384000; break; + case 5: avctx->bit_rate = 448000; break; + } + } + /* validate bit rate */ if (s->eac3) { int max_br, min_br, wpf, min_br_dist, min_br_code; diff --git a/libavcodec/ac3enc_fixed.c b/libavcodec/ac3enc_fixed.c index 202dfb8afd..98838f300b 100644 --- a/libavcodec/ac3enc_fixed.c +++ b/libavcodec/ac3enc_fixed.c @@ -151,4 +151,5 @@ AVCodec ff_ac3_fixed_encoder = { .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"), .priv_class = &ac3enc_class, .channel_layouts = ff_ac3_channel_layouts, + .defaults = ac3_defaults, }; diff --git a/libavcodec/ac3enc_float.c b/libavcodec/ac3enc_float.c index a4abd89d4d..64b360f131 100644 --- a/libavcodec/ac3enc_float.c +++ b/libavcodec/ac3enc_float.c @@ -149,5 +149,6 @@ AVCodec ff_ac3_encoder = { .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52A (AC-3)"), .priv_class = &ac3enc_class, .channel_layouts = ff_ac3_channel_layouts, + .defaults = ac3_defaults, }; #endif diff --git a/libavcodec/ac3enc_opts_template.c b/libavcodec/ac3enc_opts_template.c index a5f848e200..fa8984476e 100644 --- a/libavcodec/ac3enc_opts_template.c +++ b/libavcodec/ac3enc_opts_template.c @@ -20,6 +20,7 @@ */ #include "libavutil/opt.h" +#include "internal.h" #include "ac3.h" #if AC3ENC_TYPE == AC3ENC_TYPE_AC3_FIXED @@ -78,3 +79,8 @@ static const AVOption eac3_options[] = { {"auto", "Selected by the Encoder", 0, AV_OPT_TYPE_CONST, {.dbl = AC3ENC_OPT_AUTO }, INT_MIN, INT_MAX, AC3ENC_PARAM, "cpl_start_band"}, {NULL} }; + +static const AVCodecDefault ac3_defaults[] = { + { "b", "0" }, + { NULL } +}; diff --git a/libavcodec/eac3enc.c b/libavcodec/eac3enc.c index f3b4418896..459fb90ce6 100644 --- a/libavcodec/eac3enc.c +++ b/libavcodec/eac3enc.c @@ -258,5 +258,6 @@ AVCodec ff_eac3_encoder = { .long_name = NULL_IF_CONFIG_SMALL("ATSC A/52 E-AC-3"), .priv_class = &eac3enc_class, .channel_layouts = ff_ac3_channel_layouts, + .defaults = ac3_defaults, }; #endif From eb35ef2932e42d9b203a8bf9e5dba6f1c666ce1e Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Tue, 28 Feb 2012 18:51:04 -0500 Subject: [PATCH 38/58] libvorbis: cosmetics: renaming/pretty-printing/comments/unused code --- libavcodec/libvorbis.c | 222 +++++++++++++++++++++-------------------- 1 file changed, 114 insertions(+), 108 deletions(-) diff --git a/libavcodec/libvorbis.c b/libavcodec/libvorbis.c index 3226f86486..e519a1dbb8 100644 --- a/libavcodec/libvorbis.c +++ b/libavcodec/libvorbis.c @@ -20,7 +20,7 @@ /** * @file - * Ogg Vorbis codec support via libvorbisenc. + * Vorbis encoding support via libvorbisenc. * @author Mark Hills */ @@ -35,24 +35,26 @@ #undef NDEBUG #include +/* Number of samples the user should send in each call. + * This value is used because it is the LCD of all possible frame sizes, so + * an output packet will always start at the same point as one of the input + * packets. + */ #define OGGVORBIS_FRAME_SIZE 64 #define BUFFER_SIZE (1024 * 64) typedef struct OggVorbisContext { - AVClass *av_class; - vorbis_info vi; - vorbis_dsp_state vd; - vorbis_block vb; - uint8_t buffer[BUFFER_SIZE]; - int buffer_index; - int eof; - - /* decoder */ - vorbis_comment vc; - ogg_packet op; - - double iblock; + AVClass *av_class; /**< class for AVOptions */ + vorbis_info vi; /**< vorbis_info used during init */ + vorbis_dsp_state vd; /**< DSP state used for analysis */ + vorbis_block vb; /**< vorbis_block used for analysis */ + uint8_t buffer[BUFFER_SIZE]; /**< output packet buffer */ + int buffer_index; /**< current buffer position */ + int eof; /**< end-of-file flag */ + vorbis_comment vc; /**< VorbisComment info */ + ogg_packet op; /**< ogg packet */ + double iblock; /**< impulse block bias option */ } OggVorbisContext; static const AVOption options[] = { @@ -61,6 +63,7 @@ static const AVOption options[] = { }; static const AVClass class = { "libvorbis", av_default_item_name, options, LIBAVUTIL_VERSION_INT }; + static int vorbis_error_to_averror(int ov_err) { switch (ov_err) { @@ -71,27 +74,31 @@ static int vorbis_error_to_averror(int ov_err) } } -static av_cold int oggvorbis_init_encoder(vorbis_info *vi, AVCodecContext *avccontext) +static av_cold int oggvorbis_init_encoder(vorbis_info *vi, + AVCodecContext *avctx) { - OggVorbisContext *context = avccontext->priv_data; + OggVorbisContext *s = avctx->priv_data; double cfreq; int ret; - if (avccontext->flags & CODEC_FLAG_QSCALE) { - /* variable bitrate */ - float q = avccontext->global_quality / (float)FF_QP2LAMBDA; - if ((ret = vorbis_encode_setup_vbr(vi, avccontext->channels, - avccontext->sample_rate, + if (avctx->flags & CODEC_FLAG_QSCALE) { + /* variable bitrate + * NOTE: we use the oggenc range of -1 to 10 for global_quality for + * user convenience, but libvorbis uses -0.1 to 1.0 + */ + float q = avctx->global_quality / (float)FF_QP2LAMBDA; + if ((ret = vorbis_encode_setup_vbr(vi, avctx->channels, + avctx->sample_rate, q / 10.0))) goto error; } else { - int minrate = avccontext->rc_min_rate > 0 ? avccontext->rc_min_rate : -1; - int maxrate = avccontext->rc_min_rate > 0 ? avccontext->rc_max_rate : -1; + int minrate = avctx->rc_min_rate > 0 ? avctx->rc_min_rate : -1; + int maxrate = avctx->rc_min_rate > 0 ? avctx->rc_max_rate : -1; - /* constant bitrate */ - if ((ret = vorbis_encode_setup_managed(vi, avccontext->channels, - avccontext->sample_rate, minrate, - avccontext->bit_rate, maxrate))) + /* average bitrate */ + if ((ret = vorbis_encode_setup_managed(vi, avctx->channels, + avctx->sample_rate, minrate, + avctx->bit_rate, maxrate))) goto error; /* variable bitrate by estimate, disable slow rate management */ @@ -101,14 +108,15 @@ static av_cold int oggvorbis_init_encoder(vorbis_info *vi, AVCodecContext *avcco } /* cutoff frequency */ - if (avccontext->cutoff > 0) { - cfreq = avccontext->cutoff / 1000.0; + if (avctx->cutoff > 0) { + cfreq = avctx->cutoff / 1000.0; if ((ret = vorbis_encode_ctl(vi, OV_ECTL_LOWPASS_SET, &cfreq))) goto error; } - if (context->iblock) { - if ((ret = vorbis_encode_ctl(vi, OV_ECTL_IBLOCK_SET, &context->iblock))) + /* impulse block bias */ + if (s->iblock) { + if ((ret = vorbis_encode_ctl(vi, OV_ECTL_IBLOCK_SET, &s->iblock))) goto error; } @@ -126,59 +134,59 @@ static int xiph_len(int l) return 1 + l / 255 + l; } -static av_cold int oggvorbis_encode_close(AVCodecContext *avccontext) +static av_cold int oggvorbis_encode_close(AVCodecContext *avctx) { - OggVorbisContext *context = avccontext->priv_data; -/* ogg_packet op ; */ + OggVorbisContext *s = avctx->priv_data; - vorbis_analysis_wrote(&context->vd, 0); /* notify vorbisenc this is EOF */ + /* notify vorbisenc this is EOF */ + vorbis_analysis_wrote(&s->vd, 0); - vorbis_block_clear(&context->vb); - vorbis_dsp_clear(&context->vd); - vorbis_info_clear(&context->vi); + vorbis_block_clear(&s->vb); + vorbis_dsp_clear(&s->vd); + vorbis_info_clear(&s->vi); - av_freep(&avccontext->coded_frame); - av_freep(&avccontext->extradata); + av_freep(&avctx->coded_frame); + av_freep(&avctx->extradata); return 0; } -static av_cold int oggvorbis_encode_init(AVCodecContext *avccontext) +static av_cold int oggvorbis_encode_init(AVCodecContext *avctx) { - OggVorbisContext *context = avccontext->priv_data; + OggVorbisContext *s = avctx->priv_data; ogg_packet header, header_comm, header_code; uint8_t *p; unsigned int offset; int ret; - vorbis_info_init(&context->vi); - if ((ret = oggvorbis_init_encoder(&context->vi, avccontext))) { - av_log(avccontext, AV_LOG_ERROR, "oggvorbis_encode_init: init_encoder failed\n"); + vorbis_info_init(&s->vi); + if ((ret = oggvorbis_init_encoder(&s->vi, avctx))) { + av_log(avctx, AV_LOG_ERROR, "oggvorbis_encode_init: init_encoder failed\n"); goto error; } - if ((ret = vorbis_analysis_init(&context->vd, &context->vi))) { + if ((ret = vorbis_analysis_init(&s->vd, &s->vi))) { ret = vorbis_error_to_averror(ret); goto error; } - if ((ret = vorbis_block_init(&context->vd, &context->vb))) { + if ((ret = vorbis_block_init(&s->vd, &s->vb))) { ret = vorbis_error_to_averror(ret); goto error; } - vorbis_comment_init(&context->vc); - vorbis_comment_add_tag(&context->vc, "encoder", LIBAVCODEC_IDENT); + vorbis_comment_init(&s->vc); + vorbis_comment_add_tag(&s->vc, "encoder", LIBAVCODEC_IDENT); - if ((ret = vorbis_analysis_headerout(&context->vd, &context->vc, &header, - &header_comm, &header_code))) { + if ((ret = vorbis_analysis_headerout(&s->vd, &s->vc, &header, &header_comm, + &header_code))) { ret = vorbis_error_to_averror(ret); goto error; } - avccontext->extradata_size = - 1 + xiph_len(header.bytes) + xiph_len(header_comm.bytes) + - header_code.bytes; - p = avccontext->extradata = - av_malloc(avccontext->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); + avctx->extradata_size = 1 + xiph_len(header.bytes) + + xiph_len(header_comm.bytes) + + header_code.bytes; + p = avctx->extradata = av_malloc(avctx->extradata_size + + FF_INPUT_BUFFER_PADDING_SIZE); if (!p) { ret = AVERROR(ENOMEM); goto error; @@ -193,100 +201,97 @@ static av_cold int oggvorbis_encode_init(AVCodecContext *avccontext) offset += header_comm.bytes; memcpy(&p[offset], header_code.packet, header_code.bytes); offset += header_code.bytes; - assert(offset == avccontext->extradata_size); + assert(offset == avctx->extradata_size); -#if 0 - vorbis_block_clear(&context->vb); - vorbis_dsp_clear(&context->vd); - vorbis_info_clear(&context->vi); -#endif - vorbis_comment_clear(&context->vc); + vorbis_comment_clear(&s->vc); - avccontext->frame_size = OGGVORBIS_FRAME_SIZE; + avctx->frame_size = OGGVORBIS_FRAME_SIZE; - avccontext->coded_frame = avcodec_alloc_frame(); - if (!avccontext->coded_frame) { + avctx->coded_frame = avcodec_alloc_frame(); + if (!avctx->coded_frame) { ret = AVERROR(ENOMEM); goto error; } return 0; error: - oggvorbis_encode_close(avccontext); + oggvorbis_encode_close(avctx); return ret; } -static int oggvorbis_encode_frame(AVCodecContext *avccontext, - unsigned char *packets, +static int oggvorbis_encode_frame(AVCodecContext *avctx, unsigned char *packets, int buf_size, void *data) { - OggVorbisContext *context = avccontext->priv_data; + OggVorbisContext *s = avctx->priv_data; ogg_packet op; signed short *audio = data; - int l; + int pkt_size; + /* send samples to libvorbis */ if (data) { - const int samples = avccontext->frame_size; + const int samples = avctx->frame_size; float **buffer; - int c, channels = context->vi.channels; + int c, channels = s->vi.channels; - buffer = vorbis_analysis_buffer(&context->vd, samples); + buffer = vorbis_analysis_buffer(&s->vd, samples); for (c = 0; c < channels; c++) { + int i; int co = (channels > 8) ? c : ff_vorbis_encoding_channel_layout_offsets[channels - 1][c]; - for (l = 0; l < samples; l++) - buffer[c][l] = audio[l * channels + co] / 32768.f; + for (i = 0; i < samples; i++) + buffer[c][i] = audio[i * channels + co] / 32768.f; } - vorbis_analysis_wrote(&context->vd, samples); + vorbis_analysis_wrote(&s->vd, samples); } else { - if (!context->eof) - vorbis_analysis_wrote(&context->vd, 0); - context->eof = 1; + if (!s->eof) + vorbis_analysis_wrote(&s->vd, 0); + s->eof = 1; } - while (vorbis_analysis_blockout(&context->vd, &context->vb) == 1) { - vorbis_analysis(&context->vb, NULL); - vorbis_bitrate_addblock(&context->vb); + /* retrieve available packets from libvorbis */ + while (vorbis_analysis_blockout(&s->vd, &s->vb) == 1) { + vorbis_analysis(&s->vb, NULL); + vorbis_bitrate_addblock(&s->vb); - while (vorbis_bitrate_flushpacket(&context->vd, &op)) { + /* add any available packets to the output packet buffer */ + while (vorbis_bitrate_flushpacket(&s->vd, &op)) { /* i'd love to say the following line is a hack, but sadly it's * not, apparently the end of stream decision is in libogg. */ if (op.bytes == 1 && op.e_o_s) continue; - if (context->buffer_index + sizeof(ogg_packet) + op.bytes > BUFFER_SIZE) { - av_log(avccontext, AV_LOG_ERROR, "libvorbis: buffer overflow."); + if (s->buffer_index + sizeof(ogg_packet) + op.bytes > BUFFER_SIZE) { + av_log(avctx, AV_LOG_ERROR, "libvorbis: buffer overflow."); return -1; } - memcpy(context->buffer + context->buffer_index, &op, sizeof(ogg_packet)); - context->buffer_index += sizeof(ogg_packet); - memcpy(context->buffer + context->buffer_index, op.packet, op.bytes); - context->buffer_index += op.bytes; -// av_log(avccontext, AV_LOG_DEBUG, "e%d / %d\n", context->buffer_index, op.bytes); + memcpy(s->buffer + s->buffer_index, &op, sizeof(ogg_packet)); + s->buffer_index += sizeof(ogg_packet); + memcpy(s->buffer + s->buffer_index, op.packet, op.bytes); + s->buffer_index += op.bytes; } } - l = 0; - if (context->buffer_index) { - ogg_packet *op2 = (ogg_packet *)context->buffer; - op2->packet = context->buffer + sizeof(ogg_packet); + /* output then next packet from the output buffer, if available */ + pkt_size = 0; + if (s->buffer_index) { + ogg_packet *op2 = (ogg_packet *)s->buffer; + op2->packet = s->buffer + sizeof(ogg_packet); - l = op2->bytes; - avccontext->coded_frame->pts = ff_samples_to_time_base(avccontext, - op2->granulepos); - //FIXME we should reorder the user supplied pts and not assume that they are spaced by 1/sample_rate - - if (l > buf_size) { - av_log(avccontext, AV_LOG_ERROR, "libvorbis: buffer overflow."); + pkt_size = op2->bytes; + // FIXME: we should use the user-supplied pts and duration + avctx->coded_frame->pts = ff_samples_to_time_base(avctx, + op2->granulepos); + if (pkt_size > buf_size) { + av_log(avctx, AV_LOG_ERROR, "libvorbis: buffer overflow."); return -1; } - memcpy(packets, op2->packet, l); - context->buffer_index -= l + sizeof(ogg_packet); - memmove(context->buffer, context->buffer + l + sizeof(ogg_packet), context->buffer_index); -// av_log(avccontext, AV_LOG_DEBUG, "E%d\n", l); + memcpy(packets, op2->packet, pkt_size); + s->buffer_index -= pkt_size + sizeof(ogg_packet); + memmove(s->buffer, s->buffer + pkt_size + sizeof(ogg_packet), + s->buffer_index); } - return l; + return pkt_size; } AVCodec ff_libvorbis_encoder = { @@ -298,7 +303,8 @@ AVCodec ff_libvorbis_encoder = { .encode = oggvorbis_encode_frame, .close = oggvorbis_encode_close, .capabilities = CODEC_CAP_DELAY, - .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, + AV_SAMPLE_FMT_NONE }, .long_name = NULL_IF_CONFIG_SMALL("libvorbis Vorbis"), .priv_class = &class, }; From 182d4f1f3855460ee8634ea052f33332cf9d174e Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Tue, 28 Feb 2012 18:52:30 -0500 Subject: [PATCH 39/58] libvorbis: fix use of minrate/maxrate AVOptions - enable the options for audio encoding - properly check for user-set maxrate - use correct calling order in vorbis_encode_setup_managed() --- libavcodec/libvorbis.c | 6 +++--- libavcodec/options.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libavcodec/libvorbis.c b/libavcodec/libvorbis.c index e519a1dbb8..030da2a6d5 100644 --- a/libavcodec/libvorbis.c +++ b/libavcodec/libvorbis.c @@ -93,12 +93,12 @@ static av_cold int oggvorbis_init_encoder(vorbis_info *vi, goto error; } else { int minrate = avctx->rc_min_rate > 0 ? avctx->rc_min_rate : -1; - int maxrate = avctx->rc_min_rate > 0 ? avctx->rc_max_rate : -1; + int maxrate = avctx->rc_max_rate > 0 ? avctx->rc_max_rate : -1; /* average bitrate */ if ((ret = vorbis_encode_setup_managed(vi, avctx->channels, - avctx->sample_rate, minrate, - avctx->bit_rate, maxrate))) + avctx->sample_rate, maxrate, + avctx->bit_rate, minrate))) goto error; /* variable bitrate by estimate, disable slow rate management */ diff --git a/libavcodec/options.c b/libavcodec/options.c index 288c75437a..d25b64aee8 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -195,8 +195,8 @@ static const AVOption options[]={ {"rc_qmod_freq", "experimental quantizer modulation", OFFSET(rc_qmod_freq), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|E}, {"rc_override_count", NULL, OFFSET(rc_override_count), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX}, {"rc_eq", "set rate control equation", OFFSET(rc_eq), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, V|E}, -{"maxrate", "set max video bitrate tolerance (in bits/s)", OFFSET(rc_max_rate), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|E}, -{"minrate", "set min video bitrate tolerance (in bits/s)", OFFSET(rc_min_rate), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|E}, +{"maxrate", "set max bitrate tolerance (in bits/s)", OFFSET(rc_max_rate), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|A|E}, +{"minrate", "set min bitrate tolerance (in bits/s)", OFFSET(rc_min_rate), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, V|A|E}, {"bufsize", "set ratecontrol buffer size (in bits)", OFFSET(rc_buffer_size), AV_OPT_TYPE_INT, {.dbl = DEFAULT }, INT_MIN, INT_MAX, A|V|E}, {"rc_buf_aggressivity", "currently useless", OFFSET(rc_buffer_aggressivity), AV_OPT_TYPE_FLOAT, {.dbl = 1.0 }, -FLT_MAX, FLT_MAX, V|E}, {"i_qfactor", "qp factor between P and I frames", OFFSET(i_quant_factor), AV_OPT_TYPE_FLOAT, {.dbl = -0.8 }, -FLT_MAX, FLT_MAX, V|E}, From 147ff24a0e8d819615a0f596df3ea47dddd79fdc Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Tue, 28 Feb 2012 19:33:07 -0500 Subject: [PATCH 40/58] libvorbis: use VBR by default, with default quality of 3 --- libavcodec/libvorbis.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/libavcodec/libvorbis.c b/libavcodec/libvorbis.c index 030da2a6d5..7b44c1f671 100644 --- a/libavcodec/libvorbis.c +++ b/libavcodec/libvorbis.c @@ -61,6 +61,12 @@ static const AVOption options[] = { { "iblock", "Sets the impulse block bias", offsetof(OggVorbisContext, iblock), AV_OPT_TYPE_DOUBLE, { .dbl = 0 }, -15, 0, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, { NULL } }; + +static const AVCodecDefault defaults[] = { + { "b", "0" }, + { NULL }, +}; + static const AVClass class = { "libvorbis", av_default_item_name, options, LIBAVUTIL_VERSION_INT }; @@ -81,12 +87,15 @@ static av_cold int oggvorbis_init_encoder(vorbis_info *vi, double cfreq; int ret; - if (avctx->flags & CODEC_FLAG_QSCALE) { + if (avctx->flags & CODEC_FLAG_QSCALE || !avctx->bit_rate) { /* variable bitrate * NOTE: we use the oggenc range of -1 to 10 for global_quality for - * user convenience, but libvorbis uses -0.1 to 1.0 + * user convenience, but libvorbis uses -0.1 to 1.0. */ float q = avctx->global_quality / (float)FF_QP2LAMBDA; + /* default to 3 if the user did not set quality or bitrate */ + if (!(avctx->flags & CODEC_FLAG_QSCALE)) + q = 3.0; if ((ret = vorbis_encode_setup_vbr(vi, avctx->channels, avctx->sample_rate, q / 10.0))) @@ -307,4 +316,5 @@ AVCodec ff_libvorbis_encoder = { AV_SAMPLE_FMT_NONE }, .long_name = NULL_IF_CONFIG_SMALL("libvorbis Vorbis"), .priv_class = &class, + .defaults = defaults, }; From f15c4281dcabeddb61cb6430e0cc1047173292f8 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Tue, 28 Feb 2012 19:51:25 -0500 Subject: [PATCH 41/58] libvorbis: do not flush libvorbis analysis if dsp state was not initialized Fixes a segfault if init() fails before initializing the dsp state --- libavcodec/libvorbis.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libavcodec/libvorbis.c b/libavcodec/libvorbis.c index 7b44c1f671..d7839425ea 100644 --- a/libavcodec/libvorbis.c +++ b/libavcodec/libvorbis.c @@ -52,6 +52,7 @@ typedef struct OggVorbisContext { uint8_t buffer[BUFFER_SIZE]; /**< output packet buffer */ int buffer_index; /**< current buffer position */ int eof; /**< end-of-file flag */ + int dsp_initialized; /**< vd has been initialized */ vorbis_comment vc; /**< VorbisComment info */ ogg_packet op; /**< ogg packet */ double iblock; /**< impulse block bias option */ @@ -148,7 +149,8 @@ static av_cold int oggvorbis_encode_close(AVCodecContext *avctx) OggVorbisContext *s = avctx->priv_data; /* notify vorbisenc this is EOF */ - vorbis_analysis_wrote(&s->vd, 0); + if (s->dsp_initialized) + vorbis_analysis_wrote(&s->vd, 0); vorbis_block_clear(&s->vb); vorbis_dsp_clear(&s->vd); @@ -177,6 +179,7 @@ static av_cold int oggvorbis_encode_init(AVCodecContext *avctx) ret = vorbis_error_to_averror(ret); goto error; } + s->dsp_initialized = 1; if ((ret = vorbis_block_init(&s->vd, &s->vb))) { ret = vorbis_error_to_averror(ret); goto error; From c5063e0348db97626aecc17c42fd41718fd62f13 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Tue, 28 Feb 2012 19:55:10 -0500 Subject: [PATCH 42/58] libvorbis: use float input instead of s16 libvorbis takes float input, so we can just deinterleave/reorder the input as-is instead of also converting. --- libavcodec/libvorbis.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libavcodec/libvorbis.c b/libavcodec/libvorbis.c index d7839425ea..2ca779653e 100644 --- a/libavcodec/libvorbis.c +++ b/libavcodec/libvorbis.c @@ -236,7 +236,7 @@ static int oggvorbis_encode_frame(AVCodecContext *avctx, unsigned char *packets, { OggVorbisContext *s = avctx->priv_data; ogg_packet op; - signed short *audio = data; + float *audio = data; int pkt_size; /* send samples to libvorbis */ @@ -251,7 +251,7 @@ static int oggvorbis_encode_frame(AVCodecContext *avctx, unsigned char *packets, int co = (channels > 8) ? c : ff_vorbis_encoding_channel_layout_offsets[channels - 1][c]; for (i = 0; i < samples; i++) - buffer[c][i] = audio[i * channels + co] / 32768.f; + buffer[c][i] = audio[i * channels + co]; } vorbis_analysis_wrote(&s->vd, samples); } else { @@ -315,7 +315,7 @@ AVCodec ff_libvorbis_encoder = { .encode = oggvorbis_encode_frame, .close = oggvorbis_encode_close, .capabilities = CODEC_CAP_DELAY, - .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE }, .long_name = NULL_IF_CONFIG_SMALL("libvorbis Vorbis"), .priv_class = &class, From 94025d8a99e8eea72293850e23fffbb6d0c4aaef Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Tue, 28 Feb 2012 21:00:33 -0500 Subject: [PATCH 43/58] libvorbis: check return values for functions that can return errors --- libavcodec/libvorbis.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/libavcodec/libvorbis.c b/libavcodec/libvorbis.c index 2ca779653e..6ae47cf81c 100644 --- a/libavcodec/libvorbis.c +++ b/libavcodec/libvorbis.c @@ -237,7 +237,7 @@ static int oggvorbis_encode_frame(AVCodecContext *avctx, unsigned char *packets, OggVorbisContext *s = avctx->priv_data; ogg_packet op; float *audio = data; - int pkt_size; + int pkt_size, ret; /* send samples to libvorbis */ if (data) { @@ -253,20 +253,24 @@ static int oggvorbis_encode_frame(AVCodecContext *avctx, unsigned char *packets, for (i = 0; i < samples; i++) buffer[c][i] = audio[i * channels + co]; } - vorbis_analysis_wrote(&s->vd, samples); + if ((ret = vorbis_analysis_wrote(&s->vd, samples)) < 0) + return vorbis_error_to_averror(ret); } else { if (!s->eof) - vorbis_analysis_wrote(&s->vd, 0); + if ((ret = vorbis_analysis_wrote(&s->vd, 0)) < 0) + return vorbis_error_to_averror(ret); s->eof = 1; } /* retrieve available packets from libvorbis */ - while (vorbis_analysis_blockout(&s->vd, &s->vb) == 1) { - vorbis_analysis(&s->vb, NULL); - vorbis_bitrate_addblock(&s->vb); + while ((ret = vorbis_analysis_blockout(&s->vd, &s->vb)) == 1) { + if ((ret = vorbis_analysis(&s->vb, NULL)) < 0) + break; + if ((ret = vorbis_bitrate_addblock(&s->vb)) < 0) + break; /* add any available packets to the output packet buffer */ - while (vorbis_bitrate_flushpacket(&s->vd, &op)) { + while ((ret = vorbis_bitrate_flushpacket(&s->vd, &op)) == 1) { /* i'd love to say the following line is a hack, but sadly it's * not, apparently the end of stream decision is in libogg. */ if (op.bytes == 1 && op.e_o_s) @@ -280,7 +284,11 @@ static int oggvorbis_encode_frame(AVCodecContext *avctx, unsigned char *packets, memcpy(s->buffer + s->buffer_index, op.packet, op.bytes); s->buffer_index += op.bytes; } + if (ret < 0) + break; } + if (ret < 0) + return vorbis_error_to_averror(ret); /* output then next packet from the output buffer, if available */ pkt_size = 0; From 1fe7c1be547b92ac9f0b7e6158d76b91eee170e2 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Tue, 28 Feb 2012 21:02:22 -0500 Subject: [PATCH 44/58] libvorbis: remove unneeded e_o_s check vorbis_bitrate_flushpacket() does not return any packets that should not be output in the bitstream. --- libavcodec/libvorbis.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libavcodec/libvorbis.c b/libavcodec/libvorbis.c index 6ae47cf81c..dba089253b 100644 --- a/libavcodec/libvorbis.c +++ b/libavcodec/libvorbis.c @@ -271,10 +271,6 @@ static int oggvorbis_encode_frame(AVCodecContext *avctx, unsigned char *packets, /* add any available packets to the output packet buffer */ while ((ret = vorbis_bitrate_flushpacket(&s->vd, &op)) == 1) { - /* i'd love to say the following line is a hack, but sadly it's - * not, apparently the end of stream decision is in libogg. */ - if (op.bytes == 1 && op.e_o_s) - continue; if (s->buffer_index + sizeof(ogg_packet) + op.bytes > BUFFER_SIZE) { av_log(avctx, AV_LOG_ERROR, "libvorbis: buffer overflow."); return -1; From 592c4dbc7efbf2e308288e9d0cf7ca16cb2882c6 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Tue, 28 Feb 2012 22:39:07 -0500 Subject: [PATCH 45/58] libvorbis: use AVFifoBuffer for output packet buffer simplifies the code and does less memmove() --- libavcodec/libvorbis.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/libavcodec/libvorbis.c b/libavcodec/libvorbis.c index dba089253b..7ddc5f9048 100644 --- a/libavcodec/libvorbis.c +++ b/libavcodec/libvorbis.c @@ -26,6 +26,7 @@ #include +#include "libavutil/fifo.h" #include "libavutil/opt.h" #include "avcodec.h" #include "bytestream.h" @@ -49,8 +50,7 @@ typedef struct OggVorbisContext { vorbis_info vi; /**< vorbis_info used during init */ vorbis_dsp_state vd; /**< DSP state used for analysis */ vorbis_block vb; /**< vorbis_block used for analysis */ - uint8_t buffer[BUFFER_SIZE]; /**< output packet buffer */ - int buffer_index; /**< current buffer position */ + AVFifoBuffer *pkt_fifo; /**< output packet buffer */ int eof; /**< end-of-file flag */ int dsp_initialized; /**< vd has been initialized */ vorbis_comment vc; /**< VorbisComment info */ @@ -156,6 +156,7 @@ static av_cold int oggvorbis_encode_close(AVCodecContext *avctx) vorbis_dsp_clear(&s->vd); vorbis_info_clear(&s->vi); + av_fifo_free(s->pkt_fifo); av_freep(&avctx->coded_frame); av_freep(&avctx->extradata); @@ -219,6 +220,12 @@ static av_cold int oggvorbis_encode_init(AVCodecContext *avctx) avctx->frame_size = OGGVORBIS_FRAME_SIZE; + s->pkt_fifo = av_fifo_alloc(BUFFER_SIZE); + if (!s->pkt_fifo) { + ret = AVERROR(ENOMEM); + goto error; + } + avctx->coded_frame = avcodec_alloc_frame(); if (!avctx->coded_frame) { ret = AVERROR(ENOMEM); @@ -271,14 +278,12 @@ static int oggvorbis_encode_frame(AVCodecContext *avctx, unsigned char *packets, /* add any available packets to the output packet buffer */ while ((ret = vorbis_bitrate_flushpacket(&s->vd, &op)) == 1) { - if (s->buffer_index + sizeof(ogg_packet) + op.bytes > BUFFER_SIZE) { + if (av_fifo_space(s->pkt_fifo) < sizeof(ogg_packet) + op.bytes) { av_log(avctx, AV_LOG_ERROR, "libvorbis: buffer overflow."); return -1; } - memcpy(s->buffer + s->buffer_index, &op, sizeof(ogg_packet)); - s->buffer_index += sizeof(ogg_packet); - memcpy(s->buffer + s->buffer_index, op.packet, op.bytes); - s->buffer_index += op.bytes; + av_fifo_generic_write(s->pkt_fifo, &op, sizeof(ogg_packet), NULL); + av_fifo_generic_write(s->pkt_fifo, op.packet, op.bytes, NULL); } if (ret < 0) break; @@ -288,23 +293,17 @@ static int oggvorbis_encode_frame(AVCodecContext *avctx, unsigned char *packets, /* output then next packet from the output buffer, if available */ pkt_size = 0; - if (s->buffer_index) { - ogg_packet *op2 = (ogg_packet *)s->buffer; - op2->packet = s->buffer + sizeof(ogg_packet); - - pkt_size = op2->bytes; + if (av_fifo_size(s->pkt_fifo) >= sizeof(ogg_packet)) { + av_fifo_generic_read(s->pkt_fifo, &op, sizeof(ogg_packet), NULL); + pkt_size = op.bytes; // FIXME: we should use the user-supplied pts and duration avctx->coded_frame->pts = ff_samples_to_time_base(avctx, - op2->granulepos); + op.granulepos); if (pkt_size > buf_size) { av_log(avctx, AV_LOG_ERROR, "libvorbis: buffer overflow."); return -1; } - - memcpy(packets, op2->packet, pkt_size); - s->buffer_index -= pkt_size + sizeof(ogg_packet); - memmove(s->buffer, s->buffer + pkt_size + sizeof(ogg_packet), - s->buffer_index); + av_fifo_generic_read(s->pkt_fifo, packets, pkt_size, NULL); } return pkt_size; From a45a1ea52174233265a77632a3f3f40c67f3c6d6 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Wed, 29 Feb 2012 00:02:55 -0500 Subject: [PATCH 46/58] libvorbis: add/update error messages also use AVERROR codes for some return values instead of -1 --- libavcodec/libvorbis.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/libavcodec/libvorbis.c b/libavcodec/libvorbis.c index 7ddc5f9048..991c64f81d 100644 --- a/libavcodec/libvorbis.c +++ b/libavcodec/libvorbis.c @@ -173,15 +173,17 @@ static av_cold int oggvorbis_encode_init(AVCodecContext *avctx) vorbis_info_init(&s->vi); if ((ret = oggvorbis_init_encoder(&s->vi, avctx))) { - av_log(avctx, AV_LOG_ERROR, "oggvorbis_encode_init: init_encoder failed\n"); + av_log(avctx, AV_LOG_ERROR, "encoder setup failed\n"); goto error; } if ((ret = vorbis_analysis_init(&s->vd, &s->vi))) { + av_log(avctx, AV_LOG_ERROR, "analysis init failed\n"); ret = vorbis_error_to_averror(ret); goto error; } s->dsp_initialized = 1; if ((ret = vorbis_block_init(&s->vd, &s->vb))) { + av_log(avctx, AV_LOG_ERROR, "dsp init failed\n"); ret = vorbis_error_to_averror(ret); goto error; } @@ -260,12 +262,16 @@ static int oggvorbis_encode_frame(AVCodecContext *avctx, unsigned char *packets, for (i = 0; i < samples; i++) buffer[c][i] = audio[i * channels + co]; } - if ((ret = vorbis_analysis_wrote(&s->vd, samples)) < 0) + if ((ret = vorbis_analysis_wrote(&s->vd, samples)) < 0) { + av_log(avctx, AV_LOG_ERROR, "error in vorbis_analysis_wrote()\n"); return vorbis_error_to_averror(ret); + } } else { if (!s->eof) - if ((ret = vorbis_analysis_wrote(&s->vd, 0)) < 0) + if ((ret = vorbis_analysis_wrote(&s->vd, 0)) < 0) { + av_log(avctx, AV_LOG_ERROR, "error in vorbis_analysis_wrote()\n"); return vorbis_error_to_averror(ret); + } s->eof = 1; } @@ -279,17 +285,21 @@ static int oggvorbis_encode_frame(AVCodecContext *avctx, unsigned char *packets, /* add any available packets to the output packet buffer */ while ((ret = vorbis_bitrate_flushpacket(&s->vd, &op)) == 1) { if (av_fifo_space(s->pkt_fifo) < sizeof(ogg_packet) + op.bytes) { - av_log(avctx, AV_LOG_ERROR, "libvorbis: buffer overflow."); - return -1; + av_log(avctx, AV_LOG_ERROR, "packet buffer is too small"); + return AVERROR_BUG; } av_fifo_generic_write(s->pkt_fifo, &op, sizeof(ogg_packet), NULL); av_fifo_generic_write(s->pkt_fifo, op.packet, op.bytes, NULL); } - if (ret < 0) + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "error getting available packets\n"); break; + } } - if (ret < 0) + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "error getting available packets\n"); return vorbis_error_to_averror(ret); + } /* output then next packet from the output buffer, if available */ pkt_size = 0; @@ -300,8 +310,8 @@ static int oggvorbis_encode_frame(AVCodecContext *avctx, unsigned char *packets, avctx->coded_frame->pts = ff_samples_to_time_base(avctx, op.granulepos); if (pkt_size > buf_size) { - av_log(avctx, AV_LOG_ERROR, "libvorbis: buffer overflow."); - return -1; + av_log(avctx, AV_LOG_ERROR, "output buffer is too small"); + return AVERROR(EINVAL); } av_fifo_generic_read(s->pkt_fifo, packets, pkt_size, NULL); } From 07a180972fb369bb59bf6d4f8edb4598c51e80d2 Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Tue, 28 Feb 2012 19:00:48 -0800 Subject: [PATCH 47/58] vmnc: return error on decode_init() failure. Found-by: Mateusz "j00ru" Jurczyk and Gynvael Coldwind CC: libav-stable@libav.org --- libavcodec/vmnc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libavcodec/vmnc.c b/libavcodec/vmnc.c index 8cc78fa4c0..b1c4cbd1b7 100644 --- a/libavcodec/vmnc.c +++ b/libavcodec/vmnc.c @@ -483,6 +483,7 @@ static av_cold int decode_init(AVCodecContext *avctx) break; default: av_log(avctx, AV_LOG_ERROR, "Unsupported bitdepth %i\n", c->bpp); + return AVERROR_INVALIDDATA; } return 0; From 31b132c0948895b7a2d464232aac3a41c1f8e1c9 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Sun, 26 Feb 2012 19:23:50 +0000 Subject: [PATCH 48/58] fate: add cdxl test for bit line plane arrangement Signed-off-by: Paul B Mahol Signed-off-by: Justin Ruggles --- tests/fate/cdxl.mak | 3 +++ tests/ref/fate/cdxl-bitline-ham6 | 11 +++++++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/ref/fate/cdxl-bitline-ham6 diff --git a/tests/fate/cdxl.mak b/tests/fate/cdxl.mak index 82ac27e430..3a46c5ce50 100644 --- a/tests/fate/cdxl.mak +++ b/tests/fate/cdxl.mak @@ -10,5 +10,8 @@ fate-cdxl-pal8: CMD = framecrc -i $(SAMPLES)/cdxl/maku.cdxl -pix_fmt rgb24 -fram FATE_CDXL += fate-cdxl-pal8-small fate-cdxl-pal8-small: CMD = framecrc -i $(SAMPLES)/cdxl/fruit.cdxl -an -pix_fmt rgb24 -frames:v 46 +FATE_CDXL += fate-cdxl-bitline-ham6 +fate-cdxl-bitline-ham6: CMD = framecrc -i $(SAMPLES)/cdxl/bitline.cdxl -frames:v 10 + FATE_TESTS += $(FATE_CDXL) fate-cdxl: $(FATE_CDXL) diff --git a/tests/ref/fate/cdxl-bitline-ham6 b/tests/ref/fate/cdxl-bitline-ham6 new file mode 100644 index 0000000000..e4071a9955 --- /dev/null +++ b/tests/ref/fate/cdxl-bitline-ham6 @@ -0,0 +1,11 @@ +#tb 0: 1/11025 +0, 0, 0, 0, 63180, 0xcda82c16 +0, 220, 220, 0, 63180, 0xa6097bf9 +0, 440, 440, 0, 63180, 0x4c2fb091 +0, 660, 660, 0, 63180, 0xc597db00 +0, 880, 880, 0, 63180, 0xfa581ccd +0, 1100, 1100, 0, 63180, 0x3e51498f +0, 1320, 1320, 0, 63180, 0xe3495396 +0, 1540, 1540, 0, 63180, 0x425f5f02 +0, 1760, 1760, 0, 63180, 0x6077465f +0, 1980, 1980, 0, 63180, 0x923ba29c From 841c17177b36db48554a2eda134d4c4134afa3c7 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Fri, 24 Feb 2012 16:47:28 -0500 Subject: [PATCH 49/58] FATE: add mp3 test for sample that exhibited false overreads related to b7165426917f91ebcad84bdff366824f03b32bfe Error messages and audible artifacts were fixed in that commit. --- tests/fate/mp3.mak | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/fate/mp3.mak b/tests/fate/mp3.mak index 9dfa829008..4c16cb84e0 100644 --- a/tests/fate/mp3.mak +++ b/tests/fate/mp3.mak @@ -33,6 +33,11 @@ fate-mp3-float-conf-si_block: CMD = pcm -acodec mp3float -i $(SAMPLES)/mp3-confo fate-mp3-float-conf-si_block: CMP = stddev fate-mp3-float-conf-si_block: REF = $(SAMPLES)/mp3-conformance/si_block.pcm +FATE_MP3 += fate-mp3-float-extra_overread +fate-mp3-float-extra_overread: CMD = pcm -c:a mp3float -i $(SAMPLES)/mpegaudio/extra_overread.mp3 +fate-mp3-float-extra_overread: CMP = stddev +fate-mp3-float-extra_overread: REF = $(SAMPLES)/mpegaudio/extra_overread.pcm + FATE_TESTS += $(FATE_MP3) fate-mp3: $(FATE_MP3) $(FATE_MP3): CMP = stddev From 9b4cd586119a6c50907abc35279eb2af63f278a2 Mon Sep 17 00:00:00 2001 From: Vitor Sessak Date: Wed, 29 Feb 2012 21:06:13 +0100 Subject: [PATCH 50/58] mpegaudiodec: use DSPUtil.butterflies_float(). Signed-off-by: Ronald S. Bultje --- libavcodec/mpegaudiodec.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libavcodec/mpegaudiodec.c b/libavcodec/mpegaudiodec.c index d82432c775..d6a09c86a8 100644 --- a/libavcodec/mpegaudiodec.c +++ b/libavcodec/mpegaudiodec.c @@ -29,6 +29,7 @@ #include "get_bits.h" #include "mathops.h" #include "mpegaudiodsp.h" +#include "dsputil.h" /* * TODO: @@ -80,6 +81,7 @@ typedef struct MPADecodeContext { int err_recognition; AVCodecContext* avctx; MPADSPContext mpadsp; + DSPContext dsp; AVFrame frame; } MPADecodeContext; @@ -432,6 +434,7 @@ static av_cold int decode_init(AVCodecContext * avctx) s->avctx = avctx; ff_mpadsp_init(&s->mpadsp); + ff_dsputil_init(&s->dsp, avctx); avctx->sample_fmt= OUT_FMT; s->err_recognition = avctx->err_recognition; @@ -1153,6 +1156,9 @@ found2: /* ms stereo ONLY */ /* NOTE: the 1/sqrt(2) normalization factor is included in the global gain */ +#if CONFIG_FLOAT + s-> dsp.butterflies_float(g0->sb_hybrid, g1->sb_hybrid, 576); +#else tab0 = g0->sb_hybrid; tab1 = g1->sb_hybrid; for (i = 0; i < 576; i++) { @@ -1161,6 +1167,7 @@ found2: tab0[i] = tmp0 + tmp1; tab1[i] = tmp0 - tmp1; } +#endif } } From 4bf6775e9d4a499ca1c25a5e13ff3d055d9219f5 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Thu, 19 Jan 2012 15:48:11 -0500 Subject: [PATCH 51/58] vqf: set packet parameters after av_new_packet() Otherwise the values are overwritten. --- libavformat/vqf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libavformat/vqf.c b/libavformat/vqf.c index 08ffa734c1..b9fa8be4f3 100644 --- a/libavformat/vqf.c +++ b/libavformat/vqf.c @@ -220,12 +220,12 @@ static int vqf_read_packet(AVFormatContext *s, AVPacket *pkt) int ret; int size = (c->frame_bit_len - c->remaining_bits + 7)>>3; - pkt->pos = avio_tell(s->pb); - pkt->stream_index = 0; - if (av_new_packet(pkt, size+2) < 0) return AVERROR(EIO); + pkt->pos = avio_tell(s->pb); + pkt->stream_index = 0; + pkt->data[0] = 8 - c->remaining_bits; // Number of bits to skip pkt->data[1] = c->last_frame_bits; ret = avio_read(s->pb, pkt->data+2, size); From bdbf1fa405fbbf9c99fd9abff350d228f27304d0 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Fri, 13 Jan 2012 18:20:18 -0500 Subject: [PATCH 52/58] asfdec: Do not set AVCodecContext.frame_size --- libavformat/asfdec.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/libavformat/asfdec.c b/libavformat/asfdec.c index 8828eb583c..07899609c9 100644 --- a/libavformat/asfdec.c +++ b/libavformat/asfdec.c @@ -26,7 +26,6 @@ #include "libavutil/avstring.h" #include "libavutil/dict.h" #include "libavutil/mathematics.h" -#include "libavcodec/mpegaudio.h" #include "avformat.h" #include "internal.h" #include "avio_internal.h" @@ -323,25 +322,6 @@ static int asf_read_stream_properties(AVFormatContext *s, int64_t size) || asf_st->ds_packet_size % asf_st->ds_chunk_size) asf_st->ds_span = 0; // disable descrambling } - switch (st->codec->codec_id) { - case CODEC_ID_MP3: - st->codec->frame_size = MPA_FRAME_SIZE; - break; - case CODEC_ID_PCM_S16LE: - case CODEC_ID_PCM_S16BE: - case CODEC_ID_PCM_U16LE: - case CODEC_ID_PCM_U16BE: - case CODEC_ID_PCM_S8: - case CODEC_ID_PCM_U8: - case CODEC_ID_PCM_ALAW: - case CODEC_ID_PCM_MULAW: - st->codec->frame_size = 1; - break; - default: - /* This is probably wrong, but it prevents a crash later */ - st->codec->frame_size = 1; - break; - } } else if (type == AVMEDIA_TYPE_VIDEO && size - (avio_tell(pb) - pos1 + 24) >= 51) { avio_rl32(pb); From aa831c4093463e7feda5aa298371b639fd12fcd6 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Tue, 17 Jan 2012 10:16:34 -0500 Subject: [PATCH 53/58] psx-str: do not allow seeking by bytes --- libavformat/psxstr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libavformat/psxstr.c b/libavformat/psxstr.c index 988d1f095e..61e24e204f 100644 --- a/libavformat/psxstr.c +++ b/libavformat/psxstr.c @@ -265,4 +265,5 @@ AVInputFormat ff_str_demuxer = { .read_header = str_read_header, .read_packet = str_read_packet, .read_close = str_read_close, + .flags = AVFMT_NO_BYTE_SEEK, }; From 929dd8c108489d1da0f4fef4920f9f19a45d0b8c Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Thu, 19 Jan 2012 15:55:18 -0500 Subject: [PATCH 54/58] dxa: set audio stream time base using the sample rate --- libavformat/dxa.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libavformat/dxa.c b/libavformat/dxa.c index 13d2060465..65ace26f9e 100644 --- a/libavformat/dxa.c +++ b/libavformat/dxa.c @@ -107,6 +107,8 @@ static int dxa_read_header(AVFormatContext *s) ret = ff_get_wav_header(pb, ast->codec, fsize); if (ret < 0) return ret; + if (ast->codec->sample_rate > 0) + avpriv_set_pts_info(ast, 64, 1, ast->codec->sample_rate); // find 'data' chunk while(avio_tell(pb) < c->vidpos && !pb->eof_reached){ tag = avio_rl32(pb); From f240df6a7415c7cf44e2edeec309d137759da546 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Thu, 19 Jan 2012 23:47:48 -0500 Subject: [PATCH 55/58] FATE: do not decode audio in the nuv test. We already have sufficient coverage for 16-bit pcm. --- tests/fate/video.mak | 2 +- tests/ref/fate/nuv | 19 ------------------- 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/tests/fate/video.mak b/tests/fate/video.mak index 6d112ea1d3..5c53c11fca 100644 --- a/tests/fate/video.mak +++ b/tests/fate/video.mak @@ -144,7 +144,7 @@ fate-mpeg2-field-enc: CMD = framecrc -flags +bitexact -dct fastint -idct simple # FIXME dropped frames in this test because of coarse timebase FATE_TESTS += fate-nuv -fate-nuv: CMD = framecrc -idct simple -i $(SAMPLES)/nuv/Today.nuv +fate-nuv: CMD = framecrc -idct simple -i $(SAMPLES)/nuv/Today.nuv -an FATE_TESTS += fate-qpeg fate-qpeg: CMD = framecrc -i $(SAMPLES)/qpeg/Clock.avi -an -pix_fmt rgb24 diff --git a/tests/ref/fate/nuv b/tests/ref/fate/nuv index 3607164b98..e9286d6a6d 100644 --- a/tests/ref/fate/nuv +++ b/tests/ref/fate/nuv @@ -1,29 +1,10 @@ #tb 0: 1/1000 -#tb 1: 1/44100 -1, 0, 0, 1024, 4096, 0x00000000 -1, 1024, 1024, 1024, 4096, 0x4dfae7a6 -1, 2048, 2048, 1024, 4096, 0x3fd9f5c6 -1, 3072, 3072, 1024, 4096, 0x7b86e310 -1, 4096, 4096, 1024, 4096, 0x611cece5 -1, 5120, 5120, 1024, 4096, 0xb7d8e872 0, 118, 118, 0, 460800, 0x54aedafe -1, 6144, 6144, 1024, 4096, 0x072ef72b 0, 152, 152, 0, 460800, 0xb7aa8b56 -1, 7168, 7168, 1024, 4096, 0xb3560144 0, 177, 177, 0, 460800, 0x283ea3b5 -1, 8192, 8192, 1024, 4096, 0x0a3d119e 0, 202, 202, 0, 460800, 0x283ea3b5 -1, 9216, 9216, 1024, 4096, 0xbe391aa4 -1, 10240, 10240, 1024, 4096, 0x28f7c6e5 0, 235, 235, 0, 460800, 0x10e577de -1, 11264, 11264, 1024, 4096, 0xca9d9df2 0, 269, 269, 0, 460800, 0x4e091ee2 -1, 12288, 12288, 1024, 4096, 0x5c6b95a9 -1, 13312, 13312, 1024, 4096, 0x0bdfc0bf 0, 302, 302, 0, 460800, 0x2ea88828 -1, 14336, 14336, 1024, 4096, 0xd95a9277 0, 335, 335, 0, 460800, 0x4b7f4df0 -1, 15360, 15360, 1024, 4096, 0xae2bef2c 0, 369, 369, 0, 460800, 0xb30eb322 -1, 16384, 16384, 1024, 4096, 0xbf031e83 -1, 17408, 17408, 1024, 4096, 0x4c83e2d1 From d1604b3de96575195b219028e2c4f08b2259aa7d Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Tue, 28 Feb 2012 18:48:27 -0800 Subject: [PATCH 56/58] h264: prevent overreads in intra PCM decoding. Found-by: Mateusz "j00ru" Jurczyk and Gynvael Coldwind CC: libav-stable@libav.org --- libavcodec/h264_cabac.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libavcodec/h264_cabac.c b/libavcodec/h264_cabac.c index 75fb02cb63..2ee4bc01a8 100644 --- a/libavcodec/h264_cabac.c +++ b/libavcodec/h264_cabac.c @@ -1996,6 +1996,8 @@ decode_intra_mb: } // The pixels are stored in the same order as levels in h->mb array. + if ((int) (h->cabac.bytestream_end - ptr) < mb_size) + return -1; memcpy(h->mb, ptr, mb_size); ptr+=mb_size; ff_init_cabac_decoder(&h->cabac, ptr, h->cabac.bytestream_end - ptr); From 8a9faf33f2b4f40afbc3393b2be49867cea0c92d Mon Sep 17 00:00:00 2001 From: "Ronald S. Bultje" Date: Wed, 29 Feb 2012 13:55:09 -0800 Subject: [PATCH 57/58] cscd: use negative error values to indicate decode_init() failures. Found-by: Mateusz "j00ru" Jurczyk and Gynvael Coldwind CC: libav-stable@libav.org --- libavcodec/cscd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libavcodec/cscd.c b/libavcodec/cscd.c index 43f0e5e7d5..17f487842d 100644 --- a/libavcodec/cscd.c +++ b/libavcodec/cscd.c @@ -228,7 +228,7 @@ static av_cold int decode_init(AVCodecContext *avctx) { av_log(avctx, AV_LOG_ERROR, "CamStudio codec error: invalid depth %i bpp\n", avctx->bits_per_coded_sample); - return 1; + return AVERROR_INVALIDDATA; } c->bpp = avctx->bits_per_coded_sample; c->pic.data[0] = NULL; @@ -241,7 +241,7 @@ static av_cold int decode_init(AVCodecContext *avctx) { c->decomp_buf = av_malloc(c->decomp_size + AV_LZO_OUTPUT_PADDING); if (!c->decomp_buf) { av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n"); - return 1; + return AVERROR(ENOMEM); } return 0; } From 882abda5a26ffb8e3d1c5852dfa7cdad0a291d2d Mon Sep 17 00:00:00 2001 From: Vitor Sessak Date: Wed, 29 Feb 2012 22:09:10 +0100 Subject: [PATCH 58/58] amrnbdec: check frame size before decoding. Found-by: Mateusz "j00ru" Jurczyk and Gynvael Coldwind CC: libav-stable@libav.org Signed-off-by: Ronald S. Bultje --- libavcodec/amrnbdec.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libavcodec/amrnbdec.c b/libavcodec/amrnbdec.c index fff0e7248a..a7d0b4e337 100644 --- a/libavcodec/amrnbdec.c +++ b/libavcodec/amrnbdec.c @@ -200,6 +200,10 @@ static enum Mode unpack_bitstream(AMRContext *p, const uint8_t *buf, p->bad_frame_indicator = !get_bits1(&gb); // quality bit skip_bits(&gb, 2); // two padding bits + if (mode >= N_MODES || buf_size < frame_sizes_nb[mode] + 1) { + return NO_DATA; + } + if (mode < MODE_DTX) ff_amr_bit_reorder((uint16_t *) &p->frame, sizeof(AMRNBFrame), buf + 1, amr_unpacking_bitmaps_per_mode[mode]); @@ -947,6 +951,10 @@ static int amrnb_decode_frame(AVCodecContext *avctx, void *data, buf_out = (float *)p->avframe.data[0]; p->cur_frame_mode = unpack_bitstream(p, buf, buf_size); + if (p->cur_frame_mode == NO_DATA) { + av_log(avctx, AV_LOG_ERROR, "Corrupt bitstream\n"); + return AVERROR_INVALIDDATA; + } if (p->cur_frame_mode == MODE_DTX) { av_log_missing_feature(avctx, "dtx mode", 1); return -1;