diff options
author | maurj <[email protected]> | 2007-05-02 15:56:39 +0000 |
---|---|---|
committer | maurj <[email protected]> | 2007-05-02 15:56:39 +0000 |
commit | 7800f22f054d4a96731c94bc71310c09a2b8235f (patch) | |
tree | ccee5caab83f8bda1057985f71145ef83bbfb0be /libhb | |
parent | 3a55755f5bd2fb02d5e87f100b83f81e61f7bf82 (diff) |
Added support for DTS audio. DTS audio streams (of 5.1 audio and below) will be detected and decoded. This requires a new library - libdca (and patch) - which is included (in patched form) in a new version of the pre-built UB Darwin contribs (0012). These have been uploaded to download.m0k.org/handbrake/contrib/ .
I haven't yet added any code to Controller.mm to recognise the DTS streams as supporting mono / 6ch DPL1 / DPL2 downmixes.
Note: running Jam on the new library required me to update some tools on Mac OS X - possibly libtool, autoconf, automake. Not sure which made the difference, but these were the ones I updated. it won't jam successfully without this.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@559 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb')
-rw-r--r-- | libhb/Jamfile | 2 | ||||
-rw-r--r-- | libhb/Makefile | 38 | ||||
-rw-r--r-- | libhb/common.h | 55 | ||||
-rw-r--r-- | libhb/deca52.c | 3 | ||||
-rw-r--r-- | libhb/decdca.c | 215 | ||||
-rw-r--r-- | libhb/dvd.c | 8 | ||||
-rw-r--r-- | libhb/hb.c | 1 | ||||
-rw-r--r-- | libhb/hb.h | 2 | ||||
-rw-r--r-- | libhb/internal.h | 7 | ||||
-rw-r--r-- | libhb/scan.c | 291 | ||||
-rw-r--r-- | libhb/work.c | 131 |
11 files changed, 617 insertions, 136 deletions
diff --git a/libhb/Jamfile b/libhb/Jamfile index afc775e48..7765d01c4 100644 --- a/libhb/Jamfile +++ b/libhb/Jamfile @@ -9,7 +9,7 @@ SubDir TOP libhb ; LIBHB_SRC = ipodutil.cpp common.c hb.c ports.c scan.c work.c decmpeg2.c encavcodec.c update.c demuxmpeg.c fifo.c render.c reader.c muxcommon.c muxmp4.c sync.c -decsub.c deca52.c encfaac.c declpcm.c encx264.c decavcodec.c encxvid.c +decsub.c deca52.c decdca.c encfaac.c declpcm.c encx264.c decavcodec.c encxvid.c muxavi.c enclame.c muxogm.c encvorbis.c dvd.c ; Library libhb : $(LIBHB_SRC) ; diff --git a/libhb/Makefile b/libhb/Makefile index 902877561..6604ec428 100644 --- a/libhb/Makefile +++ b/libhb/Makefile @@ -22,33 +22,31 @@ ifeq ($(SYSTEM),Linux) endif SRCS = common.c hb.c ports.c scan.c work.c decmpeg2.c encavcodec.c \ - update.c demuxmpeg.c fifo.c render.c reader.c muxcommon.c \ - muxmp4.c sync.c decsub.c deca52.c encfaac.c declpcm.c encx264.c \ - decavcodec.c encxvid.c muxavi.c enclame.c muxogm.c encvorbis.c \ - dvd.c ipodutil.cpp + update.c demuxmpeg.c fifo.c render.c reader.c muxcommon.c \ + muxmp4.c sync.c decsub.c deca52.c decdca.c encfaac.c declpcm.c encx264.c \ + decavcodec.c encxvid.c muxavi.c enclame.c muxogm.c encvorbis.c \ + dvd.c ipodutil.cpp OTMP = $(SRCS:%.c=%.o) OBJS = $(OTMP:%.cpp=%.o) ifeq ($(SYSTEM),CYGWIN_NT-5.1) CONTRIBS = ../contrib/lib/liba52.a ../contrib/lib/libavformat.a \ - ../contrib/lib/libavcodec.a ../contrib/lib/libavutil.a \ - ../contrib/lib/libdvdread.a \ - ../contrib/lib/libfaac.a ../contrib/lib/libmp3lame.a \ - ../contrib/lib/libmpeg2.a ../contrib/lib/libmpeg2convert.a \ - ../contrib/lib/libvorbis.a ../contrib/lib/libvorbisenc.a \ - ../contrib/lib/libvorbisfile.a ../contrib/lib/libogg.a \ - ../contrib/lib/libsamplerate.a ../contrib/lib/libx264.a \ - ../contrib/lib/libxvidcore.a ../contrib/lib/libmp4v2.a + ../contrib/lib/libavcodec.a ../contrib/lib/libavutil.a \ + ../contrib/lib/libdca.a ../contrib/lib/libdvdread.a \ + ../contrib/lib/libfaac.a ../contrib/lib/libmp3lame.a \ + ../contrib/lib/libmpeg2.a ../contrib/lib/libmpeg2convert.a \ + ../contrib/lib/libvorbis.a ../contrib/lib/libvorbisenc.a \ + ../contrib/lib/libvorbisfile.a ../contrib/lib/libogg.a \ + ../contrib/lib/libsamplerate.a ../contrib/lib/libx264.a \ + ../contrib/lib/libxvidcore.a ../contrib/lib/libmp4v2.a else CONTRIBS = ../contrib/lib/liba52.a ../contrib/lib/libavformat.a \ - ../contrib/lib/libavcodec.a ../contrib/lib/libavutil.a \ - ../contrib/lib/libdvdread.a ../contrib/lib/libdvdcss.a \ - ../contrib/lib/libfaac.a ../contrib/lib/libmp3lame.a \ - ../contrib/lib/libmpeg2.a ../contrib/lib/libmpeg2convert.a \ - ../contrib/lib/libvorbis.a ../contrib/lib/libvorbisenc.a \ - ../contrib/lib/libvorbisfile.a ../contrib/lib/libogg.a \ - ../contrib/lib/libsamplerate.a ../contrib/lib/libx264.a \ - ../contrib/lib/libxvidcore.a ../contrib/lib/libmp4v2.a + ../contrib/lib/libavcodec.a ../contrib/lib/libavutil.a \ + ../contrib/lib/libdca.a ../contrib/lib/libdvdread.a \ + ../contrib/lib/libdvdcss.a ../contrib/lib/libfaac.a \ + ../contrib/lib/libmp3lame.a ../contrib/lib/libmpeg2.a \ ../contrib/lib/libmpeg2convert.a ../contrib/lib/libvorbis.a \ ../contrib/lib/libvorbisenc.a ../contrib/lib/libvorbisfile.a \ ../contrib/lib/libogg.a ../contrib/lib/libsamplerate.a \ + ../contrib/lib/libx264.a ../contrib/lib/libxvidcore.a \ + ../contrib/lib/libmp4v2.a endif CFLAGS += -I../contrib/include -D__LIBHB__ -DUSE_PTHREAD -DHB_VERSION=\"$(HB_VERSION)\" -DHB_BUILD=$(HB_BUILD) $(SYSDEF) diff --git a/libhb/common.h b/libhb/common.h index 278e34f88..fd77999fc 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -169,24 +169,42 @@ struct hb_job_s audio_mixdowns: The mixdown to be used for each audio track in audios[] */ /* define some masks, used to extract the various information from the HB_AMIXDOWN_XXXX values */ -#define HB_AMIXDOWN_A52_FORMAT_MASK 0x00FF0000 -#define HB_AMIXDOWN_DISCRETE_CHANNEL_COUNT_MASK 0x0000F000 -#define HB_AMIXDOWN_FRONT_CHANNEL_COUNT_MASK 0x00000F00 -#define HB_AMIXDOWN_REAR_CHANNEL_COUNT_MASK 0x000000F0 -#define HB_AMIXDOWN_LFE_CHANNEL_COUNT_MASK 0x0000000F +#define HB_AMIXDOWN_DCA_FORMAT_MASK 0x00FFF000 +#define HB_AMIXDOWN_A52_FORMAT_MASK 0x00000FF0 +#define HB_AMIXDOWN_DISCRETE_CHANNEL_COUNT_MASK 0x0000000F + /* define the HB_AMIXDOWN_XXXX values */ -#define HB_AMIXDOWN_MONO 0x01011100 // A52_FORMAT of A52_MONO = 1 = 0x01 -#define HB_AMIXDOWN_STEREO 0x02022200 // A52_FORMAT of A52_STEREO = 2 = 0x02 -#define HB_AMIXDOWN_DOLBY 0x040A2310 // A52_FORMAT of A52_DOLBY = 10 = 0x0A -#define HB_AMIXDOWN_DOLBYPLII 0x084A2320 // A52_FORMAT of A52_DOLBY | A52_USE_DPLII = 74 = 0x4A -#define HB_AMIXDOWN_6CH 0x10176321 // A52_FORMAT of A52_3F2R | A52_LFE = 23 = 0x17 + +#define HB_AMIXDOWN_MONO 0x01000001 +// DCA_FORMAT of DCA_MONO = 0 = 0x000 +// A52_FORMAT of A52_MONO = 1 = 0x01 +// discrete channel count of 1 + +#define HB_AMIXDOWN_STEREO 0x02002022 +// DCA_FORMAT of DCA_STEREO = 2 = 0x002 +// A52_FORMAT of A52_STEREO = 2 = 0x02 +// discrete channel count of 2 + +#define HB_AMIXDOWN_DOLBY 0x042070A2 +// DCA_FORMAT of DCA_3F1R | DCA_OUT_DPLI = 519 = 0x207 +// A52_FORMAT of A52_DOLBY = 10 = 0x0A +// discrete channel count of 2 + +#define HB_AMIXDOWN_DOLBYPLII 0x084094A2 +// DCA_FORMAT of DCA_3F2R | DCA_OUT_DPLII = 1033 = 0x409 +// A52_FORMAT of A52_DOLBY | A52_USE_DPLII = 74 = 0x4A +// discrete channel count of 2 + +#define HB_AMIXDOWN_6CH 0x10089176 +// DCA_FORMAT of DCA_3F2R | DCA_LFE = 137 = 0x089 +// A52_FORMAT of A52_3F2R | A52_LFE = 23 = 0x17 +// discrete channel count of 6 + /* define some macros to extract the various information from the HB_AMIXDOWN_XXXX values */ -#define HB_AMIXDOWN_GET_A52_FORMAT( a ) ( ( a & HB_AMIXDOWN_A52_FORMAT_MASK ) >> 16 ) -#define HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( a ) ( ( a & HB_AMIXDOWN_DISCRETE_CHANNEL_COUNT_MASK ) >> 12 ) -#define HB_AMIXDOWN_GET_FRONT_CHANNEL_COUNT( a ) ( ( a & HB_AMIXDOWN_FRONT_CHANNEL_COUNT_MASK ) >> 8 ) -#define HB_AMIXDOWN_GET_REAR_CHANNEL_COUNT( a ) ( ( a & HB_AMIXDOWN_REAR_CHANNEL_COUNT_MASK ) >> 4 ) -#define HB_AMIXDOWN_GET_LFE_CHANNEL_COUNT( a ) ( ( a & HB_AMIXDOWN_LFE_CHANNEL_COUNT_MASK ) ) -#define HB_AMIXDOWN_GET_NORMAL_CHANNEL_COUNT( a ) ( (( a & HB_AMIXDOWN_FRONT_CHANNEL_COUNT_MASK ) >> 8) + (( a & HB_AMIXDOWN_REAR_CHANNEL_COUNT_MASK ) >> 4) ) +#define HB_AMIXDOWN_GET_DCA_FORMAT( a ) ( ( a & HB_AMIXDOWN_DCA_FORMAT_MASK ) >> 12 ) +#define HB_AMIXDOWN_GET_A52_FORMAT( a ) ( ( a & HB_AMIXDOWN_A52_FORMAT_MASK ) >> 4 ) +#define HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT( a ) ( ( a & HB_AMIXDOWN_DISCRETE_CHANNEL_COUNT_MASK ) ) + int audios[8]; int audio_mixdowns[8]; @@ -203,6 +221,7 @@ struct hb_job_s #define HB_ACODEC_AC3 0x000800 #define HB_ACODEC_MPGA 0x001000 #define HB_ACODEC_LPCM 0x002000 +#define HB_ACODEC_DCA 0x004000 int acodec; int abitrate; int arate; @@ -273,6 +292,9 @@ struct hb_audio_s /* ac3flags is only set when the source audio format is HB_ACODEC_AC3 */ int ac3flags; + /* dcaflags is only set when the source audio format is HB_ACODEC_DCA */ + int dcaflags; + #ifdef __LIBHB__ /* Internal data */ hb_fifo_t * fifo_in; /* AC3/MPEG/LPCM ES */ @@ -448,6 +470,7 @@ extern hb_work_object_t hb_encavcodec; extern hb_work_object_t hb_encxvid; extern hb_work_object_t hb_encx264; extern hb_work_object_t hb_deca52; +extern hb_work_object_t hb_decdca; extern hb_work_object_t hb_decavcodec; extern hb_work_object_t hb_declpcm; extern hb_work_object_t hb_encfaac; diff --git a/libhb/deca52.c b/libhb/deca52.c index 5b5f080bc..2a8c53c31 100644 --- a/libhb/deca52.c +++ b/libhb/deca52.c @@ -208,9 +208,10 @@ static hb_buffer_t * Decode( hb_work_object_t * w ) { for ( k = 0; k < pv->out_discrete_channels; k++ ) { - samples_out[(pv->out_discrete_channels*j)+k] = samples_in[(256*k)+j]; // DJA + samples_out[(pv->out_discrete_channels*j)+k] = samples_in[(256*k)+j]; } } + } pv->sync = 0; diff --git a/libhb/decdca.c b/libhb/decdca.c new file mode 100644 index 000000000..669112f5b --- /dev/null +++ b/libhb/decdca.c @@ -0,0 +1,215 @@ +/* $Id: decdca.c,v 1.14 2005/03/03 17:21:57 titer Exp $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.m0k.org/>. + It may be used under the terms of the GNU General Public License. */ + +#include "hb.h" +#include "dca.h" + +struct hb_work_private_s +{ + hb_job_t * job; + + /* libdca handle */ + dca_state_t * state; + + int flags_in; + int flags_out; + int rate; + int bitrate; + int frame_length; + float level; + + int error; + int sync; + int size; + + /* max frame size of the 16 bits version is 16384 */ + /* max frame size of the 14 bits version is 18726 */ + uint8_t frame[18726]; + + hb_list_t * list; + + int out_discrete_channels; + +}; + +int decdcaInit( hb_work_object_t *, hb_job_t * ); +int decdcaWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** ); +void decdcaClose( hb_work_object_t * ); + +hb_work_object_t hb_decdca = +{ + WORK_DECDCA, + "DCA decoder", + decdcaInit, + decdcaWork, + decdcaClose +}; + +/*********************************************************************** + * Local prototypes + **********************************************************************/ +static hb_buffer_t * Decode( hb_work_object_t * w ); + +/*********************************************************************** + * hb_work_decdca_init + *********************************************************************** + * Allocate the work object, initialize libdca + **********************************************************************/ +int decdcaInit( hb_work_object_t * w, hb_job_t * job ) +{ + hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); + w->private_data = pv; + + pv->job = job; + + pv->list = hb_list_init(); + pv->state = dca_init( 0 ); + + /* Decide what format we want out of libdca + work.c has already done some of this deduction for us in do_job() */ + + pv->flags_out = HB_AMIXDOWN_GET_DCA_FORMAT(w->amixdown); + + /* pass the number of channels used into the private work data */ + /* will only be actually used if we're not doing AC3 passthru */ + pv->out_discrete_channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(w->amixdown); + + pv->level = 32768.0; + + return 0; +} + +/*********************************************************************** + * Close + *********************************************************************** + * Free memory + **********************************************************************/ +void decdcaClose( hb_work_object_t * w ) +{ + hb_work_private_t * pv = w->private_data; + dca_free( pv->state ); + hb_list_empty( &pv->list ); + free( pv ); + w->private_data = NULL; +} + +/*********************************************************************** + * Work + *********************************************************************** + * Add the given buffer to the data we already have, and decode as much + * as we can + **********************************************************************/ +int decdcaWork( hb_work_object_t * w, hb_buffer_t ** buf_in, + hb_buffer_t ** buf_out ) +{ + hb_work_private_t * pv = w->private_data; + hb_buffer_t * buf; + + hb_list_add( pv->list, *buf_in ); + *buf_in = NULL; + + /* If we got more than a frame, chain raw buffers */ + *buf_out = buf = Decode( w ); + while( buf ) + { + buf->next = Decode( w ); + buf = buf->next; + } + + return HB_WORK_OK; +} + +/*********************************************************************** + * Decode + *********************************************************************** + * + **********************************************************************/ +static hb_buffer_t * Decode( hb_work_object_t * w ) +{ + hb_work_private_t * pv = w->private_data; + hb_buffer_t * buf; + int i, j, k; + uint64_t pts, pos; + int num_blocks; + + /* Get a frame header if don't have one yet */ + if( !pv->sync ) + { + while( hb_list_bytes( pv->list ) >= 14 ) + { + /* We have 14 bytes, check if this is a correct header */ + hb_list_seebytes( pv->list, pv->frame, 14 ); + pv->size = dca_syncinfo( pv->state, pv->frame, &pv->flags_in, &pv->rate, + &pv->bitrate, &pv->frame_length ); + if( pv->size ) + { + /* It is. W00t. */ + if( pv->error ) + { + hb_log( "dca_syncinfo ok" ); + } + pv->error = 0; + pv->sync = 1; + break; + } + + /* It is not */ + if( !pv->error ) + { + hb_log( "dca_syncinfo failed" ); + pv->error = 1; + } + + /* Try one byte later */ + hb_list_getbytes( pv->list, pv->frame, 1, NULL, NULL ); + } + } + + if( !pv->sync || + hb_list_bytes( pv->list ) < pv->size ) + { + /* Need more data */ + return NULL; + } + + /* Get the whole frame */ + hb_list_getbytes( pv->list, pv->frame, pv->size, &pts, &pos ); + + /* Feed libdca */ + dca_frame( pv->state, pv->frame, &pv->flags_out, &pv->level, 0 ); + + /* find out how many blocks are in this frame */ + num_blocks = dca_blocks_num( pv->state ); + + /* num_blocks blocks per frame, 256 samples per block, channelsused channels */ + buf = hb_buffer_init( num_blocks * 256 * pv->out_discrete_channels * sizeof( float ) ); + buf->start = pts + ( pos / pv->size ) * num_blocks * 256 * 90000 / pv->rate; + buf->stop = buf->start + num_blocks * 256 * 90000 / pv->rate; + + for( i = 0; i < num_blocks; i++ ) + { + dca_sample_t * samples_in; + float * samples_out; + + dca_block( pv->state ); + samples_in = dca_samples( pv->state ); + samples_out = ((float *) buf->data) + 256 * pv->out_discrete_channels * i; + + /* Interleave */ + for( j = 0; j < 256; j++ ) + { + for ( k = 0; k < pv->out_discrete_channels; k++ ) + { + samples_out[(pv->out_discrete_channels*j)+k] = samples_in[(256*k)+j] * 16384; + } + } + + } + + pv->sync = 0; + return buf; +} + diff --git a/libhb/dvd.c b/libhb/dvd.c index b26c55995..5ec4d519b 100644 --- a/libhb/dvd.c +++ b/libhb/dvd.c @@ -252,6 +252,11 @@ hb_title_t * hb_dvd_title_scan( hb_dvd_t * d, int t ) audio->codec = HB_ACODEC_LPCM; break; + case 0x06: + audio->id = ( ( 0x88 + position ) << 8 ) | 0xbd; + audio->codec = HB_ACODEC_DCA; + break; + default: audio->id = 0; audio->codec = 0; @@ -287,7 +292,8 @@ hb_title_t * hb_dvd_title_scan( hb_dvd_t * d, int t ) snprintf( audio->lang, sizeof( audio->lang ), "%s (%s)", strlen(lang->native_name) ? lang->native_name : lang->eng_name, audio->codec == HB_ACODEC_AC3 ? "AC3" : ( audio->codec == - HB_ACODEC_MPGA ? "MPEG" : "LPCM" ) ); + HB_ACODEC_DCA ? "DTS" : ( audio->codec == + HB_ACODEC_MPGA ? "MPEG" : "LPCM" ) ) ); snprintf( audio->lang_simple, sizeof( audio->lang_simple ), "%s", strlen(lang->native_name) ? lang->native_name : lang->eng_name ); snprintf( audio->iso639_2, sizeof( audio->iso639_2 ), "%s", diff --git a/libhb/hb.c b/libhb/hb.c index e9d7aa129..4aa89fb05 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -204,6 +204,7 @@ hb_handle_t * hb_init_dl( int verbose, int update_check ) hb_register( &hb_encxvid ); hb_register( &hb_encx264 ); hb_register( &hb_deca52 ); + hb_register( &hb_decdca ); hb_register( &hb_decavcodec ); hb_register( &hb_declpcm ); hb_register( &hb_encfaac ); diff --git a/libhb/hb.h b/libhb/hb.h index 8b5d4696a..af9163718 100644 --- a/libhb/hb.h +++ b/libhb/hb.h @@ -26,6 +26,7 @@ hb_register( &hb_encavcodec ); \ hb_register( &hb_encxvid ); \ hb_register( &hb_encx264 ); \ hb_register( &hb_deca52 ); \ +hb_register( &hb_decdca ); \ hb_register( &hb_decavcodec ); \ hb_register( &hb_declpcm ); \ hb_register( &hb_encfaac ); \ @@ -41,6 +42,7 @@ hb_register( &hb_render ); \ hb_register( &hb_encavcodec ); \ hb_register( &hb_encx264 ); \ hb_register( &hb_deca52 ); \ +hb_register( &hb_decdca ); \ hb_register( &hb_decavcodec ); \ hb_register( &hb_declpcm ); \ hb_register( &hb_encfaac ); \ diff --git a/libhb/internal.h b/libhb/internal.h index f950205d5..0f0262e7c 100644 --- a/libhb/internal.h +++ b/libhb/internal.h @@ -154,6 +154,12 @@ union hb_esconfig_u int ac3flags; } a52; + struct + { + /* dcaflags stores the flags from the DCA source, as found in scan.c */ + int dcaflags; + } dca; + }; enum @@ -166,6 +172,7 @@ enum WORK_ENCXVID, WORK_ENCX264, WORK_DECA52, + WORK_DECDCA, WORK_DECAVCODEC, WORK_DECLPCM, WORK_ENCFAAC, diff --git a/libhb/scan.c b/libhb/scan.c index 763bc3a1c..9d229b6cf 100644 --- a/libhb/scan.c +++ b/libhb/scan.c @@ -6,6 +6,7 @@ #include "hb.h" #include "a52dec/a52.h" +#include "dca.h" typedef struct { @@ -21,8 +22,8 @@ typedef struct static void ScanFunc( void * ); static int DecodePreviews( hb_scan_t *, hb_title_t * title ); -static void LookForAC3( hb_title_t * title, hb_buffer_t * b ); -static int AllAC3OK( hb_title_t * title ); +static void LookForAC3AndDCA( hb_title_t * title, hb_buffer_t * b ); +static int AllAC3AndDCAOK( hb_title_t * title ); hb_thread_t * hb_scan_init( hb_handle_t * handle, const char * path, int title_index, hb_list_t * list_title ) @@ -127,6 +128,7 @@ static void ScanFunc( void * _data ) #undef p /* Decode previews */ + /* this will also detect more AC3 / DTS information */ if( !DecodePreviews( data, title ) ) { /* TODO: free things */ @@ -134,13 +136,15 @@ static void ScanFunc( void * _data ) continue; } - /* Make sure we found AC3 rates and bitrates */ + /* Make sure we found AC3 / DCA rates and bitrates */ for( j = 0; j < hb_list_count( title->list_audio ); ) { audio = hb_list_item( title->list_audio, j ); - if( audio->codec == HB_ACODEC_AC3 && + if( ( audio->codec == HB_ACODEC_AC3 || audio->codec == HB_ACODEC_DCA ) && !audio->bitrate ) { + hb_log( "scan: removing audio with codec of 0x%x because of no bitrate", + audio->codec ); hb_list_rem( title->list_audio, audio ); free( audio ); continue; @@ -284,12 +288,12 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title ) } else if( !i ) { - LookForAC3( title, buf_es ); + LookForAC3AndDCA( title, buf_es ); } hb_buffer_close( &buf_es ); if( hb_list_count( list_raw ) && - ( i || AllAC3OK( title ) ) ) + ( i || AllAC3AndDCAOK( title ) ) ) { /* We got a picture */ break; @@ -297,7 +301,7 @@ static int DecodePreviews( hb_scan_t * data, hb_title_t * title ) } if( hb_list_count( list_raw ) && - ( i || AllAC3OK( title ) ) ) + ( i || AllAC3AndDCAOK( title ) ) ) { break; } @@ -423,19 +427,21 @@ cleanup: return ret; } -static void LookForAC3( hb_title_t * title, hb_buffer_t * b ) +static void LookForAC3AndDCA( hb_title_t * title, hb_buffer_t * b ) { int i; int flags; int rate; int bitrate; + int frame_length; + dca_state_t * state; - /* Figure out if this is a AC3 buffer for a known track */ + /* Figure out if this is a AC3 or DCA buffer for a known track */ hb_audio_t * audio = NULL; for( i = 0; i < hb_list_count( title->list_audio ); i++ ) { audio = hb_list_item( title->list_audio, i ); - if( audio->codec == HB_ACODEC_AC3 && + if( ( audio->codec == HB_ACODEC_AC3 || audio->codec == HB_ACODEC_DCA ) && audio->id == b->id ) { break; @@ -458,95 +464,202 @@ static void LookForAC3( hb_title_t * title, hb_buffer_t * b ) for( i = 0; i < b->size - 7; i++ ) { - if( a52_syncinfo( &b->data[i], &flags, &rate, &bitrate ) ) + + if ( audio->codec == HB_ACODEC_AC3 ) { - hb_log( "scan: rate=%dHz, bitrate=%d", rate, bitrate ); - audio->rate = rate; - audio->bitrate = bitrate; - switch( flags & A52_CHANNEL_MASK ) + + /* check for a52 */ + if( a52_syncinfo( &b->data[i], &flags, &rate, &bitrate ) ) { - case A52_MONO: - case A52_CHANNEL1: - case A52_CHANNEL2: - audio->src_discrete_front_channels = 1; - audio->src_discrete_rear_channels = 0; - audio->src_encoded_front_channels = 1; - audio->src_encoded_rear_channels = 0; - break; - case A52_STEREO: - case A52_CHANNEL: - audio->src_discrete_front_channels = 2; - audio->src_discrete_rear_channels = 0; - audio->src_encoded_front_channels = 2; - audio->src_encoded_rear_channels = 0; - break; - case A52_DOLBY: - audio->src_discrete_front_channels = 2; - audio->src_discrete_rear_channels = 0; - audio->src_encoded_front_channels = 3; - audio->src_encoded_rear_channels = 1; - break; - case A52_3F: - audio->src_discrete_front_channels = 3; - audio->src_discrete_rear_channels = 0; - audio->src_encoded_front_channels = 3; - audio->src_encoded_rear_channels = 0; - break; - case A52_2F1R: - audio->src_discrete_front_channels = 2; - audio->src_discrete_rear_channels = 1; - audio->src_encoded_front_channels = 2; - audio->src_encoded_rear_channels = 1; - break; - case A52_3F1R: - audio->src_discrete_front_channels = 3; - audio->src_discrete_rear_channels = 1; - audio->src_encoded_front_channels = 3; - audio->src_encoded_rear_channels = 1; - break; - case A52_2F2R: - audio->src_discrete_front_channels = 2; - audio->src_discrete_rear_channels = 2; - audio->src_encoded_front_channels = 2; - audio->src_encoded_rear_channels = 2; - break; - case A52_3F2R: - audio->src_discrete_front_channels = 3; - audio->src_discrete_rear_channels = 2; - audio->src_encoded_front_channels = 3; - audio->src_encoded_rear_channels = 2; - break; + hb_log( "scan: AC3, rate=%dHz, bitrate=%d", rate, bitrate ); + audio->rate = rate; + audio->bitrate = bitrate; + switch( flags & A52_CHANNEL_MASK ) + { + case A52_MONO: + case A52_CHANNEL1: + case A52_CHANNEL2: + audio->src_discrete_front_channels = 1; + audio->src_discrete_rear_channels = 0; + audio->src_encoded_front_channels = 1; + audio->src_encoded_rear_channels = 0; + break; + case A52_STEREO: + case A52_CHANNEL: + audio->src_discrete_front_channels = 2; + audio->src_discrete_rear_channels = 0; + audio->src_encoded_front_channels = 2; + audio->src_encoded_rear_channels = 0; + break; + case A52_DOLBY: + audio->src_discrete_front_channels = 2; + audio->src_discrete_rear_channels = 0; + audio->src_encoded_front_channels = 3; + audio->src_encoded_rear_channels = 1; + break; + case A52_3F: + audio->src_discrete_front_channels = 3; + audio->src_discrete_rear_channels = 0; + audio->src_encoded_front_channels = 3; + audio->src_encoded_rear_channels = 0; + break; + case A52_2F1R: + audio->src_discrete_front_channels = 2; + audio->src_discrete_rear_channels = 1; + audio->src_encoded_front_channels = 2; + audio->src_encoded_rear_channels = 1; + break; + case A52_3F1R: + audio->src_discrete_front_channels = 3; + audio->src_discrete_rear_channels = 1; + audio->src_encoded_front_channels = 3; + audio->src_encoded_rear_channels = 1; + break; + case A52_2F2R: + audio->src_discrete_front_channels = 2; + audio->src_discrete_rear_channels = 2; + audio->src_encoded_front_channels = 2; + audio->src_encoded_rear_channels = 2; + break; + case A52_3F2R: + audio->src_discrete_front_channels = 3; + audio->src_discrete_rear_channels = 2; + audio->src_encoded_front_channels = 3; + audio->src_encoded_rear_channels = 2; + break; + } + + if (flags & A52_LFE) { + audio->src_discrete_lfe_channels = 1; + } else { + audio->src_discrete_lfe_channels = 0; + } + + /* store the AC3 flags for future reference + This enables us to find out if we had a stereo or Dolby source later on */ + audio->config.a52.ac3flags = flags; + + /* store the ac3 flags in the public ac3flags property too, so we can access it from the GUI */ + audio->ac3flags = audio->config.a52.ac3flags; + + /* XXX */ + if ( (flags & A52_CHANNEL_MASK) == A52_DOLBY ) { + sprintf( audio->lang + strlen( audio->lang ), + " (Dolby Surround)" ); + } else { + sprintf( audio->lang + strlen( audio->lang ), + " (%d.%d ch)", + audio->src_discrete_front_channels + audio->src_discrete_rear_channels, audio->src_discrete_lfe_channels ); + } + + break; + } - if (flags & A52_LFE) { - audio->src_discrete_lfe_channels = 1; - } else { - audio->src_discrete_lfe_channels = 0; - } - - /* store the AC3 flags for future reference - This enables us to find out if we had a stereo or Dolby source later on */ - audio->config.a52.ac3flags = flags; + } + else if ( audio->codec == HB_ACODEC_DCA ) + { - /* store the ac3 flags in the public ac3flags property too, so we can access it from the GUI */ - audio->ac3flags = audio->config.a52.ac3flags; + hb_log( "scan: checking for DCA syncinfo" ); - /* XXX */ - if ( (flags & A52_CHANNEL_MASK) == A52_DOLBY ) { - sprintf( audio->lang + strlen( audio->lang ), - " (Dolby Surround)" ); - } else { - sprintf( audio->lang + strlen( audio->lang ), - " (%d.%d ch)", - audio->src_discrete_front_channels + audio->src_discrete_rear_channels, audio->src_discrete_lfe_channels ); - } + /* check for dca */ + state = dca_init( 0 ); + if( dca_syncinfo( state, &b->data[i], &flags, &rate, &bitrate, &frame_length ) ) + { + hb_log( "scan: DCA, rate=%dHz, bitrate=%d", rate, bitrate ); + audio->rate = rate; + audio->bitrate = bitrate; + switch( flags & DCA_CHANNEL_MASK ) + { + case DCA_MONO: + audio->src_discrete_front_channels = 1; + audio->src_discrete_rear_channels = 0; + audio->src_encoded_front_channels = 1; + audio->src_encoded_rear_channels = 0; + break; + case DCA_CHANNEL: + case DCA_STEREO: + case DCA_STEREO_SUMDIFF: + case DCA_STEREO_TOTAL: + audio->src_discrete_front_channels = 2; + audio->src_discrete_rear_channels = 0; + audio->src_encoded_front_channels = 2; + audio->src_encoded_rear_channels = 0; + break; + case DCA_DOLBY: + audio->src_discrete_front_channels = 2; + audio->src_discrete_rear_channels = 0; + audio->src_encoded_front_channels = 3; + audio->src_encoded_rear_channels = 1; + break; + case DCA_3F: + audio->src_discrete_front_channels = 3; + audio->src_discrete_rear_channels = 0; + audio->src_encoded_front_channels = 3; + audio->src_encoded_rear_channels = 0; + break; + case DCA_2F1R: + audio->src_discrete_front_channels = 2; + audio->src_discrete_rear_channels = 1; + audio->src_encoded_front_channels = 2; + audio->src_encoded_rear_channels = 1; + break; + case DCA_3F1R: + audio->src_discrete_front_channels = 3; + audio->src_discrete_rear_channels = 1; + audio->src_encoded_front_channels = 3; + audio->src_encoded_rear_channels = 1; + break; + case DCA_2F2R: + audio->src_discrete_front_channels = 2; + audio->src_discrete_rear_channels = 2; + audio->src_encoded_front_channels = 2; + audio->src_encoded_rear_channels = 2; + break; + case DCA_3F2R: + audio->src_discrete_front_channels = 3; + audio->src_discrete_rear_channels = 2; + audio->src_encoded_front_channels = 3; + audio->src_encoded_rear_channels = 2; + break; + case DCA_4F2R: + audio->src_discrete_front_channels = 4; + audio->src_discrete_rear_channels = 2; + audio->src_encoded_front_channels = 4; + audio->src_encoded_rear_channels = 2; + break; + } - break; + if (flags & DCA_LFE) { + audio->src_discrete_lfe_channels = 1; + } else { + audio->src_discrete_lfe_channels = 0; + } + + /* store the DCA flags for future reference + This enables us to find out if we had a stereo or Dolby source later on */ + audio->config.dca.dcaflags = flags; + + /* store the dca flags in the public dcaflags property too, so we can access it from the GUI */ + audio->dcaflags = audio->config.dca.dcaflags; + + /* XXX */ + if ( (flags & DCA_CHANNEL_MASK) == DCA_DOLBY ) { + sprintf( audio->lang + strlen( audio->lang ), + " (Dolby Surround)" ); + } else { + sprintf( audio->lang + strlen( audio->lang ), + " (%d.%d ch)", + audio->src_discrete_front_channels + audio->src_discrete_rear_channels, audio->src_discrete_lfe_channels ); + } + + break; + } } } } -static int AllAC3OK( hb_title_t * title ) +static int AllAC3AndDCAOK( hb_title_t * title ) { int i; hb_audio_t * audio; @@ -554,7 +667,7 @@ static int AllAC3OK( hb_title_t * title ) for( i = 0; i < hb_list_count( title->list_audio ); i++ ) { audio = hb_list_item( title->list_audio, i ); - if( audio->codec == HB_ACODEC_AC3 && + if( ( audio->codec == HB_ACODEC_AC3 || audio->codec == HB_ACODEC_DCA ) && !audio->bitrate ) { return 0; diff --git a/libhb/work.c b/libhb/work.c index 3e5ec4a78..8f3c1d03c 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -6,6 +6,7 @@ #include "hb.h" #include "a52dec/a52.h" +#include "dca.h" typedef struct { @@ -230,13 +231,8 @@ static void do_job( hb_job_t * job, int cpu_count ) } } - if(audio->codec != HB_ACODEC_AC3) { - - /* assume a stereo input and output for non-AC3 audio input (LPCM, MP2), - regardless of the mixdown passed to us */ - job->audio_mixdowns[i] = HB_AMIXDOWN_STEREO; - - } else { + if (audio->codec == HB_ACODEC_AC3) + { /* sense-check the AC3 mixdown */ @@ -339,7 +335,122 @@ static void do_job( hb_job_t * job, int cpu_count ) job->audio_mixdowns[i] = HB_AMIXDOWN_STEREO; } - } + } + + } + else if (audio->codec == HB_ACODEC_DCA) + { + + /* sense-check the DCA mixdown */ + + /* audioCodecSupportsMono and audioCodecSupports6Ch are the same for now, + but this may change in the future, so they are separated for flexibility */ + int audioCodecSupportsMono = (job->acodec == HB_ACODEC_FAAC); + int audioCodecSupports6Ch = (job->acodec == HB_ACODEC_FAAC); + + /* find out what the format of our source DCA audio is */ + switch (audio->config.dca.dcaflags & DCA_CHANNEL_MASK) { + + /* mono sources */ + case DCA_MONO: + /* regardless of what stereo mixdown we've requested, a mono source always get mixed down + to mono if we can, and mixed up to stereo if we can't */ + if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecSupportsMono == 1) { + job->audio_mixdowns[i] = HB_AMIXDOWN_MONO; + } else { + job->audio_mixdowns[i] = HB_AMIXDOWN_STEREO; + } + break; + + /* stereo input */ + case DCA_CHANNEL: + case DCA_STEREO: + case DCA_STEREO_SUMDIFF: + case DCA_STEREO_TOTAL: + /* if we've requested a mono mixdown, and it is supported, then do the mix */ + /* use stereo if not supported */ + if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecSupportsMono == 0) { + job->audio_mixdowns[i] = HB_AMIXDOWN_STEREO; + /* otherwise, preserve stereo regardless of if we requested something higher */ + } else if (job->audio_mixdowns[i] > HB_AMIXDOWN_STEREO) { + job->audio_mixdowns[i] = HB_AMIXDOWN_STEREO; + } + break; + + /* dolby (DPL1 aka Dolby Surround = 4.0 matrix-encoded) input */ + /* the A52 flags don't allow for a way to distinguish between DPL1 and DPL2 on a DVD, + so we always assume a DPL1 source for A52_DOLBY */ + case DCA_DOLBY: + /* if we've requested a mono mixdown, and it is supported, then do the mix */ + /* preserve dolby if not supported */ + if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecSupportsMono == 0) { + job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBY; + /* otherwise, preserve dolby even if we requested something higher */ + /* a stereo mixdown will still be honoured here */ + } else if (job->audio_mixdowns[i] > HB_AMIXDOWN_DOLBY) { + job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBY; + } + break; + + /* 3F/2R input */ + case DCA_3F2R: + /* if we've requested a mono mixdown, and it is supported, then do the mix */ + /* use dpl2 if not supported */ + if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecSupportsMono == 0) { + job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBYPLII; + } else { + /* check if we have 3F2R input and also have an LFE - i.e. we have a 5.1 source) */ + if (audio->config.dca.dcaflags & DCA_LFE) { + /* we have a 5.1 source */ + /* if we requested 6ch, but our audio format doesn't support it, then mix to DPLII instead */ + if (job->audio_mixdowns[i] == HB_AMIXDOWN_6CH && audioCodecSupports6Ch == 0) { + job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBYPLII; + } + } else { + /* we have a 5.0 source, so we can't do 6ch conversion + default to DPL II instead */ + if (job->audio_mixdowns[i] > HB_AMIXDOWN_DOLBYPLII) { + job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBYPLII; + } + } + } + /* all other mixdowns will have been preserved here */ + break; + + /* 3F/1R input */ + case DCA_3F1R: + /* if we've requested a mono mixdown, and it is supported, then do the mix */ + /* use dpl1 if not supported */ + if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecSupportsMono == 0) { + job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBY; + } else { + /* we have a 4.0 or 4.1 source, so we can't do DPLII or 6ch conversion + default to DPL I instead */ + if (job->audio_mixdowns[i] > HB_AMIXDOWN_DOLBY) { + job->audio_mixdowns[i] = HB_AMIXDOWN_DOLBY; + } + } + /* all other mixdowns will have been preserved here */ + break; + + default: + /* if we've requested a mono mixdown, and it is supported, then do the mix */ + if (job->audio_mixdowns[i] == HB_AMIXDOWN_MONO && audioCodecSupportsMono == 1) { + job->audio_mixdowns[i] = HB_AMIXDOWN_MONO; + /* mix everything else down to stereo */ + } else { + job->audio_mixdowns[i] = HB_AMIXDOWN_STEREO; + } + } + + } + else + { + + /* assume a stereo input and output for non-AC3/DCA audio input (LPCM, MP2), + regardless of the mixdown passed to us */ + job->audio_mixdowns[i] = HB_AMIXDOWN_STEREO; + } /* log the output mixdown */ @@ -367,6 +478,9 @@ static void do_job( hb_job_t * job, int cpu_count ) case HB_ACODEC_AC3: w = getWork( WORK_DECA52 ); break; + case HB_ACODEC_DCA: + w = getWork( WORK_DECDCA ); + break; case HB_ACODEC_MPGA: w = getWork( WORK_DECAVCODEC ); break; @@ -466,6 +580,7 @@ static void do_job( hb_job_t * job, int cpu_count ) /* FIXME: This feels really hackish, anything better? */ if ( w->id == WORK_DECA52 || + w->id == WORK_DECDCA || w->id == WORK_DECLPCM || w->id == WORK_ENCFAAC || w->id == WORK_ENCLAME || |