Skip to content

Latest commit

 

History

History
999 lines (852 loc) · 31.6 KB

theoraplay.c

File metadata and controls

999 lines (852 loc) · 31.6 KB
 
Jun 10, 2011
Jun 10, 2011
1
2
3
4
5
6
7
8
/**
* TheoraPlay; multithreaded Ogg Theora/Ogg Vorbis decoding.
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
9
10
11
12
// I wrote this with a lot of peeking at the Theora example code in
// libtheora-1.1.1/examples/player_example.c, but this is all my own
// code.
Nov 29, 2022
Nov 29, 2022
13
14
// !!! FIXME: can we move this off malloc to a custom allocator?
15
16
17
18
19
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
Apr 23, 2013
Apr 23, 2013
20
21
22
23
#ifdef _WIN32
#include <windows.h>
#define THEORAPLAY_THREAD_T HANDLE
#define THEORAPLAY_MUTEX_T HANDLE
May 19, 2013
May 19, 2013
24
#define sleepms(x) Sleep(x)
Apr 23, 2013
Apr 23, 2013
25
26
#else
#include <pthread.h>
May 19, 2013
May 19, 2013
27
28
#include <unistd.h>
#define sleepms(x) usleep((x) * 1000)
Apr 23, 2013
Apr 23, 2013
29
30
31
32
#define THEORAPLAY_THREAD_T pthread_t
#define THEORAPLAY_MUTEX_T pthread_mutex_t
#endif
Jun 10, 2011
Jun 10, 2011
33
#include "theoraplay.h"
34
35
36
#include "theora/theoradec.h"
#include "vorbis/codec.h"
Jun 15, 2011
Jun 15, 2011
37
38
#define THEORAPLAY_INTERNAL 1
Jun 15, 2011
Jun 15, 2011
39
40
typedef THEORAPLAY_VideoFrame VideoFrame;
typedef THEORAPLAY_AudioPacket AudioPacket;
Jun 15, 2011
Jun 15, 2011
42
43
// !!! FIXME: these all count on the pixel format being TH_PF_420 for now.
Jun 15, 2011
Jun 15, 2011
44
45
46
typedef unsigned char *(*ConvertVideoFrameFn)(const th_info *tinfo,
const th_ycbcr_buffer ycbcr);
Jun 19, 2011
Jun 19, 2011
47
48
49
static unsigned char *ConvertVideoFrame420ToYUVPlanar(
const th_info *tinfo, const th_ycbcr_buffer ycbcr,
const int p0, const int p1, const int p2)
Jun 15, 2011
Jun 15, 2011
50
51
52
53
54
55
56
{
int i;
const int w = tinfo->pic_width;
const int h = tinfo->pic_height;
const int yoff = (tinfo->pic_x & ~1) + ycbcr[0].stride * (tinfo->pic_y & ~1);
const int uvoff = (tinfo->pic_x / 2) + (ycbcr[1].stride) * (tinfo->pic_y / 2);
unsigned char *yuv = (unsigned char *) malloc(w * h * 2);
Apr 29, 2018
Apr 29, 2018
57
58
59
60
61
62
63
const unsigned char *p0data = ycbcr[p0].data + yoff;
const int p0stride = ycbcr[p0].stride;
const unsigned char *p1data = ycbcr[p1].data + uvoff;
const int p1stride = ycbcr[p1].stride;
const unsigned char *p2data = ycbcr[p2].data + uvoff;
const int p2stride = ycbcr[p2].stride;
Jun 15, 2011
Jun 15, 2011
64
65
66
67
if (yuv)
{
unsigned char *dst = yuv;
for (i = 0; i < h; i++, dst += w)
Apr 29, 2018
Apr 29, 2018
68
memcpy(dst, p0data + (p0stride * i), w);
Jun 15, 2011
Jun 15, 2011
69
for (i = 0; i < (h / 2); i++, dst += w/2)
Apr 29, 2018
Apr 29, 2018
70
memcpy(dst, p1data + (p1stride * i), w / 2);
Jun 15, 2011
Jun 15, 2011
71
for (i = 0; i < (h / 2); i++, dst += w/2)
Apr 29, 2018
Apr 29, 2018
72
memcpy(dst, p2data + (p2stride * i), w / 2);
Jun 15, 2011
Jun 15, 2011
73
74
75
} // if
return yuv;
Jun 19, 2011
Jun 19, 2011
76
77
78
79
80
81
82
} // ConvertVideoFrame420ToYUVPlanar
static unsigned char *ConvertVideoFrame420ToYV12(const th_info *tinfo,
const th_ycbcr_buffer ycbcr)
{
return ConvertVideoFrame420ToYUVPlanar(tinfo, ycbcr, 0, 2, 1);
Jun 15, 2011
Jun 15, 2011
83
} // ConvertVideoFrame420ToYV12
Jun 15, 2011
Jun 15, 2011
84
85
Jun 19, 2011
Jun 19, 2011
86
87
88
89
90
91
92
static unsigned char *ConvertVideoFrame420ToIYUV(const th_info *tinfo,
const th_ycbcr_buffer ycbcr)
{
return ConvertVideoFrame420ToYUVPlanar(tinfo, ycbcr, 0, 1, 2);
} // ConvertVideoFrame420ToIYUV
Jun 15, 2011
Jun 15, 2011
93
94
95
96
97
98
// RGB
#define THEORAPLAY_CVT_FNNAME_420 ConvertVideoFrame420ToRGB
#define THEORAPLAY_CVT_RGB_ALPHA 0
#include "theoraplay_cvtrgb.h"
#undef THEORAPLAY_CVT_RGB_ALPHA
#undef THEORAPLAY_CVT_FNNAME_420
Jun 15, 2011
Jun 15, 2011
99
Jun 15, 2011
Jun 15, 2011
100
101
102
103
104
105
// RGBA
#define THEORAPLAY_CVT_FNNAME_420 ConvertVideoFrame420ToRGBA
#define THEORAPLAY_CVT_RGB_ALPHA 1
#include "theoraplay_cvtrgb.h"
#undef THEORAPLAY_CVT_RGB_ALPHA
#undef THEORAPLAY_CVT_FNNAME_420
Jun 15, 2011
Jun 15, 2011
106
107
Nov 29, 2022
Nov 29, 2022
108
// !!! FIXME: these volatiles really need to become atomics.
109
110
111
typedef struct TheoraDecoder
{
// Thread wrangling...
Jun 10, 2011
Jun 10, 2011
112
int thread_created;
Apr 23, 2013
Apr 23, 2013
113
THEORAPLAY_MUTEX_T lock;
114
volatile int halt;
Jun 10, 2011
Jun 10, 2011
115
int thread_done;
Apr 23, 2013
Apr 23, 2013
116
THEORAPLAY_THREAD_T worker;
117
118
// API state...
Jun 24, 2011
Jun 24, 2011
119
THEORAPLAY_Io *io;
120
unsigned int maxframes; // Max video frames to buffer.
Jun 24, 2011
Jun 24, 2011
121
122
123
124
125
126
volatile unsigned int prepped;
volatile unsigned int videocount; // currently buffered frames.
volatile unsigned int audioms; // currently buffered audio samples.
volatile int hasvideo;
volatile int hasaudio;
volatile int decode_error;
Nov 29, 2022
Nov 29, 2022
127
128
volatile unsigned int seek_generation;
volatile unsigned long new_seek_position_ms;
Jun 24, 2011
Jun 24, 2011
129
Jun 15, 2011
Jun 15, 2011
130
131
THEORAPLAY_VideoFormat vidfmt;
ConvertVideoFrameFn vidcvt;
Jun 15, 2011
Jun 15, 2011
133
134
VideoFrame *videolist;
VideoFrame *videolisttail;
Jun 15, 2011
Jun 15, 2011
136
137
AudioPacket *audiolist;
AudioPacket *audiolisttail;
138
139
140
} TheoraDecoder;
Apr 23, 2013
Apr 23, 2013
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#ifdef _WIN32
static inline int Thread_Create(TheoraDecoder *ctx, void *(*routine) (void*))
{
ctx->worker = CreateThread(
NULL,
0,
(LPTHREAD_START_ROUTINE) routine,
(LPVOID) ctx,
0,
NULL
);
return (ctx->worker == NULL);
}
static inline void Thread_Join(THEORAPLAY_THREAD_T thread)
{
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
}
static inline int Mutex_Create(TheoraDecoder *ctx)
{
ctx->lock = CreateMutex(NULL, FALSE, NULL);
return (ctx->lock == NULL);
}
static inline void Mutex_Destroy(THEORAPLAY_MUTEX_T mutex)
{
CloseHandle(mutex);
}
static inline void Mutex_Lock(THEORAPLAY_MUTEX_T mutex)
{
WaitForSingleObject(mutex, INFINITE);
}
static inline void Mutex_Unlock(THEORAPLAY_MUTEX_T mutex)
{
ReleaseMutex(mutex);
}
#else
static inline int Thread_Create(TheoraDecoder *ctx, void *(*routine) (void*))
{
return pthread_create(&ctx->worker, NULL, routine, ctx);
}
static inline void Thread_Join(THEORAPLAY_THREAD_T thread)
{
pthread_join(thread, NULL);
}
static inline int Mutex_Create(TheoraDecoder *ctx)
{
return pthread_mutex_init(&ctx->lock, NULL);
}
static inline void Mutex_Destroy(THEORAPLAY_MUTEX_T mutex)
{
pthread_mutex_destroy(&mutex);
}
static inline void Mutex_Lock(THEORAPLAY_MUTEX_T mutex)
{
pthread_mutex_lock(&mutex);
}
static inline void Mutex_Unlock(THEORAPLAY_MUTEX_T mutex)
{
pthread_mutex_unlock(&mutex);
}
#endif
Jun 23, 2011
Jun 23, 2011
204
static int FeedMoreOggData(THEORAPLAY_Io *io, ogg_sync_state *sync)
Jun 11, 2011
Jun 11, 2011
206
long buflen = 4096;
Jun 10, 2011
Jun 10, 2011
207
char *buffer = ogg_sync_buffer(sync, buflen);
208
if (buffer == NULL)
Jun 10, 2011
Jun 10, 2011
209
return -1;
Jun 23, 2011
Jun 23, 2011
211
buflen = io->read(io, buffer, buflen);
212
213
214
if (buflen <= 0)
return 0;
Jun 10, 2011
Jun 10, 2011
215
return (ogg_sync_wrote(sync, buflen) == 0) ? 1 : -1;
216
217
} // FeedMoreOggData
Jun 10, 2011
Jun 10, 2011
218
219
220
// This massive function is where all the effort happens.
static void WorkerThread(TheoraDecoder *ctx)
221
222
223
{
// make sure we initialized the stream before using pagein, but the stream
// will know to ignore pages that aren't meant for it, so pass to both.
Jun 10, 2011
Jun 10, 2011
224
225
226
227
#define queue_ogg_page(ctx) do { \
if (tpackets) ogg_stream_pagein(&tstream, &page); \
if (vpackets) ogg_stream_pagein(&vstream, &page); \
} while (0)
Nov 29, 2022
Nov 29, 2022
229
230
long streamlen = -1;
unsigned int current_seek_generation = 0;
231
double fps = 0.0;
Jun 10, 2011
Jun 10, 2011
232
233
int was_error = 1; // resets to 0 at the end.
int eos = 0; // end of stream flag.
Jun 10, 2011
Jun 10, 2011
235
236
237
238
239
// Too much Ogg/Vorbis/Theora state...
ogg_packet packet;
ogg_sync_state sync;
ogg_page page;
int vpackets = 0;
Nov 29, 2022
Nov 29, 2022
240
int vserialno = 0;
Jun 10, 2011
Jun 10, 2011
241
242
243
244
245
246
vorbis_info vinfo;
vorbis_comment vcomment;
ogg_stream_state vstream;
int vdsp_init = 0;
vorbis_dsp_state vdsp;
int tpackets = 0;
Nov 29, 2022
Nov 29, 2022
247
int tserialno = 0;
Jun 10, 2011
Jun 10, 2011
248
249
250
251
252
253
254
th_info tinfo;
th_comment tcomment;
ogg_stream_state tstream;
int vblock_init = 0;
vorbis_block vblock;
th_dec_ctx *tdec = NULL;
th_setup_info *tsetup = NULL;
Nov 29, 2022
Nov 29, 2022
255
256
257
258
259
ogg_int64_t granulepos = 0;
int resolving_audio_seek = 0;
int resolving_video_seek = 0;
int need_keyframe = 0;
unsigned long seek_target = 0;
Jun 10, 2011
Jun 10, 2011
260
261
262
263
264
265
ogg_sync_init(&sync);
vorbis_info_init(&vinfo);
vorbis_comment_init(&vcomment);
th_comment_init(&tcomment);
th_info_init(&tinfo);
266
267
268
269
int bos = 1;
while (!ctx->halt && bos)
{
Jun 23, 2011
Jun 23, 2011
270
if (FeedMoreOggData(ctx->io, &sync) <= 0)
Jun 10, 2011
Jun 10, 2011
271
goto cleanup;
272
273
// parse out the initial header.
Jun 10, 2011
Jun 10, 2011
274
while ( (!ctx->halt) && (ogg_sync_pageout(&sync, &page) > 0) )
275
276
{
ogg_stream_state test;
Nov 29, 2022
Nov 29, 2022
277
int serialno;
Jun 10, 2011
Jun 10, 2011
279
if (!ogg_page_bos(&page)) // not a header.
Jun 10, 2011
Jun 10, 2011
281
queue_ogg_page(ctx);
282
283
284
285
bos = 0;
break;
} // if
Nov 29, 2022
Nov 29, 2022
286
287
serialno = ogg_page_serialno(&page);
ogg_stream_init(&test, serialno);
Jun 10, 2011
Jun 10, 2011
288
ogg_stream_pagein(&test, &page);
289
290
ogg_stream_packetout(&test, &packet);
Jun 10, 2011
Jun 10, 2011
291
if (!tpackets && (th_decode_headerin(&tinfo, &tcomment, &tsetup, &packet) >= 0))
Jun 10, 2011
Jun 10, 2011
293
294
memcpy(&tstream, &test, sizeof (test));
tpackets = 1;
Nov 29, 2022
Nov 29, 2022
295
tserialno = serialno;
296
} // if
Jun 10, 2011
Jun 10, 2011
297
else if (!vpackets && (vorbis_synthesis_headerin(&vinfo, &vcomment, &packet) >= 0))
Jun 10, 2011
Jun 10, 2011
299
300
memcpy(&vstream, &test, sizeof (test));
vpackets = 1;
Nov 29, 2022
Nov 29, 2022
301
vserialno = serialno;
302
303
304
305
306
307
308
309
310
311
} // else if
else
{
// whatever it is, we don't care about it
ogg_stream_clear(&test);
} // else
} // while
} // while
// no audio OR video?
Jun 10, 2011
Jun 10, 2011
312
313
if (ctx->halt || (!vpackets && !tpackets))
goto cleanup;
314
315
// apparently there are two more theora and two more vorbis headers next.
Jun 10, 2011
Jun 10, 2011
316
while ((!ctx->halt) && ((tpackets && (tpackets < 3)) || (vpackets && (vpackets < 3))))
Jun 10, 2011
Jun 10, 2011
318
while (!ctx->halt && tpackets && (tpackets < 3))
Jun 10, 2011
Jun 10, 2011
320
if (ogg_stream_packetout(&tstream, &packet) != 1)
321
break; // get more data?
Jun 10, 2011
Jun 10, 2011
322
323
324
if (!th_decode_headerin(&tinfo, &tcomment, &tsetup, &packet))
goto cleanup;
tpackets++;
325
326
} // while
Jun 10, 2011
Jun 10, 2011
327
while (!ctx->halt && vpackets && (vpackets < 3))
Jun 10, 2011
Jun 10, 2011
329
if (ogg_stream_packetout(&vstream, &packet) != 1)
330
break; // get more data?
Jun 10, 2011
Jun 10, 2011
331
332
333
if (vorbis_synthesis_headerin(&vinfo, &vcomment, &packet))
goto cleanup;
vpackets++;
334
335
336
} // while
// get another page, try again?
Jun 10, 2011
Jun 10, 2011
337
338
if (ogg_sync_pageout(&sync, &page) > 0)
queue_ogg_page(ctx);
Jun 23, 2011
Jun 23, 2011
339
else if (FeedMoreOggData(ctx->io, &sync) <= 0)
Jun 10, 2011
Jun 10, 2011
340
goto cleanup;
341
342
343
} // while
// okay, now we have our streams, ready to set up decoding.
Jun 10, 2011
Jun 10, 2011
344
if (!ctx->halt && tpackets)
345
346
{
// th_decode_alloc() docs say to check for insanely large frames yourself.
Jun 10, 2011
Jun 10, 2011
347
348
if ((tinfo.frame_width > 99999) || (tinfo.frame_height > 99999))
goto cleanup;
Jun 15, 2011
Jun 15, 2011
350
351
// We treat "unspecified" as NTSC. *shrug*
if ( (tinfo.colorspace != TH_CS_UNSPECIFIED) &&
Jun 15, 2011
Jun 15, 2011
352
353
(tinfo.colorspace != TH_CS_ITU_REC_470M) &&
(tinfo.colorspace != TH_CS_ITU_REC_470BG) )
Jun 15, 2011
Jun 15, 2011
354
355
356
357
358
{
assert(0 && "Unsupported colorspace."); // !!! FIXME
goto cleanup;
} // if
Jun 10, 2011
Jun 10, 2011
359
if (tinfo.pixel_fmt != TH_PF_420) { assert(0); goto cleanup; } // !!! FIXME
Jun 10, 2011
Jun 10, 2011
361
362
if (tinfo.fps_denominator != 0)
fps = ((double) tinfo.fps_numerator) / ((double) tinfo.fps_denominator);
Jun 10, 2011
Jun 10, 2011
364
365
tdec = th_decode_alloc(&tinfo, tsetup);
if (!tdec) goto cleanup;
366
367
368
369
// Set decoder to maximum post-processing level.
// Theoretically we could try dropping this level if we're not keeping up.
int pp_level_max = 0;
Jun 15, 2011
Jun 15, 2011
370
371
// !!! FIXME: maybe an API to set this?
//th_decode_ctl(tdec, TH_DECCTL_GET_PPLEVEL_MAX, &pp_level_max, sizeof(pp_level_max));
Jun 10, 2011
Jun 10, 2011
372
th_decode_ctl(tdec, TH_DECCTL_SET_PPLEVEL, &pp_level_max, sizeof(pp_level_max));
373
374
375
} // if
// Done with this now.
Jun 10, 2011
Jun 10, 2011
376
if (tsetup != NULL)
Jun 10, 2011
Jun 10, 2011
378
379
th_setup_free(tsetup);
tsetup = NULL;
380
381
} // if
Jun 10, 2011
Jun 10, 2011
382
if (!ctx->halt && vpackets)
Jun 10, 2011
Jun 10, 2011
384
385
386
387
388
389
vdsp_init = (vorbis_synthesis_init(&vdsp, &vinfo) == 0);
if (!vdsp_init)
goto cleanup;
vblock_init = (vorbis_block_init(&vdsp, &vblock) == 0);
if (!vblock_init)
goto cleanup;
390
391
392
393
394
} // if
// Now we can start the actual decoding!
// Note that audio and video don't _HAVE_ to start simultaneously.
Apr 23, 2013
Apr 23, 2013
395
Mutex_Lock(ctx->lock);
Jun 24, 2011
Jun 24, 2011
396
397
398
ctx->prepped = 1;
ctx->hasvideo = (tpackets != 0);
ctx->hasaudio = (vpackets != 0);
Apr 23, 2013
Apr 23, 2013
399
Mutex_Unlock(ctx->lock);
Jun 24, 2011
Jun 24, 2011
400
Jun 10, 2011
Jun 10, 2011
401
while (!ctx->halt && !eos)
402
403
404
405
{
int need_pages = 0; // need more Ogg pages?
int saw_video_frame = 0;
Nov 29, 2022
Nov 29, 2022
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
if (current_seek_generation != ctx->seek_generation) // seek requested
{
unsigned long targetms;
long seekpos;
long lo, hi;
if (!ctx->io->seek)
goto cleanup; // seeking unsupported.
if (streamlen == -1) // just check this once in case it's expensive.
{
streamlen = ctx->io->streamlen ? ctx->io->streamlen(ctx->io) : -1;
if (streamlen == -1)
goto cleanup; // i/o error, unsupported, etc.
} // if
// We check ctx->seek_generation without a lock as this goes on, so if they mismatch we
// drop what we're doing and prepare to seek to a new location. But here we hold a lock
// so we can avoid the race condition where the app is halfway through requesting a
// seek while we're reading in these variables.
Mutex_Lock(ctx->lock);
current_seek_generation = ctx->seek_generation;
targetms = ctx->new_seek_position_ms;
Mutex_Unlock(ctx->lock);
lo = 0;
hi = streamlen;
if (targetms == 0)
hi = 0; /* as an optimization, just jump to the start of file if rewinding to start instead of binary searching. */
seekpos = (lo / 2) + (hi / 2);
while ((!ctx->halt) && (current_seek_generation == ctx->seek_generation))
{
//const int max_keyframe_distance = 1 << tinfo.keyframe_granule_shift;
// Do a binary search through the stream to find our starting point.
// This idea came from libtheoraplayer (no relation to theoraplay).
if (ctx->io->seek(ctx->io, seekpos) == -1)
goto cleanup; // oh well.
granulepos = -1;
ogg_sync_reset(&sync);
memset(&page, '\0', sizeof (page));
ogg_sync_pageseek(&sync, &page);
while (!ctx->halt && (current_seek_generation == ctx->seek_generation))
{
if (ogg_sync_pageout(&sync, &page) != 1)
{
if (FeedMoreOggData(ctx->io, &sync) <= 0)
goto cleanup;
continue;
} // if
granulepos = ogg_page_granulepos(&page);
if (granulepos >= 0)
{
const int serialno = ogg_page_serialno(&page);
unsigned long ms;
if (tpackets) // always tee off video frames if possible.
{
if (serialno != tserialno)
continue;
ms = (unsigned long) (th_granule_time(tdec, granulepos) * 1000.0);
} // else
else
{
if (serialno != vserialno)
continue;
ms = (unsigned long) (vorbis_granule_time(&vdsp, granulepos) * 1000.0);
} // else
if ((ms < targetms) && ((targetms - ms) <= 250)) // !!! FIXME: tweak this number?
hi = lo; // found something close enough to the target!
else // adjust binary search position and try again.
{
const long newpos = (lo / 2) + (hi / 2);
if (targetms > ms)
lo = newpos;
else
hi = newpos;
} // else
break;
} // if
} // while
const long newseekpos = (lo / 2) + (hi / 2);
if (seekpos == newseekpos)
break; // we did the best we could, just go from here.
seekpos = newseekpos;
} // while
// at this point, we have seek'd to something reasonably close to our target. Now decode until we're as close as possible to it.
vorbis_synthesis_restart(&vdsp);
resolving_audio_seek = vpackets;
resolving_video_seek = tpackets;
seek_target = targetms;
need_keyframe = tpackets;
} // if
509
510
// Try to read as much audio as we can at once. We limit the outer
// loop to one video frame and as much audio as we can eat.
Jun 11, 2011
Jun 11, 2011
511
while (!ctx->halt && vpackets)
Nov 29, 2022
Nov 29, 2022
513
514
const double audiotime = vorbis_granule_time(&vdsp, vdsp.granulepos);
const unsigned int playms = (unsigned int) (audiotime * 1000.0);
515
float **pcm = NULL;
Nov 29, 2022
Nov 29, 2022
516
517
518
519
520
521
522
523
524
int frames;
if (current_seek_generation != ctx->seek_generation)
break; // seek requested? Break out of the loop right away so we can handle it; this loop's work would be wasted.
if (resolving_audio_seek && ((playms >= seek_target) || ((seek_target - playms) <= (unsigned long) (1000.0 / fps))))
resolving_audio_seek = 0;
frames = vorbis_synthesis_pcmout(&vdsp, &pcm);
525
526
if (frames > 0)
{
Nov 29, 2022
Nov 29, 2022
527
if (!resolving_audio_seek)
Nov 29, 2022
Nov 29, 2022
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
const int channels = vinfo.channels;
int chanidx, frameidx;
float *samples;
AudioPacket *item = (AudioPacket *) malloc(sizeof (AudioPacket));
if (item == NULL) goto cleanup;
item->seek_generation = current_seek_generation;
item->playms = playms;
item->channels = channels;
item->freq = vinfo.rate;
item->frames = frames;
item->samples = (float *) malloc(sizeof (float) * frames * channels);
item->next = NULL;
if (item->samples == NULL)
{
free(item);
goto cleanup;
} // if
Nov 29, 2022
Nov 29, 2022
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
// I bet this beats the crap out of the CPU cache...
samples = item->samples;
for (frameidx = 0; frameidx < frames; frameidx++)
{
for (chanidx = 0; chanidx < channels; chanidx++)
*(samples++) = pcm[chanidx][frameidx];
} // for
//printf("Decoded %d frames of audio.\n", (int) frames);
Mutex_Lock(ctx->lock);
ctx->audioms += item->playms;
if (ctx->audiolisttail)
{
assert(ctx->audiolist);
ctx->audiolisttail->next = item;
} // if
else
{
assert(!ctx->audiolist);
ctx->audiolist = item;
} // else
ctx->audiolisttail = item;
Mutex_Unlock(ctx->lock);
} // if
Jun 10, 2011
Jun 10, 2011
573
vorbis_synthesis_read(&vdsp, frames); // we ate everything.
574
575
576
577
} // if
else // no audio available left in current packet?
{
// try to feed another packet to the Vorbis stream...
Jun 10, 2011
Jun 10, 2011
578
if (ogg_stream_packetout(&vstream, &packet) <= 0)
Jun 24, 2011
Jun 24, 2011
579
580
581
{
if (!tpackets)
need_pages = 1; // no video, get more pages now.
Jun 11, 2011
Jun 11, 2011
582
break; // we'll get more pages when the video catches up.
Jun 24, 2011
Jun 24, 2011
583
} // if
584
585
else
{
Jun 10, 2011
Jun 10, 2011
586
587
if (vorbis_synthesis(&vblock, &packet) == 0)
vorbis_synthesis_blockin(&vdsp, &vblock);
588
589
590
591
} // else
} // else
} // while
Nov 29, 2022
Nov 29, 2022
592
if (!ctx->halt && tpackets && (current_seek_generation == ctx->seek_generation))
593
594
595
{
// Theora, according to example_player.c, is
// "one [packet] in, one [frame] out."
Jun 10, 2011
Jun 10, 2011
596
if (ogg_stream_packetout(&tstream, &packet) <= 0)
597
598
599
need_pages = 1;
else
{
Aug 26, 2016
Aug 26, 2016
600
601
// you have to guide the Theora decoder to get meaningful timestamps, apparently. :/
if (packet.granulepos >= 0)
Nov 29, 2022
Nov 29, 2022
602
th_decode_ctl(tdec, TH_DECCTL_SET_GRANPOS, &packet.granulepos, sizeof (packet.granulepos));
Aug 26, 2016
Aug 26, 2016
603
604
if (th_decode_packetin(tdec, &packet, &granulepos) == 0) // new frame!
Nov 29, 2022
Nov 29, 2022
606
607
608
609
610
const double videotime = th_granule_time(tdec, granulepos);
const unsigned int playms = (unsigned int) (videotime * 1000.0);
if (need_keyframe && th_packet_iskeyframe(&packet))
need_keyframe = 0;
Nov 29, 2022
Nov 29, 2022
612
613
614
615
616
617
618
if (resolving_video_seek && !need_keyframe && ((playms >= seek_target) || ((seek_target - playms) <= (unsigned long) (1000.0 / fps))))
resolving_video_seek = 0;
if (!resolving_video_seek)
{
th_ycbcr_buffer ycbcr;
if (th_decode_ycbcr_out(tdec, ycbcr) == 0)
Nov 29, 2022
Nov 29, 2022
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
VideoFrame *item = (VideoFrame *) malloc(sizeof (VideoFrame));
if (item == NULL) goto cleanup;
item->seek_generation = current_seek_generation;
item->playms = playms;
item->fps = fps;
item->width = tinfo.pic_width;
item->height = tinfo.pic_height;
item->format = ctx->vidfmt;
item->pixels = ctx->vidcvt(&tinfo, ycbcr);
item->next = NULL;
if (item->pixels == NULL)
{
free(item);
goto cleanup;
} // if
//printf("Decoded another video frame.\n");
Mutex_Lock(ctx->lock);
if (ctx->videolisttail)
{
assert(ctx->videolist);
ctx->videolisttail->next = item;
} // if
else
{
assert(!ctx->videolist);
ctx->videolist = item;
} // else
ctx->videolisttail = item;
ctx->videocount++;
Mutex_Unlock(ctx->lock);
saw_video_frame = 1;
654
655
656
657
658
659
} // if
} // if
} // if
} // else
} // if
Nov 29, 2022
Nov 29, 2022
660
if (!ctx->halt && need_pages && (current_seek_generation == ctx->seek_generation))
Jun 23, 2011
Jun 23, 2011
662
const int rc = FeedMoreOggData(ctx->io, &sync);
Jun 10, 2011
Jun 10, 2011
663
664
665
666
667
668
669
670
671
if (rc == 0)
eos = 1; // end of stream
else if (rc < 0)
goto cleanup; // i/o error, etc.
else
{
while (!ctx->halt && (ogg_sync_pageout(&sync, &page) > 0))
queue_ogg_page(ctx);
} // else
672
673
674
675
676
677
} // if
// Sleep the process until we have space for more frames.
if (saw_video_frame)
{
int go_on = !ctx->halt;
Jun 11, 2011
Jun 11, 2011
678
//printf("Sleeping.\n");
679
680
681
while (go_on)
{
// !!! FIXME: This is stupid. I should use a semaphore for this.
Apr 23, 2013
Apr 23, 2013
682
Mutex_Lock(ctx->lock);
683
go_on = !ctx->halt && (ctx->videocount >= ctx->maxframes);
Apr 23, 2013
Apr 23, 2013
684
Mutex_Unlock(ctx->lock);
685
if (go_on)
May 19, 2013
May 19, 2013
686
sleepms(10);
687
} // while
Jun 11, 2011
Jun 11, 2011
688
//printf("Awake!\n");
689
690
} // if
} // while
Jun 10, 2011
Jun 10, 2011
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
was_error = 0;
cleanup:
ctx->decode_error = (!ctx->halt && was_error);
if (tdec != NULL) th_decode_free(tdec);
if (tsetup != NULL) th_setup_free(tsetup);
if (vblock_init) vorbis_block_clear(&vblock);
if (vdsp_init) vorbis_dsp_clear(&vdsp);
if (tpackets) ogg_stream_clear(&tstream);
if (vpackets) ogg_stream_clear(&vstream);
th_info_clear(&tinfo);
th_comment_clear(&tcomment);
vorbis_comment_clear(&vcomment);
vorbis_info_clear(&vinfo);
ogg_sync_clear(&sync);
Jun 23, 2011
Jun 23, 2011
707
ctx->io->close(ctx->io);
Jun 10, 2011
Jun 10, 2011
708
ctx->thread_done = 1;
709
710
711
712
713
714
715
} // WorkerThread
static void *WorkerThreadEntry(void *_this)
{
TheoraDecoder *ctx = (TheoraDecoder *) _this;
WorkerThread(ctx);
Jun 11, 2011
Jun 11, 2011
716
//printf("Worker thread is done.\n");
717
718
719
return NULL;
} // WorkerThreadEntry
Jun 23, 2011
Jun 23, 2011
720
721
722
723
724
725
726
727
728
static long IoFopenRead(THEORAPLAY_Io *io, void *buf, long buflen)
{
FILE *f = (FILE *) io->userdata;
const size_t br = fread(buf, 1, buflen, f);
if ((br == 0) && ferror(f))
return -1;
return (long) br;
} // IoFopenRead
Nov 29, 2022
Nov 29, 2022
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
static long IoFopenStreamLen(THEORAPLAY_Io *io)
{
FILE *f = (FILE *) io->userdata;
const long origpos = ftell(f);
long retval = -1;
if (fseek(f, 0, SEEK_END) == 0) {
retval = ftell(f);
}
fseek(f, origpos, SEEK_SET);
return retval;
} // IoFopenStreamLen
static int IoFopenSeek(THEORAPLAY_Io *io, long absolute_offset)
{
FILE *f = (FILE *) io->userdata;
return fseek(f, absolute_offset, SEEK_SET);
} // IoFopenSeek
Jun 23, 2011
Jun 23, 2011
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
static void IoFopenClose(THEORAPLAY_Io *io)
{
FILE *f = (FILE *) io->userdata;
fclose(f);
free(io);
} // IoFopenClose
THEORAPLAY_Decoder *THEORAPLAY_startDecodeFile(const char *fname,
const unsigned int maxframes,
THEORAPLAY_VideoFormat vidfmt)
{
THEORAPLAY_Io *io = (THEORAPLAY_Io *) malloc(sizeof (THEORAPLAY_Io));
if (io == NULL)
return NULL;
FILE *f = fopen(fname, "rb");
if (f == NULL)
{
free(io);
return NULL;
} // if
io->read = IoFopenRead;
Nov 29, 2022
Nov 29, 2022
771
772
io->seek = IoFopenSeek;
io->streamlen = IoFopenStreamLen;
Jun 23, 2011
Jun 23, 2011
773
774
775
776
777
778
779
io->close = IoFopenClose;
io->userdata = f;
return THEORAPLAY_startDecode(io, maxframes, vidfmt);
} // THEORAPLAY_startDecodeFile
THEORAPLAY_Decoder *THEORAPLAY_startDecode(THEORAPLAY_Io *io,
Jun 15, 2011
Jun 15, 2011
780
781
const unsigned int maxframes,
THEORAPLAY_VideoFormat vidfmt)
Jun 10, 2011
Jun 10, 2011
782
{
Jun 15, 2011
Jun 15, 2011
783
784
785
786
787
TheoraDecoder *ctx = NULL;
ConvertVideoFrameFn vidcvt = NULL;
switch (vidfmt)
{
Jun 15, 2011
Jun 15, 2011
788
789
// !!! FIXME: current expects TH_PF_420.
#define VIDCVT(t) case THEORAPLAY_VIDFMT_##t: vidcvt = ConvertVideoFrame420To##t; break;
Jun 15, 2011
Jun 15, 2011
790
VIDCVT(YV12)
Jun 19, 2011
Jun 19, 2011
791
VIDCVT(IYUV)
Jun 15, 2011
Jun 15, 2011
792
793
794
VIDCVT(RGB)
VIDCVT(RGBA)
#undef VIDCVT
Jun 23, 2011
Jun 23, 2011
795
default: goto startdecode_failed; // invalid/unsupported format.
Jun 15, 2011
Jun 15, 2011
796
797
} // switch
May 19, 2013
May 19, 2013
798
ctx = (TheoraDecoder *) malloc(sizeof (TheoraDecoder));
Jun 10, 2011
Jun 10, 2011
799
if (ctx == NULL)
Jun 23, 2011
Jun 23, 2011
800
goto startdecode_failed;
Jun 10, 2011
Jun 10, 2011
801
802
803
memset(ctx, '\0', sizeof (TheoraDecoder));
ctx->maxframes = maxframes;
Jun 15, 2011
Jun 15, 2011
804
805
ctx->vidfmt = vidfmt;
ctx->vidcvt = vidcvt;
Jun 23, 2011
Jun 23, 2011
806
ctx->io = io;
Jun 10, 2011
Jun 10, 2011
807
Apr 23, 2013
Apr 23, 2013
808
if (Mutex_Create(ctx) == 0)
Jun 10, 2011
Jun 10, 2011
809
{
Apr 23, 2013
Apr 23, 2013
810
ctx->thread_created = (Thread_Create(ctx, WorkerThreadEntry) == 0);
Jun 23, 2011
Jun 23, 2011
811
812
if (ctx->thread_created)
return (THEORAPLAY_Decoder *) ctx;
Jun 10, 2011
Jun 10, 2011
813
814
} // if
Apr 23, 2013
Apr 23, 2013
815
Mutex_Destroy(ctx->lock);
Jun 23, 2011
Jun 23, 2011
816
817
818
startdecode_failed:
io->close(io);
Jun 10, 2011
Jun 10, 2011
819
820
821
822
823
824
825
826
free(ctx);
return NULL;
} // THEORAPLAY_startDecode
void THEORAPLAY_stopDecode(THEORAPLAY_Decoder *decoder)
{
TheoraDecoder *ctx = (TheoraDecoder *) decoder;
Jun 14, 2011
Jun 14, 2011
827
828
if (!ctx)
return;
Jun 10, 2011
Jun 10, 2011
829
830
831
832
if (ctx->thread_created)
{
ctx->halt = 1;
Apr 23, 2013
Apr 23, 2013
833
834
Thread_Join(ctx->worker);
Mutex_Destroy(ctx->lock);
Jun 10, 2011
Jun 10, 2011
835
836
} // if
Jun 15, 2011
Jun 15, 2011
837
VideoFrame *videolist = ctx->videolist;
Jun 10, 2011
Jun 10, 2011
838
839
while (videolist)
{
Jun 15, 2011
Jun 15, 2011
840
VideoFrame *next = videolist->next;
Jun 15, 2011
Jun 15, 2011
841
free(videolist->pixels);
Jun 10, 2011
Jun 10, 2011
842
843
844
845
free(videolist);
videolist = next;
} // while
Jun 15, 2011
Jun 15, 2011
846
AudioPacket *audiolist = ctx->audiolist;
Jun 10, 2011
Jun 10, 2011
847
848
while (audiolist)
{
Jun 15, 2011
Jun 15, 2011
849
AudioPacket *next = audiolist->next;
Jun 10, 2011
Jun 10, 2011
850
851
852
853
854
855
856
857
858
859
860
free(audiolist->samples);
free(audiolist);
audiolist = next;
} // while
free(ctx);
} // THEORAPLAY_stopDecode
int THEORAPLAY_isDecoding(THEORAPLAY_Decoder *decoder)
{
Jun 24, 2011
Jun 24, 2011
861
862
863
864
TheoraDecoder *ctx = (TheoraDecoder *) decoder;
int retval = 0;
if (ctx)
{
Apr 23, 2013
Apr 23, 2013
865
Mutex_Lock(ctx->lock);
Jun 24, 2011
Jun 24, 2011
866
867
retval = ( ctx && (ctx->audiolist || ctx->videolist ||
(ctx->thread_created && !ctx->thread_done)) );
Apr 23, 2013
Apr 23, 2013
868
Mutex_Unlock(ctx->lock);
Jun 24, 2011
Jun 24, 2011
869
870
} // if
return retval;
Jun 10, 2011
Jun 10, 2011
871
872
873
} // THEORAPLAY_isDecoding
Jun 24, 2011
Jun 24, 2011
874
875
876
877
#define GET_SYNCED_VALUE(typ, defval, decoder, member) \
TheoraDecoder *ctx = (TheoraDecoder *) decoder; \
typ retval = defval; \
if (ctx) { \
Apr 23, 2013
Apr 23, 2013
878
Mutex_Lock(ctx->lock); \
Jun 24, 2011
Jun 24, 2011
879
retval = ctx->member; \
Apr 23, 2013
Apr 23, 2013
880
Mutex_Unlock(ctx->lock); \
Jun 24, 2011
Jun 24, 2011
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
} \
return retval;
int THEORAPLAY_isInitialized(THEORAPLAY_Decoder *decoder)
{
GET_SYNCED_VALUE(int, 0, decoder, prepped);
} // THEORAPLAY_isInitialized
int THEORAPLAY_hasVideoStream(THEORAPLAY_Decoder *decoder)
{
GET_SYNCED_VALUE(int, 0, decoder, hasvideo);
} // THEORAPLAY_hasVideoStream
int THEORAPLAY_hasAudioStream(THEORAPLAY_Decoder *decoder)
{
GET_SYNCED_VALUE(int, 0, decoder, hasaudio);
} // THEORAPLAY_hasAudioStream
unsigned int THEORAPLAY_availableVideo(THEORAPLAY_Decoder *decoder)
{
GET_SYNCED_VALUE(unsigned int, 0, decoder, videocount);
Sep 10, 2019
Sep 10, 2019
905
} // THEORAPLAY_availableVideo
Jun 24, 2011
Jun 24, 2011
906
907
908
909
910
unsigned int THEORAPLAY_availableAudio(THEORAPLAY_Decoder *decoder)
{
GET_SYNCED_VALUE(unsigned int, 0, decoder, audioms);
Sep 10, 2019
Sep 10, 2019
911
} // THEORAPLAY_availableAudio
Jun 24, 2011
Jun 24, 2011
912
913
Jun 10, 2011
Jun 10, 2011
914
915
int THEORAPLAY_decodingError(THEORAPLAY_Decoder *decoder)
{
Jun 24, 2011
Jun 24, 2011
916
GET_SYNCED_VALUE(int, 0, decoder, decode_error);
Jun 10, 2011
Jun 10, 2011
917
918
919
} // THEORAPLAY_decodingError
Jun 15, 2011
Jun 15, 2011
920
const THEORAPLAY_AudioPacket *THEORAPLAY_getAudio(THEORAPLAY_Decoder *decoder)
Jun 10, 2011
Jun 10, 2011
921
922
{
TheoraDecoder *ctx = (TheoraDecoder *) decoder;
Jun 15, 2011
Jun 15, 2011
923
AudioPacket *retval;
Jun 10, 2011
Jun 10, 2011
924
Apr 23, 2013
Apr 23, 2013
925
Mutex_Lock(ctx->lock);
Jun 10, 2011
Jun 10, 2011
926
927
928
retval = ctx->audiolist;
if (retval)
{
Jun 24, 2011
Jun 24, 2011
929
ctx->audioms -= retval->playms;
Jun 10, 2011
Jun 10, 2011
930
931
932
933
934
ctx->audiolist = retval->next;
retval->next = NULL;
if (ctx->audiolist == NULL)
ctx->audiolisttail = NULL;
} // if
Apr 23, 2013
Apr 23, 2013
935
Mutex_Unlock(ctx->lock);
Jun 10, 2011
Jun 10, 2011
936
937
938
939
940
return retval;
} // THEORAPLAY_getAudio
Jun 15, 2011
Jun 15, 2011
941
void THEORAPLAY_freeAudio(const THEORAPLAY_AudioPacket *_item)
Jun 10, 2011
Jun 10, 2011
942
{
Jun 15, 2011
Jun 15, 2011
943
THEORAPLAY_AudioPacket *item = (THEORAPLAY_AudioPacket *) _item;
Jun 11, 2011
Jun 11, 2011
944
945
946
947
948
949
if (item != NULL)
{
assert(item->next == NULL);
free(item->samples);
free(item);
} // if
Jun 10, 2011
Jun 10, 2011
950
951
952
} // THEORAPLAY_freeAudio
Jun 15, 2011
Jun 15, 2011
953
const THEORAPLAY_VideoFrame *THEORAPLAY_getVideo(THEORAPLAY_Decoder *decoder)
Jun 10, 2011
Jun 10, 2011
954
955
{
TheoraDecoder *ctx = (TheoraDecoder *) decoder;
Jun 15, 2011
Jun 15, 2011
956
VideoFrame *retval;
Jun 10, 2011
Jun 10, 2011
957
Apr 23, 2013
Apr 23, 2013
958
Mutex_Lock(ctx->lock);
Jun 10, 2011
Jun 10, 2011
959
960
961
962
963
964
965
966
967
968
retval = ctx->videolist;
if (retval)
{
ctx->videolist = retval->next;
retval->next = NULL;
if (ctx->videolist == NULL)
ctx->videolisttail = NULL;
assert(ctx->videocount > 0);
ctx->videocount--;
} // if
Apr 23, 2013
Apr 23, 2013
969
Mutex_Unlock(ctx->lock);
Jun 10, 2011
Jun 10, 2011
970
971
972
973
974
return retval;
} // THEORAPLAY_getVideo
Jun 15, 2011
Jun 15, 2011
975
void THEORAPLAY_freeVideo(const THEORAPLAY_VideoFrame *_item)
Jun 10, 2011
Jun 10, 2011
976
{
Jun 15, 2011
Jun 15, 2011
977
THEORAPLAY_VideoFrame *item = (THEORAPLAY_VideoFrame *) _item;
Jun 11, 2011
Jun 11, 2011
978
979
980
if (item != NULL)
{
assert(item->next == NULL);
Jun 15, 2011
Jun 15, 2011
981
free(item->pixels);
Jun 11, 2011
Jun 11, 2011
982
983
free(item);
} // if
Jun 10, 2011
Jun 10, 2011
984
985
} // THEORAPLAY_freeVideo
Nov 29, 2022
Nov 29, 2022
986
987
988
989
990
991
992
993
994
995
996
997
unsigned int THEORAPLAY_seek(THEORAPLAY_Decoder *decoder, unsigned long mspos)
{
unsigned int retval;
TheoraDecoder *ctx = (TheoraDecoder *) decoder;
Mutex_Lock(ctx->lock);
ctx->new_seek_position_ms = mspos;
retval = ++ctx->seek_generation;
Mutex_Unlock(ctx->lock);
return retval;
} // THEORAPLAY_seek
Nov 28, 2022
Nov 28, 2022
998
// end of theoraplay.c ...