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