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