Skip to content

Commit c26594f

Browse files
authored
Improve performance and memory use on Windows
1 parent e0ef290 commit c26594f

3 files changed

Lines changed: 67 additions & 127 deletions

File tree

oswrapper_audio.h

Lines changed: 65 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,6 @@ OSWRAPPER_AUDIO_DEF size_t oswrapper_audio_get_samples(OSWrapper_audio_spec* aud
196196
#ifndef OSWRAPPER_AUDIO_MEMCPY
197197
#define OSWRAPPER_AUDIO_MEMCPY(x, y, amount) memcpy(x, y, amount)
198198
#endif /* OSWRAPPER_AUDIO_MEMCPY */
199-
#ifndef OSWRAPPER_AUDIO_MEMMOVE
200-
#define OSWRAPPER_AUDIO_MEMMOVE(x, y, amount) memmove(x, y, amount)
201-
#endif /* OSWRAPPER_AUDIO_MEMMOVE */
202199
#ifndef OSWRAPPER_AUDIO_MEMCMP
203200
#define OSWRAPPER_AUDIO_MEMCMP(ptr1, ptr2, amount) memcmp(ptr1, ptr2, amount)
204201
#endif /* OSWRAPPER_AUDIO_MEMCMP */
@@ -542,12 +539,6 @@ OSWRAPPER_AUDIO_DEF size_t oswrapper_audio_get_samples(OSWrapper_audio_spec* aud
542539
#define OSWRAPPER_AUDIO__MF_STARTUP_VAL MFSTARTUP_LITE
543540
#endif
544541

545-
#ifndef OSWRAPPER_AUDIO__DEFAULT_INTERNAL_BUFFER_SIZE
546-
/* TODO Not sure what a good size is for this.
547-
This is the largest value I've seen on my system so far. */
548-
#define OSWRAPPER_AUDIO__DEFAULT_INTERNAL_BUFFER_SIZE 0x84E0
549-
#endif
550-
551542
typedef struct oswrapper_audio__internal_data_win {
552543
IMFSourceReader* reader;
553544
IMFByteStream* byte_stream;
@@ -759,22 +750,16 @@ OSWRAPPER_AUDIO_DEF OSWRAPPER_AUDIO_RESULT_TYPE oswrapper_audio__load_from_reade
759750
oswrapper_audio__internal_data_win* internal_data = (oswrapper_audio__internal_data_win*) OSWRAPPER_AUDIO_MALLOC(sizeof(oswrapper_audio__internal_data_win));
760751

761752
if (internal_data != NULL) {
762-
short* initial_buffer = (short*) OSWRAPPER_AUDIO_MALLOC(OSWRAPPER_AUDIO__DEFAULT_INTERNAL_BUFFER_SIZE * sizeof(short));
763-
764-
if (initial_buffer != NULL) {
765-
audio->internal_data = (void*) internal_data;
766-
internal_data->reader = reader;
767-
internal_data->byte_stream = byte_stream;
768-
internal_data->memory_stream = memory_stream;
769-
internal_data->internal_buffer = initial_buffer;
770-
internal_data->internal_buffer_pos = 0;
771-
internal_data->internal_buffer_remaining = 0;
772-
internal_data->internal_buffer_size = OSWRAPPER_AUDIO__DEFAULT_INTERNAL_BUFFER_SIZE;
773-
internal_data->no_reader_error = OSWRAPPER_AUDIO_RESULT_SUCCESS;
774-
return OSWRAPPER_AUDIO_RESULT_SUCCESS;
775-
}
776-
777-
OSWRAPPER_AUDIO_FREE(internal_data);
753+
audio->internal_data = (void*) internal_data;
754+
internal_data->reader = reader;
755+
internal_data->byte_stream = byte_stream;
756+
internal_data->memory_stream = memory_stream;
757+
internal_data->internal_buffer = NULL;
758+
internal_data->internal_buffer_pos = 0;
759+
internal_data->internal_buffer_remaining = 0;
760+
internal_data->internal_buffer_size = 0;
761+
internal_data->no_reader_error = OSWRAPPER_AUDIO_RESULT_SUCCESS;
762+
return OSWRAPPER_AUDIO_RESULT_SUCCESS;
778763
}
779764
}
780765

@@ -903,20 +888,25 @@ OSWRAPPER_AUDIO_DEF void oswrapper_audio_rewind(OSWrapper_audio_spec* audio) {
903888
internal_data->internal_buffer_pos = 0;
904889
}
905890

906-
/* TODO This code isn't optimised. If you're brave enough, you can probably speed it up and save memory. */
907-
static void oswrapper_audio__get_new_samples(OSWrapper_audio_spec* audio, size_t frames_to_do) {
891+
OSWRAPPER_AUDIO_DEF size_t oswrapper_audio_get_samples(OSWrapper_audio_spec* audio, short* buffer, size_t frames_to_do) {
892+
size_t frame_size;
893+
size_t frames_done;
908894
oswrapper_audio__internal_data_win* internal_data = (oswrapper_audio__internal_data_win*) audio->internal_data;
909-
910-
/* Move any remaining samples to the start of the buffer, if they're not at the start of the buffer */
911-
if (internal_data->internal_buffer_remaining > 0 && (internal_data->internal_buffer_pos != 0)) {
912-
OSWRAPPER_AUDIO_MEMMOVE(internal_data->internal_buffer, internal_data->internal_buffer + internal_data->internal_buffer_pos, internal_data->internal_buffer_remaining * (sizeof internal_data->internal_buffer[0]));
895+
frame_size = (audio->bits_per_channel / 8) * audio->channel_count;
896+
frames_to_do = frames_to_do * frame_size / sizeof(short);
897+
frames_done = 0;
898+
899+
/* Copy any previous excess frames from the internal buffer */
900+
if (internal_data->internal_buffer_remaining > 0) {
901+
size_t copied_sample_data_size = internal_data->internal_buffer_remaining < frames_to_do ? internal_data->internal_buffer_remaining : frames_to_do;
902+
OSWRAPPER_AUDIO_MEMCPY(buffer, internal_data->internal_buffer + internal_data->internal_buffer_pos, copied_sample_data_size * (sizeof internal_data->internal_buffer[0]));
903+
internal_data->internal_buffer_remaining -= copied_sample_data_size;
904+
internal_data->internal_buffer_pos += copied_sample_data_size;
905+
frames_done = copied_sample_data_size;
913906
}
914907

915-
/* Reset the buffer position to 0 */
916-
internal_data->internal_buffer_pos = 0;
917-
918908
/* Get new samples */
919-
while (frames_to_do > internal_data->internal_buffer_remaining) {
909+
while (frames_to_do > frames_done) {
920910
size_t new_target_frames = 0;
921911

922912
/* Check if IMFSourceReader methods can still be called */
@@ -946,33 +936,49 @@ static void oswrapper_audio__get_new_samples(OSWrapper_audio_spec* audio, size_t
946936
if (SUCCEEDED(result)) {
947937
size_t new_target_size;
948938
new_target_frames = current_length / sizeof(short);
949-
new_target_size = internal_data->internal_buffer_remaining + new_target_frames;
950-
951-
if (new_target_size > internal_data->internal_buffer_size) {
952-
/* Try to allocate enough memory to store the sample + the buffered samples */
953-
short* realloc_buffer = (short*) OSWRAPPER_AUDIO_MALLOC(new_target_size * sizeof(short));
954-
955-
if (realloc_buffer == NULL) {
956-
/* Couldn't allocate any more memory, just work with what we have */
957-
new_target_frames = internal_data->internal_buffer_size - internal_data->internal_buffer_remaining;
958-
current_length = (DWORD) (new_target_frames / sizeof(short));
959-
frames_to_do = internal_data->internal_buffer_remaining + new_target_frames;
960-
} else {
961-
/* Copy contents of the old buffer to the new buffer */
962-
OSWRAPPER_AUDIO_MEMCPY(realloc_buffer, internal_data->internal_buffer, internal_data->internal_buffer_size);
963-
/* Free old buffer */
964-
OSWRAPPER_AUDIO_FREE(internal_data->internal_buffer);
965-
/* Replace old buffer with new buffer */
966-
internal_data->internal_buffer = realloc_buffer;
967-
internal_data->internal_buffer_size = new_target_size;
939+
new_target_size = frames_done + new_target_frames;
940+
941+
/* If the size of the decoded sample would exceed the remaining buffer size,
942+
store the excess frames in the internal buffer */
943+
if (new_target_size > frames_to_do) {
944+
size_t remaining_sample_data_size = new_target_size - frames_to_do;
945+
/* Prevent copying more data to the output buffer than requested */
946+
new_target_frames -= remaining_sample_data_size;
947+
current_length = (DWORD) new_target_frames * sizeof(short);
948+
949+
/* Is the internal buffer large enough to store the excess frames? */
950+
if (internal_data->internal_buffer_size < remaining_sample_data_size) {
951+
/* Try to allocate enough memory to store the excess frames */
952+
short* realloc_buffer = (short*) OSWRAPPER_AUDIO_MALLOC(remaining_sample_data_size * sizeof(short));
953+
954+
if (realloc_buffer != NULL) {
955+
/* Free old buffer */
956+
OSWRAPPER_AUDIO_FREE(internal_data->internal_buffer);
957+
/* Replace old buffer with new buffer */
958+
internal_data->internal_buffer = realloc_buffer;
959+
internal_data->internal_buffer_size = remaining_sample_data_size;
960+
} else {
961+
/* If we can't allocate more memory, some excess frames will be lost.
962+
This is unlikely, and mostly harmless. */
963+
remaining_sample_data_size = internal_data->internal_buffer_size;
964+
}
965+
}
966+
967+
/* Copy as many excess frames as we have space for */
968+
internal_data->internal_buffer_remaining = remaining_sample_data_size;
969+
internal_data->internal_buffer_pos = 0;
970+
971+
if (remaining_sample_data_size > 0) {
972+
OSWRAPPER_AUDIO_MEMCPY((BYTE*)(internal_data->internal_buffer), sample_audio_data + current_length, remaining_sample_data_size * sizeof(short));
968973
}
969974
}
970975

976+
/* Copy decoded sample data to buffer, minus excess frames */
971977
if (new_target_frames > 0) {
972-
OSWRAPPER_AUDIO_MEMCPY((BYTE*)(internal_data->internal_buffer + internal_data->internal_buffer_remaining), sample_audio_data, current_length);
978+
OSWRAPPER_AUDIO_MEMCPY((BYTE*)(buffer + frames_done), sample_audio_data, current_length);
973979
}
974980

975-
result = IMFMediaBuffer_Unlock(media_buffer);
981+
/* result = */ IMFMediaBuffer_Unlock(media_buffer);
976982
/* TODO I'm not sure there's any way to handle this?
977983
if (FAILED(result)) {
978984
...some code?
@@ -992,35 +998,13 @@ static void oswrapper_audio__get_new_samples(OSWrapper_audio_spec* audio, size_t
992998

993999
if (new_target_frames == 0) {
9941000
/* Break the loop */
995-
frames_to_do = internal_data->internal_buffer_remaining;
1001+
break;
9961002
} else {
997-
internal_data->internal_buffer_remaining += new_target_frames;
1003+
frames_done += new_target_frames;
9981004
}
9991005
}
1000-
}
1001-
1002-
OSWRAPPER_AUDIO_DEF size_t oswrapper_audio_get_samples(OSWrapper_audio_spec* audio, short* buffer, size_t frames_to_do) {
1003-
size_t frame_size;
1004-
oswrapper_audio__internal_data_win* internal_data = (oswrapper_audio__internal_data_win*) audio->internal_data;
1005-
frame_size = (audio->bits_per_channel / 8) * audio->channel_count;
1006-
1007-
/* We have to buffer decoding ourselves due to API quirks */
1008-
if (internal_data->internal_buffer_remaining < (frames_to_do * frame_size / sizeof(short))) {
1009-
oswrapper_audio__get_new_samples(audio, frames_to_do * frame_size / sizeof(short));
1010-
}
1011-
1012-
if (internal_data->internal_buffer_remaining < (frames_to_do * frame_size / sizeof(short))) {
1013-
frames_to_do = internal_data->internal_buffer_remaining * sizeof(short) / frame_size;
1014-
}
1015-
1016-
if (frames_to_do == 0) {
1017-
return 0;
1018-
}
10191006

1020-
OSWRAPPER_AUDIO_MEMCPY(buffer, internal_data->internal_buffer + internal_data->internal_buffer_pos, frames_to_do * frame_size);
1021-
internal_data->internal_buffer_pos += (frames_to_do * frame_size / sizeof(short));
1022-
internal_data->internal_buffer_remaining -= (frames_to_do * frame_size / sizeof(short));
1023-
return frames_to_do;
1007+
return frames_done * sizeof(short) / frame_size;
10241008
}
10251009
/* End Win32 MF implementation */
10261010
#else

test/demo_oswrapper_audio_sokol_audio_no_crt.c

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@ __forceinline int FloatToInt(float f) {
3030
#define OSWRAPPER_AUDIO_MALLOC(x) HeapAlloc(GetProcessHeap(), 0, x)
3131
#define OSWRAPPER_AUDIO_FREE(x) HeapFree(GetProcessHeap(), 0, x)
3232
/* These are just macros for the C functions, so we have to implement our own versions :/
33-
#define OSWRAPPER_AUDIO_MEMCPY(x, y, amount) CopyMemory(x, y, amount)
34-
#define OSWRAPPER_AUDIO_MEMMOVE(x, y, amount) MoveMemory(x, y, amount)*/
33+
#define OSWRAPPER_AUDIO_MEMCPY(x, y, amount) CopyMemory(x, y, amount)*/
3534
#include <stddef.h>
3635

3736
/* Forward memcpy. Not optimised. */
@@ -46,28 +45,7 @@ static void* bad_memcpy(void* destination, const void* source, size_t num) {
4645

4746
return destination;
4847
}
49-
50-
/* Not optimised. */
51-
static void* bad_memmove(void* destination, const void* source, size_t num) {
52-
unsigned char* dest_cast = (unsigned char*) destination;
53-
unsigned char* source_cast = (unsigned char*) source;
54-
55-
if (dest_cast < source_cast) {
56-
/* Forward copy */
57-
return bad_memcpy(destination, source, num);
58-
} else {
59-
/* Backward copy */
60-
size_t i = num;
61-
62-
while (i--) {
63-
dest_cast[i] = source_cast[i];
64-
}
65-
66-
return destination;
67-
}
68-
}
6948
#define OSWRAPPER_AUDIO_MEMCPY(x, y, amount) bad_memcpy(x, y, amount)
70-
#define OSWRAPPER_AUDIO_MEMMOVE(x, y, amount) bad_memmove(x, y, amount)
7149
static int impl_memcmp(const void* ptr1, const void* ptr2, size_t amount) {
7250
const unsigned char* cast_1 = (const unsigned char*) ptr1;
7351
const unsigned char* cast_2 = (const unsigned char*) ptr2;

test/test_oswrapper_audio_no_crt.c

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ The latest version of this file can be found at
1818
#define OSWRAPPER_AUDIO_MALLOC(x) HeapAlloc(GetProcessHeap(), 0, x)
1919
#define OSWRAPPER_AUDIO_FREE(x) HeapFree(GetProcessHeap(), 0, x)
2020
/* These are just macros for the C functions, so we have to implement our own versions :/
21-
#define OSWRAPPER_AUDIO_MEMCPY(x, y, amount) CopyMemory(x, y, amount)
22-
#define OSWRAPPER_AUDIO_MEMMOVE(x, y, amount) MoveMemory(x, y, amount)*/
21+
#define OSWRAPPER_AUDIO_MEMCPY(x, y, amount) CopyMemory(x, y, amount)*/
2322
#include <stddef.h>
2423

2524
/* Forward memcpy. Not optimised. */
@@ -34,28 +33,7 @@ static void* bad_memcpy(void* destination, const void* source, size_t num) {
3433

3534
return destination;
3635
}
37-
38-
/* Not optimised. */
39-
static void* bad_memmove(void* destination, const void* source, size_t num) {
40-
unsigned char* dest_cast = (unsigned char*) destination;
41-
unsigned char* source_cast = (unsigned char*) source;
42-
43-
if (dest_cast < source_cast) {
44-
/* Forward copy */
45-
return bad_memcpy(destination, source, num);
46-
} else {
47-
/* Backward copy */
48-
size_t i = num;
49-
50-
while (i--) {
51-
dest_cast[i] = source_cast[i];
52-
}
53-
54-
return destination;
55-
}
56-
}
5736
#define OSWRAPPER_AUDIO_MEMCPY(x, y, amount) bad_memcpy(x, y, amount)
58-
#define OSWRAPPER_AUDIO_MEMMOVE(x, y, amount) bad_memmove(x, y, amount)
5937
static int impl_memcmp(const void* ptr1, const void* ptr2, size_t amount) {
6038
const unsigned char* cast_1 = (const unsigned char*) ptr1;
6139
const unsigned char* cast_2 = (const unsigned char*) ptr2;

0 commit comments

Comments
 (0)