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