Support for reading AAC from Matroska files.

This commit is contained in:
Moritz Bunkus 2003-05-22 11:11:30 +00:00
parent 766d97f3b7
commit e182f0191d
5 changed files with 142 additions and 70 deletions

View File

@ -1,5 +1,7 @@
2003-05-22 Moritz Bunkus <moritz@bunkus.org>
* Support for reading AAC tracks from Matroska files.
* Released v0.4.0.
2003-05-21 Moritz Bunkus <moritz@bunkus.org>

View File

@ -13,7 +13,7 @@
/*!
\file
\version \$Id: p_aac.cpp,v 1.5 2003/05/20 06:30:24 mosu Exp $
\version \$Id: p_aac.cpp,v 1.6 2003/05/22 11:11:05 mosu Exp $
\brief AAC output module
\author Moritz Bunkus <moritz@bunkus.org>
*/
@ -33,7 +33,8 @@ using namespace LIBMATROSKA_NAMESPACE;
aac_packetizer_c::aac_packetizer_c(generic_reader_c *nreader, int nid,
int nprofile,
unsigned long nsamples_per_sec,
int nchannels, track_info_t *nti)
int nchannels, track_info_t *nti,
bool nheaderless)
throw (error_c): generic_packetizer_c(nreader, nti) {
packetno = 0;
bytes_output = 0;
@ -43,9 +44,10 @@ aac_packetizer_c::aac_packetizer_c(generic_reader_c *nreader, int nid,
channels = nchannels;
id = nid;
profile = nprofile;
headerless = nheaderless;
set_track_type(track_audio);
duplicate_data_on_add(false);
duplicate_data_on_add(headerless);
}
aac_packetizer_c::~aac_packetizer_c() {
@ -167,23 +169,23 @@ unsigned char *aac_packetizer_c::get_aac_packet(unsigned long *header,
}
void aac_packetizer_c::set_headers() {
if (id == 0) {
if (profile == 0)
if (id == AAC_ID_MPEG4) {
if (profile == AAC_PROFILE_MAIN)
set_codec_id(MKV_A_AAC_4MAIN);
else if (profile == 1)
else if (profile == AAC_PROFILE_LC)
set_codec_id(MKV_A_AAC_4LC);
else if (profile == 2)
else if (profile == AAC_PROFILE_SSR)
set_codec_id(MKV_A_AAC_4SSR);
else if (profile == 3)
else if (profile == AAC_PROFILE_LTP)
set_codec_id(MKV_A_AAC_4LTP);
else
die("aac_packetizer: Unknown AAC MPEG-4 object type...");
} else {
if (profile == 0)
if (profile == AAC_PROFILE_MAIN)
set_codec_id(MKV_A_AAC_2MAIN);
else if (profile == 1)
else if (profile == AAC_PROFILE_LC)
set_codec_id(MKV_A_AAC_2LC);
else if (profile == 2)
else if (profile == AAC_PROFILE_SSR)
set_codec_id(MKV_A_AAC_2SSR);
else
die("aac_packetizer: Unknown AAC MPEG-2 profile...");
@ -201,6 +203,18 @@ int aac_packetizer_c::process(unsigned char *buf, int size,
aac_header_t aacheader;
int64_t my_timecode;
if (headerless) {
if (timecode != -1)
my_timecode = timecode;
else
my_timecode = (int64_t)(1000.0 * packetno * 1024 * ti->async.linear /
samples_per_sec);
add_packet(buf, size, my_timecode,
(int64_t)(1000.0 * 1024 * ti->async.linear / samples_per_sec));
return EMOREDATA;
}
if (timecode != -1)
my_timecode = timecode;

14
p_aac.h
View File

@ -13,7 +13,7 @@
/*!
\file
\version \$Id: p_aac.h,v 1.5 2003/05/20 06:30:24 mosu Exp $
\version \$Id: p_aac.h,v 1.6 2003/05/22 11:11:05 mosu Exp $
\brief class definition for the AAC output module
\author Moritz Bunkus <moritz@bunkus.org>
*/
@ -25,17 +25,27 @@
#include "pr_generic.h"
#include "aac_common.h"
#define AAC_ID_MPEG4 0
#define AAC_ID_MPEG2 1
#define AAC_PROFILE_MAIN 0
#define AAC_PROFILE_LC 1
#define AAC_PROFILE_SSR 2
#define AAC_PROFILE_LTP 3
class aac_packetizer_c: public generic_packetizer_c {
private:
int64_t bytes_output, packetno;
unsigned long samples_per_sec;
int channels, buffer_size, id, profile;
unsigned char *packet_buffer;
bool headerless;
public:
aac_packetizer_c(generic_reader_c *nreader, int nid, int nprofile,
unsigned long nsamples_per_sec, int nchannels,
track_info_t *nti) throw (error_c);
track_info_t *nti, bool nheaderless = false)
throw (error_c);
virtual ~aac_packetizer_c();
virtual int process(unsigned char *buf, int size, int64_t timecode = -1,

View File

@ -13,7 +13,7 @@
/*!
\file
\version \$Id: r_matroska.cpp,v 1.36 2003/05/21 22:17:33 mosu Exp $
\version \$Id: r_matroska.cpp,v 1.37 2003/05/22 11:11:05 mosu Exp $
\brief Matroska reader
\author Moritz Bunkus <moritz@bunkus.org>
*/
@ -41,6 +41,7 @@ extern "C" { // for BITMAPINFOHEADER
#include "p_mp3.h"
#include "p_ac3.h"
#include "p_dts.h"
#include "p_aac.h"
#include "EbmlContexts.h"
#include "EbmlHead.h"
@ -100,9 +101,6 @@ mkv_reader_c::mkv_reader_c(track_info_t *nti) throw (error_c):
segment_duration = 0.0;
fprintf(stdout, "WARNING! Matroska files cannot be processed at the "
"moment.\n");
if (!read_headers())
throw error_c("matroska_reader: Failed to read the headers.");
@ -197,7 +195,8 @@ void mkv_reader_c::verify_tracks() {
if (!strcmp(t->codec_id, MKV_V_MSCOMP)) {
if ((t->private_data == NULL) ||
(t->private_size < sizeof(BITMAPINFOHEADER))) {
printf("[mkv] WARNING: CodecID for track %u is '" MKV_V_MSCOMP
printf("matroska_reader: WARNING: CodecID for track %u is '"
MKV_V_MSCOMP
"', but there was no BITMAPINFOHEADER struct present. "
"Therefore we don't have a FourCC to identify the video "
"codec used.\n", t->tnum);
@ -209,8 +208,8 @@ void mkv_reader_c::verify_tracks() {
u = get_uint32(&bih->bi_width);
if (t->v_width != u) {
printf("[mkv] WARNING: (MS compatibility mode, track %u) "
"Matrosa says video width is %u, but the "
printf("matroska_reader: WARNING: (MS compatibility mode, "
"track %u) Matrosa says video width is %u, but the "
"BITMAPINFOHEADER says %u.\n", t->tnum, t->v_width, u);
if (t->v_width == 0)
t->v_width = u;
@ -218,9 +217,9 @@ void mkv_reader_c::verify_tracks() {
u = get_uint32(&bih->bi_height);
if (t->v_height != u) {
printf("[mkv] WARNING: (MS compatibility mode, track %u) "
"Matrosa video height is %u, but the BITMAPINFOHEADER "
"says %u.\n", t->tnum, t->v_height, u);
printf("matroska_reader: WARNING: (MS compatibility mode, "
"track %u) Matrosa video height is %u, but the "
"BITMAPINFOHEADER says %u.\n", t->tnum, t->v_height, u);
if (t->v_height == 0)
t->v_height = u;
}
@ -228,23 +227,25 @@ void mkv_reader_c::verify_tracks() {
memcpy(t->v_fourcc, &bih->bi_compression, 4);
if (t->v_frate == 0.0) {
printf("[mkv] ERROR: (MS compatibility mode, track %u) "
"No VideoFrameRate element was found.\n", t->tnum);
printf("matroska_reader: ERROR: (MS compatibility mode, track "
"%u) No VideoFrameRate element was found.\n", t->tnum);
continue;
}
}
} else {
printf("[mkv] Native CodecIDs for video tracks are not supported "
"yet (track %u).\n", t->tnum);
printf("matroska_reader: Native CodecIDs for video tracks are not "
"supported yet (track %u).\n", t->tnum);
continue;
}
if (t->v_width == 0) {
printf("[mkv] The width for track %u was not set.\n", t->tnum);
printf("matroska_reader: The width for track %u was not set.\n",
t->tnum);
continue;
}
if (t->v_height == 0) {
printf("[mkv] The height for track %u was not set.\n", t->tnum);
printf("matroska_reader: The height for track %u was not set.\n",
t->tnum);
continue;
}
@ -259,10 +260,10 @@ void mkv_reader_c::verify_tracks() {
if (!strcmp(t->codec_id, MKV_A_ACM)) {
if ((t->private_data == NULL) ||
(t->private_size < sizeof(WAVEFORMATEX))) {
printf("[mkv] WARNING: CodecID for track %u is '" MKV_A_ACM "', "
"but there was no WAVEFORMATEX struct present. "
"Therefore we don't have a format ID to identify the audio "
"codec used.\n", t->tnum);
printf("matroska_reader: WARNING: CodecID for track %u is '"
MKV_A_ACM "', but there was no WAVEFORMATEX struct present."
" Therefore we don't have a format ID to identify the audio"
" codec used.\n", t->tnum);
continue;
} else {
t->ms_compat = 1;
@ -270,19 +271,19 @@ void mkv_reader_c::verify_tracks() {
wfe = (WAVEFORMATEX *)t->private_data;
u = get_uint32(&wfe->n_samples_per_sec);
if (((uint32_t)t->a_sfreq) != u) {
printf("[mkv] WARNING: (MS compatibility mode for track %u) "
"Matroska says that there are %u samples per second, "
"but WAVEFORMATEX says that there are %u.\n", t->tnum,
(uint32_t)t->a_sfreq, u);
printf("matroska_reader: WARNING: (MS compatibility mode for "
"track %u) Matroska says that there are %u samples per "
"second, but WAVEFORMATEX says that there are %u.\n",
t->tnum, (uint32_t)t->a_sfreq, u);
if (t->a_sfreq == 0.0)
t->a_sfreq = (float)u;
}
u = get_uint16(&wfe->n_channels);
if (t->a_channels != u) {
printf("[mkv] WARNING: (MS compatibility mode for track %u) "
"Matroska says that there are %u channels, but the "
"WAVEFORMATEX says that there are %u.\n", t->tnum,
printf("matroska_reader: WARNING: (MS compatibility mode for "
"track %u) Matroska says that there are %u channels, but "
"the WAVEFORMATEX says that there are %u.\n", t->tnum,
t->a_channels, u);
if (t->a_channels == 0)
t->a_channels = u;
@ -290,10 +291,10 @@ void mkv_reader_c::verify_tracks() {
u = get_uint16(&wfe->w_bits_per_sample);
if (t->a_bps != u) {
printf("[mkv] WARNING: (MS compatibility mode for track %u) "
"Matroska says that there are %u bits per sample, "
"but the WAVEFORMATEX says that there are %u.\n", t->tnum,
t->a_bps, u);
printf("matroska_reader: WARNING: (MS compatibility mode for "
"track %u) Matroska says that there are %u bits per "
"sample, but the WAVEFORMATEX says that there are %u.\n",
t->tnum, t->a_bps, u);
if (t->a_bps == 0)
t->a_bps = u;
}
@ -311,14 +312,16 @@ void mkv_reader_c::verify_tracks() {
t->a_formattag = 0x0001;
else if (!strcmp(t->codec_id, MKV_A_VORBIS)) {
if (t->private_data == NULL) {
printf("[mkv] WARNING: CodecID for track %u is 'A_VORBIS', "
"but there are no header packets present.", t->tnum);
printf("matroska_reader: WARNING: CodecID for track %u is "
"'A_VORBIS', but there are no header packets present.",
t->tnum);
continue;
}
c = (unsigned char *)t->private_data;
if (c[0] != 2) {
printf("[mkv] Vorbis track does not contain valid headers.\n");
printf("matroska_reader: Vorbis track does not contain valid "
"headers.\n");
continue;
}
@ -331,7 +334,8 @@ void mkv_reader_c::verify_tracks() {
offset++;
}
if (offset >= (t->private_size - 1)) {
printf("[mkv] Vorbis track does not contain valid headers.\n");
printf("matroska_reader: Vorbis track does not contain valid "
"headers.\n");
continue;
}
length += c[offset];
@ -347,28 +351,37 @@ void mkv_reader_c::verify_tracks() {
t->header_sizes[0] - t->header_sizes[1];
t->a_formattag = 0xFFFE;
} else {
printf("[mkv] Unknown/unsupported audio codec ID '%s' for track "
"%u.\n", t->codec_id, t->tnum);
} else if (!strcmp(t->codec_id, MKV_A_AAC_2MAIN) ||
!strcmp(t->codec_id, MKV_A_AAC_2LC) ||
!strcmp(t->codec_id, MKV_A_AAC_2SSR) ||
!strcmp(t->codec_id, MKV_A_AAC_4MAIN) ||
!strcmp(t->codec_id, MKV_A_AAC_4LC) ||
!strcmp(t->codec_id, MKV_A_AAC_4SSR) ||
!strcmp(t->codec_id, MKV_A_AAC_4LTP) ||
!strcmp(t->codec_id, MKV_A_AAC_4SBR))
t->a_formattag = FOURCC('M', 'P', '4', 'A');
else {
printf("matroska_reader: Unknown/unsupported audio codec ID '%s' "
"for track %u.\n", t->codec_id, t->tnum);
continue;
}
}
if (t->a_sfreq == 0.0) {
printf("[mkv] The sampling frequency was not set for track %u.\n",
t->tnum);
printf("matroska_reader: The sampling frequency was not set for "
"track %u.\n", t->tnum);
continue;
}
if (t->a_channels == 0) {
printf("[mkv] The number of channels was not set for track %u.\n",
t->tnum);
printf("matroska_reader: The number of channels was not set for "
"track %u.\n", t->tnum);
continue;
}
if (t->a_formattag == 0) {
printf("[mkv] The audio format tag was not set for track %u.\n",
t->tnum);
printf("matroska_reader: The audio format tag was not set for track "
"%u.\n", t->tnum);
continue;
}
@ -382,13 +395,13 @@ void mkv_reader_c::verify_tracks() {
break;
default: // unknown track type!? error in demuxer...
printf("[mkv] Error: matroska_reader: unknown demuxer type for track "
"%u: '%c'\n", t->tnum, t->type);
printf("matroska_reader: Error: matroska_reader: unknown demuxer "
"type for track %u: '%c'\n", t->tnum, t->type);
continue;
}
if (t->ok)
printf("[mkv] Track %u seems to be ok.\n", t->tnum);
printf("matroska_reader: Track %u seems to be ok.\n", t->tnum);
}
}
@ -470,7 +483,9 @@ int mkv_reader_c::read_headers() {
fprintf(stdout, "matroska_reader: | + duration: %.3fs\n",
segment_duration);
} else if (!is_ebmlvoid(l2))
} else if (!is_ebmlvoid(l2) &&
!(EbmlId(*l2) == KaxWritingApp::ClassInfos.GlobalId) &&
!(EbmlId(*l2) == KaxMuxingApp::ClassInfos.GlobalId))
fprintf(stdout, "matroska_reader: | + unknown element@2: %s\n",
typeid(*l2).name());
@ -864,8 +879,7 @@ void mkv_reader_c::create_packetizers() {
(unsigned long)t->a_sfreq,
&nti);
*/
}
else if (t->a_formattag == 0xFFFE)
} else if (t->a_formattag == 0xFFFE)
t->packetizer = new vorbis_packetizer_c(this,
t->headers[0],
t->header_sizes[0],
@ -873,7 +887,38 @@ void mkv_reader_c::create_packetizers() {
t->header_sizes[1],
t->headers[2],
t->header_sizes[2], &nti);
else {
else if (t->a_formattag == FOURCC('M', 'P', '4', 'A')) {
// A_AAC/MPEG2/MAIN
// 0123456789012345
int id, profile;
if (t->codec_id[10] == '2')
id = AAC_ID_MPEG2;
else if (t->codec_id[10] == '4')
id = AAC_ID_MPEG4;
else {
fprintf(stderr, "Error: matroska_reader: Malformed codec id "
"%s for track %d.\n", t->codec_id, t->tnum);
exit(1);
}
if (!strcmp(&t->codec_id[12], "MAIN"))
profile = AAC_PROFILE_MAIN;
else if (!strcmp(&t->codec_id[12], "LC"))
profile = AAC_PROFILE_LC;
else if (!strcmp(&t->codec_id[12], "SSR"))
profile = AAC_PROFILE_SSR;
else if (!strcmp(&t->codec_id[12], "LTP"))
profile = AAC_PROFILE_LTP;
else {
fprintf(stderr, "Error: matroska_reader: Malformed codec id "
"%s for track %d.\n", t->codec_id, t->tnum);
exit(1);
}
t->packetizer = new aac_packetizer_c(this, id, profile,
(unsigned long)t->a_sfreq,
t->a_channels, &nti, true);
} else {
fprintf(stderr, "Error: matroska_reader: Unsupported track type "
"for track %d.\n", t->tnum);
exit(1);
@ -995,7 +1040,8 @@ int mkv_reader_c::read() {
} else if (!(EbmlId(*l3) ==
KaxBlockVirtual::ClassInfos.GlobalId))
printf("[mkv] Uknown element@3: %s\n", typeid(*l3).name());
printf("matroska_reader: Uknown element@3: %s\n",
typeid(*l3).name());
l3->SkipData(*es, l3->Generic().Context);
if (delete_element)
@ -1055,7 +1101,8 @@ int mkv_reader_c::read() {
} // while (l2 != NULL)
} else if (!(EbmlId(*l1) == KaxCues::ClassInfos.GlobalId) &&
!is_ebmlvoid(l1))
printf("[mkv] Unknown element@1: %s\n", typeid(*l1).name());
printf("matroska_reader: Unknown element@1: %s\n",
typeid(*l1).name());
if (exit_loop)
break;
@ -1074,7 +1121,7 @@ int mkv_reader_c::read() {
}
} // while (l1 != NULL)
} catch (exception ex) {
printf("[mkv] exception caught\n");
printf("matroska_reader: exception caught\n");
return 0;
}

View File

@ -13,7 +13,7 @@
/*!
\file
\version \$Id: r_matroska.h,v 1.13 2003/05/20 06:30:24 mosu Exp $
\version \$Id: r_matroska.h,v 1.14 2003/05/22 11:11:05 mosu Exp $
\brief class definitions for the Matroska reader
\author Moritz Bunkus <moritz@bunkus.org>
*/
@ -50,9 +50,8 @@ typedef struct {
char v_fourcc[5];
// Parameters for audio tracks
uint32_t a_channels, a_bps;
uint32_t a_channels, a_bps, a_formattag;
float a_sfreq;
uint16_t a_formattag;
void *private_data;
unsigned int private_size;