[MPlayer-dev-eng] [PATCH] Added Multi-channel MP3 on MP4 audio decoding
Larry Ruedisueli
lwr at audioresearchlabs.com
Tue Nov 16 22:03:03 CET 2004
I'm still hoping this patch might get excepted. I put two
mp4 movie test clips with 5.1 audio tracks at:
http://www.audioresearchlabs.com/mplayer/red.mp4
http://www.audioresearchlabs.com/mplayer/lotr.mp4
We've been considering making a similar patch for mencoder
so that it can produce mp4 movie files with 5.1 mp3 audio,
let me know if there is any interest.
Thanks,
Larry
Larry Ruedisueli wrote:
> This patch allows mplayer to decode mp4 files which contain a
> multi-channel mp3 audio track as specified in
> ISO/IEC 14496-3:2001/FPDAM 3 (MP3onMP4).
>
> Added two lines of code to demux_mov.c to test for indication
> of mp3on4 and set the correct audio format. Assigned new
> format as 29, since that is the value of AAC audioObjectType
> used to indicate mp3on4.
>
> Added new file, libmpcodecs/ad_mp3on4.c, which splits the
> MP4 access unit into seperate mp3 audio frames (one for
> each channel or channel pair) and calls the mp3 decoder.
> The ffmpeg mp3 decoder was chosen since it allows multiple
> instances.
>
> Added appropriate lines to etc/codecs.conf, libmpcodecs/Makefile
> and libmpcodecs/ad.c for new file.
>
> Note, when I tested this on win32 I discovered that the ffmpeg
> mp3 (mpegaudiodec.c) decoder did not work correctly (with or
> without my mods) with -O4 optimization, I had to set it to -O2,
> and then all was ok. Everything was fine on linux.
>
> Larry
>
>
> ------------------------------------------------------------------------
>
> ? libmpcodecs/ad_mp3on4.c
> Index: etc/codecs.conf
> ===================================================================
> RCS file: /cvsroot/mplayer/main/etc/codecs.conf,v
> retrieving revision 1.360
> diff -u -r1.360 codecs.conf
> --- etc/codecs.conf 16 Sep 2004 19:42:54 -0000 1.360
> +++ etc/codecs.conf 21 Sep 2004 14:43:53 -0000
> @@ -2145,6 +2145,14 @@
> driver ffmpeg
> dll "sonic"
>
> +audiocodec mp3on4
> + info "Multi-channel MPEG layer-3 on MP4 audio decoder"
> + comment "uses ffmpeg mp3 decoder"
> + status working
> + format 29
> + driver mp3on4
> + dll "mp3"
> +
> audiocodec ffmp3
> info "FFmpeg MPEG layer-3 audio decoder"
> comment "integer only"
> Index: libmpcodecs/Makefile
> ===================================================================
> RCS file: /cvsroot/mplayer/main/libmpcodecs/Makefile,v
> retrieving revision 1.135
> diff -u -r1.135 Makefile
> --- libmpcodecs/Makefile 11 Sep 2004 13:08:34 -0000 1.135
> +++ libmpcodecs/Makefile 21 Sep 2004 14:43:55 -0000
> @@ -6,7 +6,7 @@
>
> AUDIO_SRCS_LIB=ad_liba52.c ad_hwac3.c ad_mp3lib.c
> AUDIO_SRCS_NAT=ad_alaw.c ad_dk3adpcm.c ad_pcm.c ad_dvdpcm.c ad_imaadpcm.c ad_msadpcm.c ad_msgsm.c ad_ra1428.c
> -AUDIO_SRCS_OPT=ad_acm.c ad_dshow.c ad_dmo.c ad_qtaudio.c ad_ffmpeg.c ad_faad.c ad_libvorbis.c ad_libmad.c ad_realaud.c ad_libdv.c
> +AUDIO_SRCS_OPT=ad_acm.c ad_dshow.c ad_dmo.c ad_qtaudio.c ad_ffmpeg.c ad_faad.c ad_libvorbis.c ad_libmad.c ad_realaud.c ad_libdv.c ad_mp3on4.c
> AUDIO_SRCS=dec_audio.c ad.c $(AUDIO_SRCS_LIB) $(AUDIO_SRCS_NAT) $(AUDIO_SRCS_OPT)
>
> VIDEO_SRCS_LIB=vd_libmpeg2.c vd_nuv.c vd_lzo.c
> Index: libmpcodecs/ad.c
> ===================================================================
> RCS file: /cvsroot/mplayer/main/libmpcodecs/ad.c,v
> retrieving revision 1.19
> diff -u -r1.19 ad.c
> --- libmpcodecs/ad.c 15 Jul 2004 20:36:04 -0000 1.19
> +++ libmpcodecs/ad.c 21 Sep 2004 14:43:55 -0000
> @@ -18,6 +18,7 @@
> //extern ad_functions_t mpcodecs_ad_null;
> extern ad_functions_t mpcodecs_ad_mp3lib;
> extern ad_functions_t mpcodecs_ad_ffmpeg;
> +extern ad_functions_t mpcodecs_ad_mp3on4;
> extern ad_functions_t mpcodecs_ad_liba52;
> extern ad_functions_t mpcodecs_ad_hwac3;
> extern ad_functions_t mpcodecs_ad_pcm;
> @@ -51,6 +52,7 @@
> #endif
> #ifdef USE_LIBAVCODEC
> &mpcodecs_ad_ffmpeg,
> + &mpcodecs_ad_mp3on4,
> #endif
> &mpcodecs_ad_pcm,
> &mpcodecs_ad_dvdpcm,
> Index: libmpdemux/demux_mov.c
> ===================================================================
> RCS file: /cvsroot/mplayer/main/libmpdemux/demux_mov.c,v
> retrieving revision 1.108
> diff -u -r1.108 demux_mov.c
> --- libmpdemux/demux_mov.c 13 Sep 2004 21:21:47 -0000 1.108
> +++ libmpdemux/demux_mov.c 21 Sep 2004 14:43:56 -0000
> @@ -951,6 +951,8 @@
>
> // dump away the codec specific configuration for the AAC decoder
> if(esds.decoderConfigLen){
> + if( (esds.decoderConfig[0]>>3) == 29 )
> + sh->format = 29; // request multi-channel mp3 decoder
> sh->codecdata_len = esds.decoderConfigLen;
> sh->codecdata = (unsigned char *)malloc(sh->codecdata_len);
> memcpy(sh->codecdata, esds.decoderConfig, sh->codecdata_len);
>
>
> ------------------------------------------------------------------------
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <unistd.h>
>
> #include "config.h"
> #include "mp_msg.h"
> #include "help_mp.h"
>
> #ifdef USE_LIBAVCODEC
>
> #include "ad_internal.h"
>
> extern int audio_output_channels;
>
> static ad_info_t info =
> {
> "multi-channel mp3 (on mp4) audio decoder",
> "mp3on4",
> "Larry Ruedisueli, AudioResearchLabs.com",
> "ffmpeg.sf.net",
> "uses multiple instances of ffmpeg mp3 decoder"
> };
>
> LIBAD_EXTERN(mp3on4)
>
> #define assert(x)
>
> #ifdef USE_LIBAVCODEC_SO
> #include <ffmpeg/avcodec.h>
> #else
> #include "libavcodec/avcodec.h"
> #endif
>
> extern int avcodec_inited;
>
> static int preinit(sh_audio_t *sh)
> {
> sh->audio_out_minsize = 8*2304;
> return 1;
> }
>
> static int brtab[16] = {
> 0, 32, 40, 48, 56, 64, 80, 96,
> 112, 128, 160, 192, 224, 256, 320
> };
>
> static int sftab[4] = { 44100, 48000, 32000, 0 };
>
> static int
> mp3FixFrame( unsigned char *ibuf, unsigned char *obuf, int fsize )
> {
> int i, br, n;
> int pad;
> int samplerate;
> /* copy original to new */
> if( (ibuf[1] & 1) == 0 ) {
> /* original has crc, turn it off */
> memcpy( obuf, ibuf, 4 );
> memcpy( obuf+4, ibuf+6, fsize-6 ); /* remove crc bytes */
> obuf[1] |= 1;
> fsize -= 2;
> }
> else
> memcpy( obuf, ibuf, fsize );
> /* make a few corrections */
> /* set syncword */
> obuf[0] = 0xff;
> obuf[1] |= 0xf0;
> samplerate = sftab[(obuf[2]>>2)&3];
> /* find bitrate to match frame size */
> br = fsize*samplerate/144000;
> for( i=1; i<15; i++ ) {
> if( brtab[i] >= br )
> break;
> }
> if( i == 15 )
> return 0;
> n = 144000*brtab[i]/samplerate; /* new frame size */
> pad = 0;
> if( n < fsize ) {
> /* need to adjust new frame size */
> if( fsize - n == 1 )
> pad = 1;
> else {
> if( ++i == 15 )
> return 0;
> n = 144000*brtab[i]/samplerate;
> }
> }
> obuf[2] = (obuf[2] & 0x0f) | (i<<4); /* set new bitrate */
> if( pad )
> obuf[2] |= 2; /* padding == 1 */
> else
> obuf[2] &= 0xfd; /* padding == 0 */
> /* set main_data_begin (9 bits) to 0 */
> obuf[4] = 0;
> obuf[5] &= 0x7f;
> return n+pad; /* return new frame length */
> }
>
> /* Next 3 arrays are indexed by channel config number (passed via codecdata) */
> static int mp3Frames[16] = {0,1,1,2,3,3,4,5,2}; /* number of mp3 decoder instances */
> static int mp3Channels[16] = {0,1,2,3,4,5,6,8,4}; /* total output channels */
> /* offsets into output buffer, assume output order is FL FR BL BR C LFE */
> static int chan_offset[9][5] = {
> {0},
> {0}, // C
> {0}, // FLR
> {2,0}, // C FLR
> {2,0,3}, // C FLR BS
> {4,0,2}, // C FLR BLRS
> {4,0,2,5}, // C FLR BLRS LFE
> {4,0,2,6,5}, // C FLR BLRS BLR LFE
> {0,2} // FLR BLRS
> };
>
> typedef struct {
> int frames; /* total mp3 decoder instances */
> int chan_cfg; /* channel config number */
> AVCodecContext *context[5]; /* codec context per decoder instance */
> } MultiFrameContext;
>
> static int init(sh_audio_t *sh_audio)
> {
> int i;
> AVCodec *lavc_codec;
> MultiFrameContext *mfcp;
>
> if(!avcodec_inited){
> avcodec_init();
> avcodec_register_all();
> avcodec_inited=1;
> }
>
> lavc_codec = (AVCodec *)avcodec_find_decoder_by_name(sh_audio->codec->dll);
> if(!lavc_codec){
> mp_msg(MSGT_DECAUDIO,MSGL_ERR,MSGTR_MissingLAVCcodec,sh_audio->codec->dll);
> return 0;
> }
>
> if( sh_audio->codecdata_len < 2 ||
> (mfcp = malloc(sizeof(MultiFrameContext))) == 0 )
> return 0;
> sh_audio->context = mfcp;
> mfcp->chan_cfg = (sh_audio->codecdata[1]>>3)&15;
> mfcp->frames = mp3Frames[mfcp->chan_cfg];
> if( mfcp->frames == 0 )
> return 0; /* invalid channel config number */
> sh_audio->channels = mp3Channels[mfcp->chan_cfg];
> if( sh_audio->channels > 2 )
> audio_output_channels = sh_audio->channels;
>
> /* open a sepearte codec/context for each frame */
> /* each frame is 1 or 2 channels - up to 5 frames allowed */
> for( i=0; i<mfcp->frames; i++ ) {
> mfcp->context[i] = avcodec_alloc_context();
>
> mfcp->context[i]->codec_tag = sh_audio->format; //FOURCC
> mfcp->context[i]->codec_id = lavc_codec->id;
>
> /* open it */
> if( avcodec_open( mfcp->context[i], lavc_codec ) < 0 ) {
> mp_msg(MSGT_DECAUDIO,MSGL_ERR, MSGTR_CantOpenCodec);
> return 0;
> }
> }
>
> // Decode at least 1 byte: (to get header filled)
> i = decode_audio(sh_audio,sh_audio->a_buffer,1,sh_audio->a_buffer_size);
> if( i > 0 )
> sh_audio->a_buffer_len = i;
> sh_audio->samplerate = mfcp->context[0]->sample_rate;
> /* calculate bitrate over all channels */
> sh_audio->i_bps = 0;
> for( i=0; i<mfcp->frames; i++ )
> sh_audio->i_bps += mfcp->context[0]->bit_rate;
> sh_audio->i_bps /= 8; /* convert to bytes per sec */
> return 1;
> }
>
> static void uninit(sh_audio_t *sh)
> {
> MultiFrameContext *mfcp = sh->context;
> int i;
> for( i=0; i<mfcp->frames; i++ ) {
> AVCodecContext *lavc_context = mfcp->context[i];
>
> if (avcodec_close(lavc_context) < 0)
> mp_msg(MSGT_DECVIDEO, MSGL_ERR, MSGTR_CantCloseCodec);
> if (lavc_context->extradata)
> free(lavc_context->extradata);
> free(lavc_context);
> }
> free( mfcp );
> }
>
> static int control(sh_audio_t *sh,int cmd,void* arg, ...)
> {
> MultiFrameContext *mfcp = sh->context;
> int i;
> switch(cmd){
> case ADCTRL_RESYNC_STREAM:
> for( i=0; i<mfcp->frames; i++ )
> avcodec_flush_buffers(mfcp->context[i]);
> return CONTROL_TRUE;
> }
> return CONTROL_UNKNOWN;
> }
>
> static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen)
> {
> MultiFrameContext *mfcp = sh_audio->context;
> int16_t tbuf[2304], *tbp=tbuf, *obuf, *bp;
> int i, j, n;
> unsigned char *start=NULL;
> int len = 0, len2;
> int fsize, psize;
> int off = sh_audio->channels;
> int *coff = chan_offset[mfcp->chan_cfg];
> unsigned char dbuf[2048];
>
> while( len < minlen ){
> /* each frame is a seperate decoder instance (either mono or stereo) */
> /* each packet contains mfcp->frames to build one complete block */
> if( (psize = ds_get_packet( sh_audio->ds, &start )) <= 0 )
> break;
> obuf=(int16_t*)(buf+len);
> if( mfcp->frames == 1 )
> /* no need to interleave - just write directly to output buffer */
> tbp = obuf;
> for( i=0; i<mfcp->frames; i++ ) {
> /* grab next frame out of packet */
> /* frame size is held in sync word */
> fsize = (start[0]<<4)|(start[1]>>4);
> if( psize < fsize )
> return -1;
> /* make into a valid mp3 frame */
> n = mp3FixFrame( start, dbuf, fsize );
> /* send to decoder instance */
> n = avcodec_decode_audio(mfcp->context[i],tbp,&len2,dbuf,n);
> if( n<0 ) {
> mp_msg(MSGT_DECAUDIO,MSGL_V,"lavc_audio(mp3on4): error\n");
> return -1;
> }
> n = mfcp->context[i]->channels == 1 ? 1152 : 2304;
> start += fsize;
> psize -= fsize;
> len += n*2;
> if( mfcp->frames > 1 ) {
> /* interleave output data */
> bp = obuf + coff[i];
> if( mfcp->context[i]->channels == 1 ) {
> for( j=0; j<n; j++ ) {
> *bp = tbuf[j];
> bp += off;
> }
> }
> else {
> for( j=0; j<n; j++ ) {
> bp[0] = tbuf[j++];
> bp[1] = tbuf[j];
> bp += off;
> }
> }
> }
> }
> }
> return len == 0 ? -1 : len;
> }
>
> #endif
>
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> MPlayer-dev-eng mailing list
> MPlayer-dev-eng at mplayerhq.hu
> http://mplayerhq.hu/mailman/listinfo/mplayer-dev-eng
More information about the MPlayer-dev-eng
mailing list