Low bitrate AC3 tracks from Real's DNET are identified as A_AC3/BSID9 or A_AC3/BSID10.

This commit is contained in:
Moritz Bunkus 2003-08-14 17:19:46 +00:00
parent 5acb7c26e4
commit e622f34e61
13 changed files with 126 additions and 20 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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 "

View File

@ -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);

View File

@ -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 "

View File

@ -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) {
}
}

View File

@ -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