[FFmpeg-devel] [PATCH] Add Lame info tag to the Xing/Info header of mp3 files
Giovanni Motta
giovanni.motta at gmail.com
Fri May 23 02:31:09 CEST 2014
Add Lame info tag (with delay, padding, replay gain, signal peak, etc..)
to the Xing/Info header of mp3 files.
A few notes/comments:
- Fate initially failed for lavf.mp3; this is expected.
The test result has been updated with new CRC.
- The Lame info tag is generated by libmp3lame and passed to the mp3enc via extradata.
- To keep the size of the tag constant and simplify the code, vbr_scale is always added.
- The Lame string vendor in the tag is fixed length, so vendor is trimmed
to 9 bytes and padded with 0x20 if shorter.
Note: the current vendor string in ffmpeg is too long. The lame tags
currently generated doesn't work and the delay added after the string is
never parsed correctly.
- replay_gain and find_peak need a version of lame patched with
libmp3lame/lame.c Revision 1.367 (patch tracker item #66): http://sourceforge.net/p/lame/patches/66/
They have no effect otherwise.
- find_peak_sample only works if Lame is configured with --enable-decoder.
It has no effect otherwise.
- Some fields in the Lame tag are not set because not accessible from
the set/get API (preset and noise shaping, for example). I will bring this to
the attention of the Lame developers and help there with any change if we
decide to merge the patch.
Thanks
Giovanni
---
libavcodec/libmp3lame.c | 256 +++++++++++++++++++++++++++++++++++++++++++++++-
libavformat/mp3enc.c | 112 ++++++++++++++++-----
tests/ref/lavf-fate/mp3 | 2 +-
3 files changed, 344 insertions(+), 26 deletions(-)
diff --git a/libavcodec/libmp3lame.c b/libavcodec/libmp3lame.c
index a8c39cc..8f8b5ee 100644
--- a/libavcodec/libmp3lame.c
+++ b/libavcodec/libmp3lame.c
@@ -26,6 +26,7 @@
#include <lame/lame.h>
+#include "libavutil/avstring.h"
#include "libavutil/channel_layout.h"
#include "libavutil/common.h"
#include "libavutil/float_dsp.h"
@@ -40,6 +41,9 @@
#define BUFFER_SIZE (7200 + 2 * MPA_FRAME_SIZE + MPA_FRAME_SIZE / 4+1000) // FIXME: Buffer size to small? Adding 1000 to make up for it.
+/* size of the Lame Info tag added to the Xing/Info header */
+#define LAME_EXT_SIZE 40
+
typedef struct LAMEContext {
AVClass *class;
AVCodecContext *avctx;
@@ -48,6 +52,8 @@ typedef struct LAMEContext {
int buffer_index;
int buffer_size;
int reservoir;
+ int find_peak_sample;
+ int replay_gain;
int joint_stereo;
int abr;
float *samples_flt[2];
@@ -93,6 +99,10 @@ static av_cold int mp3lame_encode_init(AVCodecContext *avctx)
s->avctx = avctx;
+ /* extradata is used to store the Lame Info tag */
+ avctx->extradata = NULL;
+ avctx->extradata_size = 0;
+
/* initialize LAME and get defaults */
if ((s->gfp = lame_init()) == NULL)
return AVERROR(ENOMEM);
@@ -131,6 +141,12 @@ static av_cold int mp3lame_encode_init(AVCodecContext *avctx)
/* bit reservoir usage */
lame_set_disable_reservoir(s->gfp, !s->reservoir);
+ /* find peak sample */
+ lame_set_decode_on_the_fly(s->gfp, s->find_peak_sample);
+
+ /* compute replay gain */
+ lame_set_findReplayGain(s->gfp, s->replay_gain);
+
/* set specified parameters */
if (lame_init_params(s->gfp) < 0) {
ret = -1;
@@ -176,6 +192,226 @@ error:
s->buffer_size - s->buffer_index); \
} while (0)
+/* flow and comments adapted from PutLameVBR() in Lame's VbrTag.c */
+static int GetLameInfoTag(lame_global_flags const *gfp, uint8_t * extradata)
+{
+ int nBytesWritten = 0;
+
+ int enc_delay = lame_get_encoder_delay(gfp); // encoder delay
+ int enc_padding = lame_get_encoder_padding(gfp); // encoder padding
+
+ /* recall: gfp->VBR_q is for example set by the switch -V */
+ /* gfp->quality by -q, -h, -f, etc. */
+ int nQuality = (100 - 10 * lame_get_VBR_q(gfp) - lame_get_quality(gfp));
+
+ const char *szVersion = get_lame_very_short_version();
+ uint8_t nVBR;
+ uint8_t nRevision = 0x00;
+ uint8_t nRevMethod;
+
+ /* numbering is different in vbr_mode vs. Lame tag */
+ uint8_t vbr_type_translator[] = { 1, 5, 3, 2, 4, 0, 3 };
+
+ uint8_t nLowpass =
+ (((lame_get_lowpassfreq(gfp) / 100.0) + .5) > 255 ?
+ 255 : (lame_get_lowpassfreq(gfp) / 100.0) + .5);
+
+ uint32_t nPeakSignalAmplitude = 0;
+ uint16_t nRadioReplayGain = 0;
+ uint16_t nAudiophileReplayGain = 0;
+
+ uint8_t nNoiseShaping = 0;
+ uint8_t nStereoMode = 0;
+ int bNonOptimal = 0;
+ uint8_t nSourceFreq = 0;
+
+ uint8_t nMisc = 0;
+
+ size_t nMusicLength = 0;
+ uint16_t nMusicCRC = 0;
+ uint16_t nTagCRC = 0;
+
+ /* psy model type: Gpsycho or NsPsytune */
+ unsigned char bExpNPsyTune = lame_get_exp_nspsytune(gfp) & 1;
+ unsigned char bSafeJoint = (lame_get_exp_nspsytune(gfp) & 2) != 0;
+
+ unsigned char bNoGapMore = 0;
+ unsigned char bNoGapPrevious = 0;
+
+ int nNoGapCount = lame_get_nogap_total(gfp);
+ int nNoGapCurr = lame_get_nogap_currentindex(gfp);
+
+ uint8_t nAthType = lame_get_ATHtype(gfp); /* 4 bits */
+ int nInSampleRate = lame_get_in_samplerate(gfp);
+ uint8_t nFlags = 0;
+
+ /* if ABR, {store bitrate <= 255} else {store "-b"} */
+ int nABRBitrate;
+ switch (lame_get_VBR(gfp)) {
+ case vbr_abr:
+ nABRBitrate = lame_get_VBR_mean_bitrate_kbps(gfp);
+ break;
+ case vbr_off:
+ nABRBitrate = lame_get_brate(gfp);
+ break;
+ default: // vbr modes
+ nABRBitrate = lame_get_VBR_mean_bitrate_kbps(gfp);
+ }
+
+ /* revision and vbr method */
+ if (lame_get_VBR(gfp) < sizeof(vbr_type_translator))
+ nVBR = vbr_type_translator[lame_get_VBR(gfp)];
+ else
+ nVBR = 0x00; // unknown
+ nRevMethod = 0x10 * nRevision + nVBR;
+
+
+ /* ReplayGain */
+ if (lame_get_findReplayGain(gfp)) {
+ int nRadioGain = lame_get_RadioGain(gfp);
+ if (nRadioGain > 0x1FE)
+ nRadioGain = 0x1FE;
+ if (nRadioGain < -0x1FE)
+ nRadioGain = -0x1FE;
+
+ nRadioReplayGain = 0x2000; // set name code
+ nRadioReplayGain |= 0xC00; // set originator code to `determined automatically'
+
+ if (nRadioGain >= 0) {
+ nRadioReplayGain |= nRadioGain; // set gain adjustment
+ } else {
+ nRadioReplayGain |= 0x200; // set the sign bit
+ nRadioReplayGain |= -nRadioGain; // set gain adjustment
+ }
+ }
+
+ /* peak sample */
+ if (lame_get_decode_on_the_fly(gfp))
+ nPeakSignalAmplitude = abs((int) ((lame_get_PeakSample(gfp) / 32767.0) * pow(2, 23) + .5));
+
+ /* nogap */
+ if (nNoGapCount != -1) {
+ if (nNoGapCurr > 0)
+ bNoGapPrevious = 1;
+
+ if (nNoGapCurr < nNoGapCount - 1)
+ bNoGapMore = 1;
+ }
+
+ /* flags */
+ nFlags = nAthType + (bExpNPsyTune << 4)
+ + (bSafeJoint << 5)
+ + (bNoGapMore << 6)
+ + (bNoGapPrevious << 7);
+
+ if (nQuality < 0)
+ nQuality = 0;
+
+ /* stereo mode field... a bit ugly */
+ switch (lame_get_mode(gfp)) {
+ case MONO:
+ nStereoMode = 0;
+ break;
+ case STEREO:
+ nStereoMode = 1;
+ break;
+ case DUAL_CHANNEL:
+ nStereoMode = 2;
+ break;
+ case JOINT_STEREO:
+ if (lame_get_force_ms(gfp))
+ nStereoMode = 4;
+ else
+ nStereoMode = 3;
+ break;
+ case NOT_SET:
+ // FALLTHROUGH
+ default:
+ nStereoMode = 7;
+ break;
+ }
+
+ /* intensity stereo : nStereoMode = 6. IS is not implemented */
+ if (nInSampleRate <= 32000)
+ nSourceFreq = 0x00;
+ else if (nInSampleRate == 48000)
+ nSourceFreq = 0x02;
+ else if (nInSampleRate > 48000)
+ nSourceFreq = 0x03;
+ else
+ nSourceFreq = 0x01; // default is 44100Hz
+
+ /* check if the user overrided the default LAME behaviour with some nasty options */
+ if ((lame_get_no_short_blocks(gfp) == 1) || // short blocks dispensed
+ (lame_get_force_short_blocks(gfp) == 1) || // short blocks forced
+ ((lame_get_lowpassfreq(gfp) == -1) && (lame_get_highpassfreq(gfp) == -1)) || // "-k"
+ (lame_get_scale_left(gfp) < lame_get_scale_right(gfp)) ||
+ (lame_get_scale_left(gfp) > lame_get_scale_right(gfp)) ||
+ (lame_get_disable_reservoir(gfp) && lame_get_brate(gfp) < 320) ||
+ lame_get_noATH(gfp) || lame_get_ATHonly(gfp) || (nAthType == 0) ||
+ (nInSampleRate <= 32000))
+ bNonOptimal = 1;
+
+ nMisc = nNoiseShaping + (nStereoMode << 2)
+ + (bNonOptimal << 5)
+ + (nSourceFreq << 6);
+
+ /* write all this information to extradata */
+ AV_WB32(&extradata[nBytesWritten], nQuality);
+ nBytesWritten += 4;
+
+ av_strlcpy((char *) &extradata[nBytesWritten], szVersion, 9);
+ nBytesWritten += 9;
+
+ extradata[nBytesWritten] = nRevMethod;
+ nBytesWritten++;
+
+ extradata[nBytesWritten] = nLowpass;
+ nBytesWritten++;
+
+ AV_WB32(&extradata[nBytesWritten], nPeakSignalAmplitude);
+ nBytesWritten += 4;
+
+ AV_WB16(&extradata[nBytesWritten], nRadioReplayGain);
+ nBytesWritten += 2;
+
+ AV_WB16(&extradata[nBytesWritten], nAudiophileReplayGain);
+ nBytesWritten += 2;
+
+ extradata[nBytesWritten] = nFlags;
+ nBytesWritten++;
+
+ if (nABRBitrate >= 255)
+ extradata[nBytesWritten] = 0xFF;
+ else
+ extradata[nBytesWritten] = nABRBitrate;
+ nBytesWritten++;
+
+ extradata[nBytesWritten] = enc_delay >> 4;
+ extradata[nBytesWritten + 1] = (enc_delay << 4) + (enc_padding >> 8);
+ extradata[nBytesWritten + 2] = enc_padding;
+ nBytesWritten += 3;
+
+ extradata[nBytesWritten] = nMisc;
+ nBytesWritten++;
+
+ extradata[nBytesWritten++] = 0; // unused in rev0
+
+ AV_WB16(&extradata[nBytesWritten], 0);
+ nBytesWritten += 2;
+
+ AV_WB32(&extradata[nBytesWritten], (int) nMusicLength);
+ nBytesWritten += 4;
+
+ AV_WB16(&extradata[nBytesWritten], nMusicCRC);
+ nBytesWritten += 2;
+
+ AV_WB16(&extradata[nBytesWritten], nTagCRC);
+ nBytesWritten += 2;
+
+ return nBytesWritten;
+}
+
static int mp3lame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
const AVFrame *frame, int *got_packet_ptr)
{
@@ -213,6 +449,18 @@ static int mp3lame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
} else {
lame_result = lame_encode_flush(s->gfp, s->buffer + s->buffer_index,
s->buffer_size - s->buffer_index);
+ /* get Lame Info tag and store it in extradata */
+ if(avctx->extradata == NULL) {
+ avctx->extradata = av_malloc(LAME_EXT_SIZE);
+ avctx->extradata_size = GetLameInfoTag(s->gfp, avctx->extradata);
+ if (avctx->extradata_size != LAME_EXT_SIZE) {
+ av_log(avctx, AV_LOG_ERROR,
+ "error storing Lame info tag (%d bytes written instead of %d)\n",
+ avctx->extradata_size, LAME_EXT_SIZE);
+ } else {
+ av_log(avctx, AV_LOG_DEBUG, "lame info tag succesfully stored\n");
+ }
+ }
}
if (lame_result < 0) {
if (lame_result == -1) {
@@ -267,9 +515,11 @@ static int mp3lame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
#define OFFSET(x) offsetof(LAMEContext, x)
#define AE AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
static const AVOption options[] = {
- { "reservoir", "use bit reservoir", OFFSET(reservoir), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AE },
- { "joint_stereo", "use joint stereo", OFFSET(joint_stereo), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AE },
- { "abr", "use ABR", OFFSET(abr), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE },
+ { "reservoir", "use bit reservoir", OFFSET(reservoir), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AE },
+ { "find_peak_sample", "find peak sample", OFFSET(find_peak_sample), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE },
+ { "replay_gain", "compute replay gain", OFFSET(replay_gain), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE },
+ { "joint_stereo", "use joint stereo", OFFSET(joint_stereo), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AE },
+ { "abr", "use ABR", OFFSET(abr), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE },
{ NULL },
};
diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c
index 43f7656..fbb3303 100644
--- a/libavformat/mp3enc.c
+++ b/libavformat/mp3enc.c
@@ -77,8 +77,13 @@ static int id3v1_create_tag(AVFormatContext *s, uint8_t *buf)
#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)
+// maximum size of the xing frame: offset/Xing/flags/frames/size/TOC/vbr_scale
+#define XING_MAX_SIZE (32 + 4 + 4 + 4 + 4 + 4 + XING_TOC_SIZE)
+
+#define XING_FLAG_FRAMES 0x01
+#define XING_FLAG_SIZE 0x02
+#define XING_FLAG_TOC 0x04
+#define XING_FLAG_VBR_SCALE 0x08
typedef struct MP3Context {
const AVClass *class;
@@ -109,6 +114,15 @@ typedef struct MP3Context {
static const uint8_t xing_offtbl[2][2] = {{32, 17}, {17, 9}};
+/* Bitrates used to determine the size of a Xing header (MPEG1 and MPEG2) in kbps */
+#define XING_BITRATE1 128
+#define XING_BITRATE2 64
+#define XING_BITRATE25 32
+
+/* Size in bytes of the Lame Info tag added to the Xing/Info header */
+#define LAME_EXT_SIZE 40
+#define LAME_EXT_VENDOR_LEN 9
+
/*
* Write an empty XING header and initialize respective data.
*/
@@ -125,22 +139,46 @@ static int mp3_write_xing(AVFormatContext *s)
int xing_offset;
int ver = 0;
int bytes_needed;
- const char *vendor = (s->flags & AVFMT_FLAG_BITEXACT) ? "Lavf" : LIBAVFORMAT_IDENT;
+ int kbps_header;
if (!s->pb->seekable || !mp3->write_xing)
return 0;
+ /*
+ * Xing VBR pretends to be a 48kbs layer III frame. (at 44.1kHz).
+ * (at 48kHz they use 56kbs since 48kbs frame not big enough for
+ * table of contents)
+ * let's always embed Xing header inside a 64kbs layer III frame.
+ * this gives us enough room for a LAME version string too.
+ * size determined by sampling frequency (MPEG1)
+ * 32kHz: 216 bytes@ 48kbs 288 bytes@ 64kbs
+ * 44.1kHz: 156 bytes@ 48kbs 208 bytes@ 64kbs (+1 if padding = 1)
+ * 48kHz: 144 bytes@ 48kbs 192 bytes@ 64kbs
+ *
+ * MPEG 2 values are the same since the framesize and samplerate
+ * are each reduced by a factor of 2.
+ */
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;
-
+ if (codec->sample_rate == base_freq) {
+ ver = 0x3; // MPEG 1
+ kbps_header = XING_BITRATE1;
+ } else if (codec->sample_rate == base_freq / 2) {
+ ver = 0x2; // MPEG 2
+ kbps_header = XING_BITRATE2;
+ } else if (codec->sample_rate == base_freq / 4) {
+ ver = 0x0; // MPEG 2.5
+ kbps_header = XING_BITRATE25;
+ } else {
+ continue;
+ }
srate_idx = i;
break;
}
+
+ if (!mp3->has_variable_bitrate)
+ kbps_header = codec->bit_rate;
+
if (i == FF_ARRAY_ELEMS(avpriv_mpa_freq_tab)) {
av_log(s, AV_LOG_WARNING, "Unsupported sample rate, not writing Xing header.\n");
return -1;
@@ -162,7 +200,7 @@ static int mp3_write_xing(AVFormatContext *s)
for (bitrate_idx = 1; bitrate_idx < 15; bitrate_idx++) {
int bit_rate = 1000 * avpriv_mpa_bitrate_tab[ver != 3][3 - 1][bitrate_idx];
- int error = FFABS(bit_rate - codec->bit_rate);
+ int error = FFABS(bit_rate - kbps_header);
if (error < best_bitrate_error) {
best_bitrate_error = error;
@@ -179,14 +217,15 @@ static int mp3_write_xing(AVFormatContext *s)
avpriv_mpegaudio_decode_header(&mpah, header);
xing_offset=xing_offtbl[mpah.lsf == 1][mpah.nb_channels == 1];
- bytes_needed = 4 // header
+ bytes_needed = 4 // header
+ xing_offset
+ 4 // xing tag
- + 4 // frames/size/toc flags
+ + 4 // frames/size/toc/vbr_scale flags
+ 4 // frames
+ 4 // size
- + XING_TOC_SIZE // toc
- + 24
+ + XING_TOC_SIZE // toc
+ + 4 // vbr_scale
+ + LAME_EXT_SIZE // lame extension
;
if (bytes_needed <= mpah.frame_size)
@@ -200,7 +239,7 @@ static int mp3_write_xing(AVFormatContext *s)
ffio_fill(s->pb, 0, xing_offset);
mp3->xing_offset = avio_tell(s->pb);
ffio_wfourcc(s->pb, "Xing");
- avio_wb32(s->pb, 0x01 | 0x02 | 0x04); // frames / size / TOC
+ avio_wb32(s->pb, XING_FLAG_FRAMES | XING_FLAG_SIZE | XING_FLAG_TOC | XING_FLAG_VBR_SCALE); // frames / size / TOC / vbr_scale
mp3->size = mpah.frame_size;
mp3->want=1;
@@ -214,11 +253,10 @@ static int mp3_write_xing(AVFormatContext *s)
for (i = 0; i < XING_TOC_SIZE; ++i)
avio_w8(s->pb, (uint8_t)(255 * i / XING_TOC_SIZE));
- for (i = 0; i < strlen(vendor); ++i)
- avio_w8(s->pb, vendor[i]);
- for (; i < 21; ++i)
+ avio_wb32(s->pb, 0); // vbr_scale
+
+ for (i = 0; i < LAME_EXT_SIZE; ++i)
avio_w8(s->pb, 0);
- avio_wb24(s->pb, FFMAX(codec->delay - 528 - 1, 0)<<12);
ffio_fill(s->pb, 0, mpah.frame_size - bytes_needed);
@@ -324,6 +362,8 @@ static int mp3_queue_flush(AVFormatContext *s)
static void mp3_update_xing(AVFormatContext *s)
{
MP3Context *mp3 = s->priv_data;
+ AVCodecContext *codec = s->streams[mp3->audio_stream_idx]->codec;
+ const char *vendor = (s->flags & AVFMT_FLAG_BITEXACT) ? "Lavf" : LIBAVFORMAT_IDENT;
int i;
/* replace "Xing" identification string with "Info" for CBR files. */
@@ -344,6 +384,34 @@ static void mp3_update_xing(AVFormatContext *s)
avio_w8(s->pb, FFMIN(seek_point, 255));
}
+ /* add Lame Info tag. */
+ if (codec->extradata_size == LAME_EXT_SIZE) {
+ int64_t lame_tag_offset = mp3->xing_offset
+ + 4 // "Xing" or "Info"
+ + 4 // frames/size/toc/vbr_scale flags
+ + 4 // frame count
+ + 4 // stream size
+ + 100; // toc
+
+ /* extradata starts with vbr_scale */
+ avio_seek(s->pb, lame_tag_offset, SEEK_SET);
+
+ /* copy the tag from extradata */
+ avio_write(s->pb, codec->extradata, codec->extradata_size);
+
+ /* replace vendor string */
+ avio_seek(s->pb, lame_tag_offset + 4, SEEK_SET); // rewind and skip vbr_scale
+ for (i = 0; i < FFMIN(strlen(vendor), LAME_EXT_VENDOR_LEN); ++i)
+ avio_w8(s->pb, vendor[i]);
+ for (; i < LAME_EXT_VENDOR_LEN; ++i)
+ avio_w8(s->pb, 0x20);
+ } else if (codec->extradata_size != 0) {
+ av_log(s, AV_LOG_ERROR,
+ "lame info tag in extradata has incorrect size (%d vs. %d bytes)\n",
+ codec->extradata_size, LAME_EXT_SIZE);
+ }
+
+ avio_flush(s->pb);
avio_seek(s->pb, 0, SEEK_END);
}
@@ -363,7 +431,7 @@ static int mp3_write_trailer(struct AVFormatContext *s)
avio_write(s->pb, buf, ID3v1_TAG_SIZE);
}
- if (mp3->xing_offset)
+ if (mp3->write_xing && mp3->xing_offset)
mp3_update_xing(s);
return 0;
@@ -384,7 +452,7 @@ static int query_codec(enum AVCodecID id, int std_compliance)
AVOutputFormat ff_mp2_muxer = {
.name = "mp2",
.long_name = NULL_IF_CONFIG_SMALL("MP2 (MPEG audio layer 2)"),
- .mime_type = "audio/mpeg",
+ .mime_type = "audio/x-mpeg",
.extensions = "mp2,m2a,mpa",
.audio_codec = AV_CODEC_ID_MP2,
.video_codec = AV_CODEC_ID_NONE,
@@ -526,7 +594,7 @@ static int mp3_write_header(struct AVFormatContext *s)
AVOutputFormat ff_mp3_muxer = {
.name = "mp3",
.long_name = NULL_IF_CONFIG_SMALL("MP3 (MPEG audio layer 3)"),
- .mime_type = "audio/mpeg",
+ .mime_type = "audio/x-mpeg",
.extensions = "mp3",
.priv_data_size = sizeof(MP3Context),
.audio_codec = AV_CODEC_ID_MP3,
diff --git a/tests/ref/lavf-fate/mp3 b/tests/ref/lavf-fate/mp3
index 6f201e0..5381e0e 100644
--- a/tests/ref/lavf-fate/mp3
+++ b/tests/ref/lavf-fate/mp3
@@ -1,3 +1,3 @@
-6bdea919dc6856d76ef2553698e2b0d3 *./tests/data/lavf-fate/lavf.mp3
+e062b13f521a06e5ee579a48600974a0 *./tests/data/lavf-fate/lavf.mp3
96376 ./tests/data/lavf-fate/lavf.mp3
./tests/data/lavf-fate/lavf.mp3 CRC=0x6c9850fe
--
1.9.1.423.g4596e3a
More information about the ffmpeg-devel
mailing list