X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=libhb%2Fdecdca.c;h=4fe06613503ac4d98357295bc4881b9e75c572ca;hb=5a8c3011c696864010f1d819ac4513c90ff2a97c;hp=28081900d1a6c9a40aa15a7b556a0826b539c9c6;hpb=2707a4c05f84b3846e4e77ca4e9850cc61ffca10;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/libhb/decdca.c b/libhb/decdca.c index 28081900..4fe06613 100644 --- a/libhb/decdca.c +++ b/libhb/decdca.c @@ -14,6 +14,8 @@ struct hb_work_private_s /* libdca handle */ dca_state_t * state; + double next_pts; + int64_t last_buf_pts; int flags_in; int flags_out; int rate; @@ -35,9 +37,11 @@ struct hb_work_private_s }; -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 * ); +static int decdcaInit( hb_work_object_t *, hb_job_t * ); +static int decdcaWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** ); +static void decdcaClose( hb_work_object_t * ); +static int decdcaBSInfo( hb_work_object_t *, const hb_buffer_t *, + hb_work_info_t * ); hb_work_object_t hb_decdca = { @@ -45,7 +49,9 @@ hb_work_object_t hb_decdca = "DCA decoder", decdcaInit, decdcaWork, - decdcaClose + decdcaClose, + 0, + decdcaBSInfo }; /*********************************************************************** @@ -58,7 +64,7 @@ static hb_buffer_t * Decode( hb_work_object_t * w ); *********************************************************************** * Allocate the work object, initialize libdca **********************************************************************/ -int decdcaInit( hb_work_object_t * w, hb_job_t * job ) +static int decdcaInit( hb_work_object_t * w, hb_job_t * job ) { hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); hb_audio_t * audio = w->audio; @@ -88,7 +94,7 @@ int decdcaInit( hb_work_object_t * w, hb_job_t * job ) *********************************************************************** * Free memory **********************************************************************/ -void decdcaClose( hb_work_object_t * w ) +static void decdcaClose( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data; dca_free( pv->state ); @@ -103,12 +109,27 @@ void decdcaClose( hb_work_object_t * w ) * 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, +static 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; + if ( (*buf_in)->size <= 0 ) + { + /* EOF on input stream - send it downstream & say that we're done */ + *buf_out = *buf_in; + *buf_in = NULL; + return HB_WORK_DONE; + } + + if ( (*buf_in)->start < -1 && pv->next_pts == 0 ) + { + // discard buffers that start before video time 0 + *buf_out = NULL; + return HB_WORK_OK; + } + hb_list_add( pv->list, *buf_in ); *buf_in = NULL; @@ -132,8 +153,10 @@ static hb_buffer_t * Decode( hb_work_object_t * w ) { hb_work_private_t * pv = w->private_data; hb_buffer_t * buf; + hb_audio_t * audio = w->audio; int i, j, k; - uint64_t pts, pos; + int64_t pts, pos; + uint64_t upts, upos; int num_blocks; /* Get a frame header if don't have one yet */ @@ -169,15 +192,53 @@ static hb_buffer_t * Decode( hb_work_object_t * w ) } } - if( !pv->sync || - hb_list_bytes( pv->list ) < pv->size ) + 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 ); + hb_list_getbytes( pv->list, pv->frame, pv->size, &upts, &upos ); + pts = (int64_t)upts; + pos = (int64_t)upos; + + if ( pts != pv->last_buf_pts ) + { + pv->last_buf_pts = pts; + } + else + { + // spec says that the PTS is the start time of the first frame + // that starts in the PES frame so we only use the PTS once then + // get the following frames' PTS from the frame length. + pts = -1; + } + + // mkv files typically use a 1ms timebase which results in a lot of + // truncation error in their timestamps. Also, TSMuxer or something + // in the m2ts-to-mkv toolchain seems to take a very casual attitude + // about time - timestamps seem to randomly offset by ~40ms for a few + // seconds then recover. So, if the pts we got is within 50ms of the + // pts computed from the data stream, use the data stream pts. + if ( pts == -1 || ( pv->next_pts && fabs( pts - pv->next_pts ) < 50.*90. ) ) + { + pts = pv->next_pts; + } + + double frame_dur = (double)(pv->frame_length & ~0xFF) / (double)pv->rate * 90000.; + + /* DCA passthrough: don't decode the DCA frame */ + if( audio->config.out.codec == HB_ACODEC_DCA ) + { + buf = hb_buffer_init( pv->size ); + memcpy( buf->data, pv->frame, pv->size ); + buf->start = pts; + pv->next_pts = pts + frame_dur; + buf->stop = pv->next_pts; + pv->sync = 0; + return buf; + } /* Feed libdca */ dca_frame( pv->state, pv->frame, &pv->flags_out, &pv->level, 0 ); @@ -186,9 +247,12 @@ static hb_buffer_t * Decode( hb_work_object_t * w ) 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; + int nsamp = num_blocks * 256; + buf = hb_buffer_init( nsamp * pv->out_discrete_channels * sizeof( float ) ); + + buf->start = pts; + pv->next_pts = pts + (double)nsamp / (double)pv->rate * 90000.; + buf->stop = pv->next_pts; for( i = 0; i < num_blocks; i++ ) { @@ -214,3 +278,85 @@ static hb_buffer_t * Decode( hb_work_object_t * w ) return buf; } + +static int decdcaBSInfo( hb_work_object_t *w, const hb_buffer_t *b, + hb_work_info_t *info ) +{ + int i, flags, rate, bitrate, frame_length; + dca_state_t * state = dca_init( 0 ); + + memset( info, 0, sizeof(*info) ); + + /* since DCA frames don't line up with MPEG ES frames scan the + * entire frame for an DCA sync pattern. */ + for ( i = 0; i < b->size - 7; ++i ) + { + if( dca_syncinfo( state, &b->data[i], &flags, &rate, &bitrate, + &frame_length ) ) + { + break; + } + } + if ( i >= b->size - 7 ) + { + /* didn't find DCA sync */ + return 0; + } + + info->name = "DCA"; + info->rate = rate; + info->rate_base = 1; + info->bitrate = bitrate; + info->flags = flags; + + if ( ( flags & DCA_CHANNEL_MASK) == DCA_DOLBY ) + { + info->flags |= AUDIO_F_DOLBY; + } + + switch( flags & DCA_CHANNEL_MASK ) + { + /* mono sources */ + case DCA_MONO: + info->channel_layout = HB_INPUT_CH_LAYOUT_MONO; + break; + /* stereo input */ + case DCA_CHANNEL: + case DCA_STEREO: + case DCA_STEREO_SUMDIFF: + case DCA_STEREO_TOTAL: + info->channel_layout = HB_INPUT_CH_LAYOUT_STEREO; + break; + /* 3F/2R input */ + case DCA_3F2R: + info->channel_layout = HB_INPUT_CH_LAYOUT_3F2R; + break; + /* 3F/1R input */ + case DCA_3F1R: + info->channel_layout = HB_INPUT_CH_LAYOUT_3F1R; + break; + /* other inputs */ + case DCA_3F: + info->channel_layout = HB_INPUT_CH_LAYOUT_3F; + break; + case DCA_2F1R: + info->channel_layout = HB_INPUT_CH_LAYOUT_2F1R; + break; + case DCA_2F2R: + info->channel_layout = HB_INPUT_CH_LAYOUT_2F2R; + break; + case DCA_4F2R: + info->channel_layout = HB_INPUT_CH_LAYOUT_4F2R; + break; + /* unknown */ + default: + info->channel_layout = HB_INPUT_CH_LAYOUT_STEREO; + } + + if (flags & DCA_LFE) + { + info->channel_layout |= HB_INPUT_CH_LAYOUT_HAS_LFE; + } + + return 1; +}