1 /*---------------------------------------------------------------------------*
2 Project: THP Player
3 File: THPVideoDecode.c
4
5 Copyright (C)2002-2006 Nintendo All Rights Reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Log: THPVideoDecode.c,v $
14 Revision 1.1 02/03/2006 10:01:41 aka
15 Imported from Dolphin tree.
16
17
18 5 03/11/25 11:24 Dante
19 Japanese to English translation of comments and text strings
20
21 4 03/09/24 9:03a Akagi
22 Added explicit cast.
23
24 3 03/09/16 15:49:00 Suzuki
25 changed the process which skips to decode when decoding is delay.
26
27 2 02/05/14 9:16a Suzuki
28 Changed return value type and argument type of PopFreeTextureSet(),
29 PushFreeTextureSet(), PopDecodedTextureSet(), PushDecodedTextureSet()
30
31 1 02/01/16 10:53a Akagi
32 Initial revision made by Suzuki-san (IRD).
33
34 $NoKeywords: $
35
36 *---------------------------------------------------------------------------*/
37
38 #include <revolution.h>
39
40 #include "THPPlayer.h"
41 #include "THPVideoDecode.h"
42 #include "THPRead.h"
43
44 /*---------------------------------------------------------------------------*
45 External Function
46 *---------------------------------------------------------------------------*/
47
48 extern void PrepareReady(BOOL flag);
49
50 /*---------------------------------------------------------------------------*
51 Static Function
52 *---------------------------------------------------------------------------*/
53
54 static void *VideoDecoder(void *ptr);
55 static void *VideoDecoderForOnMemory(void *ptr);
56 static u32 VideoDecode(THPReadBuffer *readBuffer);
57
58 /*---------------------------------------------------------------------------*
59 Global Variable
60 *---------------------------------------------------------------------------*/
61
62 extern THPPlayer ActivePlayer;
63
64 /*---------------------------------------------------------------------------*
65 Static Variable
66 *---------------------------------------------------------------------------*/
67
68 static s32 VideoDecodeThreadCreated = 0;
69 static OSThread VideoDecodeThread;
70 static u8 VideoDecodeThreadStack[4*1024];
71 static OSMessageQueue FreeTextureSetQueue;
72 static OSMessageQueue DecodedTextureSetQueue;
73 static OSMessage FreeTextureSetMessage[DECODE_VIDEO_BUFFER_NUM];
74 static OSMessage DecodedTextureSetMessage[DECODE_VIDEO_BUFFER_NUM];
75 static s32 First;
76
77 /*---------------------------------------------------------------------------*
78 Name: CreateVideoDecodeThread
79
80 Description: Create video decode thread
81
82 Arguments: priority thread priority
83 ptr Pointer to memory where THP movie start data is
84 for OnMemory playback.
85
86 Returns: If thread creation succeeds returns TRUE. If fails, FALSE.
87 *---------------------------------------------------------------------------*/
88
CreateVideoDecodeThread(OSPriority priority,u8 * ptr)89 BOOL CreateVideoDecodeThread(OSPriority priority, u8 *ptr)
90 {
91 if (ptr)
92 {
93 if (OSCreateThread(&VideoDecodeThread,
94 VideoDecoderForOnMemory,
95 ptr,
96 VideoDecodeThreadStack + sizeof(VideoDecodeThreadStack),
97 sizeof(VideoDecodeThreadStack),
98 priority,
99 OS_THREAD_ATTR_DETACH) == FALSE)
100 {
101 #ifdef _DEBUG
102 OSReport("Can't create video decode thread\n");
103 #endif
104 return FALSE;
105 }
106 }
107 else
108 {
109 if (OSCreateThread(&VideoDecodeThread,
110 VideoDecoder,
111 NULL,
112 VideoDecodeThreadStack + sizeof(VideoDecodeThreadStack),
113 sizeof(VideoDecodeThreadStack),
114 priority,
115 OS_THREAD_ATTR_DETACH) == FALSE)
116 {
117 #ifdef _DEBUG
118 OSReport("Can't create video decode thread\n");
119 #endif
120 return FALSE;
121 }
122 }
123
124 OSInitMessageQueue(&FreeTextureSetQueue,
125 FreeTextureSetMessage,
126 DECODE_VIDEO_BUFFER_NUM);
127
128 OSInitMessageQueue(&DecodedTextureSetQueue,
129 DecodedTextureSetMessage,
130 DECODE_VIDEO_BUFFER_NUM);
131
132 VideoDecodeThreadCreated = 1;
133
134 First = 1;
135
136 return TRUE;
137 }
138
139 /*---------------------------------------------------------------------------*
140 Name: VideoDecodeThreadStart
141
142 Description: Start of video decode thread
143
144 Arguments: None
145
146 Returns: None
147 *---------------------------------------------------------------------------*/
148
VideoDecodeThreadStart(void)149 void VideoDecodeThreadStart(void)
150 {
151 if (VideoDecodeThreadCreated)
152 {
153 OSResumeThread(&VideoDecodeThread);
154 }
155
156 return;
157 }
158
159 /*---------------------------------------------------------------------------*
160 Name: VideoDecodeThreadCancel
161
162 Description: Cancel video decode thread
163
164 Arguments: None
165
166 Returns: None
167 *---------------------------------------------------------------------------*/
168
VideoDecodeThreadCancel(void)169 void VideoDecodeThreadCancel(void)
170 {
171 if (VideoDecodeThreadCreated)
172 {
173 OSCancelThread(&VideoDecodeThread);
174
175 VideoDecodeThreadCreated = 0;
176 }
177
178 return;
179 }
180
181 /*---------------------------------------------------------------------------*
182 Name: VideoDecoder
183
184 Description: Video decoder streaming playback
185
186 Arguments: None
187
188 Returns: None
189 *---------------------------------------------------------------------------*/
190
VideoDecoder(void * ptr)191 static void *VideoDecoder(void *ptr)
192 {
193 #pragma unused(ptr)
194 THPReadBuffer *readBuffer;
195 s32 frameNumber;
196 u32 skipCount = 0;
197
198 while (1)
199 {
200 if (ActivePlayer.audioExist)
201 {
202 // Skip decoding if video decoding is delayed
203 while (skipCount)
204 {
205 readBuffer = (THPReadBuffer *)PopReadedBuffer2();
206
207 frameNumber = (s32)((readBuffer->frameNumber + ActivePlayer.initReadFrame)
208 % ActivePlayer.header.numFrames);
209
210 // Always decode last frame with one shot playback
211 if (frameNumber == ActivePlayer.header.numFrames - 1)
212 {
213 if (!(ActivePlayer.playFlag & THP_PLAY_LOOP))
214 {
215 VideoDecode(readBuffer);
216 }
217 }
218
219 PushFreeReadBuffer(readBuffer);
220
221 skipCount--;
222 // Increment as decoded
223 ActivePlayer.videoDecodeCount++;
224 }
225 }
226
227 if (ActivePlayer.audioExist)
228 {
229 readBuffer = (THPReadBuffer *)PopReadedBuffer2();
230 }
231 else
232 {
233 readBuffer = (THPReadBuffer *)PopReadedBuffer();
234 }
235
236 skipCount = VideoDecode(readBuffer);
237
238 PushFreeReadBuffer(readBuffer);
239 }
240
241 return NULL;
242 }
243
244 /*---------------------------------------------------------------------------*
245 Name: VideoDecoderForOnMemory
246
247 Description: Video decoder for OnMemory playback
248
249 Arguments: None
250
251 Returns: None
252 *---------------------------------------------------------------------------*/
253
VideoDecoderForOnMemory(void * ptr)254 static void *VideoDecoderForOnMemory(void *ptr)
255 {
256 THPReadBuffer readBuffer;
257 s32 tmp, size, readFrame, frameNumber;
258 u32 skipCount;
259
260 size = ActivePlayer.initReadSize;
261 readBuffer.ptr = (u8 *)ptr;
262 readFrame = 0;
263 skipCount = 0;
264
265 while(1)
266 {
267 if (ActivePlayer.audioExist)
268 {
269 // Skip decoding if video decoding is delayed
270 while (skipCount)
271 {
272 skipCount--;
273 // Increment as decoded
274 ActivePlayer.videoDecodeCount++;
275
276 frameNumber = (s32)((readFrame + ActivePlayer.initReadFrame)
277 % ActivePlayer.header.numFrames);
278
279 // Check THP movie end
280 if (frameNumber == ActivePlayer.header.numFrames - 1)
281 {
282 // If loop playback, at beginning of THP movie
283 if (ActivePlayer.playFlag & THP_PLAY_LOOP)
284 {
285 size = *(s32 *)(readBuffer.ptr);
286 readBuffer.ptr = ActivePlayer.movieData;
287 }
288 // Always decode last frame with one shot playback
289 else
290 {
291 break;
292 }
293 }
294 // If not last, move pointer to next frame
295 else
296 {
297 tmp = *(s32 *)(readBuffer.ptr);
298 readBuffer.ptr += size;
299 size = tmp;
300 }
301
302 readFrame++;
303 }
304 }
305
306 readBuffer.frameNumber = readFrame;
307
308 skipCount = VideoDecode(&readBuffer);
309
310 frameNumber = (s32)((readFrame + ActivePlayer.initReadFrame)
311 % ActivePlayer.header.numFrames);
312
313 // Check THP movie end
314 if (frameNumber == ActivePlayer.header.numFrames - 1)
315 {
316 // If loop playback, at beginning of THP movie
317 if (ActivePlayer.playFlag & THP_PLAY_LOOP)
318 {
319 size = *(s32 *)(readBuffer.ptr);
320 readBuffer.ptr = ActivePlayer.movieData;
321 }
322 // If one-shot playback, stop decoding
323 else
324 {
325 OSSuspendThread(&VideoDecodeThread);
326 }
327 }
328 // If not last, move pointer to next frame
329 else
330 {
331 tmp = *(s32 *)(readBuffer.ptr);
332 readBuffer.ptr += size;
333 size = tmp;
334 }
335
336 readFrame++;
337 }
338
339 return NULL;
340 }
341
342 /*---------------------------------------------------------------------------*
343 Name: VideoDecode
344
345 Description: Decode THP video data
346
347 Arguments: readBuffer: Pointer to buffer where THP frame stored.
348
349 Returns: Frame number to show decode delay
350 *---------------------------------------------------------------------------*/
351
VideoDecode(THPReadBuffer * readBuffer)352 static u32 VideoDecode(THPReadBuffer *readBuffer)
353 {
354 THPTextureSet *textureSet;
355 u32 i;
356 u32 ret = 0;
357 u32 *compSizePtr;
358 u8 *ptr;
359
360 compSizePtr = (u32 *)(readBuffer->ptr + 8);
361 ptr = readBuffer->ptr + ActivePlayer.compInfo.numComponents * 4 + 8;
362
363 textureSet = (THPTextureSet *)PopFreeTextureSet();
364
365 for (i = 0 ; i < ActivePlayer.compInfo.numComponents ; i++)
366 {
367 switch (ActivePlayer.compInfo.frameComp[i])
368 {
369 case THP_VIDEO_COMP:
370 if ((ActivePlayer.videoError = THPVideoDecode(ptr,
371 textureSet->ytexture,
372 textureSet->utexture,
373 textureSet->vtexture,
374 ActivePlayer.thpWork)) != THP_OK)
375 {
376 if (First)
377 {
378 PrepareReady(FALSE);
379 First = 0;
380 }
381
382 OSSuspendThread(&VideoDecodeThread);
383 }
384
385 textureSet->frameNumber = readBuffer->frameNumber;
386 PushDecodedTextureSet(textureSet);
387
388 // Check decode delay
389 // curVideoNumber displays current ideal video number. Since
390 // video number starts from 0, add 1 when comparing with videoDecodeCount
391 if (ActivePlayer.curVideoNumber + 1 > ActivePlayer.videoDecodeCount)
392 {
393 // Calculate delayed frame number
394 ret = (u32)(ActivePlayer.curVideoNumber + 1 - ActivePlayer.videoDecodeCount);
395 }
396 else
397 {
398 ret = 0;
399 }
400
401 // Increment decoded THP video data count
402 ActivePlayer.videoDecodeCount++;
403 break;
404 }
405 ptr += *compSizePtr;
406 compSizePtr++;
407 }
408
409 if (First)
410 {
411 PrepareReady(TRUE);
412 First = 0;
413 }
414
415 return ret;
416 }
417
418 /*---------------------------------------------------------------------------*
419 Name: PopFreeTextureSet
420
421 Description: Acquire free texture buffers
422
423 Arguments: None
424
425 Returns: Pointer for texture buffers not used.
426 *---------------------------------------------------------------------------*/
427
PopFreeTextureSet()428 void *PopFreeTextureSet()
429 {
430 OSMessage msg;
431
432 OSReceiveMessage(&FreeTextureSetQueue, &msg, OS_MESSAGE_BLOCK);
433
434 return msg;
435 }
436
437 /*---------------------------------------------------------------------------*
438 Name: PushFreeTextureSet
439
440 Description: Free played back THP video data.
441
442 Arguments: buffer Pointer for played back THP video data.
443
444 Returns: None
445 *---------------------------------------------------------------------------*/
446
PushFreeTextureSet(void * buffer)447 void PushFreeTextureSet(void *buffer)
448 {
449 OSSendMessage(&FreeTextureSetQueue, buffer, OS_MESSAGE_NOBLOCK);
450
451 return;
452 }
453
454 /*---------------------------------------------------------------------------*
455 Name: PopDecodedTextureSet
456
457 Description: Acquire decoded THP video data
458
459 Arguments: flag If OS_MESSAGE_BLOCK, block until can get decoded
460 THP video data.
461 If OS_MESSAGE_NOBLOCK, do not block.
462
463 Returns: If successful, return pointer to texture buffer.
464 If unsuccessful, return NULL.
465 *---------------------------------------------------------------------------*/
466
PopDecodedTextureSet(s32 flag)467 void *PopDecodedTextureSet(s32 flag)
468 {
469 OSMessage msg;
470
471 if (OSReceiveMessage(&DecodedTextureSetQueue, &msg, flag) == TRUE)
472 {
473 return msg;
474 }
475 else
476 {
477 return NULL;
478 }
479 }
480
481 /*---------------------------------------------------------------------------*
482 Name: PushDecodedTextureSet
483
484 Description: Push decoded THP video data to queue.
485
486 Arguments: buffer Pointer for decoded THP video data.
487
488 Returns: None
489 *---------------------------------------------------------------------------*/
490
PushDecodedTextureSet(void * buffer)491 void PushDecodedTextureSet(void *buffer)
492 {
493 OSSendMessage(&DecodedTextureSetQueue, buffer, OS_MESSAGE_BLOCK);
494
495 return;
496 }
497