From c5b514b57764d685a0657e9c74d53b6babb05cf7 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 23 Sep 2018 12:17:23 +0200 Subject: [PATCH] Improve UE4OPUS encoder delay and fix get_opus_samples_per_frame --- src/coding/ffmpeg_decoder_custom_opus.c | 32 ++++++++++++++++++++----- src/meta/ue4opus.c | 10 +++++--- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/coding/ffmpeg_decoder_custom_opus.c b/src/coding/ffmpeg_decoder_custom_opus.c index b6f7cedb..0815ecfa 100644 --- a/src/coding/ffmpeg_decoder_custom_opus.c +++ b/src/coding/ffmpeg_decoder_custom_opus.c @@ -15,7 +15,7 @@ static size_t make_oggs_first(uint8_t * buf, int buf_size, int channels, int skip, int sample_rate); static size_t make_oggs_page(uint8_t * buf, int buf_size, size_t data_size, int page_sequence, int granule); -static uint32_t get_opus_samples_per_frame(const uint8_t * data, int Fs); +static size_t opus_get_packet_samples(const uint8_t * buf, int len); typedef enum { OPUS_SWITCH, OPUS_UE4 } opus_type_t; typedef struct { @@ -117,7 +117,7 @@ static size_t opus_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset, /* create fake OggS page (full page for checksums) */ read_streamfile(data->page_buffer+oggs_size, data->physical_offset + skip_size, data_size, streamfile); /* store page data */ - data->samples_done += get_opus_samples_per_frame(data->page_buffer+oggs_size, 48000); + data->samples_done += opus_get_packet_samples(data->page_buffer+oggs_size, data_size); make_oggs_page(data->page_buffer,sizeof(data->page_buffer), data_size, data->sequence, data->samples_done); data->sequence++; } @@ -288,8 +288,8 @@ static uint32_t get_oggs_checksum(uint8_t * data, int bytes) { return crc_reg; } -/* from opus_decoder.c */ -static uint32_t get_opus_samples_per_frame(const uint8_t * data, int Fs) { +/* from opus_decoder.c's opus_packet_get_samples_per_frame */ +static uint32_t opus_packet_get_samples_per_frame(const uint8_t * data, int Fs) { int audiosize; if (data[0]&0x80) { @@ -308,6 +308,22 @@ static uint32_t get_opus_samples_per_frame(const uint8_t * data, int Fs) { return audiosize; } +/* from opus_decoder.c's opus_packet_get_nb_frames */ +static int opus_packet_get_nb_frames(const uint8_t * packet, int len) { + int count; + if (len<1) + return 0; + count = packet[0]&0x3; + if (count==0) + return 1; + else if (count!=3) + return 2; + else if (len<2) + return 0; + else + return packet[1]&0x3F; +} + /* ******************************** */ static size_t make_oggs_page(uint8_t * buf, int buf_size, size_t data_size, int page_sequence, int granule) { @@ -440,6 +456,10 @@ fail: #ifdef VGM_USE_FFMPEG +static size_t opus_get_packet_samples(const uint8_t * buf, int len) { + return opus_packet_get_nb_frames(buf, len) * opus_packet_get_samples_per_frame(buf, 48000); +} + static size_t custom_opus_get_samples(off_t offset, size_t data_size, int sample_rate, STREAMFILE *streamFile, opus_type_t type) { size_t num_samples = 0; off_t end_offset = offset + data_size; @@ -467,8 +487,8 @@ static size_t custom_opus_get_samples(off_t offset, size_t data_size, int sample return 0; } - read_streamfile(buf, offset+skip_size, 0x04, streamFile); - num_samples += get_opus_samples_per_frame(buf, sample_rate); + read_streamfile(buf, offset+skip_size, 0x04, streamFile); /* at least 0x02 */ + num_samples += opus_get_packet_samples(buf, 0x04); offset += skip_size + data_size; } diff --git a/src/meta/ue4opus.c b/src/meta/ue4opus.c index aba2b15e..6e13f5a7 100644 --- a/src/meta/ue4opus.c +++ b/src/meta/ue4opus.c @@ -21,12 +21,16 @@ VGMSTREAM * init_vgmstream_ue4opus(STREAMFILE *streamFile) { sample_rate = (uint16_t)read_16bitLE(0x08, streamFile); - num_samples = read_32bitLE(0x0a, streamFile); + num_samples = read_32bitLE(0x0a, streamFile); /* may be less or equal to file num_samples */ channel_count = read_8bit(0x0e, streamFile); /* 0x0f(2): frame count */ - skip = 0; //todo test loop_flag = 0; + /* UE4Opus encodes 60ms (music) or 120ms (voice) frames, and encoder delay seems 1/8 + * of samples per frame (may be more complex but wave looks ok-ish) */ + //todo does UE4 actually care about encoder delay? + skip = (60 * 48000 / 1000) / 8; /* 48000 is the internal/resampled rate */ + start_offset = 0x11; data_size = get_streamfile_size(streamFile) - start_offset; @@ -37,7 +41,7 @@ VGMSTREAM * init_vgmstream_ue4opus(STREAMFILE *streamFile) { vgmstream->meta_type = meta_UE4OPUS; vgmstream->sample_rate = sample_rate; - vgmstream->num_samples = num_samples; + vgmstream->num_samples = num_samples - skip; #ifdef VGM_USE_FFMPEG {