History

player: add threaded decoder WIP

lieff committed 8 years ago

Commit 29f6dca1 parent f3efc076 files · +717 −2Browse files

Unified · Split

6 files
  1. player/build.sh +1 −1
  2. player/decode.c +122 −0
  3. player/decode.h +14 −0
  4. player/player.cpp +0 −1
  5. player/system.cpp +473 −0
  6. player/system.h +107 −0
player/build.sh+1−1
@@ -1 +1 @@
1gcc -O2 -o player player.cpp glad.c -lstdc++ -lglfw -lGL -lm -ldl1gcc -O2 -o player *.cpp *.c -lstdc++ -lglfw -lGL -lpthread -lm -ldl
player/decode.c+122−0
@@ -0,0 +1,122 @@
1#include <string.h>
2#include <errno.h>
3#include <sys/mman.h>
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <unistd.h>
7#include <fcntl.h>
8#include <stdlib.h>
9#define MINIMP3_IMPLEMENTATION
10#include "../minimp3.h"
11#include "decode.h"
12
13static void add_audio(decoder *dec, short *buf, int bytes)
14{
15 char *buf_new = 0;
16 if (dec->mp3_allocated < (dec->mp3_size + bytes))
17 {
18 int allocated = dec->mp3_allocated;
19 dec->mp3_allocated = dec->mp3_allocated ? dec->mp3_allocated*2 : 4*1024*1024;
20 buf_new = (char *)malloc(dec->mp3_allocated);
21 memcpy(buf_new, dec->mp3_buf, allocated);
22 }
23 EnterCriticalSection(&dec->mp3_lock);
24 if (buf_new)
25 {
26 if (dec->mp3_buf)
27 free(dec->mp3_buf);
28 dec->mp3_buf = (short *)buf_new;
29 dec->mp3_size += bytes;
30 }
31 LeaveCriticalSection(&dec->mp3_lock);
32}
33
34static void *load_mp3_thread(void *lpThreadParameter)
35{
36 static mp3dec_t mp3d;
37 mp3dec_frame_info_t info = { 0, };
38 struct stat st;
39 decoder *dec = (decoder *)lpThreadParameter;
40 unsigned char *inputBuffer, *buf_mp3;
41 int file, mp3_size, samples;
42retry_open:
43 file = open(dec->file_name, O_RDONLY);
44 if (file < 0 && (errno == EAGAIN || errno == EINTR))
45 goto retry_open;
46 free((void*)dec->file_name);
47 dec->file_name = 0;
48 if (file < 0 || fstat(file, &st) < 0)
49 return (void*)(size_t)errno;
50
51 dec->mp3_file_size = st.st_size;
52retry_mmap:
53 inputBuffer = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE | MAP_POPULATE, file, 0);
54 if (MAP_FAILED == inputBuffer && (errno == EAGAIN || errno == EINTR))
55 goto retry_mmap;
56 if (MAP_FAILED == inputBuffer)
57 {
58 close(file);
59 return (void*)(size_t)errno;
60 }
61 buf_mp3 = inputBuffer;
62 mp3_size = dec->mp3_file_size;
63 mp3dec_init(&mp3d);
64 do
65 {
66 short pcm[MINIMP3_MAX_SAMPLES_PER_FRAME];
67 samples = mp3dec_decode_frame(&mp3d, buf_mp3, mp3_size, pcm, &info);
68 if (samples)
69 {
70 add_audio(dec, pcm, samples*2*info.channels);
71 if (!dec->mp3_rate)
72 dec->mp3_rate = info.hz;
73 if (!dec->mp3_channels)
74 dec->mp3_channels = info.channels;
75 if (dec->mp3_rate != info.hz || dec->mp3_channels != info.channels)
76 break;
77 }
78 buf_mp3 += info.frame_bytes;
79 mp3_size -= info.frame_bytes;
80 } while (info.frame_bytes);
81
82 munmap(inputBuffer, st.st_size);
83 close(file);
84 return 0;
85}
86
87int preload_mp3(decoder *dec, const char *file_name)
88{
89 if (dec->mp3_open_thread)
90 {
91 thread_wait(dec->mp3_open_thread);
92 thread_close(dec->mp3_open_thread);
93 dec->mp3_open_thread = 0;
94 }
95 EnterCriticalSection(&dec->mp3_lock);
96 if (dec->mp3_buf)
97 {
98 free(dec->mp3_buf);
99 dec->mp3_buf = 0;
100 dec->mp3_size = 0;
101 dec->mp3_allocated = 0;
102 dec->mp3_rate = 0;
103 dec->mp3_channels = 0;
104 dec->mp3_duration = 0;
105 }
106 LeaveCriticalSection(&dec->mp3_lock);
107
108 if (!file_name || !*file_name)
109 return 0;
110
111 dec->file_name = strdup(file_name);
112 if (!dec->file_name)
113 return 0;
114 dec->mp3_open_thread = thread_create(load_mp3_thread, dec);
115 if (!dec->mp3_open_thread)
116 {
117 free((void*)dec->file_name);
118 dec->file_name = 0;
119 return 0;
120 }
121 return 1;
122}
player/decode.h+14−0
@@ -0,0 +1,14 @@
1#pragma once
2#include "system.h"
3
4typedef struct decoder
5{
6 CRITICAL_SECTION mp3_lock;
7 const char *file_name;
8 short *mp3_buf;
9 int mp3_size, mp3_allocated, mp3_file_size, mp3_rate, mp3_channels;
10 float mp3_duration;
11 HANDLE mp3_open_thread;
12} decoder;
13
14int preload_mp3(decoder *dec, const char *file_name);
player/player.cpp+0−1
@@ -10,7 +10,6 @@ · 9 unmodified lines
10#include <OpenGL/gl3.h>10#include <OpenGL/gl3.h>
11#endif11#endif
12#include "FreeSans.h"12#include "FreeSans.h"
13#include "../minimp3.h"
14 13
15#define STB_IMAGE_IMPLEMENTATION14#define STB_IMAGE_IMPLEMENTATION
16#include "stb_image.h"15#include "stb_image.h"
player/system.cpp+473−0
@@ -0,0 +1,473 @@
1#include "system.h"
2
3#ifndef _WIN32
4
5#include <stdlib.h>
6#include <time.h>
7#include <errno.h>
8#include <unistd.h>
9#if defined(__linux) || defined(__linux__)
10#include <sys/prctl.h>
11#endif
12
13#define nullptr 0
14
15struct Event
16{
17 Event * volatile pMultipleCond;
18 pthread_mutex_t mutex;
19 pthread_cond_t cond;
20 volatile bool signaled;
21 bool manual_reset;
22};
23
24static bool InitEvent(Event *e)
25{
26#if (defined(ANDROID) && !defined(__LP64__)) || defined(__APPLE__)
27 if (pthread_cond_init(&e->cond, NULL))
28 return false;
29#else
30 pthread_condattr_t attr;
31 if (pthread_condattr_init(&attr))
32 return false;
33 if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC))
34 {
35 pthread_condattr_destroy(&attr);
36 return false;
37 }
38 if (pthread_cond_init(&e->cond, &attr))
39 {
40 pthread_condattr_destroy(&attr);
41 return false;
42 }
43 pthread_condattr_destroy(&attr);
44#endif
45 if (pthread_mutex_init(&e->mutex, NULL))
46 {
47 pthread_cond_destroy(&e->cond);
48 return false;
49 }
50 e->pMultipleCond = NULL;
51 return true;
52}
53
54#ifdef __APPLE__
55#include <mach/mach_time.h>
56static inline uint64_t GetAbsTimeInNanoseconds()
57{
58 static mach_timebase_info_data_t g_timebase_info;
59 if (g_timebase_info.denom == 0)
60 mach_timebase_info(&g_timebase_info);
61 return mach_absolute_time()*g_timebase_info.numer/g_timebase_info.denom;
62}
63#endif
64
65static inline void GetAbsTime(timespec *ts, uint32_t timeout)
66{
67#if defined(__APPLE__)
68 uint64_t cur_time = GetAbsTimeInNanoseconds();
69 ts->tv_sec = cur_time/1000000000u + timeout/1000u;
70 ts->tv_nsec = (cur_time % 1000000000u) + (timeout % 1000u)*1000000u;
71#else
72 clock_gettime(CLOCK_MONOTONIC, ts);
73 ts->tv_sec += timeout/1000u;
74 ts->tv_nsec += (timeout % 1000u)*1000000u;
75#endif
76 if (ts->tv_nsec >= 1000000000)
77 {
78 ts->tv_nsec -= 1000000000;
79 ts->tv_sec++;
80 }
81}
82
83static inline int CondTimedWait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
84{
85#if defined(ANDROID) && !defined(__LP64__)
86 return pthread_cond_timedwait_monotonic_np(cond, mutex, abstime);
87#elif defined(__APPLE__)
88 timespec reltime;
89 uint64_t cur_time = GetAbsTimeInNanoseconds();
90 reltime.tv_sec = abstime->tv_sec - cur_time/1000000000u;
91 reltime.tv_nsec = abstime->tv_nsec - (cur_time % 1000000000u);
92 if (reltime.tv_nsec < 0)
93 {
94 reltime.tv_nsec += 1000000000;
95 reltime.tv_sec--;
96 }
97 if ((reltime.tv_sec < 0) || ((reltime.tv_sec == 0) && (reltime.tv_nsec == 0)))
98 return ETIMEDOUT;
99 return pthread_cond_timedwait_relative_np(cond, mutex, &reltime);
100#else
101 return pthread_cond_timedwait(cond, mutex, abstime);
102#endif
103}
104
105static bool WaitForEvent(Event *e, uint32_t timeout, bool *signaled)
106{
107 if (pthread_mutex_lock(&e->mutex))
108 return false;
109
110 if (timeout == INFINITE)
111 {
112 while (!e->signaled)
113 pthread_cond_wait(&e->cond, &e->mutex);
114 } else if (timeout != 0)
115 {
116 timespec t;
117 GetAbsTime(&t, timeout);
118 while (!e->signaled)
119 {
120 if (CondTimedWait(&e->cond, &e->mutex, &t))
121 break;
122 }
123 }
124 *signaled = e->signaled;
125 if (!e->manual_reset)
126 e->signaled = false;
127
128 if (pthread_mutex_unlock(&e->mutex))
129 return false;
130 return true;
131}
132
133static bool WaitForMultipleEvents(Event **e, uint32_t count, uint32_t timeout, bool waitAll, int *signaled_num)
134{
135 uint32_t i;
136#define PTHR(func, num) for (i = num; i < count; i++)\
137 if (func(&e[i]->mutex))\
138 return false;
139 PTHR(pthread_mutex_lock, 0);
140
141 int sig_num = -1;
142 if (timeout == 0)
143 {
144#define CHECK_SIGNALED \
145 if (waitAll)\
146 {\
147 for (i = 0; i < count; i++)\
148 if (!e[i]->signaled)\
149 break;\
150 if (i == count)\
151 for (i = 0; i < count; i++)\
152 {\
153 if (sig_num < 0 && e[i]->signaled)\
154 sig_num = (int)i;\
155 if (!e[i]->manual_reset)\
156 e[i]->signaled = false;\
157 }\
158 } else\
159 {\
160 for (i = 0; i < count; i++)\
161 if (e[i]->signaled)\
162 {\
163 sig_num = (int)i;\
164 if (!e[i]->manual_reset)\
165 e[i]->signaled = false;\
166 break;\
167 }\
168 }
169 CHECK_SIGNALED;
170 } else
171 if (timeout == INFINITE)
172 {
173#define SET_MULTIPLE(val) for (i = 1; i < count; i++)\
174 e[i]->pMultipleCond = val;
175 SET_MULTIPLE(e[0]);
176 for (;;)
177 {
178 CHECK_SIGNALED;
179 if (sig_num >= 0)
180 break;
181 PTHR(pthread_mutex_unlock, 1);
182 pthread_cond_wait(&e[0]->cond, &e[0]->mutex);
183 PTHR(pthread_mutex_lock, 1);
184 }
185 SET_MULTIPLE(0);
186 } else
187 {
188 SET_MULTIPLE(e[0]);
189 timespec t;
190 GetAbsTime(&t, timeout);
191 for (;;)
192 {
193 CHECK_SIGNALED;
194 if (sig_num >= 0)
195 break;
196 PTHR(pthread_mutex_unlock, 1);
197 int res = CondTimedWait(&e[0]->cond, &e[0]->mutex, &t);
198 PTHR(pthread_mutex_lock, 1);
199 if (res)
200 break;
201 }
202 SET_MULTIPLE(0);
203 }
204 PTHR(pthread_mutex_unlock, 0);
205 *signaled_num = sig_num;
206 return true;
207}
208
209static bool SignalEvent(Event *e)
210{
211 if (pthread_mutex_lock(&e->mutex))
212 return false;
213
214 Event *pMultipleCond = e->pMultipleCond;
215 e->signaled = true;
216 if (pthread_cond_signal(&e->cond))
217 return false;
218
219 if (pthread_mutex_unlock(&e->mutex))
220 return false;
221
222 if (pMultipleCond && pMultipleCond != e)
223 {
224 if (pthread_mutex_lock(&pMultipleCond->mutex))
225 return false;
226 if (pthread_cond_signal(&pMultipleCond->cond))
227 return false;
228 if (pthread_mutex_unlock(&pMultipleCond->mutex))
229 return false;
230 }
231 return true;
232}
233
234static bool ResetEvent(Event *e)
235{
236 if (pthread_mutex_lock(&e->mutex))
237 return false;
238 e->signaled = false;
239 if (pthread_mutex_unlock(&e->mutex))
240 return false;
241 return true;
242}
243
244HANDLE event_create(bool manualReset, bool initialState)
245{
246 Event *e = (Event *)malloc(sizeof(*e));
247 if (!e)
248 return NULL;
249 if (!InitEvent(e))
250 {
251 free(e);
252 return NULL;
253 }
254 e->manual_reset = manualReset;
255 e->signaled = initialState;
256 return (HANDLE)e;
257}
258
259bool event_destroy(HANDLE event)
260{
261 Event *e = (Event *)event;
262 if (!e)
263 return false;
264 if (pthread_cond_destroy(&e->cond))
265 return false;
266 if (pthread_mutex_destroy(&e->mutex))
267 return false;
268 free((void *)e);
269 return true;
270}
271
272bool event_set(HANDLE event)
273{
274 return SignalEvent((Event *)event);
275}
276
277bool event_reset(HANDLE event)
278{
279 return ResetEvent((Event *)event);
280}
281
282int event_wait(HANDLE event, uint32_t milliseconds)
283{
284 bool signaled;
285 if (!WaitForEvent((Event *)event, milliseconds, &signaled))
286 return WAIT_FAILED;
287 return signaled ? WAIT_OBJECT : WAIT_TIMEOUT;
288}
289
290int event_wait_multiple(uint32_t count, const HANDLE *events, bool waitAll, uint32_t milliseconds)
291{
292 if (count == 1)
293 return event_wait(events[0], milliseconds);
294 int signaled_num = -1;
295 if (!WaitForMultipleEvents((Event **)events, count, milliseconds, waitAll, &signaled_num))
296 return WAIT_FAILED;
297 return (signaled_num < 0) ? WAIT_TIMEOUT : (WAIT_OBJECT_0 + signaled_num);
298}
299
300bool InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
301{
302 pthread_mutexattr_t ma;
303 if (pthread_mutexattr_init(&ma))
304 return false;
305 if (pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE))
306 {
307 pthread_mutexattr_destroy(&ma);
308 return false;
309 }
310 if (pthread_mutex_init((pthread_mutex_t *)lpCriticalSection, &ma))
311 {
312 pthread_mutexattr_destroy(&ma);
313 return false;
314 }
315 if (pthread_mutexattr_destroy(&ma))
316 return false;
317 return true;
318}
319
320bool DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
321{
322 if (pthread_mutex_destroy((pthread_mutex_t *)lpCriticalSection))
323 return false;
324 return true;
325}
326
327bool EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
328{
329 if (pthread_mutex_lock((pthread_mutex_t *)lpCriticalSection))
330 return false;
331 return true;
332}
333
334bool LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
335{
336 if (pthread_mutex_unlock((pthread_mutex_t *)lpCriticalSection))
337 return false;
338 return true;
339}
340
341HANDLE thread_create(LPTHREAD_START_ROUTINE lpStartAddress, void *lpParameter)
342{
343 pthread_t *t = (pthread_t *)malloc(sizeof(*t));
344 if (!t)
345 return nullptr;
346 if (pthread_create(t, 0, lpStartAddress, lpParameter))
347 {
348 free(t);
349 return nullptr;
350 }
351 //if (lpThreadId)
352 // *lpThreadId = (uint32_t)*t;
353 return (HANDLE)t;
354}
355
356bool thread_close(HANDLE thread)
357{
358 if (!thread)
359 return false;
360 pthread_t *t = (pthread_t *)thread;
361 if (*t)
362 pthread_detach(*t);
363 free(t);
364 return true;
365}
366
367void *thread_wait(HANDLE thread)
368{
369 if (!thread)
370 return (void*)-1;
371 void *ret = 0;
372 pthread_t *t = (pthread_t *)thread;
373 if (!*t)
374 return ret;
375 int res = pthread_join(*t, &ret);
376 if (res)
377 return (void*)-1;
378#if 0
379 if (timeout == 0)
380 {
381 int res = pthread_tryjoin_np(*t, &ret);
382 if (res)
383 return false;
384 } else
385 if (timeout == INFINITE)
386 {
387 int res = pthread_join(*t, &ret);
388 if (res)
389 return false;
390 } else
391 {
392 timespec ts;
393 GetAbsTime(&ts, timeout);
394 int res = pthread_timedjoin_np(*t, &ret, &ts);
395 if (res)
396 return false;
397 }
398#endif
399 *t = 0; // thread joined - no need to detach
400 return ret;
401}
402
403#else //_WIN32
404
405bool event_destroy(HANDLE event)
406{
407 CloseHandle(event);
408 return true;
409}
410
411bool thread_close(HANDLE thread)
412{
413 CloseHandle(thread);
414 return true;
415}
416
417bool thread_wait(HANDLE thread)
418{
419 return WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0;
420}
421
422#endif //_WIN32
423
424bool thread_name(const char *name)
425{
426#ifdef _WIN32
427 struct tagTHREADNAME_INFO
428 {
429 DWORD dwType;
430 LPCSTR szName;
431 DWORD dwThreadID;
432 DWORD dwFlags;
433 } info = { 0x1000, name, (DWORD)-1, 0 };
434 __try
435 {
436 RaiseException(0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
437 }
438 __except(EXCEPTION_EXECUTE_HANDLER)
439 {
440 }
441 return true;
442#elif defined(__linux) || defined(__linux__)
443 return (0 == prctl(PR_SET_NAME, name, 0, 0, 0));
444 //return (0 == pthread_setname_np(pthread_self(), name));
445#else // macos, ios
446 return (0 == pthread_setname_np(name));
447#endif
448}
449
450bool thread_sleep(uint32_t milliseconds)
451{
452#ifdef _WIN32
453 Sleep(milliseconds);
454#else
455 usleep((useconds_t)milliseconds*1000);
456#endif
457}
458
459uint64_t GetTime()
460{
461 uint64_t time;
462#ifdef _WIN32
463 QueryPerformanceCounter((LARGE_INTEGER*)&time);
464#elif defined(__APPLE__)
465 time = GetAbsTimeInNanoseconds() / 1000u;
466#else
467 timespec ts;
468 // CLOCK_PROCESS_CPUTIME_ID CLOCK_THREAD_CPUTIME_ID
469 clock_gettime(CLOCK_MONOTONIC, &ts);
470 time = (uint64_t)ts.tv_sec * 1000000u + ts.tv_nsec / 1000u;
471#endif
472 return time;
473}
player/system.h+107−0
@@ -0,0 +1,107 @@
1#pragma once
2#ifndef __LGE_SYSTEM_H__
3#define __LGE_SYSTEM_H__
4
5#ifdef _WIN32
6
7#include <windows.h>
8typedef DWORD THREAD_RET;
9#define THRAPI __stdcall
10#include <stdint.h>
11
12#else //_WIN32
13
14#include <stdint.h>
15#include <pthread.h>
16
17typedef void * THREAD_RET;
18typedef THREAD_RET (*PTHREAD_START_ROUTINE)(void *lpThreadParameter);
19typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE;
20
21typedef pthread_mutex_t CRITICAL_SECTION, *PCRITICAL_SECTION, *LPCRITICAL_SECTION;
22
23#define THRAPI
24
25#ifndef FALSE
26#define FALSE 0
27#endif
28
29#ifndef TRUE
30#define TRUE 1
31#endif
32
33typedef void * HANDLE;
34#define MAXIMUM_WAIT_OBJECTS 64
35#define INFINITE (-1)
36#define WAIT_FAILED (-1)
37#define WAIT_TIMEOUT 0x102
38#define WAIT_OBJECT 0
39#define WAIT_OBJECT_0 0
40#define WAIT_ABANDONED 128
41#define WAIT_ABANDONED_0 128
42
43#ifdef __cplusplus
44extern "C" {
45#else
46#ifndef bool
47#define bool int
48#endif
49#endif
50
51HANDLE event_create(bool manualReset
52#ifdef __cplusplus
53 = false
54#endif
55 , bool initialState
56#ifdef __cplusplus
57 = false
58#endif
59 );
60bool event_set(HANDLE event);
61bool event_reset(HANDLE event);
62int event_wait(HANDLE event, uint32_t milliseconds
63#ifdef __cplusplus
64 = INFINITE
65#endif
66 );
67int event_wait_multiple(uint32_t count, const HANDLE *events, bool waitAll
68#ifdef __cplusplus
69 = false
70#endif
71 , uint32_t milliseconds
72#ifdef __cplusplus
73 = INFINITE
74#endif
75 );
76
77bool InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
78bool DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
79bool EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
80bool LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
81
82HANDLE thread_create(LPTHREAD_START_ROUTINE lpStartAddress, void *lpParameter);
83
84#ifdef __cplusplus
85}
86#endif
87
88#endif //_WIN32
89
90#ifdef __cplusplus
91extern "C" {
92#endif
93
94bool event_destroy(HANDLE event);
95
96bool thread_close(HANDLE thread);
97void *thread_wait(HANDLE thread);
98bool thread_name(const char *name);
99bool thread_sleep(uint32_t milliseconds);
100
101uint64_t GetTime();
102
103#ifdef __cplusplus
104}
105#endif
106
107#endif //__LGE_SYSTEM_H__

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t