#include #include #include #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 #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; iframes; 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; iframes; 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; iframes; 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; iframes; 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; iframes; 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