1
0
Fork 0

Perform some minor house-keeping in the mp3 and seek handler

- Cleanup some types where precision is lost.
- Explicitly cast between types (fixes all effc++ warnings)
- Simplify lossy and cast-heavy floating-point coversions with ceil_divide
This commit is contained in:
krcroft 2020-03-03 14:29:15 -08:00 committed by Patryk Obara
parent fc9711c932
commit 9828f2d912
3 changed files with 54 additions and 40 deletions

View file

@ -24,8 +24,9 @@
#endif
#include <assert.h>
#include <SDL.h> // provides: SDL_malloc, SDL_realloc, SDL_free, SDL_memcpy, and SDL_memset
#include <support.h>
#define DR_MP3_IMPLEMENTATION
#define DR_MP3_NO_STDIO 1
#define DRMP3_FREE(p) SDL_free((p))
@ -108,31 +109,30 @@ static Uint32 MP3_read(Sound_Sample* const sample, void* buffer, Uint32 desired_
static_cast<drmp3_int16*>(buffer)));
} /* MP3_read */
static Sint32 MP3_open(Sound_Sample* const sample, const char* const ext)
static int32_t MP3_open(Sound_Sample* const sample, const char* const ext)
{
(void) ext; // deliberately unused
Sound_SampleInternal* const internal = static_cast<Sound_SampleInternal*>(sample->opaque);
Sint32 result(0); // assume failure until proven otherwise
bool result = false; // assume failure until proven otherwise
mp3_t* p_mp3 = (mp3_t*) SDL_calloc(1, sizeof (mp3_t));
if (p_mp3 != nullptr) {
if (p_mp3) {
p_mp3->p_dr = (drmp3*) SDL_calloc(1, sizeof (drmp3));
if (p_mp3->p_dr != nullptr) {
result = drmp3_init(p_mp3->p_dr, mp3_read, mp3_seek, sample, nullptr, nullptr);
if (result == DRMP3_TRUE) {
if (p_mp3->p_dr) {
if (drmp3_init(p_mp3->p_dr, mp3_read, mp3_seek, sample, nullptr, nullptr) == DRMP3_TRUE) {
SNDDBG(("MP3: Accepting data stream.\n"));
sample->flags = SOUND_SAMPLEFLAG_CANSEEK;
sample->actual.channels = p_mp3->p_dr->channels;
sample->actual.channels = static_cast<uint8_t>(p_mp3->p_dr->channels);
sample->actual.rate = p_mp3->p_dr->sampleRate;
sample->actual.format = AUDIO_S16SYS; // returns native byte-order based on architecture
const Uint64 num_frames = populate_seek_points(internal->rw, p_mp3, MP3_FAST_SEEK_FILENAME); // status will be 0 or pcm_frame_count
if (num_frames != 0) {
const unsigned int rate = p_mp3->p_dr->sampleRate;
internal->total_time = ( static_cast<Sint32>(num_frames) / rate) * 1000;
internal->total_time += (num_frames % rate) * 1000 / rate;
result = 1;
} else {
internal->total_time = -1;
}
sample->actual.format = AUDIO_S16SYS; // native byte-order based on architecture
// frame count is agnostic of sample size and number of channels
const uint64_t num_frames =
populate_seek_points(internal->rw, p_mp3, MP3_FAST_SEEK_FILENAME, result);
// total_time needs milliseconds
internal->total_time = (num_frames != 0) ?
static_cast<int32_t>(ceil_divide(num_frames * 1000u, sample->actual.rate))
: -1;
}
}
}
@ -141,11 +141,12 @@ static Sint32 MP3_open(Sound_Sample* const sample, const char* const ext)
internal->decoder_private = p_mp3;
// if anything went wrong then tear down our private structure
if (result == 0) {
if (!result) {
SNDDBG(("MP3: Failed to open the data stream.\n"));
MP3_close(sample);
}
return result;
return static_cast<int32_t>(result);
} /* MP3_open */
static Sint32 MP3_rewind(Sound_Sample* const sample)
@ -159,9 +160,9 @@ static Sint32 MP3_seek(Sound_Sample* const sample, const Uint32 ms)
{
Sound_SampleInternal* const internal = static_cast<Sound_SampleInternal*>(sample->opaque);
mp3_t* p_mp3 = static_cast<mp3_t*>(internal->decoder_private);
const float frames_per_ms = sample->actual.rate / 1000.0f;
const drmp3_uint64 frame_offset = static_cast<drmp3_uint64>(frames_per_ms) * ms;
const Sint32 result = drmp3_seek_to_pcm_frame(p_mp3->p_dr, frame_offset);
const uint64_t sample_rate = sample->actual.rate;
const drmp3_uint64 pcm_frame = ceil_divide(sample_rate * ms, 1000u);
const drmp3_bool32 result = drmp3_seek_to_pcm_frame(p_mp3->p_dr, pcm_frame);
return (result == DRMP3_TRUE);
} /* MP3_seek */

View file

@ -80,6 +80,7 @@
#include <map>
// Local headers
#include "support.h"
#include "xxhash.h"
// #include "../../../include/logging.h"
#include "mp3_seek_table.h"
@ -99,13 +100,13 @@ using std::ofstream;
// time point. The trade-off is as follows:
// - a large number means slower in-game seeking but a smaller fast-seek file.
// - a smaller numbers (below 10) results in fast seeks on slow hardware.
#define FRAMES_PER_SEEK_POINT 7
#define FRAMES_PER_SEEK_POINT 7u
// Returns the size of a file in bytes (if valid), otherwise 0
size_t get_file_size(const char* filename) {
uint64_t get_file_size(const char* filename) {
struct stat stat_buf;
int rc = stat(filename, &stat_buf);
return rc == 0 ? stat_buf.st_size : -1;
return rc == 0 ? static_cast<uint64_t>(stat_buf.st_size) : 0u;
}
@ -147,7 +148,7 @@ Uint64 calculate_stream_hash(struct SDL_RWops* const context) {
// have the same trailing 32KB of content. The different seeds will produce
// unique hashes.
XXH64_state_t* const state = XXH64_createState();
const Uint64 seed = stream_size;
const uint64_t seed = static_cast<uint64_t>(stream_size);
XXH64_reset(state, seed);
while (total_bytes_read < static_cast<size_t>(tail_size)) {
@ -186,9 +187,9 @@ Uint64 generate_new_seek_points(const char* filename,
drmp3_uint64 pcm_frame_count(0);
// Get the number of compressed MP3 frames and the number of uncompressed PCM frames.
drmp3_bool8 result = drmp3_get_mp3_and_pcm_frame_count(p_dr,
&mp3_frame_count,
&pcm_frame_count);
drmp3_bool32 result = drmp3_get_mp3_and_pcm_frame_count(p_dr,
&mp3_frame_count,
&pcm_frame_count);
if ( result != DRMP3_TRUE
|| mp3_frame_count < FRAMES_PER_SEEK_POINT
@ -202,11 +203,13 @@ Uint64 generate_new_seek_points(const char* filename,
// the decoded PCM times.
// We also take into account the desired number of "FRAMES_PER_SEEK_POINT",
// which is defined above.
drmp3_uint32 num_seek_points = static_cast<drmp3_uint32>(mp3_frame_count)/FRAMES_PER_SEEK_POINT + 1;
drmp3_uint32 num_seek_points = static_cast<drmp3_uint32>
(ceil_divide(mp3_frame_count, FRAMES_PER_SEEK_POINT));
seek_points_vector.resize(num_seek_points);
result = drmp3_calculate_seek_points(p_dr,
&num_seek_points,
reinterpret_cast<drmp3_seek_point*>(seek_points_vector.data()));
&num_seek_points,
reinterpret_cast<drmp3_seek_point*>(seek_points_vector.data()));
if (result != DRMP3_TRUE || num_seek_points == 0) {
// LOG_MSG("MP3: failed to calculate sufficient seek points for stream");
@ -300,7 +303,13 @@ Uint64 load_existing_seek_points(const char* filename,
// attempting to read it from the fast-seek file and (if it can't be read for any reason), it
// calculates new data. It makes use of the above two functions.
//
Uint64 populate_seek_points(struct SDL_RWops* const context, mp3_t* p_mp3, const char* seektable_filename) {
uint64_t populate_seek_points(struct SDL_RWops* const context,
mp3_t* p_mp3,
const char* seektable_filename,
bool &result) {
// assume failure until proven otherwise
result = false;
// Calculate the stream's xxHash value.
Uint64 stream_hash = calculate_stream_hash(context);
@ -334,12 +343,13 @@ Uint64 populate_seek_points(struct SDL_RWops* const context, mp3_t* p_mp3, const
// Finally, regardless of which scenario succeeded above, we now have our seek points!
// We bind our seek points to the dr_mp3 object which will be used for fast seeking.
drmp3_bool8 result = drmp3_bind_seek_table(p_mp3->p_dr,
p_mp3->seek_points_vector.size(),
reinterpret_cast<drmp3_seek_point*>(p_mp3->seek_points_vector.data()));
if (result != DRMP3_TRUE) {
// LOG_MSG("MP3: could not bind the seek points to the dr_mp3 object");
if(drmp3_bind_seek_table(p_mp3->p_dr,
static_cast<uint32_t>(p_mp3->seek_points_vector.size()),
reinterpret_cast<drmp3_seek_point*>(p_mp3->seek_points_vector.data()))
!= DRMP3_TRUE) {
return 0;
}
result = true;
return pcm_frame_count;
}

View file

@ -54,4 +54,7 @@ struct mp3_t {
std::vector<drmp3_seek_point_serial> seek_points_vector;
};
Uint64 populate_seek_points(struct SDL_RWops* const context, mp3_t* p_mp3, const char* seektable_filename);
uint64_t populate_seek_points(struct SDL_RWops* const context,
mp3_t* p_mp3,
const char* seektable_filename,
bool &result);