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