mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-02-21 20:59:52 +01:00
move xma_get_samples from xma.c to FFmpeg utils (needed by XWB)
xma.c now uses ffmpeg's fmt_chunk_swap_endian, too
This commit is contained in:
parent
8b72e32a97
commit
d2a31378c2
@ -154,19 +154,45 @@ void decode_mp4_aac(mp4_aac_codec_data * data, sample * outbuf, int32_t samples_
|
||||
void decode_at3plus(VGMSTREAM *vgmstream, sample * outbuf, int channelspacing, int32_t samples_to_do, int channel);
|
||||
#endif
|
||||
|
||||
/* ffmpeg_decoder */
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
/* ffmpeg_decoder */
|
||||
void decode_ffmpeg(VGMSTREAM *stream, sample * outbuf, int32_t samples_to_do, int channels);
|
||||
void reset_ffmpeg(VGMSTREAM *vgmstream);
|
||||
void seek_ffmpeg(VGMSTREAM *vgmstream, int32_t num_sample);
|
||||
|
||||
void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples);
|
||||
|
||||
/* ffmpeg_decoder_utils */
|
||||
int ffmpeg_fmt_chunk_swap_endian(uint8_t * chunk, uint16_t codec);
|
||||
int ffmpeg_make_riff_atrac3(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int joint_stereo, int encoder_delay);
|
||||
int ffmpeg_make_riff_xma1(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int stream_mode);
|
||||
int ffmpeg_make_riff_xma2(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_count, int block_size);
|
||||
int ffmpeg_make_riff_xma2_from_fmt(uint8_t * buf, size_t buf_size, off_t fmt_offset, size_t fmt_size, size_t data_size, STREAMFILE *streamFile, int big_endian);
|
||||
int ffmpeg_make_riff_xwma(uint8_t * buf, size_t buf_size, int codec, size_t sample_count, size_t data_size, int channels, int sample_rate, int avg_bps, int block_align);
|
||||
|
||||
/* XMA sample parser info (struct to avoid passing so much stuff, separate for reusing) */
|
||||
typedef struct {
|
||||
int xma_version;
|
||||
int channels;
|
||||
int stream_mode;
|
||||
off_t data_offset;
|
||||
size_t data_size;
|
||||
int loop_flag;
|
||||
/* frame offsets */
|
||||
uint32_t loop_start_b;
|
||||
uint32_t loop_end_b;
|
||||
uint32_t loop_start_subframe;
|
||||
uint32_t loop_end_subframe;
|
||||
|
||||
/* output */
|
||||
int32_t num_samples;
|
||||
int32_t skip_samples;
|
||||
int32_t loop_start_sample;
|
||||
int32_t loop_end_sample;
|
||||
} xma_sample_data;
|
||||
void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /*_CODING_H*/
|
||||
|
@ -1,14 +1,39 @@
|
||||
#include "coding.h"
|
||||
#include "../vgmstream.h"
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
|
||||
#define XMA_CHECK_SKIPS 0
|
||||
#define XMA_BYTES_PER_PACKET 2048
|
||||
#define XMA_SAMPLES_PER_FRAME 512
|
||||
#define XMA_SAMPLES_PER_SUBFRAME 128
|
||||
|
||||
/* ******************************************** */
|
||||
/* INTERNAL UTILS */
|
||||
/* ******************************************** */
|
||||
|
||||
/**
|
||||
* read num_bits (up to 25) from a bit offset.
|
||||
* 25 since we read a 32 bit int, and need to adjust up to 7 bits from the byte-rounded fseek (32-7=25)
|
||||
*/
|
||||
static uint32_t read_bitsBE_b(off_t bit_offset, int num_bits, STREAMFILE *streamFile) {
|
||||
uint32_t num, mask;
|
||||
if (num_bits > 25) return -1; //???
|
||||
|
||||
num = read_32bitBE(bit_offset / 8, streamFile); /* fseek rounded to 8 */
|
||||
num = num << (bit_offset % 8); /* offset adjust (up to 7) */
|
||||
num = num >> (32 - num_bits);
|
||||
mask = 0xffffffff >> (32 - num_bits);
|
||||
|
||||
return num & mask;
|
||||
}
|
||||
|
||||
|
||||
/* ******************************************** */
|
||||
/* FAKE RIFF HELPERS */
|
||||
/* ******************************************** */
|
||||
/* All helpers copy a RIFF header to buf and returns the number of bytes in buf or -1 when buf is not big enough */
|
||||
|
||||
static int ffmpeg_fmt_chunk_swap_endian(uint8_t * chunk, uint16_t codec);
|
||||
|
||||
int ffmpeg_make_riff_atrac3(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int joint_stereo, int encoder_delay) {
|
||||
uint16_t codec_ATRAC3 = 0x0270;
|
||||
size_t riff_size = 4+4+ 4 + 0x28 + 0x10 + 4+4;
|
||||
@ -245,7 +270,7 @@ int ffmpeg_make_riff_xwma(uint8_t * buf, size_t buf_size, int codec, size_t samp
|
||||
}
|
||||
|
||||
|
||||
static int ffmpeg_fmt_chunk_swap_endian(uint8_t * chunk, uint16_t codec) {
|
||||
int ffmpeg_fmt_chunk_swap_endian(uint8_t * chunk, uint16_t codec) {
|
||||
if (codec != 0x166)/* XMA2 */
|
||||
goto fail;
|
||||
|
||||
@ -274,4 +299,199 @@ fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ******************************************** */
|
||||
/* XMA PARSING */
|
||||
/* ******************************************** */
|
||||
|
||||
/**
|
||||
* Find total and loop samples by reading XMA frame headers.
|
||||
*
|
||||
* A XMA stream is made of packets, each containing N small frames of X samples.
|
||||
* Frames are further divided into subframes for looping purposes.
|
||||
* XMA1 and XMA2 only differ in the packet headers.
|
||||
*/
|
||||
void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
|
||||
int frames = 0, samples = 0, loop_start_frame = 0, loop_end_frame = 0, skip_packets;
|
||||
#if XMA_CHECK_SKIPS
|
||||
int start_skip = 0, end_skip = 0, first_start_skip = 0, last_end_skip = 0;
|
||||
#endif
|
||||
uint32_t first_frame_b, packet_skip_count = 0, frame_size_b, packet_size_b;
|
||||
uint64_t offset_b, packet_offset_b, frame_offset_b;
|
||||
size_t size;
|
||||
|
||||
uint32_t packet_size = XMA_BYTES_PER_PACKET;
|
||||
off_t offset = xma->data_offset;
|
||||
uint32_t stream_offset_b = xma->data_offset * 8;
|
||||
|
||||
size = offset + xma->data_size;
|
||||
packet_size_b = packet_size * 8;
|
||||
|
||||
/* if we knew the streams mode then we could read just the first one and adjust samples later
|
||||
* not a big deal but maybe important for skip stuff */
|
||||
//streams = (xma->stream_mode==0 ? (xma->channels + 1) / 2 : xma->channels)
|
||||
skip_packets = 0;
|
||||
|
||||
/* read packets */
|
||||
while (offset < size) {
|
||||
offset_b = offset * 8; /* global offset in bits */
|
||||
offset += packet_size; /* global offset in bytes */
|
||||
|
||||
/* skip packets not owned by the first stream, since we only need samples from it */
|
||||
if (skip_packets && packet_skip_count) {
|
||||
packet_skip_count--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* XMA1 or XMA2 packet header */
|
||||
if (xma->xma_version == 1) {
|
||||
//packet_sequence = read_bitsBE_b(offset_b+0, 4, streamFile); /* numbered from 0 to N */
|
||||
//unknown = read_bitsBE_b(offset_b+4, 2, streamFile); /* packet_metadata? (always 2) */
|
||||
first_frame_b = read_bitsBE_b(offset_b+6, 15, streamFile); /* offset in bits inside the packet */
|
||||
packet_skip_count = read_bitsBE_b(offset_b+21, 11, streamFile); /* packets to skip for next packet of this stream */
|
||||
} else {
|
||||
//frame_count = read_bitsBE_b(offset_b+0, 6, streamFile); /* frames that begin in this packet */
|
||||
first_frame_b = read_bitsBE_b(offset_b+6, 15, streamFile); /* offset in bits inside this packet */
|
||||
//packet_metadata = read_bitsBE_b(offset_b+21, 3, streamFile); /* packet_metadata (always 1) */
|
||||
packet_skip_count = read_bitsBE_b(offset_b+24, 8, streamFile); /* packets to skip for next packet of this stream */
|
||||
}
|
||||
|
||||
/* full packet skip */
|
||||
if (packet_skip_count == 0x7FF) {
|
||||
packet_skip_count = 0;
|
||||
continue;
|
||||
}
|
||||
if (packet_skip_count > 255) { /* seen in some (converted?) XMA1 */
|
||||
packet_skip_count = 0;
|
||||
}
|
||||
VGM_ASSERT(packet_skip_count > 10, "XMA: found big packet skip %i\n", packet_skip_count);//a bit unusual...
|
||||
//VGM_LOG("packet: off=%x, ff=%i, ps=%i\n", offset, first_frame_b, packet_skip_b);
|
||||
|
||||
packet_offset_b = 4*8 + first_frame_b; /* packet offset in bits */
|
||||
|
||||
/* read packet frames */
|
||||
while (packet_offset_b < packet_size_b) {
|
||||
frame_offset_b = offset_b + packet_offset_b; /* in bits for aligment stuff */
|
||||
|
||||
//todo not sure if frames or frames+1 (considering skip_samples)
|
||||
if (xma->loop_flag && (offset_b + packet_offset_b) - stream_offset_b == xma->loop_start_b)
|
||||
loop_start_frame = frames;
|
||||
if (xma->loop_flag && (offset_b + packet_offset_b) - stream_offset_b == xma->loop_end_b)
|
||||
loop_end_frame = frames;
|
||||
|
||||
|
||||
/* XMA1/2 frame header */
|
||||
frame_size_b = read_bitsBE_b(frame_offset_b, 15, streamFile);
|
||||
frame_offset_b += 15;
|
||||
if (frame_size_b == 0) /* observed in some files with empty frames/packets */
|
||||
break;
|
||||
packet_offset_b += frame_size_b; /* including header */
|
||||
|
||||
#if 0
|
||||
{
|
||||
uint32_t frame_config
|
||||
frame_config = read_bitsBE_b(frame_offset_b, 15, streamFile);
|
||||
|
||||
//VGM_LOG(" frame %04i: off_b=%I64x (~0x%I64x), fs_b=%i (~0x%x), fs=%x\n",frames, frame_offset_b, frame_offset_b/8, frame_size_b,frame_size_b/8, frame_config);
|
||||
|
||||
//if (frame_config != 0x7f00) /* "contains all subframes"? */
|
||||
// continue; // todo read packet end bit instead
|
||||
}
|
||||
#endif
|
||||
frame_offset_b += 15;
|
||||
|
||||
if (frame_size_b == 0x7FFF) { /* end packet frame marker */
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// more header stuff (info from FFmpeg)
|
||||
{
|
||||
int flag;
|
||||
|
||||
/* ignore "postproc transform" */
|
||||
if (xma->channels > 1) {
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
frame_offset_b += 1;
|
||||
if (flag) {
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
frame_offset_b += 1;
|
||||
if (flag) {
|
||||
frame_offset_b += 1 + 4 * xma->channels*xma->channels; /* 4-something per double channel? */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* get start/end skips to get the proper number of samples */ //todo check if first bit =1 means full 512 skip
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
frame_offset_b += 1;
|
||||
if (flag) {
|
||||
int new_skip;
|
||||
|
||||
/* get start skip */
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
frame_offset_b += 1;
|
||||
if (flag) {
|
||||
new_skip = read_bitsBE_b(frame_offset_b, 10, streamFile);
|
||||
frame_offset_b += 10;
|
||||
VGM_ASSERT(start_skip, "XMA: more than one start_skip (%i)\n", new_skip);
|
||||
|
||||
if (new_skip > XMA_SAMPLES_PER_FRAME) { /* from xmaencode */
|
||||
VGM_LOG("XMA: bad start_skip (%i)\n", new_skip);
|
||||
new_skip = XMA_SAMPLES_PER_FRAME;
|
||||
}
|
||||
|
||||
if (frames==0) first_start_skip = new_skip; /* sometimes in the middle */
|
||||
start_skip += new_skip;
|
||||
}
|
||||
|
||||
/* get end skip */
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
frame_offset_b += 1;
|
||||
if (flag) {
|
||||
new_skip = read_bitsBE_b(frame_offset_b, 10, streamFile);
|
||||
frame_offset_b += 10;
|
||||
VGM_ASSERT(end_skip, "XMA: more than one end_skip (%i)\n", new_skip);
|
||||
|
||||
if (new_skip > XMA_SAMPLES_PER_FRAME) { /* from xmaencode */
|
||||
VGM_LOG("XMA: bad end_skip (%i)\n", new_skip);
|
||||
new_skip = XMA_SAMPLES_PER_FRAME;
|
||||
}
|
||||
|
||||
last_end_skip = new_skip; /* not seen */
|
||||
end_skip += new_skip;
|
||||
}
|
||||
|
||||
VGM_LOG(" skip: st=%i, ed=%i\n", start_skip, end_skip);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
samples += XMA_SAMPLES_PER_FRAME;
|
||||
frames++;
|
||||
}
|
||||
}
|
||||
|
||||
#if XMA_CHECK_SKIPS
|
||||
//todo this seems to usually work, but not always
|
||||
/* apply skips (not sure why 64, empty samples generated by the decoder not in the file?) */
|
||||
samples = samples + 64 - start_skip;
|
||||
samples = samples + 64 - end_skip;
|
||||
|
||||
xma->skip_samples = 64 + 512; //todo not always correct
|
||||
#endif
|
||||
|
||||
xma->num_samples = samples;
|
||||
|
||||
if (xma->loop_flag && loop_end_frame > loop_start_frame) {
|
||||
xma->loop_start_sample = loop_start_frame * XMA_SAMPLES_PER_FRAME + xma->loop_start_subframe * XMA_SAMPLES_PER_SUBFRAME;
|
||||
xma->loop_end_sample = loop_end_frame * XMA_SAMPLES_PER_FRAME + xma->loop_end_subframe * XMA_SAMPLES_PER_SUBFRAME;
|
||||
#if XMA_CHECK_SKIPS
|
||||
/* maybe this is needed */
|
||||
//xma->loop_start_sample -= xma->skip_samples;
|
||||
//xma->loop_end_sample -= xma->skip_samples;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
269
src/meta/xma.c
269
src/meta/xma.c
@ -4,9 +4,6 @@
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
|
||||
#define XMA_BYTES_PER_PACKET 2048
|
||||
#define XMA_SAMPLES_PER_FRAME 512
|
||||
#define XMA_SAMPLES_PER_SUBFRAME 128
|
||||
#define FAKE_RIFF_BUFFER_SIZE 100
|
||||
|
||||
|
||||
@ -38,32 +35,9 @@ typedef struct {
|
||||
int32_t loop_subframe;
|
||||
} xma_header_data;
|
||||
|
||||
/* XMA sample parser info (struct to avoid passing so much stuff, separate for reusing) */
|
||||
typedef struct {
|
||||
int xma_version;
|
||||
int channels;
|
||||
int stream_mode;
|
||||
off_t data_offset;
|
||||
size_t data_size;
|
||||
int loop_flag;
|
||||
uint32_t loop_start_b; /* frame offsets */
|
||||
uint32_t loop_end_b; /* frame offsets */
|
||||
uint32_t loop_start_subframe;
|
||||
uint32_t loop_end_subframe;
|
||||
|
||||
/* output */
|
||||
int32_t num_samples;
|
||||
int32_t skip_samples;
|
||||
int32_t loop_start_sample;
|
||||
int32_t loop_end_sample;
|
||||
} xma_sample_data;
|
||||
|
||||
static int parse_header(xma_header_data * xma, STREAMFILE *streamFile);
|
||||
static void fix_samples(xma_header_data * xma, STREAMFILE *streamFile);
|
||||
static void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile);
|
||||
static uint32_t read_bitsBE_b(off_t bit_offset, int num_bits, STREAMFILE *streamFile);
|
||||
static int create_riff_header(uint8_t * buf, size_t buf_size, xma_header_data * xma, STREAMFILE *streamFile);
|
||||
static int fmt_chunk_swap_endian(uint8_t * chunk, uint16_t codec);
|
||||
|
||||
/**
|
||||
* XMA 1/2 (Microsoft)
|
||||
@ -361,212 +335,6 @@ static void fix_samples(xma_header_data * xma, STREAMFILE *streamFile) {
|
||||
/* XMA2 loop/num_samples don't seem to skip_samples */
|
||||
}
|
||||
|
||||
#define XMA_CHECK_SKIPS 0
|
||||
/**
|
||||
* Find total and loop samples by reading XMA frame headers.
|
||||
*
|
||||
* A XMA stream is made of packets, each containing N small frames of X samples.
|
||||
* Frames are further divided into subframes for looping purposes.
|
||||
* XMA1 and XMA2 only differ in the packet headers.
|
||||
*/
|
||||
static void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
|
||||
int frames = 0, samples = 0, loop_start_frame = 0, loop_end_frame = 0, skip_packets;
|
||||
#if XMA_CHECK_SKIPS
|
||||
int start_skip = 0, end_skip = 0, first_start_skip = 0, last_end_skip = 0;
|
||||
#endif
|
||||
uint32_t first_frame_b, packet_skip_count = 0, frame_size_b, packet_size_b;
|
||||
uint64_t offset_b, packet_offset_b, frame_offset_b;
|
||||
size_t size;
|
||||
|
||||
uint32_t packet_size = XMA_BYTES_PER_PACKET;
|
||||
off_t offset = xma->data_offset;
|
||||
uint32_t stream_offset_b = xma->data_offset * 8;
|
||||
|
||||
size = offset + xma->data_size;
|
||||
packet_size_b = packet_size * 8;
|
||||
|
||||
/* if we knew the streams mode then we could read just the first one and adjust samples later
|
||||
* not a big deal but maybe important for skip stuff */
|
||||
//streams = (xma->stream_mode==0 ? (xma->channels + 1) / 2 : xma->channels)
|
||||
skip_packets = 0;
|
||||
|
||||
/* read packets */
|
||||
while (offset < size) {
|
||||
offset_b = offset * 8; /* global offset in bits */
|
||||
offset += packet_size; /* global offset in bytes */
|
||||
|
||||
/* skip packets not owned by the first stream, since we only need samples from it */
|
||||
if (skip_packets && packet_skip_count) {
|
||||
packet_skip_count--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* XMA1 or XMA2 packet header */
|
||||
if (xma->xma_version == 1) {
|
||||
//packet_sequence = read_bitsBE_b(offset_b+0, 4, streamFile); /* numbered from 0 to N */
|
||||
//unknown = read_bitsBE_b(offset_b+4, 2, streamFile); /* packet_metadata? (always 2) */
|
||||
first_frame_b = read_bitsBE_b(offset_b+6, 15, streamFile); /* offset in bits inside the packet */
|
||||
packet_skip_count = read_bitsBE_b(offset_b+21, 11, streamFile); /* packets to skip for next packet of this stream */
|
||||
} else {
|
||||
//frame_count = read_bitsBE_b(offset_b+0, 6, streamFile); /* frames that begin in this packet */
|
||||
first_frame_b = read_bitsBE_b(offset_b+6, 15, streamFile); /* offset in bits inside this packet */
|
||||
//packet_metadata = read_bitsBE_b(offset_b+21, 3, streamFile); /* packet_metadata (always 1) */
|
||||
packet_skip_count = read_bitsBE_b(offset_b+24, 8, streamFile); /* packets to skip for next packet of this stream */
|
||||
}
|
||||
|
||||
/* full packet skip */
|
||||
if (packet_skip_count == 0x7FF) {
|
||||
packet_skip_count = 0;
|
||||
continue;
|
||||
}
|
||||
if (packet_skip_count > 255) { /* seen in some (converted?) XMA1 */
|
||||
packet_skip_count = 0;
|
||||
}
|
||||
VGM_ASSERT(packet_skip_count > 10, "XMA: found big packet skip %i\n", packet_skip_count);//a bit unusual...
|
||||
//VGM_LOG("packet: off=%x, ff=%i, ps=%i\n", offset, first_frame_b, packet_skip_b);
|
||||
|
||||
packet_offset_b = 4*8 + first_frame_b; /* packet offset in bits */
|
||||
|
||||
/* read packet frames */
|
||||
while (packet_offset_b < packet_size_b) {
|
||||
frame_offset_b = offset_b + packet_offset_b; /* in bits for aligment stuff */
|
||||
|
||||
//todo not sure if frames or frames+1 (considering skip_samples)
|
||||
if (xma->loop_flag && (offset_b + packet_offset_b) - stream_offset_b == xma->loop_start_b)
|
||||
loop_start_frame = frames;
|
||||
if (xma->loop_flag && (offset_b + packet_offset_b) - stream_offset_b == xma->loop_end_b)
|
||||
loop_end_frame = frames;
|
||||
|
||||
/* XMA1/2 frame header */
|
||||
frame_size_b = read_bitsBE_b(frame_offset_b, 15, streamFile);
|
||||
frame_offset_b += 15;
|
||||
if (frame_size_b == 0) /* observed in some files with empty frames/packets */
|
||||
break;
|
||||
packet_offset_b += frame_size_b; /* including header */
|
||||
|
||||
#if 0
|
||||
{
|
||||
uint32_t frame_config
|
||||
frame_config = read_bitsBE_b(frame_offset_b, 15, streamFile);
|
||||
|
||||
//VGM_LOG(" frame %04i: off_b=%I64x (~0x%I64x), fs_b=%i (~0x%x), fs=%x\n",frames, frame_offset_b, frame_offset_b/8, frame_size_b,frame_size_b/8, frame_config);
|
||||
|
||||
//if (frame_config != 0x7f00) /* "contains all subframes"? */
|
||||
// continue; // todo read packet end bit instead
|
||||
}
|
||||
#endif
|
||||
frame_offset_b += 15;
|
||||
|
||||
if (frame_size_b == 0x7FFF) { /* end packet frame marker */
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// more header stuff (info from FFmpeg)
|
||||
{
|
||||
int flag;
|
||||
|
||||
/* ignore "postproc transform" */
|
||||
if (xma->channels > 1) {
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
frame_offset_b += 1;
|
||||
if (flag) {
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
frame_offset_b += 1;
|
||||
if (flag) {
|
||||
frame_offset_b += 1 + 4 * xma->channels*xma->channels; /* 4-something per double channel? */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* get start/end skips to get the proper number of samples */ //todo check if first bit =1 means full 512 skip
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
frame_offset_b += 1;
|
||||
if (flag) {
|
||||
int new_skip;
|
||||
|
||||
/* get start skip */
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
frame_offset_b += 1;
|
||||
if (flag) {
|
||||
new_skip = read_bitsBE_b(frame_offset_b, 10, streamFile);
|
||||
frame_offset_b += 10;
|
||||
VGM_ASSERT(start_skip, "XMA: more than one start_skip (%i)\n", new_skip);
|
||||
|
||||
if (new_skip > XMA_SAMPLES_PER_FRAME) { /* from xmaencode */
|
||||
VGM_LOG("XMA: bad start_skip (%i)\n", new_skip);
|
||||
new_skip = XMA_SAMPLES_PER_FRAME;
|
||||
}
|
||||
|
||||
if (frames==0) first_start_skip = new_skip; /* sometimes in the middle */
|
||||
start_skip += new_skip;
|
||||
}
|
||||
|
||||
/* get end skip */
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
frame_offset_b += 1;
|
||||
if (flag) {
|
||||
new_skip = read_bitsBE_b(frame_offset_b, 10, streamFile);
|
||||
frame_offset_b += 10;
|
||||
VGM_ASSERT(end_skip, "XMA: more than one end_skip (%i)\n", new_skip);
|
||||
|
||||
if (new_skip > XMA_SAMPLES_PER_FRAME) { /* from xmaencode */
|
||||
VGM_LOG("XMA: bad end_skip (%i)\n", new_skip);
|
||||
new_skip = XMA_SAMPLES_PER_FRAME;
|
||||
}
|
||||
|
||||
last_end_skip = new_skip; /* not seen */
|
||||
end_skip += new_skip;
|
||||
}
|
||||
|
||||
VGM_LOG(" skip: st=%i, ed=%i\n", start_skip, end_skip);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
samples += XMA_SAMPLES_PER_FRAME;
|
||||
frames++;
|
||||
}
|
||||
}
|
||||
|
||||
#if XMA_CHECK_SKIPS
|
||||
//todo this seems to usually work, but not always
|
||||
/* apply skips (not sure why 64, empty samples generated by the decoder not in the file?) */
|
||||
samples = samples + 64 - start_skip;
|
||||
samples = samples + 64 - end_skip;
|
||||
|
||||
xma->skip_samples = 64 + 512; //todo not always correct
|
||||
#endif
|
||||
|
||||
xma->num_samples = samples;
|
||||
|
||||
if (xma->loop_flag) {
|
||||
xma->loop_start_sample = loop_start_frame * XMA_SAMPLES_PER_FRAME + xma->loop_start_subframe * XMA_SAMPLES_PER_SUBFRAME;
|
||||
xma->loop_end_sample = loop_end_frame * XMA_SAMPLES_PER_FRAME + xma->loop_start_subframe * XMA_SAMPLES_PER_SUBFRAME;
|
||||
VGM_LOG("ls=%i, le=%i, %i, %i", loop_start_frame, loop_end_frame, xma->loop_start_subframe, xma->loop_start_subframe);
|
||||
#if XMA_CHECK_SKIPS
|
||||
/* maybe this is needed */
|
||||
//xma->loop_start_sample -= xma->skip_samples;
|
||||
//xma->loop_end_sample -= xma->skip_samples;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read num_bits (up to 25) from a bit offset.
|
||||
* 25 since we read a 32 bit int, and need to adjust up to 7 bits from the byte-rounded fseek (32-7=25)
|
||||
*/
|
||||
static uint32_t read_bitsBE_b(off_t bit_offset, int num_bits, STREAMFILE *streamFile) {
|
||||
uint32_t num, mask;
|
||||
if (num_bits > 25) return -1; //???
|
||||
|
||||
num = read_32bitBE(bit_offset / 8, streamFile); /* fseek rounded to 8 */
|
||||
num = num << (bit_offset % 8); /* offset adjust (up to 7) */
|
||||
num = num >> (32 - num_bits);
|
||||
mask = 0xffffffff >> (32 - num_bits);
|
||||
|
||||
return num & mask;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@ -608,7 +376,7 @@ static int create_riff_header(uint8_t * buf, size_t buf_size, xma_header_data *
|
||||
internal_size = 4+4+xma->chunk_size;
|
||||
|
||||
if (xma->force_little_endian ) {
|
||||
if ( !fmt_chunk_swap_endian(chunk, xma->fmt_codec) )
|
||||
if ( !ffmpeg_fmt_chunk_swap_endian(chunk, xma->fmt_codec) )
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -636,41 +404,6 @@ fail:
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Swaps endianness
|
||||
*
|
||||
* returns 0 on error
|
||||
*/
|
||||
static int fmt_chunk_swap_endian(uint8_t * chunk, uint16_t codec) {
|
||||
if (codec != 0x166)
|
||||
goto fail;
|
||||
|
||||
put_16bitLE(chunk + 0x00, get_16bitBE(chunk + 0x00));/*wFormatTag*/
|
||||
put_16bitLE(chunk + 0x02, get_16bitBE(chunk + 0x02));/*nChannels*/
|
||||
put_32bitLE(chunk + 0x04, get_32bitBE(chunk + 0x04));/*nSamplesPerSec*/
|
||||
put_32bitLE(chunk + 0x08, get_32bitBE(chunk + 0x08));/*nAvgBytesPerSec*/
|
||||
put_16bitLE(chunk + 0x0c, get_16bitBE(chunk + 0x0c));/*nBlockAlign*/
|
||||
put_16bitLE(chunk + 0x0e, get_16bitBE(chunk + 0x0e));/*wBitsPerSample*/
|
||||
put_16bitLE(chunk + 0x10, get_16bitBE(chunk + 0x10));/*cbSize*/
|
||||
put_16bitLE(chunk + 0x12, get_16bitBE(chunk + 0x12));/*NumStreams*/
|
||||
put_32bitLE(chunk + 0x14, get_32bitBE(chunk + 0x14));/*ChannelMask*/
|
||||
put_32bitLE(chunk + 0x18, get_32bitBE(chunk + 0x18));/*SamplesEncoded*/
|
||||
put_32bitLE(chunk + 0x1c, get_32bitBE(chunk + 0x1c));/*BytesPerBlock*/
|
||||
put_32bitLE(chunk + 0x20, get_32bitBE(chunk + 0x20));/*PlayBegin*/
|
||||
put_32bitLE(chunk + 0x24, get_32bitBE(chunk + 0x24));/*PlayLength*/
|
||||
put_32bitLE(chunk + 0x28, get_32bitBE(chunk + 0x28));/*LoopBegin*/
|
||||
put_32bitLE(chunk + 0x2c, get_32bitBE(chunk + 0x2c));/*LoopLength*/
|
||||
/* put_8bit(chunk + 0x30, get_8bit(chunk + 0x30));*//*LoopCount*/
|
||||
/* put_8bit(chunk + 0x31, get_8bit(chunk + 0x31));*//*EncoderVersion*/
|
||||
put_16bitLE(chunk + 0x32, get_16bitBE(chunk + 0x32));/*BlockCount*/
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Get real XMA sample rate (from Microsoft docs).
|
||||
|
Loading…
x
Reference in New Issue
Block a user