Updated VGMStream.
parent
03dab36e26
commit
3453e6a3c7
|
@ -135,4 +135,6 @@ void decode_lsf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
|||
|
||||
void decode_mtaf(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel, int channels);
|
||||
|
||||
void decode_hca(hca_codec_data * data, sample * outbuf, int32_t samples_to_do, int channels);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -117,6 +117,7 @@ void decode_ffmpeg(VGMSTREAM *vgmstream,
|
|||
endOfStream = data->endOfStream;
|
||||
endOfAudio = data->endOfAudio;
|
||||
|
||||
/* keep reading and decoding packets until the requested number of samples (in bytes) */
|
||||
while (bytesRead < bytesToRead) {
|
||||
int planeSize;
|
||||
int planar = av_sample_fmt_is_planar(codecCtx->sample_fmt);
|
||||
|
@ -127,6 +128,7 @@ void decode_ffmpeg(VGMSTREAM *vgmstream,
|
|||
if (dataSize < 0)
|
||||
dataSize = 0;
|
||||
|
||||
/* read packet */
|
||||
while (readNextPacket && !endOfAudio) {
|
||||
if (!endOfStream) {
|
||||
av_packet_unref(lastReadPacket);
|
||||
|
@ -138,7 +140,7 @@ void decode_ffmpeg(VGMSTREAM *vgmstream,
|
|||
break;
|
||||
}
|
||||
if (lastReadPacket->stream_index != streamIndex)
|
||||
continue;
|
||||
continue; /* ignore non audio streams */
|
||||
}
|
||||
|
||||
if ((errcode = avcodec_send_packet(codecCtx, endOfStream ? NULL : lastReadPacket)) < 0) {
|
||||
|
@ -150,6 +152,7 @@ void decode_ffmpeg(VGMSTREAM *vgmstream,
|
|||
readNextPacket = 0;
|
||||
}
|
||||
|
||||
/* decode packet */
|
||||
if (dataSize <= bytesConsumedFromDecodedFrame) {
|
||||
if (endOfStream && endOfAudio)
|
||||
break;
|
||||
|
@ -178,21 +181,32 @@ void decode_ffmpeg(VGMSTREAM *vgmstream,
|
|||
|
||||
toConsume = FFMIN((dataSize - bytesConsumedFromDecodedFrame), (bytesToRead - bytesRead));
|
||||
|
||||
/* discard packet if needed (fully or partially) */
|
||||
if (data->samplesToDiscard) {
|
||||
int samplesToConsume;
|
||||
int bytesPerFrame = ((data->bitsPerSample / 8) * channels);
|
||||
int samplesToConsume = toConsume / bytesPerFrame;
|
||||
if (data->samplesToDiscard >= samplesToConsume) {
|
||||
|
||||
/* discard all if there are more samples to do than the packet's samples */
|
||||
if (data->samplesToDiscard >= dataSize / bytesPerFrame) {
|
||||
samplesToConsume = dataSize / bytesPerFrame;
|
||||
}
|
||||
else {
|
||||
samplesToConsume = toConsume / bytesPerFrame;
|
||||
}
|
||||
|
||||
if (data->samplesToDiscard >= samplesToConsume) { /* full discard: skip to next */
|
||||
data->samplesToDiscard -= samplesToConsume;
|
||||
bytesConsumedFromDecodedFrame = dataSize;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
else { /* partial discard: copy below */
|
||||
bytesConsumedFromDecodedFrame += data->samplesToDiscard * bytesPerFrame;
|
||||
toConsume -= data->samplesToDiscard * bytesPerFrame;
|
||||
data->samplesToDiscard = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* copy packet to buffer (mux channels if needed) */
|
||||
if (!planar || channels == 1) {
|
||||
memmove(targetBuf + bytesRead, (lastDecodedFrame->data[0] + bytesConsumedFromDecodedFrame), toConsume);
|
||||
}
|
||||
|
@ -210,6 +224,7 @@ void decode_ffmpeg(VGMSTREAM *vgmstream,
|
|||
}
|
||||
}
|
||||
|
||||
/* consume */
|
||||
bytesConsumedFromDecodedFrame += toConsume;
|
||||
bytesRead += toConsume;
|
||||
}
|
||||
|
|
|
@ -109,6 +109,16 @@ VGMSTREAM * init_vgmstream_adx(STREAMFILE *streamFile) {
|
|||
loop_end_sample = read_32bitBE(0x30,streamFile);
|
||||
//loop_end_offset = read_32bitBE(0x34,streamFile);
|
||||
}
|
||||
|
||||
/* AINF header can also start after the loop points
|
||||
* (may be inserted by CRI's tools but is rarely used) */
|
||||
/* ainf_magic = read_32bitBE(0x38,streamFile); */ /* 0x41494E46 */
|
||||
/* ainf_length = read_32bitBE(0x3c,streamFile); */
|
||||
/* ainf_str_id = read_string(0x40,streamFile); */ /* max size 0x10 */
|
||||
/* ainf_volume = read_16bitBE(0x50,streamFile); */ /* 0=base/max?, negative=reduce */
|
||||
/* ainf_pan_l = read_16bitBE(0x54,streamFile); */ /* 0=base, max +-128 */
|
||||
/* ainf_pan_r = read_16bitBE(0x56,streamFile); */
|
||||
|
||||
} else if (version_signature == 0x0500) { /* found in some SFD : Buggy Heat, appears to have no loop */
|
||||
header_type = meta_ADX_05;
|
||||
} else goto fail; /* not a known/supported version signature */
|
||||
|
|
|
@ -393,6 +393,13 @@ VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, const ch
|
|||
loop_flag=1;
|
||||
loop_end_found=1;
|
||||
}
|
||||
else if (strstr(comment->user_comments[i],"COMMENT=loop(")==
|
||||
comment->user_comments[i]) {
|
||||
sscanf(strrchr(comment->user_comments[i],'(')+1,"%d,%d",
|
||||
&loop_start,&loop_end);
|
||||
loop_flag=1;
|
||||
loop_end_found=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,48 +1,58 @@
|
|||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* 2PFS
|
||||
- Mahoromatic: Moetto - KiraKira Maid-San (PS2)
|
||||
|
||||
/* 2PFS (Konami)
|
||||
- Mahoromatic: Moetto - KiraKira Maid-San (PS2) [.2pfs (V1, 2003)]
|
||||
- GANTZ The Game (PS2) [.sap (V2, 2005)]
|
||||
|
||||
There are two versions of the format, though they use different extensions.
|
||||
Implemented both versions here in case there are .2pfs with the V2 header out there.
|
||||
Both loop correctly AFAIK (there is a truncated Mahoromatic rip around, beware).
|
||||
*/
|
||||
VGMSTREAM * init_vgmstream_ps2_2pfs(STREAMFILE *streamFile)
|
||||
{
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
off_t start_offset;
|
||||
off_t start_offset = 0x800;
|
||||
int interleave = 0x1000;
|
||||
|
||||
int loop_flag = 0;
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
int version; /* v1=1, v2=2 */
|
||||
|
||||
int loop_start_block; /* block number where the loop starts */
|
||||
int loop_end_block; /* usually the last block */
|
||||
int loop_start_sample_adjust; /* loops start/end a few samples into the start/end block */
|
||||
int loop_end_sample_adjust;
|
||||
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("2pfs",filename_extension(filename))) goto fail;
|
||||
if ( strcasecmp("2pfs",filename_extension(filename))
|
||||
&& strcasecmp("sap",filename_extension(filename)) )
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
/* check header ("2PFS") */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x32504653)
|
||||
goto fail;
|
||||
|
||||
// channel count
|
||||
version = read_16bitLE(0x04,streamFile);
|
||||
if ( version!=0x01 && version!=0x02 )
|
||||
goto fail;
|
||||
|
||||
|
||||
channel_count = read_8bit(0x40,streamFile);
|
||||
loop_flag = read_8bit(0x41,streamFile);
|
||||
/* other header values
|
||||
* 0x06 (4): unknown, v1=0x0004 v2=0x0001
|
||||
* 0x08 (32): unique file id
|
||||
* 0x0c (32): base header size (v1=0x50, v2=0x60) + datasize (without the 0x800 full header size)
|
||||
* 0x10-0x30: unknown (v1 differs from v2)
|
||||
* 0x38-0x40: unknown (v1 same as v2)
|
||||
* 0x4c (32) in V2: unknown, some kind of total samples?
|
||||
*/
|
||||
|
||||
// header size
|
||||
start_offset = 0x800;
|
||||
|
||||
// loop flag
|
||||
//if ((read_32bitLE(0x38, streamFile) != 0 ||
|
||||
// (read_32bitLE(0x34, streamFile) != 0)))
|
||||
//{
|
||||
// loop_flag = 1;
|
||||
//}
|
||||
|
||||
// Loop info unknown right now
|
||||
//if (loop_flag)
|
||||
//{
|
||||
// vgmstream->loop_start_sample = read_32bitLE(0x38,streamFile)*28/16/channel_count;
|
||||
// vgmstream->loop_end_sample = read_32bitLE(0x34,streamFile)*28/16/channel_count;
|
||||
//}
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
|
@ -50,14 +60,37 @@ VGMSTREAM * init_vgmstream_ps2_2pfs(STREAMFILE *streamFile)
|
|||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = read_32bitLE(0x44,streamFile);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->num_samples = read_32bitLE(0x0C,streamFile)*28/16/channel_count;
|
||||
|
||||
vgmstream->num_samples = read_32bitLE(0x34,streamFile) * 28 / 16 / channel_count;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x1000;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
vgmstream->meta_type = meta_PS2_2PFS;
|
||||
|
||||
if ( version==0x01 ) {
|
||||
vgmstream->sample_rate = read_32bitLE(0x44,streamFile);
|
||||
loop_start_sample_adjust = read_16bitLE(0x42,streamFile);
|
||||
loop_start_block = read_32bitLE(0x48,streamFile);
|
||||
loop_end_block = read_32bitLE(0x4c,streamFile);
|
||||
} else {
|
||||
vgmstream->sample_rate = read_32bitLE(0x48,streamFile);
|
||||
loop_start_sample_adjust = read_32bitLE(0x44,streamFile);
|
||||
loop_start_block = read_32bitLE(0x50,streamFile);
|
||||
loop_end_block = read_32bitLE(0x54,streamFile);
|
||||
}
|
||||
loop_end_sample_adjust = interleave; /* loops end after all samples in the end_block AFAIK */
|
||||
|
||||
if ( loop_flag ) {
|
||||
/* block to offset > offset to sample + adjust (number of samples into the block) */
|
||||
vgmstream->loop_start_sample = ((loop_start_block * channel_count * interleave)
|
||||
* 28 / 16 / channel_count)
|
||||
+ (loop_start_sample_adjust * 28 / 16);
|
||||
vgmstream->loop_end_sample = ((loop_end_block * channel_count * interleave)
|
||||
* 28 / 16 / channel_count)
|
||||
+ (loop_end_sample_adjust * 28 / 16);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* open the file for reading */
|
||||
{
|
||||
int i;
|
||||
|
@ -69,11 +102,10 @@ VGMSTREAM * init_vgmstream_ps2_2pfs(STREAMFILE *streamFile)
|
|||
{
|
||||
vgmstream->ch[i].streamfile = file;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=start_offset + (vgmstream->interleave_block_size * i);
|
||||
|
||||
vgmstream->ch[i].channel_start_offset =
|
||||
vgmstream->ch[i].offset =
|
||||
start_offset + (vgmstream->interleave_block_size * i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
|
|
@ -173,15 +173,17 @@ int read_fmt(int big_endian,
|
|||
fmt->interleave = 8;
|
||||
break;
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x270:
|
||||
case 0xFFFE:
|
||||
case 0x270: /* ATRAC3 */
|
||||
#if defined(VGM_USE_FFMPEG) && !defined(VGM_USE_MAIATRAC3PLUS)
|
||||
case 0xFFFE: /* WAVEFORMATEXTENSIBLE / ATRAC3plus */
|
||||
#endif /* defined */
|
||||
fmt->coding_type = coding_FFmpeg;
|
||||
fmt->block_size = 2048;
|
||||
fmt->interleave = 0;
|
||||
break;
|
||||
#endif
|
||||
#endif /* VGM_USE_FFMPEG */
|
||||
#ifdef VGM_USE_MAIATRAC3PLUS
|
||||
case 0xFFFE: /* WAVEFORMATEXTENSIBLE */
|
||||
case 0xFFFE: /* WAVEFORMATEXTENSIBLE / ATRAC3plus */
|
||||
if (read_32bit(current_chunk+0x20,streamFile) == 0xE923AABF &&
|
||||
read_16bit(current_chunk+0x24,streamFile) == (int16_t)0xCB58 &&
|
||||
read_16bit(current_chunk+0x26,streamFile) == 0x4471 &&
|
||||
|
|
|
@ -359,6 +359,13 @@ VGMSTREAM * init_vgmstream_internal(STREAMFILE *streamFile, int do_dfs) {
|
|||
if (vgmstream) {
|
||||
/* these are little hacky checks */
|
||||
|
||||
/* fail if there is nothing to play
|
||||
* (without this check vgmstream can generate empty files) */
|
||||
if ( vgmstream->num_samples==0 ) {
|
||||
close_vgmstream(vgmstream);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* everything should have a reasonable sample rate
|
||||
* (a verification of the metadata) */
|
||||
if (!check_sample_rate(vgmstream->sample_rate)) {
|
||||
|
@ -1783,6 +1790,10 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) {
|
|||
if (vgmstream->coding_type==coding_FFmpeg) {
|
||||
ffmpeg_codec_data *data = (ffmpeg_codec_data *)(vgmstream->codec_data);
|
||||
int64_t ts;
|
||||
|
||||
/* Seek to loop start by timestamp (closest frame) + adjust skipping some samples */
|
||||
/* FFmpeg seeks by ts by design (since not all containers can accurately skip to a frame). */
|
||||
/* TODO: this seems to be off by +-1 frames in some cases */
|
||||
ts = vgmstream->loop_start_sample;
|
||||
if (ts >= data->sampleRate * 2) {
|
||||
data->samplesToDiscard = data->sampleRate * 2;
|
||||
|
@ -1794,14 +1805,26 @@ int vgmstream_do_loop(VGMSTREAM * vgmstream) {
|
|||
}
|
||||
data->framesRead = (int)ts;
|
||||
ts = data->framesRead * (data->formatCtx->duration) / data->totalFrames;
|
||||
|
||||
|
||||
#ifdef VGM_USE_FFMPEG_ACCURATE_LOOPING
|
||||
/* Start from 0 and discard samples until loop_start for accurate looping (slower but not too noticeable) */
|
||||
/* We could also seek by offset (AVSEEK_FLAG_BYTE) to the frame closest to the loop then discard
|
||||
* some samples, which is fast but would need calculations per format / when frame size is not constant */
|
||||
data->samplesToDiscard = vgmstream->loop_start_sample;
|
||||
data->framesRead = 0;
|
||||
ts = 0;
|
||||
#endif /* VGM_USE_FFMPEG_ACCURATE_LOOPING */
|
||||
|
||||
avformat_seek_file(data->formatCtx, -1, ts - 1000, ts, ts, AVSEEK_FLAG_ANY);
|
||||
avcodec_flush_buffers(data->codecCtx);
|
||||
|
||||
data->readNextPacket = 1;
|
||||
data->bytesConsumedFromDecodedFrame = INT_MAX;
|
||||
data->endOfStream = 0;
|
||||
data->endOfAudio = 0;
|
||||
}
|
||||
#endif
|
||||
#endif /* VGM_USE_FFMPEG */
|
||||
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
|
||||
if (vgmstream->coding_type==coding_MP4_AAC) {
|
||||
mp4_aac_codec_data *data = (mp4_aac_codec_data *)(vgmstream->codec_data);
|
||||
|
|
Loading…
Reference in New Issue