{"MP3 (lame)", "lame", HB_ACODEC_LAME, "lame"},
{"Vorbis", "vorbis", HB_ACODEC_VORBIS, "vorbis"},
{"AC3 (pass-thru)", "ac3", HB_ACODEC_AC3, "ac3"},
-// {"DTS (pass-thru)", "dts", HB_ACODEC_DCA, "dts"},
+ {"DTS (pass-thru)", "dts", HB_ACODEC_DCA, "dts"},
};
combo_opts_t acodec_opts =
{
samples_per_frame = 1152;
break;
case HB_ACODEC_AC3:
+ case HB_ACODEC_DCA:
samples_per_frame = 1536;
break;
default:
{
hb_work_private_t * pv = w->private_data;
hb_buffer_t * buf;
+ hb_audio_t * audio = w->audio;
int i, j, k;
int64_t pts, pos;
int num_blocks;
pts = -1;
}
- /* 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 */
- int nsamp = num_blocks * 256;
- buf = hb_buffer_init( nsamp * pv->out_discrete_channels * sizeof( float ) );
-
// 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
{
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 );
+
+ /* 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 */
+ 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;
hb_mux_data_t * mux_data;
int audio_count = hb_list_count( title->list_audio );
+ int is_passthru = 0;
int is_ac3 = 0;
int hdrl_bytes;
int i;
audio = hb_list_item( title->list_audio, i );
is_ac3 = (audio->config.out.codec == HB_ACODEC_AC3);
+ is_passthru = (audio->config.out.codec == HB_ACODEC_AC3) ||
+ (audio->config.out.codec == HB_ACODEC_DCA);
mux_data = calloc( sizeof( hb_mux_data_t ), 1 );
audio->priv.mux_data = mux_data;
h.Type = FOURCC( "auds" );
h.InitialFrames = 1;
h.Scale = 1;
- h.Rate = is_ac3 ? ( audio->config.in.bitrate / 8 ) :
+ h.Rate = is_passthru ? ( audio->config.in.bitrate / 8 ) :
( audio->config.out.bitrate * 1000 / 8 );
h.Quality = 0xFFFFFFFF;
h.SampleSize = 1;
/* Audio stream format */
f.FourCC = FOURCC( "strf" );
- if( is_ac3 )
+ if( is_passthru )
{
f.BytesCount = sizeof( hb_wave_formatex_t ) - 8;
- f.FormatTag = 0x2000;
+ f.FormatTag = is_ac3 ? 0x2000 : 0x2001;
f.Channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(audio->config.in.channel_layout);
f.SamplesPerSec = audio->config.in.samplerate;
}
}
f.AvgBytesPerSec = h.Rate;
f.BlockAlign = 1;
- if( is_ac3 )
+ if( is_passthru )
{
f.Size = 0;
}
( job->anamorphic.mode ? sizeof( hb_avi_vprp_info_t ) : 0 ) +
/* audios strf */
audio_count * ( sizeof( hb_wave_formatex_t ) +
- ( is_ac3 ? 0 : sizeof( hb_wave_mp3_t ) ) );
+ ( is_passthru ? 0 : sizeof( hb_wave_mp3_t ) ) );
/* Here we really start to write into the file */
WriteInt32( m->file, FOURCC( "LIST" ) );
WriteInt32( m->file, 4 + sizeof( hb_avi_stream_header_t ) +
sizeof( hb_wave_formatex_t ) +
- ( is_ac3 ? 0 : sizeof( hb_wave_mp3_t ) ) );
+ ( is_passthru ? 0 : sizeof( hb_wave_mp3_t ) ) );
WriteInt32( m->file, FOURCC( "strl" ) );
WriteStreamHeader( m->file, &mux_data->header );
WriteWaveFormatEx( m->file, &mux_data->format.a.f );
- if( !is_ac3 )
+ if( !is_passthru )
{
WriteWaveMp3( m->file, &mux_data->format.a.m );
}
WriteInt32( m->file, job->mux_data->header.Length );
for( i = 0; i < hb_list_count( title->list_audio ); i++ )
{
+ int is_passthru;
audio = hb_list_item( title->list_audio, i );
+ is_passthru = (audio->config.out.codec == HB_ACODEC_AC3) ||
+ (audio->config.out.codec == HB_ACODEC_DCA);
fseek( m->file, 264 + i *
- ( 102 + ( ( audio->config.out.codec == HB_ACODEC_AC3 ) ? 0 :
+ ( 102 + ( is_passthru ? 0 :
sizeof( hb_wave_mp3_t ) ) ), SEEK_SET );
WriteInt32( m->file, audio->priv.mux_data->header.Length );
}
switch (audio->config.out.codec)
{
+ case HB_ACODEC_DCA:
+ track->codecPrivate = NULL;
+ track->codecPrivateSize = 0;
+ track->codecID = MK_ACODEC_DTS;
+ break;
case HB_ACODEC_AC3:
track->codecPrivate = NULL;
track->codecPrivateSize = 0;
track->trackType = MK_TRACK_AUDIO;
track->language = audio->config.lang.iso639_2;
track->extra.audio.samplingFreq = (float)audio->config.out.samplerate;
- track->extra.audio.channels = (audio->config.out.codec == HB_ACODEC_AC3 ) ? HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(audio->config.in.channel_layout) : HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown);
+ if (audio->config.out.codec == HB_ACODEC_AC3 ||
+ audio->config.out.codec == HB_ACODEC_DCA)
+ {
+ track->extra.audio.channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(audio->config.in.channel_layout);
+ }
+ else
+ {
+ track->extra.audio.channels = HB_AMIXDOWN_GET_DISCRETE_CHANNEL_COUNT(audio->config.out.mixdown);
+ }
// track->defaultDuration = job->arate * 1000;
mux_data->track = mk_createTrack(m->file, track);
if (audio->config.out.codec == HB_ACODEC_VORBIS && track->codecPrivate != NULL)
/* Audio */
hb_sync_audio_t sync_audio[8];
+ int64_t audio_passthru_slip;
/* Statistics */
uint64_t st_counts[4];
* can deal with overlaps of up to a frame time but anything larger
* we handle by dropping frames here.
*/
- if ( (int64_t)( next->start - cur->start ) <= 0 )
+ if ( (int64_t)( next->start - cur->start ) <= 0 ||
+ (int64_t)( (cur->start - pv->audio_passthru_slip ) - pv->next_pts ) < 0 )
{
if ( pv->first_drop == 0 )
{
hb_audio_t * audio = sync->audio;
hb_buffer_t * buf;
hb_fifo_t * fifo;
+ int64_t start;
- if( audio->config.out.codec == HB_ACODEC_AC3 )
+ if( audio->config.out.codec == HB_ACODEC_AC3 ||
+ audio->config.out.codec == HB_ACODEC_DCA )
{
fifo = audio->priv.fifo_out;
}
while( !hb_fifo_is_full( fifo ) && ( buf = hb_fifo_see( audio->priv.fifo_raw ) ) )
{
+ start = buf->start - pv->audio_passthru_slip;
/* if the next buffer is an eof send it downstream */
if ( buf->size <= 0 )
{
pv->busy &=~ (1 << (i + 1) );
return;
}
- if ( (int64_t)( buf->start - sync->next_pts ) < 0 )
+ if ( (int64_t)( start - sync->next_pts ) < 0 )
{
// audio time went backwards.
// If our output clock is more than a half frame ahead of the
// input clock drop this frame to move closer to sync.
// Otherwise drop frames until the input clock matches the output clock.
- if ( sync->first_drop || sync->next_start - buf->start > 90*15 )
+ if ( sync->first_drop || sync->next_start - start > 90*15 )
{
// Discard data that's in the past.
if ( sync->first_drop == 0 )
hb_buffer_close( &buf );
continue;
}
- sync->next_pts = buf->start;
+ sync->next_pts = start;
}
if ( sync->first_drop )
{
sync->drop_count, sync->first_drop, sync->next_pts );
sync->first_drop = 0;
sync->drop_count = 0;
- sync->next_pts = buf->start;
+ sync->next_pts = start;
}
- if ( buf->start - sync->next_pts >= (90 * 70) )
+ if ( start - sync->next_pts >= (90 * 70) )
{
- if ( buf->start - sync->next_pts > (90000LL * 60) )
+ if ( start - sync->next_pts > (90000LL * 60) )
{
// there's a gap of more than a minute between the last
// frame and this. assume we got a corrupted timestamp
// and just drop the next buf.
hb_log( "sync: %d minute time gap in audio %d - dropping buf"
" start %lld, next %lld",
- (int)((buf->start - sync->next_pts) / (90000*60)),
- i, buf->start, sync->next_pts );
+ (int)((start - sync->next_pts) / (90000*60)),
+ i, start, sync->next_pts );
buf = hb_fifo_get( audio->priv.fifo_raw );
hb_buffer_close( &buf );
continue;
/*
* there's a gap of at least 70ms between the last
* frame we processed & the next. Fill it with silence.
+ * Or in the case of DCA, skip some frames from the
+ * other streams.
*/
+ if( sync->audio->config.out.codec == HB_ACODEC_DCA )
+ {
+ hb_log( "sync: audio gap %d ms. Skipping frames. Audio %d"
+ " start %lld, next %lld",
+ (int)((start - sync->next_pts) / 90),
+ i, start, sync->next_pts );
+ pv->audio_passthru_slip += (start - sync->next_pts);
+ return;
+ }
hb_log( "sync: adding %d ms of silence to audio %d"
" start %lld, next %lld",
- (int)((buf->start - sync->next_pts) / 90),
- i, buf->start, sync->next_pts );
- InsertSilence( w, i, buf->start - sync->next_pts );
+ (int)((start - sync->next_pts) / 90),
+ i, start, sync->next_pts );
+ InsertSilence( w, i, start - sync->next_pts );
return;
}
/* sense-check the requested mixdown */
if( audio->config.out.mixdown == 0 &&
- audio->config.out.codec != HB_ACODEC_AC3 )
+ audio->config.out.codec != HB_ACODEC_AC3 &&
+ audio->config.out.codec != HB_ACODEC_DCA )
{
/*
* Mixdown wasn't specified and this is not pass-through,
/*
* Audio Encoder Thread
*/
- if( audio->config.out.codec != HB_ACODEC_AC3 )
+ if( audio->config.out.codec != HB_ACODEC_AC3 &&
+ audio->config.out.codec != HB_ACODEC_DCA )
{
/*
* Add the encoder thread if not doing AC-3 pass through