1 /*---------------------------------------------------------------------------*
2   Project:  THP Player
3   File:     THPPlayer.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: THPPlayer.c,v $
14   Revision 1.2  02/03/2006 11:44:07  aka
15   Changed audio frame from 5msec to 3msec.
16 
17   Revision 1.1  02/03/2006 10:01:41  aka
18   Imported from Dolphin tree.
19 
20 
21     5     03/11/25 11:24 Dante
22     Japanese to English translation of comments and text strings
23 
24     4     03/09/16 15:48:00 Suzuki
25     changed the process which skips to decode when decoding is delay.
26 
27     3     02/05/31 9:06a Suzuki
28     supported multi audio track
29 
30     2     02/02/28 6:36p Akagi
31     enabled to use with MusyX/AX by Suzuki-san (IRD).
32 
33     1     02/01/16 10:53gi
34     Initial revision made by Suzuki-san (IRD).
35 
36   $NoKeywords: $
37 
38  *---------------------------------------------------------------------------*/
39 
40 #include <string.h>
41 #include <revolution.h>
42 #include "THPPlayer.h"
43 #include "THPVideoDecode.h"
44 #include "THPAudioDecode.h"
45 #include "THPRead.h"
46 #include "THPDraw.h"
47 
48 #define SAMPLES_PER_AUDIO_FRAME (96) // 3msec (32khz)
49 #define BYTES_PER_AUDIO_FRAME   (SAMPLES_PER_AUDIO_FRAME * 4)
50 
51 /*---------------------------------------------------------------------------*
52    Global Function
53  *---------------------------------------------------------------------------*/
54 
55 void PrepareReady(BOOL flag);
56 
57 /*---------------------------------------------------------------------------*
58    Static Function
59  *---------------------------------------------------------------------------*/
60 
61 static void PlayControl(u32 retraceCount);
62 static BOOL ProperTimingForStart(void);
63 static BOOL ProperTimingForGettingNextFrame(void);
64 static void PushUsedTextureSet(void *buffer);
65 static void *PopUsedTextureSet(void);
66 static void THPAudioMixCallback(void);
67 static void MixAudio(s16 *destination, s16 *source, u32 sample);
68 
69 /*---------------------------------------------------------------------------*
70    Global Variable
71  *---------------------------------------------------------------------------*/
72 
73 THPPlayer ActivePlayer;
74 
75 /*---------------------------------------------------------------------------*
76    Static Variable
77  *---------------------------------------------------------------------------*/
78 
79 // 32768 * ((vol * vol) / (127 * 127))
80 static u16 VolumeTable[] =
81 {
82       0,     2,     8,    18,    32,    50,    73,    99,
83     130,   164,   203,   245,   292,   343,   398,   457,
84     520,   587,   658,   733,   812,   895,   983,  1074,
85    1170,  1269,  1373,  1481,  1592,  1708,  1828,  1952,
86    2080,  2212,  2348,  2488,  2632,  2781,  2933,  3090,
87    3250,  3415,  3583,  3756,  3933,  4114,  4298,  4487,
88    4680,  4877,  5079,  5284,  5493,  5706,  5924,  6145,
89    6371,  6600,  6834,  7072,  7313,  7559,  7809,  8063,
90    8321,  8583,  8849,  9119,  9394,  9672,  9954, 10241,
91   10531, 10826, 11125, 11427, 11734, 12045, 12360, 12679,
92   13002, 13329, 13660, 13995, 14335, 14678, 15025, 15377,
93   15732, 16092, 16456, 16823, 17195, 17571, 17951, 18335,
94   18723, 19115, 19511, 19911, 20316, 20724, 21136, 21553,
95   21974, 22398, 22827, 23260, 23696, 24137, 24582, 25031,
96   25484, 25941, 26402, 26868, 27337, 27810, 28288, 28769,
97   29255, 29744, 30238, 30736, 31238, 31744, 32254, 32768
98 };
99 
100 static BOOL              Initialized = 0;
101 static s32               WorkBuffer[16] ATTRIBUTE_ALIGN(32);
102 static OSMessageQueue    PrepareReadyQueue;
103 static OSMessageQueue    UsedTextureSetQueue;
104 static OSMessage         PrepareReadyMessage;
105 static OSMessage         UsedTextureSetMessage[DECODE_VIDEO_BUFFER_NUM];
106 static VIRetraceCallback OldVIPostCallback = NULL;
107 static s16               SoundBuffer[2][SAMPLES_PER_AUDIO_FRAME * 2] ATTRIBUTE_ALIGN(32);
108 static s32               SoundBufferIndex;
109 static AIDCallback       OldAIDCallback = NULL;
110 static s16               *LastAudioBuffer;
111 static s16               *CurAudioBuffer;
112 static s32               AudioSystem = 0;
113 
114 /*---------------------------------------------------------------------------*
115     Name:           THPPlayerInit
116 
117     Description:    Enables locked-cache, and initializes player and THP library.
118                     Register AI FIFO DMA call back for player.
119 
120     Arguments:      audioSystem   Specifies the audio library to be used simultaneously.
121                                   If no audio library is to be used simultaneously,
122                                   specifies THP_MODE_ALONE.
123 
124     Returns:        Returns TRUE if succeeds, and FALSE if fails.
125  *---------------------------------------------------------------------------*/
126 
THPPlayerInit(s32 audioSystem)127 BOOL THPPlayerInit(s32 audioSystem)
128 {
129     BOOL old;
130 
131     ASSERTMSG(audioSystem >= 0 && audioSystem <= THP_MODE_WITH_MUSYX, "audioSystem flag is invalid\n");
132 
133     memset(&ActivePlayer, 0, sizeof(THPPlayer));
134 
135     LCEnable();
136 
137     OSInitMessageQueue(&UsedTextureSetQueue,
138                        UsedTextureSetMessage,
139                        DECODE_VIDEO_BUFFER_NUM);
140 
141     if (THPInit() == FALSE)
142     {
143         return FALSE;
144     }
145 
146     old = OSDisableInterrupts();
147 
148     AudioSystem      = audioSystem;
149     SoundBufferIndex = 0;
150     LastAudioBuffer  = NULL;
151     CurAudioBuffer   = NULL;
152 
153     OldAIDCallback = AIRegisterDMACallback(THPAudioMixCallback);
154 
155     if (OldAIDCallback == NULL && AudioSystem != THP_MODE_ALONE)
156     {
157         AIRegisterDMACallback(NULL);
158 
159         OSRestoreInterrupts(old);
160 
161 #ifdef _DEBUG
162         OSReport("Pleae call AXInit or sndInit before you call THPPlayerInit\n");
163 #endif
164         return FALSE;
165     }
166 
167     OSRestoreInterrupts(old);
168 
169     if (AudioSystem == THP_MODE_ALONE)
170     {
171         memset(SoundBuffer, 0, BYTES_PER_AUDIO_FRAME << 1);
172 
173         DCFlushRange(SoundBuffer, BYTES_PER_AUDIO_FRAME << 1);
174 
175         AIInitDMA((u32)SoundBuffer[SoundBufferIndex], BYTES_PER_AUDIO_FRAME);
176 
177         AIStartDMA();
178     }
179 
180     Initialized = TRUE;
181 
182     return TRUE;
183 }
184 
185 /*---------------------------------------------------------------------------*
186     Name:           THPPlayerQuit
187 
188     Description:    Disables locked cache.
189                     Restores AI FIFO DMA callback to the status before THPPlayerInit is called.
190 
191     Arguments:      None
192 
193     Returns:        None
194  *---------------------------------------------------------------------------*/
195 
THPPlayerQuit(void)196 void THPPlayerQuit(void)
197 {
198     BOOL old;
199 
200     LCDisable();
201 
202     old = OSDisableInterrupts();
203 
204     if (OldAIDCallback)
205     {
206         AIRegisterDMACallback(OldAIDCallback);
207     }
208 
209     OSRestoreInterrupts(old);
210 
211     Initialized = FALSE;
212 
213     return;
214 }
215 
216 /*---------------------------------------------------------------------------*
217     Name:           THPPlayerOpen
218 
219     Description:    Opens THP movie file. Loads required data.
220 
221     Arguments:      fileName   Filename of THP movie.
222                     onMemory   Flag to do OnMemory playback or not.
223 
224     Returns:        Returns TRUE if successful, and FALSE if unsuccessful.
225  *---------------------------------------------------------------------------*/
226 
THPPlayerOpen(char * fileName,BOOL onMemory)227 BOOL THPPlayerOpen(char *fileName, BOOL onMemory)
228 {
229     s32 offset, i;
230 
231     if (!Initialized)
232     {
233 #ifdef _DEBUG
234         OSReport("You must call THPPlayerInit before you call this function\n");
235 #endif
236         return FALSE;
237     }
238 
239     if (ActivePlayer.open)
240     {
241 #ifdef _DEBUG
242         OSReport("Can't open %s. Because thp file have already opened.\n");
243 #endif
244         return FALSE;
245     }
246 
247     // Clears current video data and audio data
248     memset(&ActivePlayer.videoInfo, 0, sizeof(THPVideoInfo));
249     memset(&ActivePlayer.audioInfo, 0, sizeof(THPAudioInfo));
250 
251     if (DVDOpen(fileName, &ActivePlayer.fileInfo) == FALSE)
252     {
253 #ifdef _DEBUG
254         OSReport("Can't open %s.\n", fileName);
255 #endif
256         return FALSE;
257     }
258 
259     // Get THP header
260     if (DVDRead(&ActivePlayer.fileInfo, WorkBuffer, 64, 0) < 0)
261     {
262 #ifdef _DEBUG
263         OSReport("Fail to read the header from THP file.\n");
264 #endif
265         DVDClose(&ActivePlayer.fileInfo);
266         return FALSE;
267     }
268 
269     memcpy(&ActivePlayer.header, WorkBuffer, sizeof(THPHeader));
270 
271     // Check if THP movie file
272     if (strcmp(ActivePlayer.header.magic, "THP") != 0)
273     {
274 #ifdef _DEBUG
275         OSReport("This file is not THP file.\n");
276 #endif
277         DVDClose(&ActivePlayer.fileInfo);
278         return FALSE;
279     }
280 
281     // Check version
282     if (ActivePlayer.header.version != THP_VERSION)
283     {
284 #ifdef _DEBUG
285         OSReport("invalid version.\n");
286 #endif
287         DVDClose(&ActivePlayer.fileInfo);
288         return FALSE;
289     }
290 
291     offset = (s32)ActivePlayer.header.compInfoDataOffsets;
292 
293     // Get component data in frame
294     if (DVDRead(&ActivePlayer.fileInfo, WorkBuffer, 32, offset) < 0)
295     {
296 #ifdef _DEBUG
297         OSReport("Fail to read the frame component infomation from THP file.\n");
298 #endif
299         DVDClose(&ActivePlayer.fileInfo);
300         return FALSE;
301     }
302 
303     memcpy(&ActivePlayer.compInfo, WorkBuffer, sizeof(THPFrameCompInfo));
304 
305     offset += sizeof(THPFrameCompInfo);
306 
307     ActivePlayer.audioExist = 0;
308 
309     // Check components in frame
310     for(i = 0 ; i < ActivePlayer.compInfo.numComponents ; i++)
311     {
312         switch(ActivePlayer.compInfo.frameComp[i])
313         {
314             case THP_VIDEO_COMP: // Get video data of components
315                 if (DVDRead(&ActivePlayer.fileInfo, WorkBuffer, 32, offset) < 0)
316                 {
317 #ifdef _DEBUG
318                     OSReport("Fail to read the video infomation from THP file.\n");
319 #endif
320                     DVDClose(&ActivePlayer.fileInfo);
321                     return FALSE;
322                 }
323                 memcpy(&ActivePlayer.videoInfo, WorkBuffer, sizeof(THPVideoInfo));
324                 offset += sizeof(THPVideoInfo);
325                 break;
326             case THP_AUDIO_COMP: // Get audio data of components
327                 if (DVDRead(&ActivePlayer.fileInfo, WorkBuffer, 32, offset) < 0)
328                 {
329 #ifdef _DEBUG
330                     OSReport("Fail to read the video infomation from THP file.\n");
331 #endif
332                     DVDClose(&ActivePlayer.fileInfo);
333                     return FALSE;
334                 }
335                 memcpy(&ActivePlayer.audioInfo, WorkBuffer, sizeof(THPAudioInfo));
336                 ActivePlayer.audioExist = 1;
337                 offset += sizeof(THPAudioInfo);
338 
339                 break;
340             default:
341 #ifdef _DEBUG
342                 OSReport("Unknow frame components.\n");
343 #endif
344                 return FALSE;
345         }
346     }
347 
348     ActivePlayer.state        = ActivePlayer.internalState = THP_PLAYER_STOP;
349     ActivePlayer.playFlag     = 0;
350     ActivePlayer.onMemory     = onMemory;
351     ActivePlayer.open         = TRUE;
352     ActivePlayer.curVolume    = 127.0f;
353     ActivePlayer.targetVolume = ActivePlayer.curVolume;
354     ActivePlayer.rampCount    = 0;
355 
356     return TRUE;
357 }
358 
359 /*---------------------------------------------------------------------------*
360     Name:           THPPlayerClose
361 
362     Description:    Close THP movie file.
363 
364     Arguments:      None
365 
366     Returns:        Returns TRUE if successful, and FALSE if unsuccessful.
367  *---------------------------------------------------------------------------*/
368 
THPPlayerClose(void)369 BOOL THPPlayerClose(void)
370 {
371     if (ActivePlayer.open)
372     {
373         if (ActivePlayer.state == THP_PLAYER_STOP)
374         {
375             ActivePlayer.open = FALSE;
376             DVDClose(&ActivePlayer.fileInfo);
377 
378             return TRUE;
379         }
380     }
381 
382     return FALSE;
383 }
384 
385 /*---------------------------------------------------------------------------*
386     Name:           THPPlayerCalcNeedMemory
387 
388     Description:    Calculates needed memory for THP movie playback
389 
390     Arguments:      None
391 
392     Returns:        Returns needed memory size if successful, and 0 if unsuccessful.
393  *---------------------------------------------------------------------------*/
394 
THPPlayerCalcNeedMemory(void)395 u32 THPPlayerCalcNeedMemory(void)
396 {
397     u32 size;
398 
399     if (ActivePlayer.open)
400     {
401         // Buffer size for read
402         if (ActivePlayer.onMemory)
403         {
404             size = OSRoundUp32B(ActivePlayer.header.movieDataSize);
405         }
406         else
407         {
408             size = OSRoundUp32B(ActivePlayer.header.bufSize) * READ_BUFFER_NUM;
409         }
410 
411         // Size of texture buffer
412         size += OSRoundUp32B(ActivePlayer.videoInfo.xSize * ActivePlayer.videoInfo.ySize)
413               * DECODE_VIDEO_BUFFER_NUM; //Y
414         size += OSRoundUp32B(ActivePlayer.videoInfo.xSize * ActivePlayer.videoInfo.ySize / 4)
415               * DECODE_VIDEO_BUFFER_NUM; //U
416         size += OSRoundUp32B(ActivePlayer.videoInfo.xSize * ActivePlayer.videoInfo.ySize / 4)
417               * DECODE_VIDEO_BUFFER_NUM; //V
418 
419         // Size of audio buffer
420         if (ActivePlayer.audioExist)
421         {
422             size += (OSRoundUp32B(ActivePlayer.header.audioMaxSamples * 4) * DECODE_AUDIO_BUFFER_NUM);
423         }
424 
425         size += THP_WORK_SIZE;
426 
427         return size;
428     }
429 
430     return 0;
431 }
432 
433 /*---------------------------------------------------------------------------*
434     Name:           THPPlayerSetBuffer
435 
436     Description:    Allocate required memory for movie playback to THPPlayer structure.
437 
438     Arguments:      buffer   Pointer to memory area for THP movie set aside externally.
439 
440     Returns:        Returns TRUE if successful, and FALSE if successful.
441  *---------------------------------------------------------------------------*/
442 
THPPlayerSetBuffer(u8 * buffer)443 BOOL THPPlayerSetBuffer(u8 *buffer)
444 {
445     u32 i;
446     u8  *ptr;
447     u32 ysize, uvsize;
448 
449     ASSERTMSG(buffer != NULL, "buffer is NULL");
450 
451     if (ActivePlayer.open && (ActivePlayer.state == THP_PLAYER_STOP))
452     {
453         ptr = buffer;
454 
455         // Set buffer for read
456         if (ActivePlayer.onMemory)
457         {
458             ActivePlayer.movieData = ptr;
459             ptr += ActivePlayer.header.movieDataSize;
460         }
461         else
462         {
463             for (i = 0 ; i < READ_BUFFER_NUM ; i++)
464             {
465                 ActivePlayer.readBuffer[i].ptr = ptr;
466                 ptr += OSRoundUp32B(ActivePlayer.header.bufSize);
467             }
468         }
469 
470         ysize  = OSRoundUp32B(ActivePlayer.videoInfo.xSize * ActivePlayer.videoInfo.ySize);
471         uvsize = OSRoundUp32B(ActivePlayer.videoInfo.xSize * ActivePlayer.videoInfo.ySize / 4);
472 
473         // Set texture buffer
474         for (i = 0 ; i < DECODE_VIDEO_BUFFER_NUM ; i++)
475         {
476             ActivePlayer.textureSet[i].ytexture = ptr;
477             DCInvalidateRange(ptr, ysize);
478             ptr += ysize;
479             ActivePlayer.textureSet[i].utexture = ptr;
480             DCInvalidateRange(ptr, uvsize);
481             ptr += uvsize;
482             ActivePlayer.textureSet[i].vtexture = ptr;
483             DCInvalidateRange(ptr, uvsize);
484             ptr += uvsize;
485         }
486 
487         // Set audio buffer
488         if (ActivePlayer.audioExist)
489         {
490             for (i = 0 ; i < DECODE_AUDIO_BUFFER_NUM ; i++)
491             {
492                 ActivePlayer.audioBuffer[i].buffer = (s16 *)ptr;
493                 ActivePlayer.audioBuffer[i].curPtr = (s16 *)ptr;
494                 ActivePlayer.audioBuffer[i].validSample = 0;
495                 ptr += OSRoundUp32B(ActivePlayer.header.audioMaxSamples * 4);
496             }
497         }
498 
499         ActivePlayer.thpWork = (void *)ptr;
500 
501         return TRUE;
502     }
503 
504     return FALSE;
505 }
506 
507 /*---------------------------------------------------------------------------*
508     Name:           InitAllMessageQueue
509 
510     Description:    Initializes queue used with video decode thread, audio
511                     thread, and read thread.
512 
513     Arguments:      None
514 
515     Returns:        None
516  *---------------------------------------------------------------------------*/
517 
InitAllMessageQueue(void)518 static void InitAllMessageQueue(void)
519 {
520     s32 i;
521     THPReadBuffer  *readBuffer;
522     THPTextureSet  *textureSet;
523     THPAudioBuffer *audioBuffer;
524 
525     // Push all read buffers to free read buffer queue
526     if (!ActivePlayer.onMemory)
527     {
528         for (i = 0 ; i < READ_BUFFER_NUM ; i++)
529         {
530             readBuffer = &ActivePlayer.readBuffer[i];
531             PushFreeReadBuffer(readBuffer);
532         }
533     }
534 
535     // Push all texture buffers for storing decoded THP video data to
536     // free texture buffer queue.
537     for (i = 0 ; i < DECODE_VIDEO_BUFFER_NUM ; i++)
538     {
539         textureSet = &ActivePlayer.textureSet[i];
540         PushFreeTextureSet(textureSet);
541     }
542 
543     // Push all audio buffers for storing decoded THP audio data to
544     // free audio buffer queue.
545     if (ActivePlayer.audioExist)
546     {
547         for (i = 0 ; i < DECODE_AUDIO_BUFFER_NUM ; i++)
548         {
549             audioBuffer = &ActivePlayer.audioBuffer[i];
550             PushFreeAudioBuffer(audioBuffer);
551         }
552     }
553 
554     OSInitMessageQueue(&PrepareReadyQueue,
555                        &PrepareReadyMessage,
556                        1);
557 }
558 
559 /*---------------------------------------------------------------------------*
560     Name:           WaitUntilPrepare
561 
562     Description:    Waits until playback preparations completed.
563 
564     Arguments:      None
565 
566     Returns:        If playback preparations complete, returns TRUE. If preparations fail, returns FALSE.
567  *---------------------------------------------------------------------------*/
568 
WaitUntilPrepare(void)569 static BOOL WaitUntilPrepare(void)
570 {
571     OSMessage msg;
572 
573     OSReceiveMessage(&PrepareReadyQueue, &msg, OS_MESSAGE_BLOCK);
574 
575     if ((BOOL)msg)
576     {
577         return TRUE;
578     }
579     else
580     {
581         return FALSE;
582     }
583 }
584 
585 /*---------------------------------------------------------------------------*
586     Name:           PrepareReady
587 
588     Description:    Sends message about whether or not playback preparations are completed.
589 
590     Arguments:      flag   If playback preparations complete, returns TRUE.  If preparations fail, returns FALSE.
591 
592     Returns:        None
593  *---------------------------------------------------------------------------*/
594 
PrepareReady(BOOL flag)595 void PrepareReady(BOOL flag)
596 {
597     OSSendMessage(&PrepareReadyQueue, (OSMessage)flag, OS_MESSAGE_BLOCK);
598 
599     return;
600 }
601 
602 /*---------------------------------------------------------------------------*
603     Name:           THPPlayerPrepare
604 
605     Description:    Carries out preparations for movie playback. Does not
606                     return until THP movie playback preparations completed.
607                     If the THP movie has no audio, the audioTrack argument is ignored.
608 
609     Arguments:      frameNum   Specifies the frame number of the movie playback.
610                                If the THP movie file does not contain THPFrameOffsetData,
611                                anything other than 0 is an error.
612                     playFlag   Specifies one-shot or loop playback flag.
613                     audioTrack Specifies audio track number to be played back.
614 
615     Returns:        If playback is ready, returns TRUE. If playback preparation fails, returns FALSE.
616  *---------------------------------------------------------------------------*/
617 
THPPlayerPrepare(s32 frameNum,s32 playFlag,s32 audioTrack)618 BOOL THPPlayerPrepare(s32 frameNum, s32 playFlag, s32 audioTrack)
619 {
620     s32 offset;
621     u8  *ptr;
622 
623     if (ActivePlayer.open && (ActivePlayer.state == THP_PLAYER_STOP))
624     {
625         // Check if specified starting frame number is appropriate
626         if (frameNum > 0)
627         {
628             // Does THP movie file have offset data?
629             if (!ActivePlayer.header.offsetDataOffsets)
630             {
631 #ifdef _DEBUG
632                 OSReport("This THP file doesn't have the offset data\n");
633 #endif
634                 return FALSE;
635             }
636 
637             // Does starting frame number exceed total frames?
638             if (ActivePlayer.header.numFrames > frameNum)
639             {
640                 offset = (s32)(ActivePlayer.header.offsetDataOffsets + (frameNum - 1) * 4);
641 
642                 if (DVDRead(&ActivePlayer.fileInfo,
643                             WorkBuffer,
644                             32,
645                             offset) < 0)
646                 {
647 #ifdef _DEBUG
648                     OSReport("Fail to read the offset data from THP file.\n");
649 #endif
650                     return FALSE;
651                 }
652 
653                 // Set starting file offset, frame size, and frame number
654                 ActivePlayer.initOffset    = (s32)(ActivePlayer.header.movieDataOffsets
655                                            + WorkBuffer[0]);
656                 ActivePlayer.initReadFrame = frameNum;
657                 ActivePlayer.initReadSize  = (s32)(WorkBuffer[1] - WorkBuffer[0]);
658             }
659             else
660             {
661 #ifdef _DEBUG
662                 OSReport("Specified frame number is over total frame number\n");
663 #endif
664                 return FALSE;
665             }
666         }
667         // If 0, from beginning
668         else
669         {
670             ActivePlayer.initOffset    = (s32)ActivePlayer.header.movieDataOffsets;
671             ActivePlayer.initReadSize  = (s32)ActivePlayer.header.firstFrameSize;
672             ActivePlayer.initReadFrame = frameNum;
673         }
674 
675         if (ActivePlayer.audioExist)
676         {
677             if (audioTrack < 0 || audioTrack >= ActivePlayer.audioInfo.sndNumTracks)
678             {
679 #ifdef _DEBUG
680                 OSReport("Specified audio track number is invalid\n");
681 #endif
682                 return FALSE;
683             }
684             else
685             {
686                 ActivePlayer.curAudioTrack = audioTrack;
687             }
688         }
689 
690         playFlag                     &= THP_PLAY_LOOP;
691         ActivePlayer.playFlag         = (u8)playFlag;
692         ActivePlayer.videoDecodeCount = 0;
693 
694         // If On Memory playback, load all THP movie data to memory
695         if (ActivePlayer.onMemory)
696         {
697             if (DVDRead(&ActivePlayer.fileInfo,
698                         ActivePlayer.movieData,
699                         (s32)ActivePlayer.header.movieDataSize,
700                         (s32)ActivePlayer.header.movieDataOffsets) < 0)
701             {
702 #ifdef _DEBUG
703                 OSReport("Fail to read all movie data from THP file\n");
704 #endif
705                 return FALSE;
706             }
707 
708             ptr = ActivePlayer.movieData + ActivePlayer.initOffset - ActivePlayer.header.movieDataOffsets;
709 
710             // Create video decode thread
711             CreateVideoDecodeThread(VIDEO_THREAD_PRIORITY, ptr);
712 
713             // Create audio decode thread if required
714             if (ActivePlayer.audioExist)
715             {
716                 CreateAudioDecodeThread(AUDIO_THREAD_PRIORITY, ptr);
717             }
718         }
719         // Not On Memory playback
720         else
721         {
722             // Create video decode thread
723             CreateVideoDecodeThread(VIDEO_THREAD_PRIORITY, NULL);
724 
725             // Create audio decode thread if required
726             if (ActivePlayer.audioExist)
727             {
728                 CreateAudioDecodeThread(AUDIO_THREAD_PRIORITY, NULL);
729             }
730 
731             // Create read thread
732             CreateReadThread(READ_THREAD_PRIORITY);
733         }
734 
735         ActivePlayer.curVideoNumber = -1;
736         ActivePlayer.curAudioNumber = 0;
737 
738         // Initialize queues used with various threads
739         InitAllMessageQueue();
740 
741         VideoDecodeThreadStart();
742 
743         if (ActivePlayer.audioExist)
744         {
745             AudioDecodeThreadStart();
746         }
747 
748         if (!ActivePlayer.onMemory)
749         {
750             ReadThreadStart();
751         }
752 
753         // Wait until thread preparation completed.
754         if (WaitUntilPrepare() == FALSE)
755         {
756             return FALSE;
757         }
758 
759         // If preparations complete, state goes to preparations complete
760         ActivePlayer.state = THP_PLAYER_PREPARE;
761         ActivePlayer.internalState = THP_PLAYER_STOP;
762 
763         // Initialize variables
764         ActivePlayer.dispTextureSet  = NULL;
765         ActivePlayer.playAudioBuffer = NULL;
766 
767         // Register VI post callback that controls playback
768         OldVIPostCallback = VISetPostRetraceCallback(PlayControl);
769 
770         return TRUE;
771     }
772 
773     return FALSE;
774 }
775 
776 /*---------------------------------------------------------------------------*
777     Name:           THPPlayerPlay
778 
779     Description:    Start of movie playback.
780 
781     Arguments:      None
782 
783     Returns:        Returns TRUE if successful, and FALSE if unsuccessful.
784  *---------------------------------------------------------------------------*/
785 
THPPlayerPlay(void)786 BOOL THPPlayerPlay(void)
787 {
788     if (ActivePlayer.open && ((ActivePlayer.state == THP_PLAYER_PREPARE)
789         || (ActivePlayer.state == THP_PLAYER_PAUSE)))
790     {
791         ActivePlayer.state        = THP_PLAYER_PLAY;
792         ActivePlayer.prevCount    = 0;
793         ActivePlayer.curCount     = 0;
794         ActivePlayer.retraceCount = -1;
795 
796         return TRUE;
797     }
798 
799     return FALSE;
800 }
801 
802 /*---------------------------------------------------------------------------*
803     Name:           THPPlayerStop
804 
805     Description:    Stop for movie playback.
806                     Returns VI post callback to original state and stops threads.
807 
808     Arguments:      None
809 
810     Returns:        Returns TRUE if successful, and FALSE if unsuccessful.
811  *---------------------------------------------------------------------------*/
812 
THPPlayerStop(void)813 void THPPlayerStop(void)
814 {
815     void *texture;
816 
817     if (ActivePlayer.open && !(ActivePlayer.state == THP_PLAYER_STOP))
818     {
819         ActivePlayer.state = ActivePlayer.internalState = THP_PLAYER_STOP;
820 
821         // Return VI post callback
822         VISetPostRetraceCallback(OldVIPostCallback);
823 
824         // Cancel if stopping threads and loading data
825         if (!ActivePlayer.onMemory)
826         {
827             DVDCancel(&ActivePlayer.fileInfo.cb);
828             ReadThreadCancel();
829         }
830 
831         VideoDecodeThreadCancel();
832 
833         if (ActivePlayer.audioExist)
834         {
835             AudioDecodeThreadCancel();
836         }
837 
838         // Empty played back texture queues.
839         while (1)
840         {
841             texture = PopUsedTextureSet();
842             if (texture == NULL)
843             {
844                 break;
845             }
846         }
847 
848         ActivePlayer.curVolume = ActivePlayer.targetVolume;
849         ActivePlayer.rampCount = 0;
850 
851         // Clear errors
852         ActivePlayer.dvdError   = FALSE;
853         ActivePlayer.videoError = FALSE;
854     }
855 
856     return;
857 }
858 
859 /*---------------------------------------------------------------------------*
860     Name:           THPPlayerPause
861 
862     Description:    Pause movie playback
863 
864     Arguments:      None
865 
866     Returns:        Returns TRUE if successful, and FALSE if unsuccessful.
867  *---------------------------------------------------------------------------*/
868 
THPPlayerPause(void)869 BOOL THPPlayerPause(void)
870 {
871     if (ActivePlayer.open && (ActivePlayer.state == THP_PLAYER_PLAY))
872     {
873         ActivePlayer.state = ActivePlayer.internalState = THP_PLAYER_PAUSE;
874 
875         return TRUE;
876     }
877 
878     return FALSE;
879 }
880 
881 /*---------------------------------------------------------------------------*
882     Name:           THPPlayerSkip
883 
884     Description:    Skip movie ahead one frame.
885 
886     Arguments:      None
887 
888     Returns:        Returns TRUE if successful, and FALSE if unsuccessful.
889  *---------------------------------------------------------------------------*/
890 
THPPlayerSkip(void)891 BOOL THPPlayerSkip(void)
892 {
893     s32  frameNumber, audioGet, videoGet;
894 
895     if (ActivePlayer.open && (ActivePlayer.state == THP_PLAYER_PAUSE))
896     {
897         // Block in function until get decoded THP video data so
898         // release played back THP video data in advance.
899         THPPlayerDrawDone();
900 
901         // If have audio
902         if (ActivePlayer.audioExist)
903         {
904             frameNumber = ActivePlayer.curAudioNumber + ActivePlayer.initReadFrame;
905 
906             // Check if one shot and also if audio has reached end.
907             if (!(ActivePlayer.playFlag & THP_PLAY_LOOP) && (frameNumber == ActivePlayer.header.numFrames))
908             {
909                 if (ActivePlayer.playAudioBuffer)
910                 {
911                     PushFreeAudioBuffer(ActivePlayer.playAudioBuffer);
912                     ActivePlayer.playAudioBuffer = NULL;
913                 }
914                 audioGet = 0;
915             }
916             else
917             {
918                 // Release current audio buffer
919                 if (ActivePlayer.playAudioBuffer)
920                 {
921                     PushFreeAudioBuffer(ActivePlayer.playAudioBuffer);
922                 }
923 
924                 // Wait until get next audio buffer
925                 ActivePlayer.playAudioBuffer = (THPAudioBuffer *)PopDecodedAudioBuffer(OS_MESSAGE_BLOCK);
926                 ActivePlayer.curAudioNumber++;
927 
928                 audioGet = 1;
929             }
930         }
931 
932         if (ActivePlayer.dispTextureSet)
933         {
934             frameNumber = ActivePlayer.dispTextureSet->frameNumber + ActivePlayer.initReadFrame;
935         }
936         else
937         {
938             frameNumber = ActivePlayer.initReadFrame - 1;
939         }
940 
941         // Check if one shot and also if video has reached end.
942         if (!(ActivePlayer.playFlag & THP_PLAY_LOOP) && (frameNumber == ActivePlayer.header.numFrames - 1))
943         {
944             videoGet = 0;
945         }
946         else
947         {
948             // Release current texture buffer
949             if (ActivePlayer.dispTextureSet)
950             {
951                 PushFreeTextureSet(ActivePlayer.dispTextureSet);
952             }
953 
954             // Wait until get next texture buffer
955             ActivePlayer.dispTextureSet = (THPTextureSet *)PopDecodedTextureSet(OS_MESSAGE_BLOCK);
956 
957             if (ActivePlayer.audioExist)
958             {
959                 ActivePlayer.curVideoNumber++;
960             }
961 
962             videoGet = 1;
963         }
964 
965         if (audioGet || videoGet)
966         {
967             return TRUE;
968         }
969         else
970         {
971             return FALSE;
972         }
973     }
974 
975     return FALSE;
976 }
977 
978 /*---------------------------------------------------------------------------*
979     Name:           PlayControl
980 
981     Description:    Controls movie playback. Gets decoded THP video data at
982                     appropriate timing.
983 
984     Arguments:      retraceCount  Current retrace count
985 
986     Returns:        None
987  *---------------------------------------------------------------------------*/
988 
PlayControl(u32 retraceCount)989 static void PlayControl(u32 retraceCount)
990 {
991     s32 diff, frameNumber;
992     THPTextureSet *textureSet;
993 
994     if (OldVIPostCallback)
995     {
996         OldVIPostCallback(retraceCount);
997     }
998 
999     textureSet = (THPTextureSet *)0xFFFFFFFF;
1000 
1001     if (ActivePlayer.open && (ActivePlayer.state == THP_PLAYER_PLAY))
1002     {
1003         // If an error has occurred, change state to error.
1004         if (ActivePlayer.dvdError || ActivePlayer.videoError)
1005         {
1006             ActivePlayer.state = ActivePlayer.internalState = THP_PLAYER_ERROR;
1007 
1008             return;
1009         }
1010 
1011         ActivePlayer.retraceCount++;
1012 
1013         // When start THP movie playback and when end pause
1014         if (ActivePlayer.retraceCount == 0)
1015         {
1016             // Appropriate timing for start of playback?
1017             if (ProperTimingForStart())
1018             {
1019                 // If THP movie has audio
1020                 if (ActivePlayer.audioExist)
1021                 {
1022                     // Calculate difference between current audio playback frames and current video playback frames
1023                     diff = ActivePlayer.curVideoNumber - ActivePlayer.curAudioNumber;
1024 
1025                     // If audio is not slower than video, move video ahead
1026                     if (diff <= 1)
1027                     {
1028                         // Acquire decoded THP video data
1029                         textureSet = (THPTextureSet *)PopDecodedTextureSet(OS_MESSAGE_NOBLOCK);
1030 
1031                         // Increment THP video data number (ideal value)
1032                         ActivePlayer.curVideoNumber++;
1033                     }
1034                     // Allow audio output if slow
1035                     else
1036                     {
1037                         ActivePlayer.internalState = THP_PLAYER_PLAY;
1038                     }
1039                 }
1040                 // If THP movie has no audio
1041                 else
1042                 {
1043                     textureSet = (THPTextureSet *)PopDecodedTextureSet(OS_MESSAGE_NOBLOCK);
1044                 }
1045             }
1046             // If not appropriate timing, wait for next VSYNC.
1047             else
1048             {
1049                 ActivePlayer.retraceCount = -1;
1050             }
1051         }
1052         // During playback
1053         else
1054         {
1055             // Enables audio output after 1 VSYNC to obtain starting THP video
1056             // data.  It is assumed that the movie rendering loop is looping with 1 VSYNC.
1057             // The reason for this is:
1058             //
1059             // [Flow from THPPlayerPlay to display of starting frame]
1060             //
1061             //           <Call THPPlayerPlay>
1062             //  -----------------VSYNC----------------------------------------
1063             //   <Obtain starting THP video data in VI post-callback>
1064             //   <Render starting THP video data with your rendering loop, and
1065             //    call VISetNextFrameBuffer and VIFlush.>
1066             // ------------------VSYNC----------------------------
1067             // From this point, movie is shown on TV. Audio output is enabled
1068             // with this timing.
1069             if (ActivePlayer.retraceCount == 1)
1070             {
1071                 ActivePlayer.internalState = THP_PLAYER_PLAY;
1072             }
1073 
1074             if (ProperTimingForGettingNextFrame())
1075             {
1076                 // If THP movie has audio
1077                 if (ActivePlayer.audioExist)
1078                 {
1079                     //Calculate difference between current audio playback frames
1080                     diff = ActivePlayer.curVideoNumber - ActivePlayer.curAudioNumber;
1081 
1082                     // If audio is not slower than video, move video ahead
1083                     if (diff <= 1)
1084                     {
1085                         // Acquire decoded THP video data
1086                         textureSet = (THPTextureSet *)PopDecodedTextureSet(OS_MESSAGE_NOBLOCK);
1087 
1088                         // Increment THP video data number (ideal value)
1089                         ActivePlayer.curVideoNumber++;
1090                     }
1091                 }
1092                 // If THP movie has no audio
1093                 else
1094                 {
1095                     // Acquire decoded video data
1096                     textureSet = (THPTextureSet *)PopDecodedTextureSet(OS_MESSAGE_NOBLOCK);
1097                 }
1098             }
1099         }
1100 
1101         // If can get decoded THP video data, push THP video data held until
1102         // that point to cache for data played back.
1103         if (textureSet && (textureSet != (THPTextureSet *)0xFFFFFFFF))
1104         {
1105             if (ActivePlayer.dispTextureSet)
1106             {
1107                 // If you call PushFreeTextureSet here, newly decoded THP video
1108                 // data may be written to the texture buffer the graphics
1109                 // processor is accessing, so the data is pushed to a temporary
1110                 // cache. After verifying with THPPlayerDrawDone() that access from
1111                 // the graphics processor is done, the actual release is done.
1112                 PushUsedTextureSet(ActivePlayer.dispTextureSet);
1113             }
1114             ActivePlayer.dispTextureSet = textureSet;
1115         }
1116 
1117         // Check if playback has reached end during one shot playback
1118         if (!(ActivePlayer.playFlag & THP_PLAY_LOOP))
1119         {
1120             // If THP movie has audio, check if video and audio has reached end
1121             if (ActivePlayer.audioExist)
1122             {
1123                 frameNumber = ActivePlayer.curAudioNumber + ActivePlayer.initReadFrame;
1124 
1125                 // If reached to the end, set state to THP_PLAYER_PLAYED
1126                 if (frameNumber == ActivePlayer.header.numFrames && ActivePlayer.playAudioBuffer == NULL)
1127                 {
1128                     ActivePlayer.state = ActivePlayer.internalState = THP_PLAYER_PLAYED;
1129                 }
1130             }
1131             // If THP movie has audio, check if video has reached end
1132             else
1133             {
1134                 if (ActivePlayer.dispTextureSet)
1135                 {
1136                     frameNumber = ActivePlayer.dispTextureSet->frameNumber + ActivePlayer.initReadFrame;
1137                 }
1138                 else
1139                 {
1140                     frameNumber = ActivePlayer.initReadFrame - 1;
1141                 }
1142 
1143                 if ((frameNumber == ActivePlayer.header.numFrames - 1)
1144                      &&
1145                     (textureSet == NULL))
1146                 {
1147                     ActivePlayer.state = ActivePlayer.internalState = THP_PLAYER_PLAYED;
1148                 }
1149             }
1150         }
1151     }
1152 
1153     return;
1154 }
1155 
1156 /*---------------------------------------------------------------------------*
1157     Name:           ProperTimingForStart
1158 
1159     Description:    Check if appropriate timing for movie playback start.
1160                     Movie rendering loop may be looping with 1 VSYNC.
1161 
1162     Arguments:      None
1163 
1164     Returns:        If appropriate timing returns TRUE. If inappropriate returns FALSE.
1165  *---------------------------------------------------------------------------*/
1166 
ProperTimingForStart(void)1167 static BOOL ProperTimingForStart(void)
1168 {
1169     if (ActivePlayer.videoInfo.videoType & THP_VIDEO_ODD_INTERLACE)
1170     {
1171         if (VIGetNextField() == VI_FIELD_BELOW)
1172         {
1173             return TRUE;
1174         }
1175     }
1176     else if (ActivePlayer.videoInfo.videoType & THP_VIDEO_EVEN_INTERLACE)
1177     {
1178         if (VIGetNextField() == VI_FIELD_ABOVE)
1179         {
1180             return TRUE;
1181         }
1182     }
1183     else
1184     {
1185         return TRUE;
1186     }
1187 
1188     return FALSE;
1189 }
1190 
1191 /*---------------------------------------------------------------------------*
1192     Name:           ProperTimingForGettingNextFrame
1193 
1194     Description:    Checks if appropriate timing to get decoded THP
1195                       video data.
1196 
1197     Arguments:      None
1198 
1199     Returns:        If appropriate timing, returns TRUE. If inappropriate, returns FALSE.
1200  *---------------------------------------------------------------------------*/
1201 
ProperTimingForGettingNextFrame(void)1202 static BOOL ProperTimingForGettingNextFrame(void)
1203 {
1204     s32 frameRate;
1205 
1206     if (ActivePlayer.videoInfo.videoType & THP_VIDEO_ODD_INTERLACE)
1207     {
1208         if (VIGetNextField() == VI_FIELD_BELOW)
1209         {
1210             return TRUE;
1211         }
1212     }
1213     else if (ActivePlayer.videoInfo.videoType & THP_VIDEO_EVEN_INTERLACE)
1214     {
1215         if (VIGetNextField() == VI_FIELD_ABOVE)
1216         {
1217             return TRUE;
1218         }
1219     }
1220     else
1221     {
1222         // Convert framerate to an integer
1223         frameRate = (s32)((ActivePlayer.header.frameRate) * 100.0f);
1224 
1225         if (VIGetTvFormat() == VI_PAL)
1226         {
1227             ActivePlayer.curCount = (s32)((ActivePlayer.retraceCount * frameRate) / PAL_RATE);
1228         }
1229         else
1230         {
1231             ActivePlayer.curCount = (s32)((ActivePlayer.retraceCount * frameRate) / NTSC_RATE);
1232         }
1233 
1234         if (ActivePlayer.prevCount != ActivePlayer.curCount)
1235         {
1236             ActivePlayer.prevCount = ActivePlayer.curCount;
1237             return TRUE;
1238         }
1239     }
1240 
1241     return FALSE;
1242 }
1243 
1244 /*---------------------------------------------------------------------------*
1245     Name:           THPPlayerDrawCurrentFrame
1246 
1247     Description:    Draw currently acquired decoded THP video data.
1248                     If none acquired, not displayed.
1249 
1250     Arguments:      rmode    Pointer for currently set GXRenderModeObj
1251                     x        X coordinate of upper left TV screen for THP movie display
1252                     y        Y coordinate of upper left TV screen for THP movie display
1253                     polygonW Width of polygon for THP movie display
1254                     polygonH Height of polygon for THP movie display
1255 
1256     Returns:        If able to draw, return drawn frame number. If unable to draw, return -1.
1257  *---------------------------------------------------------------------------*/
1258 
THPPlayerDrawCurrentFrame(GXRenderModeObj * rmode,u32 x,u32 y,u32 polygonW,u32 polygonH)1259 s32 THPPlayerDrawCurrentFrame(GXRenderModeObj *rmode, u32 x, u32 y, u32 polygonW, u32 polygonH)
1260 {
1261     s32 currentFrameNumber;
1262 
1263     if (ActivePlayer.open && !(ActivePlayer.state == THP_PLAYER_STOP) && ActivePlayer.dispTextureSet)
1264     {
1265         THPGXYuv2RgbSetup(rmode);
1266         THPGXYuv2RgbDraw(ActivePlayer.dispTextureSet->ytexture,
1267                          ActivePlayer.dispTextureSet->utexture,
1268                          ActivePlayer.dispTextureSet->vtexture,
1269                          (s16)x, (s16)y,
1270                          (s16)ActivePlayer.videoInfo.xSize, (s16)ActivePlayer.videoInfo.ySize,
1271                          (s16)polygonW, (s16)polygonH);
1272 
1273         THPGXRestore();
1274 
1275         currentFrameNumber = (s32)((ActivePlayer.dispTextureSet->frameNumber + ActivePlayer.initReadFrame)
1276                            % ActivePlayer.header.numFrames);
1277 
1278         return currentFrameNumber;
1279     }
1280 
1281     return -1;
1282 }
1283 
1284 /*---------------------------------------------------------------------------*
1285     Name:           THPPlayerGetVideoInfo
1286 
1287     Description:    Get THP movie video data.
1288 
1289     Arguments:      videoInfo  Pointer for THPVideoInfo structure.
1290 
1291     Returns:        If successful, returns TRUE. If unsuccessful, returns FALSE.
1292  *---------------------------------------------------------------------------*/
1293 
THPPlayerGetVideoInfo(THPVideoInfo * videoInfo)1294 BOOL THPPlayerGetVideoInfo(THPVideoInfo *videoInfo)
1295 {
1296     if (ActivePlayer.open)
1297     {
1298         memcpy(videoInfo, &ActivePlayer.videoInfo, sizeof(THPVideoInfo));
1299 
1300         return TRUE;
1301     }
1302 
1303     return FALSE;
1304 }
1305 
1306 /*---------------------------------------------------------------------------*
1307     Name:           THPPlayerGetAudioInfo
1308 
1309     Description:    Get THP movie audio data.
1310 
1311     Arguments:      audioInfo  Pointer for THPAudioInfo structure.
1312 
1313     Returns:        If successful, returns TRUE. If unsuccessful, returns FALSE.
1314  *---------------------------------------------------------------------------*/
1315 
THPPlayerGetAudioInfo(THPAudioInfo * audioInfo)1316 BOOL THPPlayerGetAudioInfo(THPAudioInfo *audioInfo)
1317 {
1318     if (ActivePlayer.open)
1319     {
1320         memcpy(audioInfo, &ActivePlayer.audioInfo, sizeof(THPAudioInfo));
1321 
1322         return TRUE;
1323     }
1324 
1325     return FALSE;
1326 }
1327 
1328 /*---------------------------------------------------------------------------*
1329     Name:           THPPlayerGetFrameRate
1330 
1331     Description:    Get THP movie frame rate
1332 
1333     Arguments:      None
1334 
1335     Returns:        If successful, returns THP movie frame rate. If unsuccessful,  returns 0.0f.
1336  *---------------------------------------------------------------------------*/
1337 
THPPlayerGetFrameRate(void)1338 f32 THPPlayerGetFrameRate(void)
1339 {
1340     if (ActivePlayer.open)
1341     {
1342 
1343         return ActivePlayer.header.frameRate;
1344     }
1345 
1346     return 0.0f;
1347 }
1348 
1349 /*---------------------------------------------------------------------------*
1350     Name:           THPPlayerGetTotalFrame
1351 
1352     Description:    Acquire total frames for THP movie
1353 
1354     Arguments:      None
1355 
1356     Returns:        If successful, returns THP movie total frames. If unsuccessful, returns 0.
1357  *---------------------------------------------------------------------------*/
1358 
THPPlayerGetTotalFrame(void)1359 u32 THPPlayerGetTotalFrame(void)
1360 {
1361     if (ActivePlayer.open)
1362     {
1363         return ActivePlayer.header.numFrames;
1364     }
1365 
1366     return 0;
1367 }
1368 
1369 /*---------------------------------------------------------------------------*
1370     Name:           THPPlayerGetState
1371 
1372     Description:    Acquire current player status.
1373 
1374     Arguments:      None
1375 
1376     Returns:        Player status
1377                     THP_PLAYER_STOP    stopped
1378                     THP_PLAYER_PREPARE preparations completed
1379                     THP_PLAYER_PLAY    playing
1380                     THP_PLAYER_PLAYED  played THP movie to end
1381                     THP_PLAYER_ERROR   error occurred
1382  *---------------------------------------------------------------------------*/
1383 
THPPlayerGetState(void)1384 s32 THPPlayerGetState(void)
1385 {
1386     return ActivePlayer.state;
1387 }
1388 
1389 /*---------------------------------------------------------------------------*
1390     Name:           PushUsedTextureSet
1391 
1392     Description:    Remove played back THP video data from played back THP
1393                     video data queue.
1394 
1395     Arguments:      None
1396 
1397     Returns:        None
1398  *---------------------------------------------------------------------------*/
1399 
PushUsedTextureSet(void * buffer)1400 static void PushUsedTextureSet(void *buffer)
1401 {
1402     OSSendMessage(&UsedTextureSetQueue, buffer, OS_MESSAGE_NOBLOCK);
1403 
1404     return;
1405 }
1406 
1407 /*---------------------------------------------------------------------------*
1408     Name:           PopUsedTextureSet
1409 
1410     Description:    Remove played back THP video data from played back THP
1411                     video data queue.
1412 
1413     Arguments:      None
1414 
1415     Returns:        Pointer for played back THP video data.
1416  *---------------------------------------------------------------------------*/
1417 
PopUsedTextureSet(void)1418 static void *PopUsedTextureSet(void)
1419 {
1420     OSMessage msg;
1421 
1422     if (OSReceiveMessage(&UsedTextureSetQueue, &msg, OS_MESSAGE_NOBLOCK) == TRUE)
1423     {
1424         return msg;
1425     }
1426     else
1427     {
1428         return NULL;
1429     }
1430 }
1431 
1432 /*---------------------------------------------------------------------------*
1433     Name:           THPPlayerDrawDone
1434 
1435     Description:    Function used instead of GXDrawDone to synchronize with
1436                     the graphics processor during movie playback. It waits for
1437                     the graphics processor to complete processing and frees
1438                     internally THP video data determined to be played back.
1439 
1440     Arguments:      None
1441 
1442     Returns:        None
1443  *---------------------------------------------------------------------------*/
1444 
THPPlayerDrawDone(void)1445 void THPPlayerDrawDone(void)
1446 {
1447     void *textureSet;
1448 
1449     GXDrawDone();
1450 
1451     if (Initialized)
1452     {
1453         while(1)
1454         {
1455             textureSet = PopUsedTextureSet();
1456             if (textureSet == NULL)
1457             {
1458                 break;
1459             }
1460             else
1461             {
1462                 PushFreeTextureSet(textureSet);
1463             }
1464         }
1465     }
1466 }
1467 
1468 /*---------------------------------------------------------------------------*
1469     Name:           THPAudioMixCallback
1470 
1471     Description:    AI callback function for player.
1472                     Call callback functions of AX and MusyX internally when
1473                     used with AX and MusyX, and mix output data of AX and
1474                     MusyX with THP audio data.
1475 
1476     Arguments:      None
1477 
1478     Returns:        None
1479  *---------------------------------------------------------------------------*/
1480 
THPAudioMixCallback(void)1481 void THPAudioMixCallback(void)
1482 {
1483     BOOL old;
1484 
1485     if (AudioSystem == THP_MODE_ALONE)
1486     {
1487         SoundBufferIndex ^= 1;
1488 
1489         AIInitDMA((u32)SoundBuffer[SoundBufferIndex], BYTES_PER_AUDIO_FRAME);
1490 
1491         old = OSEnableInterrupts();
1492 
1493         MixAudio(SoundBuffer[SoundBufferIndex], NULL, SAMPLES_PER_AUDIO_FRAME);
1494 
1495         DCFlushRange(SoundBuffer[SoundBufferIndex], BYTES_PER_AUDIO_FRAME);
1496 
1497         OSRestoreInterrupts(old);
1498     }
1499     else
1500     {
1501         if (AudioSystem == THP_MODE_WITH_AX)
1502         {
1503             if (LastAudioBuffer)
1504             {
1505                 CurAudioBuffer = LastAudioBuffer;
1506             }
1507 
1508             OldAIDCallback();
1509 
1510             LastAudioBuffer = (s16 *)OSPhysicalToCached(AIGetDMAStartAddr());
1511         }
1512         else
1513         {
1514             OldAIDCallback();
1515 
1516             CurAudioBuffer = (s16 *)OSPhysicalToCached(AIGetDMAStartAddr());
1517         }
1518 
1519         SoundBufferIndex ^= 1;
1520 
1521         AIInitDMA((u32)SoundBuffer[SoundBufferIndex], BYTES_PER_AUDIO_FRAME);
1522 
1523         old = OSEnableInterrupts();
1524 
1525         if (CurAudioBuffer)
1526         {
1527             DCInvalidateRange(CurAudioBuffer, BYTES_PER_AUDIO_FRAME);
1528         }
1529 
1530         MixAudio(SoundBuffer[SoundBufferIndex], CurAudioBuffer, SAMPLES_PER_AUDIO_FRAME);
1531 
1532         DCFlushRange(SoundBuffer[SoundBufferIndex], BYTES_PER_AUDIO_FRAME);
1533 
1534         OSRestoreInterrupts(old);
1535     }
1536 }
1537 
1538 /*---------------------------------------------------------------------------*
1539     Name:           MixAudio
1540 
1541     Description:    Mix THP audio data in the specified buffer.
1542 
1543     Arguments:      destination Buffer in which mixed data is stored.
1544                     source      Output buffer from audio library
1545                     sample      Sample number of audio data to be mixed.
1546                                 Specified by stereo sample.
1547 
1548     Returns:        None
1549  *---------------------------------------------------------------------------*/
1550 
MixAudio(s16 * destination,s16 * source,u32 sample)1551 static void MixAudio(s16 *destination, s16 *source, u32 sample)
1552 {
1553     u32 sampleNum, requestSample, i;
1554     s32 mix;
1555     s16 *dst, *libsrc, *thpsrc;
1556     u16 attenuation;
1557 
1558     // When mixed with audio library output
1559     if (source)
1560     {
1561         if (ActivePlayer.open && (ActivePlayer.internalState == THP_PLAYER_PLAY) && ActivePlayer.audioExist)
1562         {
1563             requestSample = sample;
1564             dst           = destination;
1565             libsrc        = source;
1566 
1567             while (1)
1568             {
1569                 if (ActivePlayer.playAudioBuffer == NULL)
1570                 {
1571                     if ((ActivePlayer.playAudioBuffer = (THPAudioBuffer *)PopDecodedAudioBuffer(OS_MESSAGE_NOBLOCK)) == NULL)
1572                     {
1573                         memcpy(dst, libsrc, requestSample << 2);
1574                         break;
1575                     }
1576                     else
1577                     {
1578                         ActivePlayer.curAudioNumber++;
1579                     }
1580                 }
1581 
1582                 if (ActivePlayer.playAudioBuffer->validSample)
1583                 {
1584                     if (ActivePlayer.playAudioBuffer->validSample >= requestSample)
1585                     {
1586                         sampleNum = requestSample;
1587                     }
1588                     else
1589                     {
1590                         sampleNum = ActivePlayer.playAudioBuffer->validSample;
1591                     }
1592 
1593                     thpsrc = ActivePlayer.playAudioBuffer->curPtr;
1594 
1595                     // Mixing
1596                     for (i = 0 ; i < sampleNum ; i++)
1597                     {
1598                         if (ActivePlayer.rampCount)
1599                         {
1600                             ActivePlayer.rampCount--;
1601                             ActivePlayer.curVolume += ActivePlayer.deltaVolume;
1602                         }
1603                         else
1604                         {
1605                             ActivePlayer.curVolume = ActivePlayer.targetVolume;
1606                         }
1607 
1608                         attenuation = VolumeTable[(s32)ActivePlayer.curVolume];
1609 
1610                         // Right
1611                         mix = (*libsrc) + ((attenuation * (*thpsrc)) >> 15);
1612 
1613                         if (mix < -32768)
1614                         {
1615                             mix = -32768;
1616                         }
1617                         if (mix > 32767)
1618                         {
1619                             mix = 32767;
1620                         }
1621 
1622                         *dst = (s16)mix;
1623                         dst++;
1624                         libsrc++;
1625                         thpsrc++;
1626 
1627                         // Left
1628                         mix = (*libsrc) + ((attenuation * (*thpsrc)) >> 15);
1629 
1630                         if (mix < -32768)
1631                         {
1632                             mix = -32768;
1633                         }
1634                         if (mix > 32767)
1635                         {
1636                             mix = 32767;
1637                         }
1638 
1639                         *dst = (s16)mix;
1640                         dst++;
1641                         libsrc++;
1642                         thpsrc++;
1643                     }
1644 
1645                     requestSample -= sampleNum;
1646 
1647                     ActivePlayer.playAudioBuffer->validSample -= sampleNum;
1648                     ActivePlayer.playAudioBuffer->curPtr       = thpsrc;
1649 
1650                     if (ActivePlayer.playAudioBuffer->validSample == 0)
1651                     {
1652                         // Release used THP audio data
1653                         PushFreeAudioBuffer(ActivePlayer.playAudioBuffer);
1654                         ActivePlayer.playAudioBuffer = NULL;
1655                     }
1656 
1657                     if (!requestSample)
1658                     {
1659                         break;
1660                     }
1661                 }
1662             }
1663         }
1664         else
1665         {
1666             memcpy(destination, source, sample << 2);
1667         }
1668     }
1669     // When not mixing with audio library output
1670     else
1671     {
1672         if (ActivePlayer.open && (ActivePlayer.internalState == THP_PLAYER_PLAY) && ActivePlayer.audioExist)
1673         {
1674             requestSample = sample;
1675             dst           = destination;
1676 
1677             while (1)
1678             {
1679                 if (ActivePlayer.playAudioBuffer == NULL)
1680                 {
1681                     if ((ActivePlayer.playAudioBuffer = (THPAudioBuffer *)PopDecodedAudioBuffer(OS_MESSAGE_NOBLOCK)) == NULL)
1682                     {
1683                         memset(dst, 0, requestSample << 2);
1684                         break;
1685                     }
1686                     else
1687                     {
1688                         ActivePlayer.curAudioNumber++;
1689                     }
1690                 }
1691 
1692                 if (ActivePlayer.playAudioBuffer->validSample)
1693                 {
1694                     if (ActivePlayer.playAudioBuffer->validSample >= requestSample)
1695                     {
1696                         sampleNum = requestSample;
1697                     }
1698                     else
1699                     {
1700                         sampleNum = ActivePlayer.playAudioBuffer->validSample;
1701                     }
1702 
1703                     thpsrc = ActivePlayer.playAudioBuffer->curPtr;
1704 
1705                     // Mixing
1706                     for (i = 0 ; i < sampleNum ; i++)
1707                     {
1708                         if (ActivePlayer.rampCount)
1709                         {
1710                             ActivePlayer.rampCount--;
1711                             ActivePlayer.curVolume += ActivePlayer.deltaVolume;
1712                         }
1713                         else
1714                         {
1715                             ActivePlayer.curVolume = ActivePlayer.targetVolume;
1716                         }
1717 
1718                         attenuation = VolumeTable[(s32)ActivePlayer.curVolume];
1719 
1720                         // Right
1721                         mix = (attenuation * (*thpsrc)) >> 15;
1722 
1723                         if (mix < -32768)
1724                         {
1725                             mix = -32768;
1726                         }
1727                         if (mix > 32767)
1728                         {
1729                             mix = 32767;
1730                         }
1731 
1732                         *dst = (s16)mix;
1733                         dst++;
1734                         thpsrc++;
1735 
1736                         // Left
1737                         mix = (attenuation * (*thpsrc)) >> 15;
1738 
1739                         if (mix < -32768)
1740                         {
1741                             mix = -32768;
1742                         }
1743                         if (mix > 32767)
1744                         {
1745                             mix = 32767;
1746                         }
1747 
1748                         *dst = (s16)mix;
1749                         dst++;
1750                         thpsrc++;
1751                     }
1752 
1753                     requestSample -= sampleNum;
1754 
1755                     ActivePlayer.playAudioBuffer->validSample -= sampleNum;
1756                     ActivePlayer.playAudioBuffer->curPtr       = thpsrc;
1757 
1758                     if (ActivePlayer.playAudioBuffer->validSample == 0)
1759                     {
1760                         // Release used THP audio data
1761                         PushFreeAudioBuffer(ActivePlayer.playAudioBuffer);
1762                         ActivePlayer.playAudioBuffer = NULL;
1763                     }
1764 
1765                     if (!requestSample)
1766                     {
1767                         break;
1768                     }
1769                 }
1770             }
1771         }
1772         else
1773         {
1774             memset(destination, 0, sample << 2);
1775         }
1776     }
1777 
1778     return;
1779 }
1780 
1781 /*---------------------------------------------------------------------------*
1782     Name:           THPPlayerSetVolume
1783 
1784     Description:    Set volume of player. Volume will be changed in the
1785                     specified time.
1786 
1787     Arguments:      vol  volume to be set (0 - 127)
1788                     time Specify the time required to go from current volume to
1789                          specified volume in units of milliseconds (0 - 60000)
1790 
1791     Returns:        Returns TRUE if succeeds, and FALSE if fails.
1792  *---------------------------------------------------------------------------*/
1793 
THPPlayerSetVolume(s32 vol,s32 time)1794 BOOL THPPlayerSetVolume(s32 vol, s32 time)
1795 {
1796     BOOL old;
1797     s32  samplePerMs;
1798 
1799     if (ActivePlayer.open && ActivePlayer.audioExist)
1800     {
1801         if (AIGetDSPSampleRate() == AI_SAMPLERATE_32KHZ)
1802         {
1803             samplePerMs = 32;
1804         }
1805         else
1806         {
1807             samplePerMs = 48;
1808         }
1809 
1810         if (vol > 127)
1811         {
1812             vol = 127;
1813         }
1814 
1815         if (vol < 0)
1816         {
1817             vol = 0;
1818         }
1819 
1820         if (time > 60000)
1821         {
1822             time = 60000;
1823         }
1824 
1825         if (time < 0)
1826         {
1827             time = 0;
1828         }
1829 
1830         old = OSDisableInterrupts();
1831 
1832         ActivePlayer.targetVolume = (f32)vol;
1833 
1834         if (time)
1835         {
1836             ActivePlayer.rampCount   = samplePerMs * time;
1837             ActivePlayer.deltaVolume = (ActivePlayer.targetVolume - ActivePlayer.curVolume)
1838                                      / (f32)ActivePlayer.rampCount;
1839         }
1840         else
1841         {
1842             ActivePlayer.rampCount = 0;
1843             ActivePlayer.curVolume = ActivePlayer.targetVolume;
1844         }
1845 
1846         OSRestoreInterrupts(old);
1847 
1848         return TRUE;
1849     }
1850 
1851     return FALSE;
1852 }
1853 
1854 /*---------------------------------------------------------------------------*
1855     Name:           THPPlayerGetVolume
1856 
1857     Description:    Acquire current volume of player
1858 
1859     Arguments:      None
1860 
1861     Returns:        Returns current playback volume if successful, and -1 if unsuccessful.
1862  *---------------------------------------------------------------------------*/
1863 
THPPlayerGetVolume(void)1864 s32 THPPlayerGetVolume(void)
1865 {
1866     if (ActivePlayer.open)
1867     {
1868         return (s32)ActivePlayer.curVolume;
1869     }
1870 
1871     return -1;
1872 }
1873