/*********************************************************************** * Decode *********************************************************************** * **********************************************************************/ 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; int64_t pts, pos; uint64_t upts, upos; 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, &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_PASS ) { 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; 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] * 32767; } } } pv->sync = 0; return buf; }
static int Decode( decoder_t *p_dec, block_t *p_in_buf ) { decoder_sys_t *p_sys = p_dec->p_sys; if (p_in_buf == NULL) /* No Drain */ return VLCDEC_SUCCESS; sample_t i_sample_level = 1; int i_flags = p_sys->i_flags; size_t i_bytes_per_block = 256 * p_sys->i_nb_channels * sizeof(float); block_t *p_out_buf = block_Alloc( 6 * i_bytes_per_block ); if( unlikely(p_out_buf == NULL) ) goto out; /* * Do the actual decoding now. */ /* Needs to be called so the decoder knows which type of bitstream it is * dealing with. */ int i_sample_rate, i_bit_rate, i_frame_length; if( !dca_syncinfo( p_sys->p_libdca, p_in_buf->p_buffer, &i_flags, &i_sample_rate, &i_bit_rate, &i_frame_length ) ) { msg_Warn( p_dec, "libdca couldn't sync on frame" ); p_out_buf->i_nb_samples = p_out_buf->i_buffer = 0; goto out; } i_flags = p_sys->i_flags; dca_frame( p_sys->p_libdca, p_in_buf->p_buffer, &i_flags, &i_sample_level, 0 ); if ( (i_flags & DCA_CHANNEL_MASK) != (p_sys->i_flags & DCA_CHANNEL_MASK) && !p_sys->b_dontwarn ) { msg_Warn( p_dec, "libdca couldn't do the requested downmix 0x%x->0x%x", p_sys->i_flags & DCA_CHANNEL_MASK, i_flags & DCA_CHANNEL_MASK ); p_sys->b_dontwarn = 1; } if( 0)//!p_sys->b_dynrng ) { dca_dynrng( p_sys->p_libdca, NULL, NULL ); } for( int i = 0; i < dca_blocks_num(p_sys->p_libdca); i++ ) { sample_t * p_samples; if( dca_block( p_sys->p_libdca ) ) { msg_Warn( p_dec, "dca_block failed for block %d", i ); break; } p_samples = dca_samples( p_sys->p_libdca ); if ( (p_sys->i_flags & DCA_CHANNEL_MASK) == DCA_MONO && (p_dec->fmt_out.audio.i_physical_channels & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) ) { Duplicate( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block), p_samples ); } else if ( p_dec->fmt_out.audio.i_original_channels & AOUT_CHAN_REVERSESTEREO ) { Exchange( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block), p_samples ); } else { /* Interleave the *$£%ù samples. */ Interleave( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block), p_samples, p_sys->i_nb_channels, p_sys->pi_chan_table); } } p_out_buf->i_nb_samples = dca_blocks_num(p_sys->p_libdca) * 256; p_out_buf->i_buffer = p_in_buf->i_nb_samples * sizeof(float) * p_sys->i_nb_channels; p_out_buf->i_dts = p_in_buf->i_dts; p_out_buf->i_pts = p_in_buf->i_pts; p_out_buf->i_length = p_in_buf->i_length; out: if (p_out_buf != NULL) decoder_QueueAudio(p_dec, p_out_buf); block_Release( p_in_buf ); return VLCDEC_SUCCESS; }
static GstFlowReturn gst_dtsdec_handle_frame (GstAudioDecoder * bdec, GstBuffer * buffer) { GstDtsDec *dts; gint channels, i, num_blocks; gboolean need_renegotiation = FALSE; guint8 *data; gsize size; GstMapInfo map; gint chans; gint length = 0, flags, sample_rate, bit_rate, frame_length; GstFlowReturn result = GST_FLOW_OK; GstBuffer *outbuf; dts = GST_DTSDEC (bdec); /* no fancy draining */ if (G_UNLIKELY (!buffer)) return GST_FLOW_OK; /* parsed stuff already, so this should work out fine */ gst_buffer_map (buffer, &map, GST_MAP_READ); data = map.data; size = map.size; g_assert (size >= 7); bit_rate = dts->bit_rate; sample_rate = dts->sample_rate; flags = 0; length = dca_syncinfo (dts->state, data, &flags, &sample_rate, &bit_rate, &frame_length); g_assert (length == size); if (flags != dts->prev_flags) { dts->prev_flags = flags; dts->flag_update = TRUE; } /* go over stream properties, renegotiate or update streaminfo if needed */ if (dts->sample_rate != sample_rate) { need_renegotiation = TRUE; dts->sample_rate = sample_rate; } if (flags) { dts->stream_channels = flags & (DCA_CHANNEL_MASK | DCA_LFE); } if (bit_rate != dts->bit_rate) { dts->bit_rate = bit_rate; gst_dtsdec_update_streaminfo (dts); } /* If we haven't had an explicit number of channels chosen through properties * at this point, choose what to downmix to now, based on what the peer will * accept - this allows a52dec to do downmixing in preference to a * downstream element such as audioconvert. * FIXME: Add the property back in for forcing output channels. */ if (dts->request_channels != DCA_CHANNEL) { flags = dts->request_channels; } else if (dts->flag_update) { GstCaps *caps; dts->flag_update = FALSE; caps = gst_pad_get_allowed_caps (GST_AUDIO_DECODER_SRC_PAD (dts)); if (caps && gst_caps_get_size (caps) > 0) { GstCaps *copy = gst_caps_copy_nth (caps, 0); GstStructure *structure = gst_caps_get_structure (copy, 0); gint channels; const int dts_channels[6] = { DCA_MONO, DCA_STEREO, DCA_STEREO | DCA_LFE, DCA_2F2R, DCA_2F2R | DCA_LFE, DCA_3F2R | DCA_LFE, }; /* Prefer the original number of channels, but fixate to something * preferred (first in the caps) downstream if possible. */ gst_structure_fixate_field_nearest_int (structure, "channels", flags ? gst_dtsdec_channels (flags, NULL) : 6); gst_structure_get_int (structure, "channels", &channels); if (channels <= 6) flags = dts_channels[channels - 1]; else flags = dts_channels[5]; gst_caps_unref (copy); } else if (flags) { flags = dts->stream_channels; } else { flags = DCA_3F2R | DCA_LFE; } if (caps) gst_caps_unref (caps); } else { flags = dts->using_channels; } /* process */ flags |= DCA_ADJUST_LEVEL; dts->level = 1; if (dca_frame (dts->state, data, &flags, &dts->level, dts->bias)) { gst_buffer_unmap (buffer, &map); GST_AUDIO_DECODER_ERROR (dts, 1, STREAM, DECODE, (NULL), ("dts_frame error"), result); goto exit; } gst_buffer_unmap (buffer, &map); channels = flags & (DCA_CHANNEL_MASK | DCA_LFE); if (dts->using_channels != channels) { need_renegotiation = TRUE; dts->using_channels = channels; } /* negotiate if required */ if (need_renegotiation) { GST_DEBUG_OBJECT (dts, "dtsdec: sample_rate:%d stream_chans:0x%x using_chans:0x%x", dts->sample_rate, dts->stream_channels, dts->using_channels); if (!gst_dtsdec_renegotiate (dts)) goto failed_negotiation; } if (dts->dynamic_range_compression == FALSE) { dca_dynrng (dts->state, NULL, NULL); } flags &= (DCA_CHANNEL_MASK | DCA_LFE); chans = gst_dtsdec_channels (flags, NULL); if (!chans) goto invalid_flags; /* handle decoded data, one block is 256 samples */ num_blocks = dca_blocks_num (dts->state); outbuf = gst_buffer_new_and_alloc (256 * chans * (SAMPLE_WIDTH / 8) * num_blocks); gst_buffer_map (outbuf, &map, GST_MAP_WRITE); data = map.data; size = map.size; { guint8 *ptr = data; for (i = 0; i < num_blocks; i++) { if (dca_block (dts->state)) { /* also marks discont */ GST_AUDIO_DECODER_ERROR (dts, 1, STREAM, DECODE, (NULL), ("error decoding block %d", i), result); if (result != GST_FLOW_OK) goto exit; } else { gint n, c; gint *reorder_map = dts->channel_reorder_map; for (n = 0; n < 256; n++) { for (c = 0; c < chans; c++) { ((sample_t *) ptr)[n * chans + reorder_map[c]] = dts->samples[c * 256 + n]; } } } ptr += 256 * chans * (SAMPLE_WIDTH / 8); } } gst_buffer_unmap (outbuf, &map); result = gst_audio_decoder_finish_frame (bdec, outbuf, 1); exit: return result; /* ERRORS */ failed_negotiation: { GST_ELEMENT_ERROR (dts, CORE, NEGOTIATION, (NULL), (NULL)); return GST_FLOW_ERROR; } invalid_flags: { GST_ELEMENT_ERROR (GST_ELEMENT (dts), STREAM, DECODE, (NULL), ("Invalid channel flags: %d", flags)); return GST_FLOW_ERROR; } }
HRESULT TaudioCodecLibDTS::decode(TbyteBuffer &src) { unsigned char *p = src.size() ? &src[0] : NULL; unsigned char *base = p; unsigned char *end = p + src.size(); while (end - p >= 14) { int size = 0, flags, sample_rate, frame_length, bit_rate; if ((size = dca_syncinfo(state, p, &flags, &sample_rate, &bit_rate, &frame_length)) > 0) { bool enoughData = p + size <= end; if (enoughData) { if (codecId == CODEC_ID_SPDIF_DTS) { bpssum += (lastbps = bit_rate / 1000); numframes++; BYTE type; switch (frame_length) { case 512: type = 0x0b; break; case 1024: type = 0x0c; break; default : type = 0x0d; break; } HRESULT hr = deciA->deliverSampleBistream(p, size, bit_rate, sample_rate, true, frame_length, 0); if (hr != S_OK) { return hr; } } else { flags |= DCA_ADJUST_LEVEL; libdca::sample_t level = 1, bias = 0; if (dca_frame(state, p, &flags, &level, bias) == 0) { bpssum += (lastbps = bit_rate / 1000); numframes++; // Dynamic range compression - Not suppored yet by libdts if (deci->getParam2(IDFF_audio_decoder_DRC)) { libdca::sample_t drcLevel = ((libdca::sample_t)deci->getParam2(IDFF_audio_decoder_DRC_Level) / 100); if (drcLevel <= 0.5) { dca_dynrng(state, NULL, NULL); } } else { dca_dynrng(state, NULL, NULL); } int scmapidx = std::min(flags & DCA_CHANNEL_MASK, int(countof(scmaps) / 2)); const Tscmap &scmap = scmaps[scmapidx + ((flags & DCA_LFE) ? (countof(scmaps) / 2) : 0)]; int blocks = dca_blocks_num(state); float *dst0, *dst; dst0 = dst = (float*)getDst(blocks * 256 * scmap.nchannels * sizeof(float)); int i = 0; for (; i < blocks && dca_block(state) == 0; i++) { libdca::sample_t* samples = dca_samples(state); for (int j = 0; j < 256; j++, samples++) for (int ch = 0; ch < scmap.nchannels; ch++) { *dst++ = float(*(samples + 256 * scmap.ch[ch]) / level); } } if (i == blocks) { fmt.sf = TsampleFormat::SF_FLOAT32; fmt.freq = sample_rate; fmt.setChannels(scmap.nchannels, scmap.channelMask); HRESULT hr = sinkA->deliverDecodedSample(dst0, blocks * 256, fmt); if (hr != S_OK) { return hr; } } } } p += size; } memmove(base, p, end - p); end = base + (end - p); p = base; if (!enoughData) { break; } } else { p++; } } src.resize(end - p); return S_OK; }