mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-24 11:54:01 +00:00
Low bitrate AC3 tracks from Real's DNET are identified as A_AC3/BSID9 or A_AC3/BSID10.
This commit is contained in:
parent
5acb7c26e4
commit
e622f34e61
@ -1,5 +1,8 @@
|
||||
2003-08-14 Moritz Bunkus <moritz@bunkus.org>
|
||||
|
||||
* mkvmerge: Low bitrate AC3 tracks from Real's DNET are identified
|
||||
as A_AC3/BSID9 or A_AC3/BSID10.
|
||||
|
||||
* mkvmerge: The RealMedia reader takes the number of packets into
|
||||
account when reading which results in better end-of-file detection.
|
||||
|
||||
|
@ -22,6 +22,21 @@
|
||||
|
||||
#include "ac3_common.h"
|
||||
|
||||
/*
|
||||
<S_O> AC3 Header:
|
||||
<S_O> AAAAAAAA AAAAAAAA BBBBBBBB BBBBBBBB CCDDDDDD EEEEEFFF
|
||||
<S_O> A = sync, always 0x0B77
|
||||
<S_O> B = CRC 16 of 5/8 frame
|
||||
<S_O> C = samplerate:
|
||||
<S_O> if E <= 8: 00 = 48kHz; 01 = 44,1kHz; 10 = 32kHz; 11 = reserved
|
||||
<S_O> if E = 9: 00 = 24kHz; 01 = 22,05kHz; 10 = 16kHz; 11 = reserved
|
||||
<S_O> if E = 10: 00 = 12kHz; 01 = 11,025kHz; 10 = 8KHz; 11 = reserved
|
||||
<S_O> D = framesize code, 12/24KHz is like 48kHz, 8/16kHz like 32kHz etc.
|
||||
<S_O> E = bitstream ID, if <=8 compatible to all standard decoders
|
||||
<S_O> 9 and 10 = low samplerate additions
|
||||
<S_O> F = bitstream mode
|
||||
*/
|
||||
|
||||
int find_ac3_header(unsigned char *buf, int size, ac3_header_t *ac3_header) {
|
||||
static int rate[] = { 32, 40, 48, 56, 64, 80, 96, 112, 128, 160,
|
||||
192, 224, 256, 320, 384, 448, 512, 576, 640};
|
||||
@ -90,6 +105,7 @@ int find_ac3_header(unsigned char *buf, int size, ac3_header_t *ac3_header) {
|
||||
}
|
||||
if (header.flags & A52_LFE)
|
||||
header.channels++;
|
||||
header.bsid = (buf[i + 5] >> 3);
|
||||
memcpy(ac3_header, &header, sizeof(ac3_header_t));
|
||||
|
||||
return i;
|
||||
|
@ -42,6 +42,7 @@ typedef struct {
|
||||
int channels;
|
||||
int flags;
|
||||
int bytes;
|
||||
int bsid;
|
||||
} ac3_header_t;
|
||||
|
||||
int find_ac3_header(unsigned char *buf, int size, ac3_header_t *ac3_header);
|
||||
|
@ -32,7 +32,7 @@ using namespace libmatroska;
|
||||
|
||||
ac3_packetizer_c::ac3_packetizer_c(generic_reader_c *nreader,
|
||||
unsigned long nsamples_per_sec,
|
||||
int nchannels, track_info_t *nti)
|
||||
int nchannels, int nbsid, track_info_t *nti)
|
||||
throw (error_c): generic_packetizer_c(nreader, nti) {
|
||||
packetno = 0;
|
||||
bytes_output = 0;
|
||||
@ -40,6 +40,7 @@ ac3_packetizer_c::ac3_packetizer_c(generic_reader_c *nreader,
|
||||
buffer_size = 0;
|
||||
samples_per_sec = nsamples_per_sec;
|
||||
channels = nchannels;
|
||||
bsid = nbsid;
|
||||
|
||||
set_track_type(track_audio);
|
||||
set_track_default_duration_ns((int64_t)(1536000000000.0 *ti->async.linear /
|
||||
@ -148,7 +149,13 @@ unsigned char *ac3_packetizer_c::get_ac3_packet(unsigned long *header,
|
||||
}
|
||||
|
||||
void ac3_packetizer_c::set_headers() {
|
||||
set_codec_id(MKV_A_AC3);
|
||||
string id = MKV_A_AC3;
|
||||
|
||||
if (bsid == 9)
|
||||
id += "/BSID9";
|
||||
else if (bsid == 10)
|
||||
id += "/BSID10";
|
||||
set_codec_id(id.c_str());
|
||||
set_audio_sampling_freq((float)samples_per_sec);
|
||||
set_audio_channels(channels);
|
||||
|
||||
@ -190,9 +197,10 @@ void ac3_packetizer_c::dump_debug_info() {
|
||||
|
||||
ac3_bs_packetizer_c::ac3_bs_packetizer_c(generic_reader_c *nreader,
|
||||
unsigned long nsamples_per_sec,
|
||||
int nchannels, track_info_t *nti)
|
||||
int nchannels, int nbsid,
|
||||
track_info_t *nti)
|
||||
throw (error_c): ac3_packetizer_c(nreader, nsamples_per_sec, nchannels,
|
||||
nti) {
|
||||
nbsid, nti) {
|
||||
bsb_present = false;
|
||||
}
|
||||
|
||||
|
@ -31,12 +31,13 @@ class ac3_packetizer_c: public generic_packetizer_c {
|
||||
protected:
|
||||
int64_t bytes_output, packetno;
|
||||
unsigned long samples_per_sec;
|
||||
int channels, buffer_size;
|
||||
int channels, buffer_size, bsid;
|
||||
unsigned char *packet_buffer;
|
||||
|
||||
public:
|
||||
ac3_packetizer_c(generic_reader_c *nreader, unsigned long nsamples_per_sec,
|
||||
int nchannels, track_info_t *nti) throw (error_c);
|
||||
int nchannels, int nbsid, track_info_t *nti)
|
||||
throw (error_c);
|
||||
virtual ~ac3_packetizer_c();
|
||||
|
||||
virtual int process(unsigned char *buf, int size, int64_t timecode = -1,
|
||||
@ -62,7 +63,8 @@ protected:
|
||||
public:
|
||||
ac3_bs_packetizer_c(generic_reader_c *nreader,
|
||||
unsigned long nsamples_per_sec,
|
||||
int nchannels, track_info_t *nti) throw (error_c);
|
||||
int nchannels, int nbsid, track_info_t *nti)
|
||||
throw (error_c);
|
||||
|
||||
protected:
|
||||
virtual void add_to_buffer(unsigned char *buf, int size);
|
||||
|
@ -232,7 +232,7 @@ int generic_packetizer_c::get_track_num() {
|
||||
return hserialno;
|
||||
}
|
||||
|
||||
void generic_packetizer_c::set_codec_id(char *id) {
|
||||
void generic_packetizer_c::set_codec_id(const char *id) {
|
||||
safefree(hcodec_id);
|
||||
if (id == NULL) {
|
||||
hcodec_id = NULL;
|
||||
@ -241,7 +241,8 @@ void generic_packetizer_c::set_codec_id(char *id) {
|
||||
hcodec_id = safestrdup(id);
|
||||
}
|
||||
|
||||
void generic_packetizer_c::set_codec_private(unsigned char *cp, int length) {
|
||||
void generic_packetizer_c::set_codec_private(const unsigned char *cp,
|
||||
int length) {
|
||||
safefree(hcodec_private);
|
||||
if (cp == NULL) {
|
||||
hcodec_private = NULL;
|
||||
@ -330,7 +331,7 @@ void generic_packetizer_c::force_default_track(int type) {
|
||||
default_tracks[idx] = hserialno;
|
||||
}
|
||||
|
||||
void generic_packetizer_c::set_language(char *language) {
|
||||
void generic_packetizer_c::set_language(const char *language) {
|
||||
safefree(ti->language);
|
||||
ti->language = safestrdup(language);
|
||||
}
|
||||
|
@ -177,10 +177,10 @@ public:
|
||||
virtual int set_uid(uint32_t uid);
|
||||
virtual void set_track_type(int type);
|
||||
virtual int get_track_type();
|
||||
virtual void set_language(char *language);
|
||||
virtual void set_language(const char *language);
|
||||
|
||||
virtual void set_codec_id(char *id);
|
||||
virtual void set_codec_private(unsigned char *cp, int length);
|
||||
virtual void set_codec_id(const char *id);
|
||||
virtual void set_codec_private(const unsigned char *cp, int length);
|
||||
|
||||
virtual void set_track_min_cache(int min_cache);
|
||||
virtual void set_track_max_cache(int max_cache);
|
||||
|
@ -80,7 +80,7 @@ ac3_reader_c::ac3_reader_c(track_info_t *nti) throw (error_c):
|
||||
bytes_processed = 0;
|
||||
ti->id = 0; // ID for this track.
|
||||
ac3packetizer = new ac3_packetizer_c(this, ac3header.sample_rate,
|
||||
ac3header.channels, ti);
|
||||
ac3header.channels, ac3header.bsid, ti);
|
||||
if (verbose)
|
||||
mxprint(stdout, "Using AC3 demultiplexer for %s.\n+-> Using "
|
||||
"AC3 output module for audio stream.\n", ti->fname);
|
||||
|
@ -229,7 +229,7 @@ void avi_reader_c::add_audio_demuxer(avi_t *avi, int aid) {
|
||||
demuxer->bits_per_sample = AVI_audio_mp3rate(avi);
|
||||
demuxer->packetizer = new ac3_packetizer_c(this,
|
||||
demuxer->samples_per_second,
|
||||
demuxer->channels, ti);
|
||||
demuxer->channels, 0, ti);
|
||||
break;
|
||||
default:
|
||||
mxprint(stderr, "Error: Unknown audio format 0x%04x for audio track ID "
|
||||
|
@ -335,7 +335,7 @@ void kax_reader_c::verify_tracks() {
|
||||
} else {
|
||||
if (!strcmp(t->codec_id, MKV_A_MP3))
|
||||
t->a_formattag = 0x0055;
|
||||
else if (!strcmp(t->codec_id, MKV_A_AC3))
|
||||
else if (!strncmp(t->codec_id, MKV_A_AC3, strlen(MKV_A_AC3)))
|
||||
t->a_formattag = 0x2000;
|
||||
else if (!strcmp(t->codec_id, MKV_A_DTS))
|
||||
t->a_formattag = 0x2001;
|
||||
@ -1141,9 +1141,17 @@ void kax_reader_c::create_packetizers() {
|
||||
mxprint(stdout, "Matroska demultiplexer (%s): using the MP3 "
|
||||
"output module for track ID %u.\n", ti->fname, t->tnum);
|
||||
} else if (t->a_formattag == 0x2000) {
|
||||
int bsid;
|
||||
|
||||
if (!strcmp(t->codec_id, "A_AC3/BSID9"))
|
||||
bsid = 9;
|
||||
else if (!strcmp(t->codec_id, "A_AC3/BSID10"))
|
||||
bsid = 10;
|
||||
else
|
||||
bsid = 0;
|
||||
t->packetizer = new ac3_packetizer_c(this,
|
||||
(unsigned long)t->a_sfreq,
|
||||
t->a_channels, &nti);
|
||||
t->a_channels, bsid, &nti);
|
||||
if (verbose)
|
||||
mxprint(stdout, "Matroska demultiplexer (%s): using the AC3 "
|
||||
"output module for track ID %u.\n", ti->fname, t->tnum);
|
||||
|
@ -291,7 +291,7 @@ void ogm_reader_c::create_packetizers() {
|
||||
try {
|
||||
dmx->packetizer =
|
||||
new ac3_packetizer_c(this, get_uint64(&sth->samples_per_unit),
|
||||
get_uint16(&sth->sh.audio.channels), ti);
|
||||
get_uint16(&sth->sh.audio.channels), 0, ti);
|
||||
} catch (error_c &error) {
|
||||
mxprint(stderr, "Error: ogm_reader: could not initialize AC3 "
|
||||
"packetizer for stream id %d. Will try to continue and "
|
||||
|
@ -174,6 +174,7 @@ real_reader_c::real_reader_c(track_info_t *nti) throw (error_c):
|
||||
mxprint(stdout, "Using RealMedia demultiplexer for %s.\n", ti->fname);
|
||||
|
||||
parse_headers();
|
||||
get_information_from_data();
|
||||
if (!identifying)
|
||||
create_packetizers();
|
||||
}
|
||||
@ -468,7 +469,7 @@ void real_reader_c::create_packetizers() {
|
||||
if (!strncmp(dmx->fourcc, "dnet", 4)) {
|
||||
dmx->packetizer =
|
||||
new ac3_bs_packetizer_c(this, dmx->samples_per_second, dmx->channels,
|
||||
ti);
|
||||
dmx->bsid, ti);
|
||||
if (verbose)
|
||||
mxprint(stdout, "+-> Using AC3 output module for stream "
|
||||
"%u (FourCC: %s).\n", dmx->id, dmx->fourcc);
|
||||
@ -945,3 +946,68 @@ void real_reader_c::set_dimensions(real_demuxer_t *dmx, unsigned char *buffer,
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
||||
void real_reader_c::get_information_from_data() {
|
||||
uint32_t length, id;
|
||||
int i;
|
||||
unsigned char *chunk;
|
||||
real_demuxer_t *dmx;
|
||||
bool done;
|
||||
|
||||
io->save_pos();
|
||||
|
||||
done = true;
|
||||
for (i = 0; i < demuxers.size(); i++) {
|
||||
dmx = demuxers[i];
|
||||
if (!strcasecmp(dmx->fourcc, "DNET")) {
|
||||
dmx->bsid = -1;
|
||||
done = false;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
while (!done) {
|
||||
io->skip(2);
|
||||
length = io->read_uint16_be();
|
||||
id = io->read_uint16_be();
|
||||
io->skip(4 + 1 + 1);
|
||||
|
||||
if (length < 12)
|
||||
die("real_reader: Data packet too small.");
|
||||
|
||||
dmx = find_demuxer(id);
|
||||
|
||||
if (dmx == NULL) {
|
||||
io->skip(length - 12);
|
||||
continue;
|
||||
}
|
||||
|
||||
length -= 12;
|
||||
|
||||
chunk = (unsigned char *)safemalloc(length);
|
||||
if (io->read(chunk, length) != length)
|
||||
break;
|
||||
|
||||
num_packets++;
|
||||
|
||||
if (!strcasecmp(dmx->fourcc, "DNET"))
|
||||
dmx->bsid = chunk[4] >> 3;
|
||||
|
||||
safefree(chunk);
|
||||
|
||||
done = true;
|
||||
for (i = 0; i < demuxers.size(); i++) {
|
||||
dmx = demuxers[i];
|
||||
if (!strcasecmp(dmx->fourcc, "DNET") && (dmx->bsid == -1))
|
||||
done = false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
io->restore_pos();
|
||||
num_packets = 0;
|
||||
|
||||
} catch (exception &ex) {
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ typedef struct {
|
||||
|
||||
uint32_t start_time, preroll;
|
||||
|
||||
int channels, bits_per_sample, samples_per_second;
|
||||
int channels, bits_per_sample, samples_per_second, bsid;
|
||||
|
||||
int width, height;
|
||||
float fps;
|
||||
@ -97,6 +97,7 @@ protected:
|
||||
uint32_t &height);
|
||||
virtual void set_dimensions(real_demuxer_t *dmx, unsigned char *buffer,
|
||||
int size);
|
||||
virtual void get_information_from_data();
|
||||
};
|
||||
|
||||
#endif // __R_REAL_H
|
||||
|
Loading…
Reference in New Issue
Block a user