Added new GENH codecs: ATRAC3/plus, XMA1/2, FFMPEG

Also some extra fields: total samples, skip samples, data size,
atrac3/xma modes
This commit is contained in:
bnnm 2017-03-09 19:33:31 +01:00
parent 2cdef093cb
commit ce591bbe12

View File

@ -23,6 +23,11 @@ typedef enum {
MS_IMA = 15, /* Microsoft IMA ADPCM */ MS_IMA = 15, /* Microsoft IMA ADPCM */
PCM8_U = 16, /* 8bit unsigned PCM */ PCM8_U = 16, /* 8bit unsigned PCM */
APPLE_IMA4 = 17, /* Apple Quicktime 4-bit IMA ADPCM */ APPLE_IMA4 = 17, /* Apple Quicktime 4-bit IMA ADPCM */
ATRAC3 = 18, /* raw ATRAC3 */
ATRAC3PLUS = 19, /* raw ATRAC3PLUS */
XMA1 = 20, /* raw XMA1 */
XMA2 = 21, /* raw XMA2 */
FFMPEG = 22, /* any headered FFmpeg format */
} genh_type; } genh_type;
/* GENH is an artificial "generic" header for headerless streams */ /* GENH is an artificial "generic" header for headerless streams */
@ -30,12 +35,15 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM * vgmstream = NULL;
int channel_count, loop_flag, sample_rate, interleave; int channel_count, loop_flag, sample_rate, interleave;
int32_t num_samples = 0, loop_start, loop_end; int32_t num_samples = 0, loop_start, loop_end, skip_samples = 0;
int32_t start_offset, header_size; int32_t start_offset, header_size;
off_t datasize = 0;
int32_t coef[2]; int32_t coef[2];
int32_t coef_splitted[2]; int32_t coef_splitted[2];
int32_t dsp_interleave_type; int32_t dsp_interleave_type;
int32_t coef_type; int32_t coef_type;
int skip_samples_mode, atrac3_mode, xma_mode;
int i, j; int i, j;
coding_t coding; coding_t coding;
@ -73,6 +81,13 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
case MS_IMA: coding = coding_MS_IMA; break; case MS_IMA: coding = coding_MS_IMA; break;
case PCM8_U: coding = coding_PCM8_U; break; case PCM8_U: coding = coding_PCM8_U; break;
case APPLE_IMA4: coding = coding_APPLE_IMA4; break; case APPLE_IMA4: coding = coding_APPLE_IMA4; break;
#ifdef VGM_USE_FFMPEG
case ATRAC3:
case ATRAC3PLUS:
case XMA1:
case XMA2:
case FFMPEG: coding = coding_FFmpeg; break;
#endif
default: default:
goto fail; goto fail;
} }
@ -106,6 +121,16 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
coef_splitted[0] = read_32bitLE(0x34,streamFile); coef_splitted[0] = read_32bitLE(0x34,streamFile);
coef_splitted[1] = read_32bitLE(0x38,streamFile); coef_splitted[1] = read_32bitLE(0x38,streamFile);
/* other fields */
num_samples = read_32bitLE(0x40,streamFile);
skip_samples = read_32bitLE(0x44,streamFile); /* for FFmpeg based codecs */
skip_samples_mode = read_8bit(0x48,streamFile); /* 0=autodetect, 1=force manual value @ 0x44 */
atrac3_mode = read_8bit(0x49,streamFile); /* 0=autodetect, 1=force joint stereo, 2=force full stereo */
xma_mode = read_8bit(0x4a,streamFile); /* 0=default (4ch = 2ch + 2ch), 1=single (4ch = 1ch + 1ch + 1ch + 1ch) */
datasize = read_32bitLE(0x50,streamFile);
if (!datasize)
datasize = get_streamfile_size(streamFile)-start_offset;
num_samples = num_samples > 0 ? num_samples : loop_end; num_samples = num_samples > 0 ? num_samples : loop_end;
loop_flag = loop_start != -1; loop_flag = loop_start != -1;
@ -223,6 +248,68 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
if (!vgmstream->codec_data) goto fail; if (!vgmstream->codec_data) goto fail;
break; break;
#endif
#ifdef VGM_USE_FFMPEG
case coding_FFmpeg: {
ffmpeg_codec_data *ffmpeg_data = NULL;
if (type == FFMPEG) {
/* default FFmpeg */
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,datasize);
if ( !ffmpeg_data ) goto fail;
}
else {
/* fake header FFmpeg */
uint8_t buf[200];
int32_t bytes;
if (type == ATRAC3) {
int block_size = interleave;
int joint_stereo;
switch(atrac3_mode) {
case 0: joint_stereo = vgmstream->channels > 1 && interleave/vgmstream->channels==0x60 ? 1 : 0; break; /* autodetect */
case 1: joint_stereo = 1; break; /* force joint stereo */
case 2: joint_stereo = 0; break; /* force stereo */
default: goto fail;
}
bytes = ffmpeg_make_riff_atrac3(buf, 200, vgmstream->num_samples, datasize, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, skip_samples);
}
else if (type == ATRAC3PLUS) {
int block_size = interleave;
bytes = ffmpeg_make_riff_atrac3plus(buf, 200, vgmstream->num_samples, datasize, vgmstream->channels, vgmstream->sample_rate, block_size, skip_samples);
}
else if (type == XMA1) {
int xma_stream_mode = xma_mode == 1 ? 1 : 0;
bytes = ffmpeg_make_riff_xma1(buf, 100, vgmstream->num_samples, datasize, vgmstream->channels, vgmstream->sample_rate, xma_stream_mode);
}
else if (type == XMA2) {
int block_size = interleave ? interleave : 2048;
int block_count = datasize / block_size;
bytes = ffmpeg_make_riff_xma2(buf, 200, vgmstream->num_samples, datasize, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
}
else {
goto fail;
}
if (bytes <= 0) goto fail;
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,datasize);
if ( !ffmpeg_data ) goto fail;
}
vgmstream->codec_data = ffmpeg_data;
vgmstream->layout_type = layout_none;
/* force encoder delay */
if (skip_samples_mode) {
ffmpeg_set_skip_samples(ffmpeg_data, skip_samples);
}
break;
}
#endif #endif
default: default:
break; break;