mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-25 12:27:21 +00:00
378 lines
11 KiB
C++
378 lines
11 KiB
C++
/*
|
|
mkvmerge -- utility for splicing together matroska files
|
|
from component media subtypes
|
|
|
|
dts_common.cpp
|
|
|
|
Written by Moritz Bunkus <moritz@bunkus.org>
|
|
|
|
Distributed under the GPL
|
|
see the file COPYING for details
|
|
or visit http://www.gnu.org/copyleft/gpl.html
|
|
*/
|
|
|
|
/*!
|
|
\file
|
|
\version $Id$
|
|
\brief helper function for DTS data
|
|
\author Peter Niemayer <niemayer@isg.de>
|
|
\author Moritz Bunkus <moritz@bunkus.org>
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include "common.h"
|
|
#include "dts_common.h"
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
struct channel_arrangement {
|
|
int num_channels;
|
|
const char * description;
|
|
};
|
|
|
|
static const channel_arrangement channel_arrangements[16] = {
|
|
{ 1, "A (mono)" },
|
|
{ 2, "A, B (dual mono)" },
|
|
{ 2, "L, R (left, right)" },
|
|
{ 2, "L+R, L-R (sum, difference)" },
|
|
{ 2, "LT, RT (left and right total)" },
|
|
{ 3, "C, L, R (center, left, right)" },
|
|
{ 3, "L, R, S (left, right, surround)" },
|
|
{ 4, "C, L, R, S (center, left, right, surround)" },
|
|
{ 4, "L, R, SL, SR (left, right, surround-left, surround-right)"},
|
|
{ 5, "C, L, R, SL, SR (center, left, right, surround-left, surround-right)"},
|
|
{ 6, "CL, CR, L, R, SL, SR (center-left, center-right, left, right, "
|
|
"surround-left, surround-right)"},
|
|
{ 6, "C, L, R, LR, RR, OV (center, left, right, left-rear, right-rear, "
|
|
"overhead)"},
|
|
{ 6, "CF, CR, LF, RF, LR, RR (center-front, center-rear, left-front, "
|
|
"right-front, left-rear, right-rear)"},
|
|
{ 7, "CL, C, CR, L, R, SL, SR (center-left, center, center-right, left, "
|
|
"right, surround-left, surround-right)"},
|
|
{ 8, "CL, CR, L, R, SL1, SL2, SR1, SR2 (center-left, center-right, left, "
|
|
"right, surround-left1, surround-left2, surround-right1, "
|
|
"surround-right2)"},
|
|
{ 8, "CL, C, CR, L, R, SL, S, SR (center-left, center, center-right, left, "
|
|
"right, surround-left, surround, surround-right)"}
|
|
// other modes are not defined as of yet
|
|
};
|
|
|
|
static const int core_samplefreqs[16] = {
|
|
-1, 8000, 16000, 32000, -1, -1, 11025, 22050,
|
|
44100, -1, -1, 12000, 24000, 48000, -1, -1
|
|
};
|
|
|
|
static const int transmission_bitrates[32] = {
|
|
32000, 56000, 64000, 96000,
|
|
112000, 128000, 192000, 224000,
|
|
256000, 320000, 384000, 448000,
|
|
512000, 576000, 640000, 768000,
|
|
960000, 1024000, 1152000, 1280000,
|
|
1344000, 1408000, 1411200, 1472000,
|
|
1536000, 1920000, 2048000, 3072000,
|
|
3840000, -1 /*open*/, -2 /*variable*/, -3 /*lossless*/
|
|
// [15] 768000 is actually 754500 for DVD
|
|
// [24] 1536000 is actually 1509750 for DVD
|
|
// [22] 1411200 is actually 1234800 for 14-bit DTS-CD audio
|
|
};
|
|
|
|
enum source_pcm_resolution {
|
|
spr_16 = 0,
|
|
spr_16_ES, //_ES means: surround channels mastered in DTS-ES
|
|
spr_20,
|
|
spr_20_ES,
|
|
spr_invalid4,
|
|
spr_24_ES,
|
|
spr_24,
|
|
spr_invalid7
|
|
};
|
|
|
|
int find_dts_header(const unsigned char *buf, unsigned int size,
|
|
struct dts_header_s *dts_header) {
|
|
|
|
unsigned int size_to_search = size-15;
|
|
if (size_to_search > size) {
|
|
// not enough data for one header
|
|
return -1;
|
|
}
|
|
|
|
unsigned int offset;
|
|
for (offset = 0; offset < size_to_search; offset++) {
|
|
// sync words appear aligned in the bit stream
|
|
if (buf[offset] == 0x7f &&
|
|
buf[offset + 1] == 0xfe &&
|
|
buf[offset + 2] == 0x80 &&
|
|
buf[offset + 3] == 0x01) {
|
|
break;
|
|
}
|
|
}
|
|
if (offset >= size_to_search) {
|
|
// no header found
|
|
return -1;
|
|
}
|
|
|
|
bit_cursor_c bc(buf+offset+4, size-offset-4);
|
|
|
|
unsigned int t;
|
|
|
|
bc.get_bits(1, t);
|
|
dts_header->frametype = (t)? dts_header_s::frametype_normal :
|
|
dts_header_s::frametype_termination;
|
|
|
|
bc.get_bits(5, t);
|
|
dts_header->deficit_sample_count = (t+1) % 32;
|
|
|
|
bc.get_bits(1, t);
|
|
dts_header->crc_present = (t)? true : false;
|
|
|
|
bc.get_bits(7, t);
|
|
if (t < 5) {
|
|
fprintf(stderr,"DTS_Header problem: invalid number of blocks in frame\n");
|
|
//return -1;
|
|
}
|
|
dts_header->num_pcm_sample_blocks = t + 1;
|
|
|
|
bc.get_bits(14, t);
|
|
if (t < 95) {
|
|
fprintf(stderr,"DTS_Header problem: invalid frame bytes size\n");
|
|
return -1;
|
|
}
|
|
dts_header->frame_byte_size = t+1;
|
|
|
|
bc.get_bits(6, t);
|
|
if (t >= 16) {
|
|
dts_header->audio_channels = -1;
|
|
dts_header->audio_channel_arrangement = "unknown (user defined)";
|
|
} else {
|
|
dts_header->audio_channels = channel_arrangements[t].num_channels;
|
|
dts_header->audio_channel_arrangement =
|
|
channel_arrangements[t].description;
|
|
}
|
|
|
|
bc.get_bits(4, t);
|
|
dts_header->core_sampling_frequency = core_samplefreqs[t];
|
|
if (dts_header->core_sampling_frequency < 0) {
|
|
fprintf(stderr,"DTS_Header problem: invalid core sampling frequency\n");
|
|
return -1;
|
|
}
|
|
|
|
bc.get_bits(5, t);
|
|
dts_header->transmission_bitrate = transmission_bitrates[t];
|
|
|
|
bc.get_bit(dts_header->embedded_down_mix);
|
|
bc.get_bit(dts_header->embedded_dynamic_range);
|
|
bc.get_bit(dts_header->embedded_time_stamp);
|
|
bc.get_bit(dts_header->auxiliary_data);
|
|
bc.get_bit(dts_header->hdcd_master);
|
|
|
|
bc.get_bits(3, t);
|
|
dts_header->extension_audio_descriptor =
|
|
(dts_header_s::extension_audio_descriptor_enum)t;
|
|
|
|
bc.get_bit(dts_header->extended_coding);
|
|
|
|
bc.get_bit(dts_header->audio_sync_word_in_sub_sub);
|
|
|
|
bc.get_bits(2, t);
|
|
dts_header->lfe_type = (dts_header_s::lfe_type_enum)t;
|
|
|
|
bc.get_bit(dts_header->predictor_history_flag);
|
|
|
|
if (dts_header->crc_present) {
|
|
bc.get_bits(16, t);
|
|
// unsigned short header_CRC_sum = t; // not used yet
|
|
}
|
|
|
|
bc.get_bits(1, t);
|
|
dts_header->multirate_interpolator =
|
|
(dts_header_s::multirate_interpolator_enum)t;
|
|
|
|
bc.get_bits(4, t);
|
|
dts_header->encoder_software_revision = t;
|
|
if (t > 7) {
|
|
fprintf(stderr,"DTS_Header problem: encoded with an incompatible new "
|
|
"encoder version\n");
|
|
return -1;
|
|
}
|
|
|
|
bc.get_bits(2, t);
|
|
dts_header->copy_history = t;
|
|
|
|
bc.get_bits(3, t);
|
|
switch (t) {
|
|
case spr_16:
|
|
dts_header->source_pcm_resolution = 16;
|
|
dts_header->source_surround_in_es = false;
|
|
break;
|
|
|
|
case spr_16_ES:
|
|
dts_header->source_pcm_resolution = 16;
|
|
dts_header->source_surround_in_es = true;
|
|
break;
|
|
|
|
case spr_20:
|
|
dts_header->source_pcm_resolution = 20;
|
|
dts_header->source_surround_in_es = false;
|
|
break;
|
|
|
|
case spr_20_ES:
|
|
dts_header->source_pcm_resolution = 20;
|
|
dts_header->source_surround_in_es = true;
|
|
break;
|
|
|
|
case spr_24:
|
|
dts_header->source_pcm_resolution = 24;
|
|
dts_header->source_surround_in_es = false;
|
|
break;
|
|
|
|
case spr_24_ES:
|
|
dts_header->source_pcm_resolution = 24;
|
|
dts_header->source_surround_in_es = true;
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr,"DTS_Header problem: invalid source PCM resolution\n");
|
|
return -1;
|
|
}
|
|
|
|
bc.get_bit(dts_header->front_sum_difference);
|
|
|
|
bc.get_bit(dts_header->surround_sum_difference);
|
|
|
|
bool out_of_data = bc.get_bits(4, t);
|
|
if (dts_header->encoder_software_revision == 7) {
|
|
dts_header->dialog_normalization_gain = -((int)t);
|
|
} else if (dts_header->encoder_software_revision == 6) {
|
|
dts_header->dialog_normalization_gain = -16-((int)t);
|
|
} else {
|
|
dts_header->dialog_normalization_gain = 0;
|
|
}
|
|
|
|
if (out_of_data) {
|
|
fprintf(stderr,"DTS_Header problem: not enough data to read header\n");
|
|
return -1;
|
|
}
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
// ============================================================================
|
|
|
|
void print_dts_header(const struct dts_header_s *h) {
|
|
|
|
fprintf(stderr,"DTS Frame Header Information:\n");
|
|
|
|
fprintf(stderr,"Frame Type : ");
|
|
if (h->frametype == dts_header_s::frametype_normal) {
|
|
fprintf(stderr,"normal");
|
|
} else {
|
|
fprintf(stderr,"termination, deficit sample count = %u",
|
|
h->deficit_sample_count);
|
|
}
|
|
fprintf(stderr,"\n");
|
|
|
|
fprintf(stderr,"CRC available : %s\n", (h->crc_present)? "yes" :
|
|
"no");
|
|
|
|
fprintf(stderr,"Frame Size : PCM core samples=32*%u=%u, %f "
|
|
"milliseconds, %u byte\n",
|
|
h->num_pcm_sample_blocks, h->num_pcm_sample_blocks * 32,
|
|
(h->num_pcm_sample_blocks * 32000.0) / h->core_sampling_frequency,
|
|
h->frame_byte_size);
|
|
|
|
fprintf(stderr,"Audio Channels : %d%s, arrangement: %s\n",
|
|
h->audio_channels, (h->source_surround_in_es)? " ES" : "" ,
|
|
h->audio_channel_arrangement);
|
|
|
|
fprintf(stderr,"Core sampling frequency: %u\n", h->core_sampling_frequency);
|
|
|
|
fprintf(stderr,"Transmission_bitrate : ");
|
|
if (h->transmission_bitrate == -1) {
|
|
fprintf(stderr,"open");
|
|
} else if (h->transmission_bitrate == -2) {
|
|
fprintf(stderr,"variable");
|
|
} else if (h->transmission_bitrate == -3) {
|
|
fprintf(stderr,"lossless");
|
|
} else {
|
|
fprintf(stderr,"%d", h->transmission_bitrate);
|
|
}
|
|
fprintf(stderr,"\n");
|
|
|
|
|
|
fprintf(stderr,"Embedded Down Mix : %s\n",
|
|
(h->embedded_down_mix)? "yes" : "no");
|
|
fprintf(stderr,"Embedded Dynamic Range : %s\n",
|
|
(h->embedded_dynamic_range)? "yes" : "no");
|
|
fprintf(stderr,"Embedded Time Stamp : %s\n",
|
|
(h->embedded_time_stamp)? "yes" : "no");
|
|
fprintf(stderr,"Embedded Auxiliary Data: %s\n",
|
|
(h->auxiliary_data)? "yes" : "no");
|
|
fprintf(stderr,"HDCD Master : %s\n",
|
|
(h->hdcd_master)? "yes" : "no");
|
|
|
|
fprintf(stderr,"Extended Coding : ");
|
|
if (h->extended_coding) {
|
|
switch (h->extension_audio_descriptor) {
|
|
case dts_header_s::extension_xch:
|
|
fprintf(stderr,"Extra Channels");
|
|
break;
|
|
case dts_header_s::extension_x96k:
|
|
fprintf(stderr,"Extended frequency (x96k)");
|
|
break;
|
|
case dts_header_s::extension_xch_x96k:
|
|
fprintf(stderr,"Extra Channels and Extended frequency (x96k)");
|
|
break;
|
|
default:
|
|
fprintf(stderr,"yes, but unknown");
|
|
break;
|
|
}
|
|
} else {
|
|
fprintf(stderr,"no");
|
|
}
|
|
fprintf(stderr,"\n");
|
|
|
|
fprintf(stderr,"Audio Sync in sub-subs : %s\n",
|
|
(h->audio_sync_word_in_sub_sub)? "yes" : "no");
|
|
|
|
fprintf(stderr,"Low Frequency Effects : ");
|
|
switch (h->lfe_type) {
|
|
case dts_header_s::lfe_none:
|
|
fprintf(stderr,"none");
|
|
break;
|
|
case dts_header_s::lfe_128:
|
|
fprintf(stderr,"yes, interpolation factor 128");
|
|
break;
|
|
case dts_header_s::lfe_64:
|
|
fprintf(stderr,"yes, interpolation factor 64");
|
|
break;
|
|
case dts_header_s::lfe_invalid:
|
|
fprintf(stderr,"Invalid");
|
|
break;
|
|
}
|
|
fprintf(stderr,"\n");
|
|
|
|
fprintf(stderr,"Predictor History used : %s\n",
|
|
(h->predictor_history_flag)? "yes" : "no");
|
|
|
|
fprintf(stderr,"Multirate Interpolator : %s\n",
|
|
(h->multirate_interpolator == dts_header_s::mi_non_perfect)?
|
|
"non perfect" : "perfect");
|
|
|
|
fprintf(stderr,"Encoder Software Vers. : %u\n",
|
|
h->encoder_software_revision);
|
|
fprintf(stderr,"Copy History Bits : %u\n", h->copy_history);
|
|
fprintf(stderr,"Source PCM Resolution : %d\n", h->source_pcm_resolution);
|
|
|
|
fprintf(stderr,"Front Encoded as Diff. : %s\n",
|
|
(h->front_sum_difference)? "yes" : "no");
|
|
fprintf(stderr,"Surr. Encoded as Diff. : %s\n",
|
|
(h->surround_sum_difference)? "yes" : "no");
|
|
|
|
fprintf(stderr,"Dialog Normaliz. Gain : %d\n",
|
|
h->dialog_normalization_gain);
|
|
}
|
|
|