Add AAC codec for TXTH and bytes-to-samples

This commit is contained in:
bnnm 2019-03-09 22:57:21 +01:00
parent c114dc3ba1
commit 2b4570395a
5 changed files with 53 additions and 4 deletions

View File

@ -101,26 +101,31 @@ A text file with the above commands must be saved as ".vag.txth" or ".txth", not
# - MSADPCM Microsoft ADPCM (mono/stereo)
# * For some PC games
# * Interleave (frame size) varies, often multiple of 0x100 [required]
# - SDX2 Squareroot-delta-exact 8-bit DPCM (3DO games)
# - SDX2 Squareroot-delta-exact 8-bit DPCM
# * For many 3DO games
# - MPEG MPEG Audio Layer file (MP1/2/3)
# * For some games (usually PC/PS3)
# * May set skip_samples
# - ATRAC3 Sony ATRAC3
# * For some PS2 and PS3 games
# * Interleave (frame size) can be 0x60/0x98/0xC0 * channels [required]
# * Should set skip_samples (more than 1024 but varies)
# - ATRAC3PLUS Sony ATRAC3plus
# * For many PSP games and rare PS3 games
# * Interleave (frame size) can be: [required]
# Mono: 0x0118|0178|0230|02E8
# Stereo: 0x0118|0178|0230|02E8|03A8|0460|05D0|0748|0800
# * Should set skip_samples (more than 2048 but varies)
# - XMA1 Microsoft XMA1
# * For early X360 games
# - XMA2 Microsoft XMA2
# * For later X360 games
# - FFMPEG Any headered FFmpeg format
# * For uncommon games
# * May set skip_samples
# - AC3 AC3/SPDIF
# * For few PS2 games
# * Should set skip_samples (around 256 but varies)
# - PCFX PC-FX ADPCM
# * For many PC-FX games
# * Interleave is multiple of 0x1, often +0x8000
@ -131,6 +136,9 @@ A text file with the above commands must be saved as ".vag.txth" or ".txth", not
# * Variation with modified encoding
# - OKI16 OKI ADPCM with 16-bit output (not VOX/Dialogic 12-bit)
# * For few PS2 games (Sweet Legacy, Hooligan)
# - AAC Advanced Audio Coding (raw without .mp4)
# * For some 3DS games and many iOS games
# * Should set skip_samples (around 1024 but varies)
codec = (codec string)
# Codec variations [OPTIONAL, depends on codec]

View File

@ -353,6 +353,7 @@ int riff_get_fact_skip_samples(STREAMFILE * streamFile, off_t start_offset);
size_t atrac3_bytes_to_samples(size_t bytes, int full_block_align);
size_t atrac3plus_bytes_to_samples(size_t bytes, int full_block_align);
size_t aac_get_samples(STREAMFILE *streamFile, off_t start_offset, size_t bytes);

View File

@ -1017,6 +1017,38 @@ size_t atrac3plus_bytes_to_samples(size_t bytes, int full_block_align) {
return (bytes / full_block_align) * 2048;
}
size_t aac_get_samples(STREAMFILE *streamFile, off_t start_offset, size_t bytes) {
const int samples_per_frame = 1024; /* theoretically 960 exists in .MP4 so may need a flag */
int frames = 0;
off_t offset = start_offset;
off_t max_offset = start_offset + bytes;
if (max_offset > get_streamfile_size(streamFile))
max_offset = get_streamfile_size(streamFile);
/* AAC sometimes comes with an "ADIF" header right before data but probably not in games,
* while standard raw frame headers are called "ADTS" and are similar to MPEG's:
* (see https://wiki.multimedia.cx/index.php/ADTS) */
/* AAC uses VBR so must read all frames */
while (offset < max_offset) {
uint16_t frame_sync = read_u16be(offset+0x00, streamFile);
uint32_t frame_size = read_u32be(offset+0x02, streamFile);
frame_sync = (frame_sync >> 4) & 0x0FFF; /* 12b */
frame_size = (frame_size >> 5) & 0x1FFF; /* 13b */
if (frame_sync != 0xFFF)
break;
if (frame_size <= 0x08)
break;
frames++;
offset += frame_size;
}
return frames * samples_per_frame;
}
/* ******************************************** */
/* BITSTREAM */

View File

@ -33,7 +33,8 @@ typedef enum {
PCFX = 24, /* PC-FX ADPCM */
PCM4 = 25, /* 4-bit signed PCM (3rd and 4th gen games) */
PCM4_U = 26, /* 4-bit unsigned PCM (3rd and 4th gen games) */
OKI16 = 27, /* OKI ADPCM with 16-bit output (unlike OKI/VOX/Dialogic ADPCM's 12-bit) */
OKI16 = 27, /* OKI ADPCM with 16-bit output (unlike OKI/VOX/Dialogic ADPCM's 12-bit) */
AAC = 28, /* Advanced Audio Coding (raw without .mp4) */
} genh_type;
typedef struct {
@ -115,6 +116,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
case XMA1:
case XMA2:
case AC3:
case AAC:
case FFMPEG: coding = coding_FFmpeg; break;
#endif
case PCFX: coding = coding_PCFX; break;
@ -293,7 +295,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
case coding_FFmpeg: {
ffmpeg_codec_data *ffmpeg_data = NULL;
if (genh.codec == FFMPEG || genh.codec == AC3) {
if (genh.codec == FFMPEG || genh.codec == AC3 || genh.codec == AAC) {
/* default FFmpeg */
ffmpeg_data = init_ffmpeg_offset(streamFile, genh.start_offset,genh.data_size);
if ( !ffmpeg_data ) goto fail;

View File

@ -34,6 +34,7 @@ typedef enum {
PCM4 = 25, /* 4-bit signed PCM (3rd and 4th gen games) */
PCM4_U = 26, /* 4-bit unsigned PCM (3rd and 4th gen games) */
OKI16 = 27, /* OKI ADPCM with 16-bit output (unlike OKI/VOX/Dialogic ADPCM's 12-bit) */
AAC = 28, /* Advanced Audio Coding (raw without .mp4) */
} txth_type;
typedef struct {
@ -177,6 +178,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
case XMA1:
case XMA2:
case AC3:
case AAC:
case FFMPEG: coding = coding_FFmpeg; break;
#endif
case PCFX: coding = coding_PCFX; break;
@ -375,7 +377,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
case coding_FFmpeg: {
ffmpeg_codec_data *ffmpeg_data = NULL;
if (txth.codec == FFMPEG || txth.codec == AC3) {
if (txth.codec == FFMPEG || txth.codec == AC3 || txth.codec == AAC) {
/* default FFmpeg */
ffmpeg_data = init_ffmpeg_offset(txth.streamBody, txth.start_offset,txth.data_size);
if ( !ffmpeg_data ) goto fail;
@ -631,6 +633,7 @@ static int parse_keyval(STREAMFILE * streamFile_, txth_header * txth, const char
else if (0==strcmp(val,"PCM4")) txth->codec = PCM4;
else if (0==strcmp(val,"PCM4_U")) txth->codec = PCM4_U;
else if (0==strcmp(val,"OKI16")) txth->codec = OKI16;
else if (0==strcmp(val,"AAC")) txth->codec = AAC;
else goto fail;
/* set common interleaves to simplify usage
@ -998,6 +1001,9 @@ static int get_bytes_to_samples(txth_header * txth, uint32_t bytes) {
case ATRAC3PLUS:
if (!txth->interleave) return 0;
return atrac3plus_bytes_to_samples(bytes, txth->interleave);
case AAC:
if (!txth->streamBody) return 0;
return aac_get_samples(txth->streamBody, txth->start_offset, bytes);
/* XMA bytes-to-samples is done at the end as the value meanings are a bit different */
case XMA1: