Implemented a switch that has to be used for SBR AAC / AAC+ / HE-AAC if the source file is an AAC file and the AAC file contains SBR AAC data (no automatic detection possible in this case!).

This commit is contained in:
Moritz Bunkus 2003-08-18 17:58:56 +00:00
parent e622f34e61
commit a58d1beb74
10 changed files with 74 additions and 5 deletions

View File

@ -1,3 +1,9 @@
2003-08-18 Moritz Bunkus <moritz@bunkus.org>
* mkvmerge: Implemented a switch that has to be used for SBR AAC /
AAC+ / HE-AAC if the source file is an AAC file and the AAC file
contains SBR AAC data (no automatic detection possible in this case!).
2003-08-14 Moritz Bunkus <moritz@bunkus.org> 2003-08-14 Moritz Bunkus <moritz@bunkus.org>
* mkvmerge: Low bitrate AC3 tracks from Real's DNET are identified * mkvmerge: Low bitrate AC3 tracks from Real's DNET are identified

View File

@ -226,6 +226,21 @@ tracks by selecting different track IDs each time.
\fB\-t\fR, \fB\-\-tags\fR <\fITID\fR:\fIfile\fR> \fB\-t\fR, \fB\-\-tags\fR <\fITID\fR:\fIfile\fR>
Read tags for the track with the number \fITID\fR from the \fIfile\fR. See Read tags for the track with the number \fITID\fR from the \fIfile\fR. See
the section about tags below for details. the section about tags below for details.
.TP
\fB\-\-aab\-is\-sbr\fR <\fITID\fR>
Tells \fBmkvmerge\fR that the track with the ID \fITID\fR is SBR AAC (also
known as HE-AAC or AAC+). This options is needed if a) the source file is an
AAC file (NOT for a Matroska file) and b) the AAC file contains SBR AAC data.
The reason for this switch is that it is technically impossible to
automatically tell normal AAC data from SBR AAC data without decoding a
complete AAC frame. As there are several patent issues with AAC decoders I
won't implement this decoding stage. So for SBR AAC files this switch is
mandatory. The resulting file might not play back correctly or even not at
all if the switch was omitted.
.br
If the source file is a Matroska file then the CodecID should be enough to
detect SBR AAC. However, if the CodecID is wrong then this switch can be used
to correct that.
.LP .LP
Options that only apply to video tracks: Options that only apply to video tracks:

View File

@ -26,11 +26,12 @@
#define MKV_A_AAC_2MAIN "A_AAC/MPEG2/MAIN" #define MKV_A_AAC_2MAIN "A_AAC/MPEG2/MAIN"
#define MKV_A_AAC_2LC "A_AAC/MPEG2/LC" #define MKV_A_AAC_2LC "A_AAC/MPEG2/LC"
#define MKV_A_AAC_2SSR "A_AAC/MPEG2/SSR" #define MKV_A_AAC_2SSR "A_AAC/MPEG2/SSR"
#define MKV_A_AAC_2SBR "A_AAC/MPEG2/LC/SBR"
#define MKV_A_AAC_4MAIN "A_AAC/MPEG4/MAIN" #define MKV_A_AAC_4MAIN "A_AAC/MPEG4/MAIN"
#define MKV_A_AAC_4LC "A_AAC/MPEG4/LC" #define MKV_A_AAC_4LC "A_AAC/MPEG4/LC"
#define MKV_A_AAC_4SSR "A_AAC/MPEG4/SSR" #define MKV_A_AAC_4SSR "A_AAC/MPEG4/SSR"
#define MKV_A_AAC_4LTP "A_AAC/MPEG4/LTP" #define MKV_A_AAC_4LTP "A_AAC/MPEG4/LTP"
#define MKV_A_AAC_4SBR "A_AAC/MPEG4/SBR" #define MKV_A_AAC_4SBR "A_AAC/MPEG4/LC/SBR"
#define MKV_A_AC3 "A_AC3" #define MKV_A_AC3 "A_AC3"
#define MKV_A_DTS "A_DTS" #define MKV_A_DTS "A_DTS"
#define MKV_A_MP3 "A_MPEG/L3" #define MKV_A_MP3 "A_MPEG/L3"

View File

@ -279,6 +279,7 @@ static void usage() {
" --language <TID:lang> Sets the language for the track (ISO639-2\n" " --language <TID:lang> Sets the language for the track (ISO639-2\n"
" code, see --list-languages).\n" " code, see --list-languages).\n"
" -t, --tags <TID:file> Read tags for the track from a XML file.\n" " -t, --tags <TID:file> Read tags for the track from a XML file.\n"
" --aac-is-sbr <TID> Track with the ID is HE-AAC/AAC+/SBR-AAC.\n"
"\n Options that only apply to video tracks:\n" "\n Options that only apply to video tracks:\n"
" -f, --fourcc <FOURCC> Forces the FourCC to the specified value.\n" " -f, --fourcc <FOURCC> Forces the FourCC to the specified value.\n"
" Works only for video tracks.\n" " Works only for video tracks.\n"
@ -1043,6 +1044,7 @@ static void identify(const char *filename) {
ti.atracks = new vector<int64_t>; ti.atracks = new vector<int64_t>;
ti.vtracks = new vector<int64_t>; ti.vtracks = new vector<int64_t>;
ti.stracks = new vector<int64_t>; ti.stracks = new vector<int64_t>;
ti.aac_is_sbr = new vector<int64_t>;
file = (filelist_t *)safemalloc(sizeof(filelist_t)); file = (filelist_t *)safemalloc(sizeof(filelist_t));
@ -1096,6 +1098,7 @@ static void parse_args(int argc, char **argv) {
ti.languages = new vector<language_t>; ti.languages = new vector<language_t>;
ti.sub_charsets = new vector<language_t>; ti.sub_charsets = new vector<language_t>;
ti.all_tags = new vector<tags_t>; ti.all_tags = new vector<tags_t>;
ti.aac_is_sbr = new vector<int64_t>;
ti.aspect_ratio = 0.0; ti.aspect_ratio = 0.0;
ti.atracks = new vector<int64_t>; ti.atracks = new vector<int64_t>;
ti.vtracks = new vector<int64_t>; ti.vtracks = new vector<int64_t>;
@ -1474,6 +1477,18 @@ static void parse_args(int argc, char **argv) {
parse_tags(argv[i + 1], tags); parse_tags(argv[i + 1], tags);
ti.all_tags->push_back(tags); ti.all_tags->push_back(tags);
i++; i++;
} else if (!strcmp(argv[i], "--aac-is-sbr")) {
if ((i + 1) >= argc) {
mxprint(stderr, "Error: %s lacks the track ID.\n", argv[i]);
exit(1);
}
if (!parse_int(argv[i + 1], id) || (id < 0)) {
mxprint(stderr, "Error: '%s' is not a valid track ID.\n", argv[i + 1]);
exit(1);
}
ti.aac_is_sbr->push_back(id);
i++;
} }
// The argument is an input file. // The argument is an input file.
@ -1523,6 +1538,7 @@ static void parse_args(int argc, char **argv) {
delete ti.languages; delete ti.languages;
delete ti.sub_charsets; delete ti.sub_charsets;
delete ti.all_tags; delete ti.all_tags;
delete ti.aac_is_sbr;
memset(&ti, 0, sizeof(track_info_t)); memset(&ti, 0, sizeof(track_info_t));
ti.audio_syncs = new vector<audio_sync_t>; ti.audio_syncs = new vector<audio_sync_t>;
ti.cue_creations = new vector<cue_creation_t>; ti.cue_creations = new vector<cue_creation_t>;
@ -1530,6 +1546,7 @@ static void parse_args(int argc, char **argv) {
ti.languages = new vector<language_t>; ti.languages = new vector<language_t>;
ti.sub_charsets = new vector<language_t>; ti.sub_charsets = new vector<language_t>;
ti.all_tags = new vector<tags_t>; ti.all_tags = new vector<tags_t>;
ti.aac_is_sbr = new vector<int64_t>;
ti.aspect_ratio = 0.0; ti.aspect_ratio = 0.0;
ti.atracks = new vector<int64_t>; ti.atracks = new vector<int64_t>;
ti.vtracks = new vector<int64_t>; ti.vtracks = new vector<int64_t>;

View File

@ -184,6 +184,8 @@ void aac_packetizer_c::set_headers() {
set_codec_id(MKV_A_AAC_4SSR); set_codec_id(MKV_A_AAC_4SSR);
else if (profile == AAC_PROFILE_LTP) else if (profile == AAC_PROFILE_LTP)
set_codec_id(MKV_A_AAC_4LTP); set_codec_id(MKV_A_AAC_4LTP);
else if (profile == AAC_PROFILE_SBR)
set_codec_id(MKV_A_AAC_4SBR);
else else
die("aac_packetizer: Unknown AAC MPEG-4 object type %d.", profile); die("aac_packetizer: Unknown AAC MPEG-4 object type %d.", profile);
} else { } else {
@ -193,6 +195,8 @@ void aac_packetizer_c::set_headers() {
set_codec_id(MKV_A_AAC_2LC); set_codec_id(MKV_A_AAC_2LC);
else if (profile == AAC_PROFILE_SSR) else if (profile == AAC_PROFILE_SSR)
set_codec_id(MKV_A_AAC_2SSR); set_codec_id(MKV_A_AAC_2SSR);
else if (profile == AAC_PROFILE_SBR)
set_codec_id(MKV_A_AAC_2SBR);
else else
die("aac_packetizer: Unknown AAC MPEG-2 profile %d.", profile); die("aac_packetizer: Unknown AAC MPEG-2 profile %d.", profile);
} }

View File

@ -34,6 +34,7 @@
#define AAC_PROFILE_LC 1 #define AAC_PROFILE_LC 1
#define AAC_PROFILE_SSR 2 #define AAC_PROFILE_SSR 2
#define AAC_PROFILE_LTP 3 #define AAC_PROFILE_LTP 3
#define AAC_PROFILE_SBR 4
class aac_packetizer_c: public generic_packetizer_c { class aac_packetizer_c: public generic_packetizer_c {
private: private:

View File

@ -614,6 +614,7 @@ track_info_t *duplicate_track_info(track_info_t *src) {
dst->all_tags = new vector<tags_t>(*src->all_tags); dst->all_tags = new vector<tags_t>(*src->all_tags);
for (i = 0; i < src->all_tags->size(); i++) for (i = 0; i < src->all_tags->size(); i++)
(*dst->all_tags)[i].file_name = safestrdup((*src->all_tags)[i].file_name); (*dst->all_tags)[i].file_name = safestrdup((*src->all_tags)[i].file_name);
dst->aac_is_sbr = new vector<int64_t>(*src->aac_is_sbr);
dst->private_data = (unsigned char *)safememdup(src->private_data, dst->private_data = (unsigned char *)safememdup(src->private_data,
src->private_size); src->private_size);
dst->sub_charset = safestrdup(src->sub_charset); dst->sub_charset = safestrdup(src->sub_charset);
@ -643,6 +644,7 @@ void free_track_info(track_info_t *ti) {
for (i = 0; i < ti->all_tags->size(); i++) for (i = 0; i < ti->all_tags->size(); i++)
safefree((*ti->all_tags)[i].file_name); safefree((*ti->all_tags)[i].file_name);
delete ti->all_tags; delete ti->all_tags;
delete ti->aac_is_sbr;
safefree(ti->language); safefree(ti->language);
safefree(ti->private_data); safefree(ti->private_data);
safefree(ti->sub_charset); safefree(ti->sub_charset);

View File

@ -109,6 +109,8 @@ typedef struct {
vector<tags_t> *all_tags; // As given on the command line vector<tags_t> *all_tags; // As given on the command line
tags_t *tags_ptr; // For this very track tags_t *tags_ptr; // For this very track
KaxTags *tags; // For this very track KaxTags *tags; // For this very track
vector<int64_t> *aac_is_sbr; // For AAC+/HE-AAC/SBR
} track_info_t; } track_info_t;
class generic_reader_c; class generic_reader_c;

View File

@ -56,7 +56,7 @@ int aac_reader_c::probe_file(mm_io_c *mm_io, int64_t size) {
aac_reader_c::aac_reader_c(track_info_t *nti) throw (error_c): aac_reader_c::aac_reader_c(track_info_t *nti) throw (error_c):
generic_reader_c(nti) { generic_reader_c(nti) {
int adif; int adif, i;
aac_header_t aacheader; aac_header_t aacheader;
try { try {
@ -77,12 +77,24 @@ aac_reader_c::aac_reader_c(track_info_t *nti) throw (error_c):
throw error_c("aac_reader: No valid AAC packet found in the first " throw error_c("aac_reader: No valid AAC packet found in the first "
SINITCHUNKSIZE " bytes.\n"); SINITCHUNKSIZE " bytes.\n");
guess_adts_version(); guess_adts_version();
mxprint(stdout, "emphasis_present: %s\n", emphasis_present ? "true" :
"false");
adif = 0; adif = 0;
} }
bytes_processed = 0; bytes_processed = 0;
ti->id = 0; // ID for this track. ti->id = 0; // ID for this track.
for (i = 0; i < ti->aac_is_sbr->size(); i++)
if ((*ti->aac_is_sbr)[i] == 0) {
aacheader.profile = AAC_PROFILE_SBR;
break;
}
if (aacheader.profile != AAC_PROFILE_SBR)
mxprint(stdout,
"WARNING! AAC files may contain HE-AAC / AAC+ / SBR AAC audio. "
"This can NOT be detected automatically. Therefore you have to "
"specifiy '--aac-is-sbr 0' manually for this input file if the "
"file actually contains SBR AAC. The file will be muxed in the "
"WRONG way otherwise. Also read mkvmerge's documentation.\n");
aacpacketizer = new aac_packetizer_c(this, aacheader.id, aacheader.profile, aacpacketizer = new aac_packetizer_c(this, aacheader.id, aacheader.profile,
aacheader.sample_rate, aacheader.sample_rate,
aacheader.channels, ti, aacheader.channels, ti,

View File

@ -392,6 +392,8 @@ void kax_reader_c::verify_tracks() {
!strcmp(t->codec_id, MKV_A_AAC_4LC) || !strcmp(t->codec_id, MKV_A_AAC_4LC) ||
!strcmp(t->codec_id, MKV_A_AAC_4SSR) || !strcmp(t->codec_id, MKV_A_AAC_4SSR) ||
!strcmp(t->codec_id, MKV_A_AAC_4LTP) || !strcmp(t->codec_id, MKV_A_AAC_4LTP) ||
!strcmp(t->codec_id, MKV_A_AAC_4SBR) ||
!strcmp(t->codec_id, MKV_A_AAC_2SBR) ||
!strcmp(t->codec_id, MKV_A_AAC_4SBR)) !strcmp(t->codec_id, MKV_A_AAC_4SBR))
t->a_formattag = FOURCC('M', 'P', '4', 'A'); t->a_formattag = FOURCC('M', 'P', '4', 'A');
else { else {
@ -1179,7 +1181,7 @@ void kax_reader_c::create_packetizers() {
} else if (t->a_formattag == FOURCC('M', 'P', '4', 'A')) { } else if (t->a_formattag == FOURCC('M', 'P', '4', 'A')) {
// A_AAC/MPEG2/MAIN // A_AAC/MPEG2/MAIN
// 0123456789012345 // 0123456789012345
int id, profile; int id, profile, sbridx;
if (t->codec_id[10] == '2') if (t->codec_id[10] == '2')
id = AAC_ID_MPEG2; id = AAC_ID_MPEG2;
@ -1198,11 +1200,18 @@ void kax_reader_c::create_packetizers() {
profile = AAC_PROFILE_SSR; profile = AAC_PROFILE_SSR;
else if (!strcmp(&t->codec_id[12], "LTP")) else if (!strcmp(&t->codec_id[12], "LTP"))
profile = AAC_PROFILE_LTP; profile = AAC_PROFILE_LTP;
else if (!strcmp(&t->codec_id[12], "LC/SBR"))
profile = AAC_PROFILE_SBR;
else { else {
mxprint(stderr, "Error: matroska_reader: Malformed codec id " mxprint(stderr, "Error: matroska_reader: Malformed codec id "
"%s for track %d.\n", t->codec_id, t->tnum); "%s for track %d.\n", t->codec_id, t->tnum);
exit(1); exit(1);
} }
for (sbridx = 0; sbridx < ti->aac_is_sbr->size(); sbridx++)
if ((*ti->aac_is_sbr)[sbridx] == t->tnum) {
profile = AAC_PROFILE_SBR;
break;
}
t->packetizer = new aac_packetizer_c(this, id, profile, t->packetizer = new aac_packetizer_c(this, id, profile,
(unsigned long)t->a_sfreq, (unsigned long)t->a_sfreq,