2016-07-17 08:02:27 +02:00
|
|
|
#include "meta.h"
|
2017-05-19 17:21:22 +02:00
|
|
|
#include "../coding/coding.h"
|
2016-07-17 08:02:27 +02:00
|
|
|
|
|
|
|
#ifdef VGM_USE_FFMPEG
|
|
|
|
|
2018-03-29 20:38:06 +02:00
|
|
|
static int read_pos_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile);
|
|
|
|
|
2016-11-26 13:43:59 +01:00
|
|
|
/**
|
|
|
|
* Generic init FFmpeg and vgmstream for any file supported by FFmpeg.
|
2017-05-19 17:21:22 +02:00
|
|
|
* Called by vgmstream when trying to identify the file type (if the player allows it).
|
2016-11-26 13:43:59 +01:00
|
|
|
*/
|
2016-07-17 08:02:27 +02:00
|
|
|
VGMSTREAM * init_vgmstream_ffmpeg(STREAMFILE *streamFile) {
|
|
|
|
return init_vgmstream_ffmpeg_offset( streamFile, 0, streamFile->get_size(streamFile) );
|
|
|
|
}
|
|
|
|
|
|
|
|
VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size) {
|
|
|
|
VGMSTREAM *vgmstream = NULL;
|
2016-12-11 13:05:54 +01:00
|
|
|
int loop_flag = 0;
|
|
|
|
int32_t loop_start = 0, loop_end = 0, num_samples = 0;
|
2018-06-09 17:30:28 +02:00
|
|
|
int total_subsongs, target_subsong = streamFile->stream_index;
|
2016-11-26 13:43:59 +01:00
|
|
|
|
2016-12-11 13:05:54 +01:00
|
|
|
/* init ffmpeg */
|
2016-07-17 08:02:27 +02:00
|
|
|
ffmpeg_codec_data *data = init_ffmpeg_offset(streamFile, start, size);
|
|
|
|
if (!data) return NULL;
|
2016-12-11 13:05:54 +01:00
|
|
|
|
2018-06-09 17:30:28 +02:00
|
|
|
total_subsongs = data->streamCount;
|
|
|
|
if (target_subsong == 0) target_subsong = 1;
|
|
|
|
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
2016-12-11 13:05:54 +01:00
|
|
|
|
|
|
|
/* try to get .pos data */
|
|
|
|
{
|
|
|
|
uint8_t posbuf[4+4+4];
|
|
|
|
|
|
|
|
if ( read_pos_file(posbuf, 4+4+4, streamFile) ) {
|
|
|
|
loop_start = get_32bitLE(posbuf+0);
|
|
|
|
loop_end = get_32bitLE(posbuf+4);
|
|
|
|
loop_flag = 1; /* incorrect looping will be validated outside */
|
|
|
|
/* FFmpeg can't always determine totalSamples correctly so optionally load it (can be 0/NULL)
|
|
|
|
* won't crash and will output silence if no loop points and bigger than actual stream's samples */
|
|
|
|
num_samples = get_32bitLE(posbuf+8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* build VGMSTREAM */
|
|
|
|
vgmstream = allocate_vgmstream(data->channels, loop_flag);
|
2016-07-17 08:02:27 +02:00
|
|
|
if (!vgmstream) goto fail;
|
|
|
|
|
|
|
|
vgmstream->sample_rate = data->sampleRate;
|
2018-08-19 19:09:37 +02:00
|
|
|
vgmstream->meta_type = meta_FFMPEG;
|
2016-07-17 08:02:27 +02:00
|
|
|
vgmstream->coding_type = coding_FFmpeg;
|
2018-08-19 10:07:27 +02:00
|
|
|
vgmstream->codec_data = data;
|
2016-07-17 08:02:27 +02:00
|
|
|
vgmstream->layout_type = layout_none;
|
2016-11-26 13:43:59 +01:00
|
|
|
|
2016-12-11 13:05:54 +01:00
|
|
|
if (!num_samples) {
|
|
|
|
num_samples = data->totalSamples;
|
|
|
|
}
|
|
|
|
vgmstream->num_samples = num_samples;
|
|
|
|
|
|
|
|
if (loop_flag) {
|
|
|
|
vgmstream->loop_start_sample = loop_start;
|
|
|
|
vgmstream->loop_end_sample = loop_end;
|
|
|
|
}
|
|
|
|
|
2018-08-19 10:07:27 +02:00
|
|
|
/* this may happen for some streams if FFmpeg can't determine it (ex. AAC) */
|
2016-12-01 23:49:00 +01:00
|
|
|
if (vgmstream->num_samples <= 0)
|
|
|
|
goto fail;
|
|
|
|
|
2019-03-02 15:57:41 +01:00
|
|
|
vgmstream->channel_layout = ffmpeg_get_channel_layout(vgmstream->codec_data);
|
|
|
|
|
2016-07-17 08:02:27 +02:00
|
|
|
return vgmstream;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
free_ffmpeg(data);
|
2016-12-01 23:49:00 +01:00
|
|
|
if (vgmstream) {
|
|
|
|
vgmstream->codec_data = NULL;
|
|
|
|
close_vgmstream(vgmstream);
|
|
|
|
}
|
2016-07-17 08:02:27 +02:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-03-29 20:38:06 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* open file containing looping data and copy to buffer
|
|
|
|
*
|
|
|
|
* returns true if found and copied
|
|
|
|
*/
|
|
|
|
int read_pos_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile) {
|
|
|
|
char posname[PATH_LIMIT];
|
|
|
|
char filename[PATH_LIMIT];
|
|
|
|
/*size_t bytes_read;*/
|
|
|
|
STREAMFILE * streamFilePos= NULL;
|
|
|
|
|
|
|
|
streamFile->get_name(streamFile,filename,sizeof(filename));
|
|
|
|
|
|
|
|
if (strlen(filename)+4 > sizeof(posname)) goto fail;
|
|
|
|
|
|
|
|
/* try to open a posfile using variations: "(name.ext).pos" */
|
|
|
|
{
|
|
|
|
strcpy(posname, filename);
|
|
|
|
strcat(posname, ".pos");
|
|
|
|
streamFilePos = streamFile->open(streamFile,posname,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
|
|
|
if (streamFilePos) goto found;
|
|
|
|
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
found:
|
|
|
|
//if (get_streamfile_size(streamFilePos) != bufsize) goto fail;
|
|
|
|
|
|
|
|
/* allow pos files to be of different sizes in case of new features, just fill all we can */
|
|
|
|
memset(buf, 0, bufsize);
|
|
|
|
read_streamfile(buf, 0, bufsize, streamFilePos);
|
|
|
|
|
|
|
|
close_streamfile(streamFilePos);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
if (streamFilePos) close_streamfile(streamFilePos);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-07-17 08:02:27 +02:00
|
|
|
#endif
|