mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 08:20:54 +01:00
init_ffmpeg accepts any generic header; init_seek edge cases (for XMA)
This commit is contained in:
parent
ce040bbb36
commit
c1c1cd1ba6
@ -186,18 +186,73 @@ static int64_t ffmpeg_seek(void *opaque, int64_t offset, int whence)
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manually init FFmpeg only, from an offset.
|
* Manually init FFmpeg, from an offset.
|
||||||
* Can be used if the stream has an extra header over data recognized by FFmpeg.
|
* Can be used if the stream has an extra header over data recognized by FFmpeg.
|
||||||
*/
|
*/
|
||||||
ffmpeg_codec_data * init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size) {
|
ffmpeg_codec_data * init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size) {
|
||||||
return init_ffmpeg_faux_riff(streamFile, -1, start, size, 0);
|
return init_ffmpeg_header_offset(streamFile, NULL, 0, start, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manually init FFmpeg, from an offset and creating a fake RIFF from a streamfile.
|
||||||
|
*/
|
||||||
|
ffmpeg_codec_data * init_ffmpeg_faux_riff(STREAMFILE *streamFile, int64_t fmt_offset, uint64_t start, uint64_t size, int big_endian) {
|
||||||
|
if (fmt_offset > 0) {
|
||||||
|
size_t header_size = 0;
|
||||||
|
int max_header_size = (int)(start - fmt_offset);
|
||||||
|
uint8_t p[100];
|
||||||
|
if (max_header_size < 18 || max_header_size > 100)
|
||||||
|
goto fail;
|
||||||
|
//p = av_malloc(max_header_size + 8 + 4 + 8 + 8);
|
||||||
|
//if (!p) goto fail;
|
||||||
|
if (read_streamfile(p + 8 + 4 + 8, fmt_offset, max_header_size, streamFile) != max_header_size)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (big_endian) {
|
||||||
|
int shift = 8 + 4 + 8;
|
||||||
|
put_16bitLE(p+shift, get_16bitBE(p));
|
||||||
|
put_16bitLE(p+shift + 2, get_16bitBE(p + 2));
|
||||||
|
put_32bitLE(p+shift + 4, get_32bitBE(p + 4));
|
||||||
|
put_32bitLE(p+shift + 8, get_32bitBE(p + 8));
|
||||||
|
put_16bitLE(p+shift + 12, get_16bitBE(p + 12));
|
||||||
|
put_16bitLE(p+shift + 14, get_16bitBE(p + 14));
|
||||||
|
put_16bitLE(p+shift + 16, get_16bitBE(p + 16));
|
||||||
|
}
|
||||||
|
header_size = 8 + 4 + 8 + 8 + 18 + get_16bitLE(p + 8 + 4 + 8 + 16);
|
||||||
|
// Meh, dunno how to handle swapping the extra data
|
||||||
|
// FFmpeg doesn't need most of this data anyway
|
||||||
|
if ((unsigned)(get_16bitLE(p + 8 + 4 + 8) - 0x165) < 2)
|
||||||
|
memset(p + 8 + 4 + 8 + 18, 0, 34);
|
||||||
|
|
||||||
|
// Fill out the RIFF structure
|
||||||
|
memcpy(p, "RIFF", 4);
|
||||||
|
put_32bitLE(p + 4, header_size + size - 8);
|
||||||
|
memcpy(p + 8, "WAVE", 4);
|
||||||
|
memcpy(p + 12, "fmt ", 4);
|
||||||
|
put_32bitLE(p + 16, 18 + get_16bitLE(p + 8 + 4 + 8 + 16));
|
||||||
|
memcpy(p + header_size - 8, "data", 4);
|
||||||
|
put_32bitLE(p + header_size - 4, size);
|
||||||
|
|
||||||
|
|
||||||
|
return init_ffmpeg_header_offset(streamFile, p, header_size, start, size);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return init_ffmpeg_header_offset(streamFile, NULL, 0, start, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manually init FFmpeg only, from an offset / fake RIFF.
|
* Manually init FFmpeg, from a fake header / offset.
|
||||||
* Can insert a fake RIFF header, to trick FFmpeg into demuxing/decoding the stream.
|
*
|
||||||
|
* Can take a fake header, to trick FFmpeg into demuxing/decoding the stream.
|
||||||
|
* This header will be seamlessly inserted before 'start' offset, and total filesize will be 'header_size' + 'size'.
|
||||||
|
* The header buffer will be copied and memory-managed internally.
|
||||||
*/
|
*/
|
||||||
ffmpeg_codec_data * init_ffmpeg_faux_riff(STREAMFILE *streamFile, int64_t fmt_offset, uint64_t start, uint64_t size, int big_endian) {
|
ffmpeg_codec_data * init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size) {
|
||||||
char filename[PATH_LIMIT];
|
char filename[PATH_LIMIT];
|
||||||
|
|
||||||
ffmpeg_codec_data * data;
|
ffmpeg_codec_data * data;
|
||||||
@ -226,41 +281,12 @@ ffmpeg_codec_data * init_ffmpeg_faux_riff(STREAMFILE *streamFile, int64_t fmt_of
|
|||||||
data->size = size;
|
data->size = size;
|
||||||
|
|
||||||
|
|
||||||
/* insert fake RIFF header to trick FFmpeg into demuxing/decoding the stream */
|
/* insert fake header to trick FFmpeg into demuxing/decoding the stream */
|
||||||
if (fmt_offset > 0) {
|
if (header_size > 0) {
|
||||||
int max_header_size = (int)(start - fmt_offset);
|
data->header_size = header_size;
|
||||||
uint8_t *p;
|
data->header_insert_block = av_memdup(header, header_size);
|
||||||
if (max_header_size < 18) goto fail;
|
|
||||||
data->header_insert_block = p = av_malloc(max_header_size + 8 + 4 + 8 + 8);
|
|
||||||
if (!data->header_insert_block) goto fail;
|
if (!data->header_insert_block) goto fail;
|
||||||
if (read_streamfile(p + 8 + 4 + 8, fmt_offset, max_header_size, streamFile) != max_header_size) goto fail;
|
|
||||||
if (big_endian) {
|
|
||||||
p += 8 + 4 + 8;
|
|
||||||
put_16bitLE(p, get_16bitBE(p));
|
|
||||||
put_16bitLE(p + 2, get_16bitBE(p + 2));
|
|
||||||
put_32bitLE(p + 4, get_32bitBE(p + 4));
|
|
||||||
put_32bitLE(p + 8, get_32bitBE(p + 8));
|
|
||||||
put_16bitLE(p + 12, get_16bitBE(p + 12));
|
|
||||||
put_16bitLE(p + 14, get_16bitBE(p + 14));
|
|
||||||
put_16bitLE(p + 16, get_16bitBE(p + 16));
|
|
||||||
p -= 8 + 4 + 8;
|
|
||||||
}
|
}
|
||||||
data->header_size = 8 + 4 + 8 + 8 + 18 + get_16bitLE(p + 8 + 4 + 8 + 16);
|
|
||||||
// Meh, dunno how to handle swapping the extra data
|
|
||||||
// FFmpeg doesn't need most of this data anyway
|
|
||||||
if ((unsigned)(get_16bitLE(p + 8 + 4 + 8) - 0x165) < 2)
|
|
||||||
memset(p + 8 + 4 + 8 + 18, 0, 34);
|
|
||||||
|
|
||||||
// Fill out the RIFF structure
|
|
||||||
memcpy(p, "RIFF", 4);
|
|
||||||
put_32bitLE(p + 4, data->header_size + size - 8);
|
|
||||||
memcpy(p + 8, "WAVE", 4);
|
|
||||||
memcpy(p + 12, "fmt ", 4);
|
|
||||||
put_32bitLE(p + 16, 18 + get_16bitLE(p + 8 + 4 + 8 + 16));
|
|
||||||
memcpy(p + data->header_size - 8, "data", 4);
|
|
||||||
put_32bitLE(p + data->header_size - 4, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* setup IO, attempt to autodetect format and gather some info */
|
/* setup IO, attempt to autodetect format and gather some info */
|
||||||
data->buffer = av_malloc(FFMPEG_DEFAULT_IO_BUFFER_SIZE);
|
data->buffer = av_malloc(FFMPEG_DEFAULT_IO_BUFFER_SIZE);
|
||||||
@ -411,8 +437,8 @@ fail:
|
|||||||
static int init_seek(ffmpeg_codec_data * data) {
|
static int init_seek(ffmpeg_codec_data * data) {
|
||||||
int ret, ts_index, found_first = 0;
|
int ret, ts_index, found_first = 0;
|
||||||
int64_t ts = 0;
|
int64_t ts = 0;
|
||||||
int64_t pos; /* offset */
|
int64_t pos = 0; /* offset */
|
||||||
int size; /* coded size */
|
int size = 0; /* coded size */
|
||||||
int distance = 0; /* always? */
|
int distance = 0; /* always? */
|
||||||
|
|
||||||
AVStream * stream;
|
AVStream * stream;
|
||||||
@ -436,7 +462,7 @@ static int init_seek(ffmpeg_codec_data * data) {
|
|||||||
av_packet_unref(pkt);
|
av_packet_unref(pkt);
|
||||||
ret = av_read_frame(data->formatCtx, pkt);
|
ret = av_read_frame(data->formatCtx, pkt);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto fail;
|
break;
|
||||||
if (pkt->stream_index != data->streamIndex)
|
if (pkt->stream_index != data->streamIndex)
|
||||||
continue; /* ignore non-selected streams */
|
continue; /* ignore non-selected streams */
|
||||||
|
|
||||||
@ -450,6 +476,15 @@ static int init_seek(ffmpeg_codec_data * data) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!found_first)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* in rare cases there is only one packet */
|
||||||
|
/* if (size == 0) { size = data_end - pos; } */ /* no easy way to know, ignore (most formats don's need size) */
|
||||||
|
|
||||||
|
/* some formats (XMA1) don't seem to have packet.dts, pretend it's 0 */
|
||||||
|
if (ts == INT64_MIN)
|
||||||
|
ts = 0;
|
||||||
|
|
||||||
/* apparently some (non-audio?) streams start with a DTS before 0, but some read_seeks expect 0, which would disrupt the index
|
/* apparently some (non-audio?) streams start with a DTS before 0, but some read_seeks expect 0, which would disrupt the index
|
||||||
* we may need to keep start_ts around, since avstream/codec/format isn't always set */
|
* we may need to keep start_ts around, since avstream/codec/format isn't always set */
|
||||||
|
@ -119,6 +119,7 @@ VGMSTREAM * init_vgmstream_hca_offset(STREAMFILE *streamFile, uint64_t start, ui
|
|||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
ffmpeg_codec_data * init_ffmpeg_faux_riff(STREAMFILE *streamFile, int64_t fmt_offset, uint64_t stream_offset, uint64_t stream_size, int fmt_big_endian);
|
ffmpeg_codec_data * init_ffmpeg_faux_riff(STREAMFILE *streamFile, int64_t fmt_offset, uint64_t stream_offset, uint64_t stream_size, int fmt_big_endian);
|
||||||
ffmpeg_codec_data * init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size);
|
ffmpeg_codec_data * init_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size);
|
||||||
|
ffmpeg_codec_data * init_ffmpeg_header_offset(STREAMFILE *streamFile, uint8_t * header, uint64_t header_size, uint64_t start, uint64_t size);
|
||||||
|
|
||||||
void free_ffmpeg(ffmpeg_codec_data *);
|
void free_ffmpeg(ffmpeg_codec_data *);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user