From cb6632809d27a0dfe2f63fea1c656bd39ce046ed Mon Sep 17 00:00:00 2001 From: Mans Rullgard Date: Sat, 25 Aug 2012 11:51:57 +0100 Subject: [PATCH 01/10] libavcodec: remove av_destruct_packet_nofree() This function was deprecated two major versions ago (2009). Signed-off-by: Mans Rullgard --- libavcodec/avcodec.h | 5 ----- libavcodec/avpacket.c | 11 +---------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 8a091bd524..d0c5e07d10 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -3333,11 +3333,6 @@ void avsubtitle_free(AVSubtitle *sub); * @{ */ -/** - * @deprecated use NULL instead - */ -attribute_deprecated void av_destruct_packet_nofree(AVPacket *pkt); - /** * Default packet destructor. */ diff --git a/libavcodec/avpacket.c b/libavcodec/avpacket.c index 3344cf9f0b..cb24948a48 100644 --- a/libavcodec/avpacket.c +++ b/libavcodec/avpacket.c @@ -25,14 +25,6 @@ #include "libavutil/mem.h" #include "avcodec.h" -void av_destruct_packet_nofree(AVPacket *pkt) -{ - pkt->data = NULL; - pkt->size = 0; - pkt->side_data = NULL; - pkt->side_data_elems = 0; -} - void av_destruct_packet(AVPacket *pkt) { int i; @@ -131,8 +123,7 @@ int av_dup_packet(AVPacket *pkt) { AVPacket tmp_pkt; - if (((pkt->destruct == av_destruct_packet_nofree) || - (pkt->destruct == NULL)) && pkt->data) { + if (pkt->destruct == NULL && pkt->data) { tmp_pkt = *pkt; pkt->data = NULL; From 990450c5bf17afc31a81d6225afaac86d0dca5dd Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Tue, 11 Sep 2012 11:03:52 +0200 Subject: [PATCH 02/10] cmdutils: avoid setting data pointers to invalid values in alloc_buffer() Fixes bug 352. --- cmdutils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmdutils.c b/cmdutils.c index 6fb991884f..0d216db469 100644 --- a/cmdutils.c +++ b/cmdutils.c @@ -1316,7 +1316,7 @@ static int alloc_buffer(FrameBuffer **pool, AVCodecContext *s, FrameBuffer **pbu const int v_shift = i==0 ? 0 : v_chroma_shift; if (s->flags & CODEC_FLAG_EMU_EDGE) buf->data[i] = buf->base[i]; - else + else if (buf->base[i]) buf->data[i] = buf->base[i] + FFALIGN((buf->linesize[i]*edge >> v_shift) + (pixel_size*edge >> h_shift), 32); From 0443879089f29e53e79d473076b99d7618ee673f Mon Sep 17 00:00:00 2001 From: Andrey Utkin Date: Fri, 14 Sep 2012 11:27:19 +0300 Subject: [PATCH 03/10] Enhance doc on asyncts audiofilter Signed-off-by: Anton Khirnov --- doc/filters.texi | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index e77256e005..4825b0d547 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -196,14 +196,17 @@ The filter accepts the following named parameters: @table @option @item compensate -Enable stretching/squeezing the data to make it match the timestamps. +Enable stretching/squeezing the data to make it match the timestamps. Disabled +by default. When disabled, time gaps are covered with silence. @item min_delta Minimum difference between timestamps and audio data (in seconds) to trigger -adding/dropping samples. +adding/dropping samples. Default value is 0.1. If you get non-perfect sync with +this filter, try setting this parameter to 0. @item max_comp -Maximum compensation in samples per second. +Maximum compensation in samples per second. Relevant only with compensate=1. +Default value 500. @item first_pts Assume the first pts should be this value. From 5d1203f0635a0b14bea6cc609026936bd7ae9e3a Mon Sep 17 00:00:00 2001 From: Stefano Sabatini Date: Thu, 16 Aug 2012 01:25:05 +0200 Subject: [PATCH 04/10] avio: flush the internal buffer in avio_close() This is consistent with stdio, and thus what people would naturally expect. --- libavformat/avio.h | 3 +++ libavformat/aviobuf.c | 1 + libavformat/img2enc.c | 2 -- libavformat/version.h | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libavformat/avio.h b/libavformat/avio.h index 10c0a12ccb..55c96bc432 100644 --- a/libavformat/avio.h +++ b/libavformat/avio.h @@ -349,6 +349,9 @@ int avio_open2(AVIOContext **s, const char *url, int flags, * Close the resource accessed by the AVIOContext s and free it. * This function can only be used if s was opened by avio_open(). * + * The internal buffer is automatically flushed before closing the + * resource. + * * @return 0 on success, an AVERROR < 0 on error. */ int avio_close(AVIOContext *s); diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c index fb01613298..7dc66e25a6 100644 --- a/libavformat/aviobuf.c +++ b/libavformat/aviobuf.c @@ -761,6 +761,7 @@ int avio_close(AVIOContext *s) if (!s) return 0; + avio_flush(s); h = s->opaque; av_freep(&s->buffer); av_free(s); diff --git a/libavformat/img2enc.c b/libavformat/img2enc.c index 6273af94f8..bf183560e0 100644 --- a/libavformat/img2enc.c +++ b/libavformat/img2enc.c @@ -86,8 +86,6 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) avio_write(pb[0], pkt->data , ysize); avio_write(pb[1], pkt->data + ysize, (pkt->size - ysize)/2); avio_write(pb[2], pkt->data + ysize +(pkt->size - ysize)/2, (pkt->size - ysize)/2); - avio_flush(pb[1]); - avio_flush(pb[2]); avio_close(pb[1]); avio_close(pb[2]); }else{ diff --git a/libavformat/version.h b/libavformat/version.h index fa4d49a33a..a86f35a6b4 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -31,7 +31,7 @@ #define LIBAVFORMAT_VERSION_MAJOR 54 #define LIBAVFORMAT_VERSION_MINOR 16 -#define LIBAVFORMAT_VERSION_MICRO 0 +#define LIBAVFORMAT_VERSION_MICRO 1 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ From 0c270239c2acec8cf2f3924e2b956e15a41e8d1c Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 9 Sep 2012 20:47:38 +0200 Subject: [PATCH 05/10] lavf: cosmetics, reformat av_write_trailer(). --- libavformat/utils.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libavformat/utils.c b/libavformat/utils.c index c0da7f2fb9..b555ad0ff7 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -3250,28 +3250,28 @@ int av_write_trailer(AVFormatContext *s) { int ret, i; - for(;;){ + for (;;) { AVPacket pkt; - ret= interleave_packet(s, &pkt, NULL, 1); - if(ret<0) //FIXME cleanup needed for ret<0 ? + ret = interleave_packet(s, &pkt, NULL, 1); + if (ret < 0) //FIXME cleanup needed for ret<0 ? goto fail; - if(!ret) + if (!ret) break; - ret= s->oformat->write_packet(s, &pkt); + ret = s->oformat->write_packet(s, &pkt); if (ret >= 0) s->streams[pkt.stream_index]->nb_frames++; av_free_packet(&pkt); - if(ret<0) + if (ret < 0) goto fail; } - if(s->oformat->write_trailer) + if (s->oformat->write_trailer) ret = s->oformat->write_trailer(s); fail: - for(i=0;inb_streams;i++) { + for (i = 0; i < s->nb_streams; i++) { av_freep(&s->streams[i]->priv_data); av_freep(&s->streams[i]->index_entries); } From 3b4bb19e63b41a0a542ba3ef254443b2e76a6a3e Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sun, 9 Sep 2012 21:35:23 +0200 Subject: [PATCH 06/10] lavf: flush the output AVIOContext in av_write_trailer(). This is consistent with stdio and is what we want to do in all cases. Fixes a bug in the voc muxer which didn't flush in write_trailer() previously. This is the cause of the change in the test results. --- libavformat/asfenc.c | 1 - libavformat/assenc.c | 2 -- libavformat/avienc.c | 1 - libavformat/crcenc.c | 2 +- libavformat/ffmenc.c | 3 --- libavformat/ffmetaenc.c | 2 -- libavformat/filmstripenc.c | 2 +- libavformat/gif.c | 2 +- libavformat/matroskaenc.c | 2 +- libavformat/movenc.c | 2 -- libavformat/mxfenc.c | 2 -- libavformat/nutenc.c | 2 +- libavformat/rmenc.c | 2 +- libavformat/rsoenc.c | 2 -- libavformat/smjpegenc.c | 1 - libavformat/swfenc.c | 2 -- libavformat/utils.c | 4 ++++ tests/ref/lavf/voc | 6 +++--- tests/ref/lavf/voc_s16 | 6 +++--- 19 files changed, 16 insertions(+), 30 deletions(-) diff --git a/libavformat/asfenc.c b/libavformat/asfenc.c index bcb741e04d..5c820becb2 100644 --- a/libavformat/asfenc.c +++ b/libavformat/asfenc.c @@ -872,7 +872,6 @@ static int asf_write_trailer(AVFormatContext *s) asf_write_header1(s, file_size, data_size - asf->data_offset); } - avio_flush(s->pb); av_free(asf->index_ptr); return 0; } diff --git a/libavformat/assenc.c b/libavformat/assenc.c index 1ae8680597..5bf2e20134 100644 --- a/libavformat/assenc.c +++ b/libavformat/assenc.c @@ -72,8 +72,6 @@ static int write_trailer(AVFormatContext *s) avio_write(s->pb, avctx->extradata + ass->extra_index, avctx->extradata_size - ass->extra_index); - avio_flush(s->pb); - return 0; } diff --git a/libavformat/avienc.c b/libavformat/avienc.c index 40fd7adda8..86698794df 100644 --- a/libavformat/avienc.c +++ b/libavformat/avienc.c @@ -626,7 +626,6 @@ static int avi_write_trailer(AVFormatContext *s) avi_write_counters(s, avi->riff_id); } } - avio_flush(pb); for (i=0; inb_streams; i++) { AVIStream *avist= s->streams[i]->priv_data; diff --git a/libavformat/crcenc.c b/libavformat/crcenc.c index 4a13f1cd5d..3b30cc9199 100644 --- a/libavformat/crcenc.c +++ b/libavformat/crcenc.c @@ -50,7 +50,7 @@ static int crc_write_trailer(struct AVFormatContext *s) snprintf(buf, sizeof(buf), "CRC=0x%08x\n", crc->crcval); avio_write(s->pb, buf, strlen(buf)); - avio_flush(s->pb); + return 0; } diff --git a/libavformat/ffmenc.c b/libavformat/ffmenc.c index 806930948b..c020672bf1 100644 --- a/libavformat/ffmenc.c +++ b/libavformat/ffmenc.c @@ -226,15 +226,12 @@ static int ffm_write_packet(AVFormatContext *s, AVPacket *pkt) static int ffm_write_trailer(AVFormatContext *s) { - AVIOContext *pb = s->pb; FFMContext *ffm = s->priv_data; /* flush packets */ if (ffm->packet_ptr > ffm->packet) flush_packet(s); - avio_flush(pb); - return 0; } diff --git a/libavformat/ffmetaenc.c b/libavformat/ffmetaenc.c index f75efea876..19fe6c960f 100644 --- a/libavformat/ffmetaenc.c +++ b/libavformat/ffmetaenc.c @@ -80,8 +80,6 @@ static int write_trailer(AVFormatContext *s) write_tags(s->pb, ch->metadata); } - avio_flush(s->pb); - return 0; } diff --git a/libavformat/filmstripenc.c b/libavformat/filmstripenc.c index 91706fb993..d000c4f9f5 100644 --- a/libavformat/filmstripenc.c +++ b/libavformat/filmstripenc.c @@ -67,7 +67,7 @@ static int write_trailer(AVFormatContext *s) avio_wb16(pb, 1/av_q2d(st->codec->time_base)); for (i = 0; i < 16; i++) avio_w8(pb, 0x00); // reserved - avio_flush(pb); + return 0; } diff --git a/libavformat/gif.c b/libavformat/gif.c index bfe63f3617..f11b267033 100644 --- a/libavformat/gif.c +++ b/libavformat/gif.c @@ -347,7 +347,7 @@ static int gif_write_trailer(AVFormatContext *s) AVIOContext *pb = s->pb; avio_w8(pb, 0x3b); - avio_flush(s->pb); + return 0; } diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 2400a6b914..9d9c223dbb 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -1265,7 +1265,7 @@ static int mkv_write_trailer(AVFormatContext *s) av_freep(&mkv->cues->entries); av_freep(&mkv->cues); av_destruct_packet(&mkv->cur_audio_pkt); - avio_flush(pb); + return 0; } diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 441da5c3c2..90c5806f50 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -3237,8 +3237,6 @@ static int mov_write_trailer(AVFormatContext *s) } - avio_flush(pb); - av_freep(&mov->tracks); return res; diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c index f25e08bb38..3d32be354a 100644 --- a/libavformat/mxfenc.c +++ b/libavformat/mxfenc.c @@ -1804,8 +1804,6 @@ static int mxf_write_footer(AVFormatContext *s) } } - avio_flush(pb); - ff_audio_interleave_close(s); av_freep(&mxf->index_entries); diff --git a/libavformat/nutenc.c b/libavformat/nutenc.c index 9675af176e..df0301b5e7 100644 --- a/libavformat/nutenc.c +++ b/libavformat/nutenc.c @@ -851,7 +851,7 @@ static int nut_write_trailer(AVFormatContext *s){ while(nut->header_count<3) write_headers(s, bc); - avio_flush(bc); + ff_nut_free_sp(nut); av_freep(&nut->stream); av_freep(&nut->chapter); diff --git a/libavformat/rmenc.c b/libavformat/rmenc.c index 63202b1221..ed1ba7c75b 100644 --- a/libavformat/rmenc.c +++ b/libavformat/rmenc.c @@ -455,7 +455,7 @@ static int rm_write_trailer(AVFormatContext *s) avio_wb32(pb, 0); avio_wb32(pb, 0); } - avio_flush(pb); + return 0; } diff --git a/libavformat/rsoenc.c b/libavformat/rsoenc.c index 4d560cbca0..cc76f9afd2 100644 --- a/libavformat/rsoenc.c +++ b/libavformat/rsoenc.c @@ -95,8 +95,6 @@ static int rso_write_trailer(AVFormatContext *s) avio_wb16(pb, coded_file_size); avio_seek(pb, file_size, SEEK_SET); - avio_flush(pb); - return 0; } diff --git a/libavformat/smjpegenc.c b/libavformat/smjpegenc.c index 86b6afaa16..59ede7a266 100644 --- a/libavformat/smjpegenc.c +++ b/libavformat/smjpegenc.c @@ -130,7 +130,6 @@ static int smjpeg_write_trailer(AVFormatContext *s) } avio_wl32(pb, SMJPEG_DONE); - avio_flush(pb); return 0; } diff --git a/libavformat/swfenc.c b/libavformat/swfenc.c index 19166503e8..9de8b679d7 100644 --- a/libavformat/swfenc.c +++ b/libavformat/swfenc.c @@ -485,8 +485,6 @@ static int swf_write_trailer(AVFormatContext *s) put_swf_tag(s, TAG_END); put_swf_end_tag(s); - avio_flush(s->pb); - /* patch file size and number of frames if not streamed */ if (s->pb->seekable && video_enc) { file_size = avio_tell(pb); diff --git a/libavformat/utils.c b/libavformat/utils.c index b555ad0ff7..b5b49c93c4 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -3270,6 +3270,10 @@ int av_write_trailer(AVFormatContext *s) if (s->oformat->write_trailer) ret = s->oformat->write_trailer(s); + + if (!(s->oformat->flags & AVFMT_NOFILE)) + avio_flush(s->pb); + fail: for (i = 0; i < s->nb_streams; i++) { av_freep(&s->streams[i]->priv_data); diff --git a/tests/ref/lavf/voc b/tests/ref/lavf/voc index 25e8b44434..ea903b6ce7 100644 --- a/tests/ref/lavf/voc +++ b/tests/ref/lavf/voc @@ -1,3 +1,3 @@ -b0bc287ce4e3eef7c1012610dd7ff6d0 *./tests/data/lavf/lavf.voc -32768 ./tests/data/lavf/lavf.voc -./tests/data/lavf/lavf.voc CRC=0xa2d77c12 +5c4ee01048e7a8a138a97e80cf7a1924 *./tests/data/lavf/lavf.voc +45261 ./tests/data/lavf/lavf.voc +./tests/data/lavf/lavf.voc CRC=0x74b2b546 diff --git a/tests/ref/lavf/voc_s16 b/tests/ref/lavf/voc_s16 index 425d9655ad..d53c9506e6 100644 --- a/tests/ref/lavf/voc_s16 +++ b/tests/ref/lavf/voc_s16 @@ -1,3 +1,3 @@ -b20728bf036d2e23508869acbad4e576 *./tests/data/lavf/lavf.s16.voc -163840 ./tests/data/lavf/lavf.s16.voc -./tests/data/lavf/lavf.s16.voc CRC=0xfa9b6c39 +8ed10b311e49b4d4b18679b126492159 *./tests/data/lavf/lavf.s16.voc +180437 ./tests/data/lavf/lavf.s16.voc +./tests/data/lavf/lavf.s16.voc CRC=0x7bd585ff From 6365e4db79cc1a8c2c153e73828e922962d1086e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reimar=20D=C3=B6ffinger?= Date: Sun, 9 Sep 2012 20:39:40 +0200 Subject: [PATCH 07/10] mp3enc: downgrade some errors in writing Xing frame to warnings Also clarify the meaning of the log message. --- libavformat/mp3enc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c index fac39d9efd..602071cf05 100644 --- a/libavformat/mp3enc.c +++ b/libavformat/mp3enc.c @@ -110,14 +110,17 @@ static void mp3_write_xing(AVFormatContext *s) break; } if (i == FF_ARRAY_ELEMS(avpriv_mpa_freq_tab)) { - av_log(s, AV_LOG_ERROR, "Unsupported sample rate.\n"); + av_log(s, AV_LOG_WARNING, "Unsupported sample rate, not writing Xing " + "header.\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; + default: av_log(s, AV_LOG_WARNING, "Unsupported number of channels, " + "not writing Xing header.\n"); + return; } /* dummy MPEG audio header */ From ca8e39dd0d2ed737bcf025236be9fdd1bd05cc4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20B=C5=93sch?= Date: Wed, 9 May 2012 22:39:40 +0200 Subject: [PATCH 08/10] mp3enc: support MPEG-2 and MPEG-2.5 in Xing header. --- libavformat/mp3enc.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c index 602071cf05..6a6e60226e 100644 --- a/libavformat/mp3enc.c +++ b/libavformat/mp3enc.c @@ -90,25 +90,34 @@ typedef struct MP3Context { AVPacketList *queue, *queue_end; } MP3Context; +static const uint8_t xing_offtbl[2][2] = {{32, 17}, {17, 9}}; + /* insert a dummy frame containing number of frames */ static void mp3_write_xing(AVFormatContext *s) { MP3Context *mp3 = s->priv_data; 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; MPADecodeHeader mpah; int srate_idx, i, channels; + int xing_offset; + int ver = 0; 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; - } + for (i = 0; i < FF_ARRAY_ELEMS(avpriv_mpa_freq_tab); i++) { + const uint16_t base_freq = avpriv_mpa_freq_tab[i]; + + if (codec->sample_rate == base_freq) ver = 0x3; // MPEG 1 + else if (codec->sample_rate == base_freq / 2) ver = 0x2; // MPEG 2 + else if (codec->sample_rate == base_freq / 4) ver = 0x0; // MPEG 2.5 + else continue; + + srate_idx = i; + break; + } if (i == FF_ARRAY_ELEMS(avpriv_mpa_freq_tab)) { av_log(s, AV_LOG_WARNING, "Unsupported sample rate, not writing Xing " "header.\n"); @@ -125,13 +134,14 @@ static void mp3_write_xing(AVFormatContext *s) /* 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 |= (0x7 << 5 | ver << 3 | 0x1 << 1 | 0x1) << 16; // sync/audio-version/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); + xing_offset = xing_offtbl[ver != 3][codec->channels == 1]; ffio_fill(s->pb, 0, xing_offset); ffio_wfourcc(s->pb, "Xing"); avio_wb32(s->pb, 0x1); // only number of frames From 7040c9fac246ad9f8333d635045d24bc107ecfa8 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 10 Sep 2012 14:44:32 +0200 Subject: [PATCH 09/10] mp3enc: write Xing TOC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Based on the code by: Peter Belkner , Michael Niedermayer , Clément Bœsch , Reimar Döffinger , and Tobias Rapp Alex Converse Signed-off-by: Anton Khirnov --- libavformat/mp3enc.c | 140 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 120 insertions(+), 20 deletions(-) diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c index 6a6e60226e..c969777255 100644 --- a/libavformat/mp3enc.c +++ b/libavformat/mp3enc.c @@ -74,12 +74,27 @@ static int id3v1_create_tag(AVFormatContext *s, uint8_t *buf) return count; } +#define XING_NUM_BAGS 400 +#define XING_TOC_SIZE 100 +// maximum size of the xing frame: offset/Xing/flags/frames/size/TOC +#define XING_MAX_SIZE (32 + 4 + 4 + 4 + 4 + XING_TOC_SIZE) + typedef struct MP3Context { const AVClass *class; ID3v2EncContext id3; int id3v2_version; int write_id3v1; - int64_t nb_frames_offset; + + /* xing header */ + int64_t xing_offset; + int32_t frames; + int32_t size; + uint32_t want; + uint32_t seen; + uint32_t pos; + uint64_t bag[XING_NUM_BAGS]; + int initial_bitrate; + int has_variable_bitrate; /* index of the audio stream */ int audio_stream_idx; @@ -92,15 +107,17 @@ typedef struct MP3Context { static const uint8_t xing_offtbl[2][2] = {{32, 17}, {17, 9}}; -/* insert a dummy frame containing number of frames */ +/* + * Write an empty XING header and initialize respective data. + */ static void mp3_write_xing(AVFormatContext *s) { MP3Context *mp3 = s->priv_data; AVCodecContext *codec = s->streams[mp3->audio_stream_idx]->codec; - int bitrate_idx = 1; // 32 kbps int32_t header; MPADecodeHeader mpah; int srate_idx, i, channels; + int bitrate_idx; int xing_offset; int ver = 0; @@ -132,6 +149,9 @@ static void mp3_write_xing(AVFormatContext *s) return; } + /* 64 kbps frame, should be large enough */ + bitrate_idx = (ver == 3) ? 5 : 8; + /* dummy MPEG audio header */ header = 0xff << 24; // sync header |= (0x7 << 5 | ver << 3 | 0x1 << 1 | 0x1) << 16; // sync/audio-version/layer 3/no crc*/ @@ -141,17 +161,78 @@ static void mp3_write_xing(AVFormatContext *s) avpriv_mpegaudio_decode_header(&mpah, header); + av_assert0(mpah.frame_size >= XING_MAX_SIZE); + xing_offset = xing_offtbl[ver != 3][codec->channels == 1]; ffio_fill(s->pb, 0, xing_offset); + mp3->xing_offset = avio_tell(s->pb); 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); + avio_wb32(s->pb, 0x01 | 0x02 | 0x04); // frames / size / TOC - mpah.frame_size -= 4 + xing_offset + 4 + 4 + 4; + mp3->size = mpah.frame_size; + mp3->want = 1; + + avio_wb32(s->pb, 0); // frames + avio_wb32(s->pb, 0); // size + + // TOC + for (i = 0; i < XING_TOC_SIZE; i++) + avio_w8(s->pb, 255 * i / XING_TOC_SIZE); + + mpah.frame_size -= 4 + xing_offset + 4 + 4 + 4 + 4 + XING_TOC_SIZE; ffio_fill(s->pb, 0, mpah.frame_size); } +/* + * Add a frame to XING data. + * Following lame's "VbrTag.c". + */ +static void mp3_xing_add_frame(MP3Context *mp3, AVPacket *pkt) +{ + int i; + + mp3->frames++; + mp3->seen++; + mp3->size += pkt->size; + + if (mp3->want == mp3->seen) { + mp3->bag[mp3->pos] = mp3->size; + + if (XING_NUM_BAGS == ++mp3->pos) { + /* shrink table to half size by throwing away each second bag. */ + for (i = 1; i < XING_NUM_BAGS; i += 2) + mp3->bag[i / 2] = mp3->bag[i]; + + /* double wanted amount per bag. */ + mp3->want *= 2; + /* adjust current position to half of table size. */ + mp3->pos = XING_NUM_BAGS / 2; + } + + mp3->seen = 0; + } +} + +static int mp3_write_audio_packet(AVFormatContext *s, AVPacket *pkt) +{ + MP3Context *mp3 = s->priv_data; + + if (mp3->xing_offset && pkt->size >= 4) { + MPADecodeHeader c; + + avpriv_mpegaudio_decode_header(&c, AV_RB32(pkt->data)); + + if (!mp3->initial_bitrate) + mp3->initial_bitrate = c.bit_rate; + if ((c.bit_rate == 0) || (mp3->initial_bitrate != c.bit_rate)) + mp3->has_variable_bitrate = 1; + + mp3_xing_add_frame(mp3, pkt); + } + + return ff_raw_write_packet(s, pkt); +} + static int mp3_queue_flush(AVFormatContext *s) { MP3Context *mp3 = s->priv_data; @@ -162,7 +243,7 @@ static int mp3_queue_flush(AVFormatContext *s) mp3_write_xing(s); while ((pktl = mp3->queue)) { - if (write && (ret = ff_raw_write_packet(s, &pktl->pkt)) < 0) + if (write && (ret = mp3_write_audio_packet(s, &pktl->pkt)) < 0) write = 0; av_free_packet(&pktl->pkt); mp3->queue = pktl->next; @@ -172,30 +253,50 @@ static int mp3_queue_flush(AVFormatContext *s) return ret; } +static void mp3_update_xing(AVFormatContext *s) +{ + MP3Context *mp3 = s->priv_data; + int i; + + /* replace "Xing" identification string with "Info" for CBR files. */ + if (!mp3->has_variable_bitrate) { + avio_seek(s->pb, mp3->xing_offset, SEEK_SET); + ffio_wfourcc(s->pb, "Info"); + } + + avio_seek(s->pb, mp3->xing_offset + 8, SEEK_SET); + avio_wb32(s->pb, mp3->frames); + avio_wb32(s->pb, mp3->size); + + avio_w8(s->pb, 0); // first toc entry has to be zero. + + for (i = 1; i < XING_TOC_SIZE; ++i) { + int j = i * mp3->pos / XING_TOC_SIZE; + int seek_point = 256LL * mp3->bag[j] / mp3->size; + avio_w8(s->pb, FFMIN(seek_point, 255)); + } + + avio_seek(s->pb, 0, SEEK_END); +} + 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) { + if (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) { + if (mp3->write_id3v1 && id3v1_create_tag(s, buf) > 0) { avio_write(s->pb, buf, ID3v1_TAG_SIZE); } - /* 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[mp3->audio_stream_idx]->nb_frames); - avio_seek(s->pb, 0, SEEK_END); - } - - avio_flush(s->pb); + if (mp3->xing_offset) + mp3_update_xing(s); return 0; } @@ -209,7 +310,6 @@ AVOutputFormat ff_mp2_muxer = { .audio_codec = AV_CODEC_ID_MP2, .video_codec = AV_CODEC_ID_NONE, .write_packet = ff_raw_write_packet, - .write_trailer = mp3_write_trailer, .flags = AVFMT_NOTIMESTAMPS, }; #endif @@ -251,7 +351,7 @@ static int mp3_write_packet(AVFormatContext *s, AVPacket *pkt) mp3->queue = pktl; mp3->queue_end = pktl; } else - return ff_raw_write_packet(s, pkt); + return mp3_write_audio_packet(s, pkt); } else { int ret; From 3f7fd59d151a2773f0e2e93e56b6b13ec6e5334b Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Sat, 15 Sep 2012 20:16:32 +0200 Subject: [PATCH 10/10] avformat: fix typo in avformat_close_input The condition should not be &&. --- libavformat/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavformat/utils.c b/libavformat/utils.c index b5b49c93c4..e4e4a8b445 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -2704,7 +2704,7 @@ void avformat_close_input(AVFormatContext **ps) AVFormatContext *s = *ps; AVIOContext *pb = s->pb; - if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) && + if ((s->iformat && s->iformat->flags & AVFMT_NOFILE) || (s->flags & AVFMT_FLAG_CUSTOM_IO)) pb = NULL;