[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