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.1  02/03/2006 10:01:27  aka
15   Imported from Dolphin tree.
16 
17 
18     4     03/11/25 11:24 Dante
19     Japanese to English translation of comments and text strings
20 
21     3     03/09/16 15:50:00 Suzuki
22     changed the process which skips to decode when decoding is delay.
23 
24     2     03/06/12 15:33 Suzuki
25     corresponded to multi audio frequency.
26 
27     1     02/05/31 8:57a Suzuki
28     Initial check-in.
29 
30   $NoKeywords: $
31 
32  *---------------------------------------------------------------------------*/
33 
34 #include <string.h>
35 #include <revolution.h>
36 #include <revolution/mix.h>
37 
38 #include "THPPlayerStrmAX.h"
39 #include "THPVideoDecode.h"
40 #include "THPAudioDecode.h"
41 #include "THPRead.h"
42 #include "THPDraw.h"
43 
44 /*---------------------------------------------------------------------------*
45    Definition
46  *---------------------------------------------------------------------------*/
47 
48 #define STREAM_BUFFER_MS 40
49 #define BOUNDARY_NUM 5
50 
51 enum
52 {
53     SUCCESS,
54     EMPTY_AUDIO_BUFFER,
55     EMPTY_AUDIO_DATA
56 };
57 
58 typedef struct
59 {
60     u64 boundary[BOUNDARY_NUM];
61     s32 top;
62     s32 bottom;
63     u32 lastPos;
64     u64 curSampleNum;
65     u64 endSampleNum;
66 } AudioStreamInfo;
67 
68 /*---------------------------------------------------------------------------*
69    Global Function
70  *---------------------------------------------------------------------------*/
71 
72 void PrepareReady(BOOL flag);
73 
74 /*---------------------------------------------------------------------------*
75    Static Function
76  *---------------------------------------------------------------------------*/
77 
78 static void PlayControl(u32 retraceCount);
79 static BOOL ProperTimingForStart(void);
80 static BOOL ProperTimingForGettingNextFrame(void);
81 static void PushUsedTextureSet(THPTextureSet *buffer);
82 static void *PopUsedTextureSet(void);
83 
84 #ifndef HOLLYWOOD_REV
85 static void InitAramTransferDone(u32 user);
86 #endif
87 
88 static void EntryBoundary(u64 boundarySampleNum);
89 static void CheckBoundary(u64 curSampleNum);
90 static void TransferStreamData(s32 flag);
91 static u32  GetAudioSample(s16 *left, s16 *right, u32 sample, s32 *reason);
92 static void FillStreamBuffer(s16 *left, s16 *right, u32 sample);
93 static u32  StreamUpdateCallback(void *buffer1, u32 len1, void *buffer2, u32 len2, u32 user);
94 static BOOL StreamInit(void);
95 static void StreamReInit(void);
96 static void StreamPlay(void);
97 static void StreamPause(void);
98 static void StreamQuit(void);
99 
100 /*---------------------------------------------------------------------------*
101    Global Function
102  *---------------------------------------------------------------------------*/
103 
104 THPPlayer ActivePlayer;
105 
106 /*---------------------------------------------------------------------------*
107    Static Function
108  *---------------------------------------------------------------------------*/
109 
110 static BOOL              Initialized = FALSE;
111 static s16               WorkBuffer[24 * STREAM_BUFFER_MS] ATTRIBUTE_ALIGN(32);
112 static OSMessageQueue    PrepareReadyQueue;
113 static OSMessageQueue    UsedTextureSetQueue;
114 static OSMessage         PrepareReadyMessage[2];
115 static OSMessage         UsedTextureSetMessage[DECODE_VIDEO_BUFFER_NUM];
116 static VIRetraceCallback OldVIPostCallback = NULL;
117 
118 static AXVPB           *StreamL = NULL;
119 static AXVPB           *StreamR = NULL;
120 static s16             *StreamBufferL = NULL;
121 static s16             *StreamBufferR = NULL;
122 static AudioStreamInfo StreamInfo;
123 
124 #ifndef HOLLYWOOD_REV
125 static u32             AmemoryL = 0;
126 static u32             AmemoryR = 0;
127 static ARQRequest      TaskL;
128 static ARQRequest      TaskR;
129 static OSMessageQueue  InitAramTransferQueue;
130 static OSMessage       InitAramTransferMessage;
131 #endif
132 
133 /*---------------------------------------------------------------------------*
134     Name:           THPPlayerInit
135 
136     Description:    Enables locked-cache, and initializes player and THP library.
137 
138     Arguments:      None
139 
140     Returns:        Returns TRUE if successful, and FALSE if unsuccessful.
141  *---------------------------------------------------------------------------*/
142 
THPPlayerInit(void)143 BOOL THPPlayerInit(void)
144 {
145     memset(&ActivePlayer, 0, sizeof(THPPlayer));
146 
147     LCEnable();
148 
149     OSInitMessageQueue(&UsedTextureSetQueue,
150                        UsedTextureSetMessage,
151                        DECODE_VIDEO_BUFFER_NUM);
152 
153     if (THPInit() == FALSE)
154     {
155         return FALSE;
156     }
157 
158     Initialized = TRUE;
159 
160     return TRUE;
161 }
162 
163 /*---------------------------------------------------------------------------*
164     Name:           THPPlayerQuit
165 
166     Description:    Disables locked cache.
167 
168     Arguments:      None
169 
170     Returns:        None
171  *---------------------------------------------------------------------------*/
172 
THPPlayerQuit(void)173 void THPPlayerQuit(void)
174 {
175     LCDisable();
176 
177     Initialized = FALSE;
178 
179     return;
180 }
181 
182 /*---------------------------------------------------------------------------*
183     Name:           THPPlayerOpen
184 
185     Description:    Opens THP movie file. Loads required data.
186 
187     Arguments:      fileName   Filename of THP movie.
188                     onMemory   Flag to do OnMemory playback or not.
189 
190     Returns:        Returns TRUE if successful, and FALSE if unsuccessful.
191  *---------------------------------------------------------------------------*/
192 
THPPlayerOpen(char * fileName,BOOL onMemory)193 BOOL THPPlayerOpen(char *fileName, BOOL onMemory)
194 {
195     s32 offset, i;
196 
197     if (!Initialized)
198     {
199 #ifdef _DEBUG
200         OSReport("You must call THPPlayerInit before you call this function\n");
201 #endif
202         return FALSE;
203     }
204 
205     if (ActivePlayer.open)
206     {
207 #ifdef _DEBUG
208         OSReport("Can't open %s. Because thp file have already opened.\n");
209 #endif
210         return FALSE;
211     }
212 
213     // Clears current video data and audio data
214     memset(&ActivePlayer.videoInfo, 0, sizeof(THPVideoInfo));
215     memset(&ActivePlayer.audioInfo, 0, sizeof(THPAudioInfo));
216 
217     if (DVDOpen(fileName, &ActivePlayer.fileInfo) == FALSE)
218     {
219 #ifdef _DEBUG
220         OSReport("Can't open %s.\n", fileName);
221 #endif
222         return FALSE;
223     }
224 
225     // Get THP header
226     if (DVDRead(&ActivePlayer.fileInfo, WorkBuffer, 64, 0) < 0)
227     {
228 #ifdef _DEBUG
229         OSReport("Fail to read the header from THP file.\n");
230 #endif
231         DVDClose(&ActivePlayer.fileInfo);
232         return FALSE;
233     }
234 
235     memcpy(&ActivePlayer.header, WorkBuffer, sizeof(THPHeader));
236 
237     // Check if THP movie file
238     if (strcmp(ActivePlayer.header.magic, "THP") != 0)
239     {
240 #ifdef _DEBUG
241         OSReport("This file is not THP file.\n");
242 #endif
243         DVDClose(&ActivePlayer.fileInfo);
244         return FALSE;
245     }
246 
247     // Check version
248     if (ActivePlayer.header.version != THP_VERSION)
249     {
250 #ifdef _DEBUG
251         OSReport("invalid version.\n");
252 #endif
253         DVDClose(&ActivePlayer.fileInfo);
254         return FALSE;
255     }
256 
257     offset = (s32)ActivePlayer.header.compInfoDataOffsets;
258 
259     // Acquire component data in frame
260     if (DVDRead(&ActivePlayer.fileInfo, WorkBuffer, 32, offset) < 0)
261     {
262 #ifdef _DEBUG
263         OSReport("Fail to read the frame component infomation from THP file.\n");
264 #endif
265         DVDClose(&ActivePlayer.fileInfo);
266         return FALSE;
267     }
268 
269     memcpy(&ActivePlayer.compInfo, WorkBuffer, sizeof(THPFrameCompInfo));
270 
271     offset += sizeof(THPFrameCompInfo);
272 
273     ActivePlayer.audioExist = 0;
274 
275     // Check components in frame
276     for(i = 0 ; i < ActivePlayer.compInfo.numComponents ; i++)
277     {
278         switch(ActivePlayer.compInfo.frameComp[i])
279         {
280             case THP_VIDEO_COMP: // Get video data of components
281                 if (DVDRead(&ActivePlayer.fileInfo, WorkBuffer, 32, offset) < 0)
282                 {
283 #ifdef _DEBUG
284                     OSReport("Fail to read the video infomation from THP file.\n");
285 #endif
286                     DVDClose(&ActivePlayer.fileInfo);
287                     return FALSE;
288                 }
289                 memcpy(&ActivePlayer.videoInfo, WorkBuffer, sizeof(THPVideoInfo));
290                 offset += sizeof(THPVideoInfo);
291                 break;
292             case THP_AUDIO_COMP: // Get audio data of components
293                 if (DVDRead(&ActivePlayer.fileInfo, WorkBuffer, 32, offset) < 0)
294                 {
295 #ifdef _DEBUG
296                     OSReport("Fail to read the video infomation from THP file.\n");
297 #endif
298                     DVDClose(&ActivePlayer.fileInfo);
299                     return FALSE;
300                 }
301                 memcpy(&ActivePlayer.audioInfo, WorkBuffer, sizeof(THPAudioInfo));
302                 ActivePlayer.audioExist = 1;
303                 offset += sizeof(THPAudioInfo);
304 
305                 break;
306             default:
307 #ifdef _DEBUG
308                 OSReport("Unknow frame components.\n");
309 #endif
310                 return FALSE;
311         }
312     }
313 
314     ActivePlayer.state    = ActivePlayer.internalState = THP_PLAYER_STOP;
315     ActivePlayer.playFlag = 0;
316     ActivePlayer.onMemory = onMemory;
317     ActivePlayer.open     = TRUE;
318 
319     return TRUE;
320 }
321 
322 /*---------------------------------------------------------------------------*
323     Name:           THPPlayerClose
324 
325     Description:    Close THP movie file.
326 
327     Arguments:      None
328 
329     Returns:        Returns TRUE if successful, and FALSE if unsuccessful.
330  *---------------------------------------------------------------------------*/
331 
THPPlayerClose(void)332 BOOL THPPlayerClose(void)
333 {
334     if (ActivePlayer.open)
335     {
336         if (ActivePlayer.state == THP_PLAYER_STOP)
337         {
338             ActivePlayer.open = FALSE;
339             DVDClose(&ActivePlayer.fileInfo);
340 
341             return TRUE;
342         }
343     }
344 
345     return FALSE;
346 }
347 
348 /*---------------------------------------------------------------------------*
349     Name:           THPPlayerCalcNeedMemory
350 
351     Description:    Calculates needed memory for THP movie playback
352 
353     Arguments:      None
354 
355     Returns:        Returns needed memory size if successful, and 0 if unsuccessful.
356  *---------------------------------------------------------------------------*/
357 
THPPlayerCalcNeedMemory(void)358 u32 THPPlayerCalcNeedMemory(void)
359 {
360     u32 size;
361 
362     if (ActivePlayer.open)
363     {
364         // Buffer size for read
365         if (ActivePlayer.onMemory)
366         {
367             size = OSRoundUp32B(ActivePlayer.header.movieDataSize);
368         }
369         else
370         {
371             size = OSRoundUp32B(ActivePlayer.header.bufSize) * READ_BUFFER_NUM;
372         }
373 
374         // Size of texture buffer
375         size += OSRoundUp32B(ActivePlayer.videoInfo.xSize * ActivePlayer.videoInfo.ySize)
376               * DECODE_VIDEO_BUFFER_NUM; //Y
377         size += OSRoundUp32B(ActivePlayer.videoInfo.xSize * ActivePlayer.videoInfo.ySize / 4)
378               * DECODE_VIDEO_BUFFER_NUM; //U
379         size += OSRoundUp32B(ActivePlayer.videoInfo.xSize * ActivePlayer.videoInfo.ySize / 4)
380               * DECODE_VIDEO_BUFFER_NUM; //V
381 
382         // Size of audio buffer
383         if (ActivePlayer.audioExist)
384         {
385             size += (OSRoundUp32B(ActivePlayer.header.audioMaxSamples * 4) * DECODE_AUDIO_BUFFER_NUM);
386             size += (OSRoundUp32B(STREAM_BUFFER_MS * ActivePlayer.audioInfo.sndFrequency / 1000.0f + 0.5f) * 2
387                   * ActivePlayer.audioInfo.sndChannels);
388         }
389 
390         size += THP_WORK_SIZE;
391 
392         return size;
393     }
394 
395     return 0;
396 }
397 
398 /*---------------------------------------------------------------------------*
399     Name:           THPPlayerSetBuffer
400 
401     Description:    Allocate required memory for movie playback to THPPlayer structure.
402 
403     Arguments:      Pointer to memory area for THP movie set aside externally.
404 
405     Returns:        Returns TRUE if successful, and FALSE if unsuccessful.
406  *---------------------------------------------------------------------------*/
407 
THPPlayerSetBuffer(u8 * buffer)408 BOOL THPPlayerSetBuffer(u8 *buffer)
409 {
410     u32 i;
411     u8  *ptr;
412     u32 ysize, uvsize;
413 
414     ASSERTMSG(buffer != NULL, "buffer is NULL");
415 
416     if (ActivePlayer.open && (ActivePlayer.state == THP_PLAYER_STOP))
417     {
418         ptr = buffer;
419 
420         // Set buffer for read
421         if (ActivePlayer.onMemory)
422         {
423             ActivePlayer.movieData = ptr;
424             ptr += ActivePlayer.header.movieDataSize;
425         }
426         else
427         {
428             for (i = 0 ; i < READ_BUFFER_NUM ; i++)
429             {
430                 ActivePlayer.readBuffer[i].ptr = ptr;
431                 ptr += OSRoundUp32B(ActivePlayer.header.bufSize);
432             }
433         }
434 
435         ysize  = OSRoundUp32B(ActivePlayer.videoInfo.xSize * ActivePlayer.videoInfo.ySize);
436         uvsize = OSRoundUp32B(ActivePlayer.videoInfo.xSize * ActivePlayer.videoInfo.ySize / 4);
437 
438         // Set texture buffer
439         for (i = 0 ; i < DECODE_VIDEO_BUFFER_NUM ; i++)
440         {
441             ActivePlayer.textureSet[i].ytexture = ptr;
442             DCInvalidateRange(ptr, ysize);
443             ptr += ysize;
444             ActivePlayer.textureSet[i].utexture = ptr;
445             DCInvalidateRange(ptr, uvsize);
446             ptr += uvsize;
447             ActivePlayer.textureSet[i].vtexture = ptr;
448             DCInvalidateRange(ptr, uvsize);
449             ptr += uvsize;
450         }
451 
452         // Set audio buffer
453         if (ActivePlayer.audioExist)
454         {
455             for (i = 0 ; i < DECODE_AUDIO_BUFFER_NUM ; i++)
456             {
457                 ActivePlayer.audioBuffer[i].buffer = (s16 *)ptr;
458                 ActivePlayer.audioBuffer[i].curPtr = (s16 *)ptr;
459                 ActivePlayer.audioBuffer[i].validSample = 0;
460                 ptr += OSRoundUp32B(ActivePlayer.header.audioMaxSamples * 4);
461             }
462 
463             StreamBufferL = (s16 *)ptr;
464             ptr += (OSRoundUp32B(STREAM_BUFFER_MS * ActivePlayer.audioInfo.sndFrequency / 1000.0f + 0.5f) * 2);
465             if (ActivePlayer.audioInfo.sndChannels == 2)
466             {
467                 StreamBufferR = (s16 *)ptr;
468                 ptr += (OSRoundUp32B(STREAM_BUFFER_MS * ActivePlayer.audioInfo.sndFrequency / 1000.0f + 0.5f) * 2);
469             }
470         }
471 
472         ActivePlayer.thpWork = (void *)ptr;
473 
474         return TRUE;
475     }
476 
477     return FALSE;
478 }
479 
480 /*---------------------------------------------------------------------------*
481     Name:           InitAllMessageQueue
482 
483     Description:    Initializes queue used with video decode thread, audio
484                     thread, and read thread.
485 
486     Arguments:      None
487 
488     Returns:        None
489  *---------------------------------------------------------------------------*/
490 
InitAllMessageQueue(void)491 static void InitAllMessageQueue(void)
492 {
493     s32 i;
494     THPReadBuffer  *readBuffer;
495     THPTextureSet  *textureSet;
496     THPAudioBuffer *audioBuffer;
497 
498     // Push all read buffers to free read buffer queue
499     if (!ActivePlayer.onMemory)
500     {
501         for (i = 0 ; i < READ_BUFFER_NUM ; i++)
502         {
503             readBuffer = &ActivePlayer.readBuffer[i];
504             PushFreeReadBuffer(readBuffer);
505         }
506     }
507 
508     // Push all texture buffers for storing decoded THP video data to
509     // free texture buffer queue.
510     for (i = 0 ; i < DECODE_VIDEO_BUFFER_NUM ; i++)
511     {
512         textureSet = &ActivePlayer.textureSet[i];
513         PushFreeTextureSet(textureSet);
514     }
515 
516     // Push all audio buffers for storing decoded THP audio data to
517     // free audio buffer queue.
518     if (ActivePlayer.audioExist)
519     {
520         for (i = 0 ; i < DECODE_AUDIO_BUFFER_NUM ; i++)
521         {
522             audioBuffer = &ActivePlayer.audioBuffer[i];
523             PushFreeAudioBuffer(audioBuffer);
524         }
525     }
526 
527     OSInitMessageQueue(&PrepareReadyQueue,
528                        PrepareReadyMessage,
529                        2);
530 }
531 
532 /*---------------------------------------------------------------------------*
533     Name:           WaitUntilPrepare
534 
535     Description:    Waits until playback preparations completed.
536 
537     Arguments:      None
538 
539     Returns:        If playback preparations complete, returns TRUE. If preparations fail, returns FALSE.
540  *---------------------------------------------------------------------------*/
541 
WaitUntilPrepare(void)542 static BOOL WaitUntilPrepare(void)
543 {
544     OSMessage msg1, msg2;
545 
546     if (ActivePlayer.audioExist)
547     {
548         OSReceiveMessage(&PrepareReadyQueue, &msg1, OS_MESSAGE_BLOCK);
549         OSReceiveMessage(&PrepareReadyQueue, &msg2, OS_MESSAGE_BLOCK);
550 
551         if ((BOOL)msg1 && (BOOL)msg2)
552         {
553             return TRUE;
554         }
555         else
556         {
557             return FALSE;
558         }
559     }
560     else
561     {
562         OSReceiveMessage(&PrepareReadyQueue, &msg1, OS_MESSAGE_BLOCK);
563 
564         if ((BOOL)msg1)
565         {
566             return TRUE;
567         }
568         else
569         {
570             return FALSE;
571         }
572     }
573 }
574 
575 /*---------------------------------------------------------------------------*
576     Name:           PrepareReady
577 
578     Description:    Sends message about whether or not playback preparations are completed.
579 
580     Arguments:      flag   If playback preparations completed, returns TRUE. If preparations fail, returns FALSE.
581 
582     Returns:        None
583  *---------------------------------------------------------------------------*/
584 
PrepareReady(BOOL flag)585 void PrepareReady(BOOL flag)
586 {
587     OSSendMessage(&PrepareReadyQueue, (OSMessage)flag, OS_MESSAGE_BLOCK);
588 
589     return;
590 }
591 
592 /*---------------------------------------------------------------------------*
593     Name:           THPPlayerPrepare
594 
595     Description:    Carries out preparations for movie playback. Does not
596                     return until THP movie playback preparations are completed.
597 
598     Arguments:      frameNum   Specifies the frame number of the movie playback.
599                                If the THP movie file does not contain THPFrameOffsetData,
600                                anything other than 0 is an error.
601                     playFlag   Specifies one-shot or loop playback flag.
602                     audioTrack Specifies audio track number to be played back.
603 
604     Returns:        If playback is ready, returns TRUE. If playback preparation fails, returns FALSE.
605  *---------------------------------------------------------------------------*/
606 
THPPlayerPrepare(s32 frameNum,s32 playFlag,s32 audioTrack)607 BOOL THPPlayerPrepare(s32 frameNum, s32 playFlag, s32 audioTrack)
608 {
609     s32 offset;
610     u8  *ptr;
611 
612     if (ActivePlayer.open && (ActivePlayer.state == THP_PLAYER_STOP))
613     {
614         // Check if specified starting frame number is appropriate
615         if (frameNum > 0)
616         {
617             // Does THP movie file have offset data?
618             if (!ActivePlayer.header.offsetDataOffsets)
619             {
620 #ifdef _DEBUG
621                 OSReport("This THP file doesn't have the offset data\n");
622 #endif
623                 return FALSE;
624             }
625 
626             // Does starting frame number exceed total frames?
627             if (ActivePlayer.header.numFrames > frameNum)
628             {
629                 offset = (s32)(ActivePlayer.header.offsetDataOffsets + (frameNum - 1) * 4);
630 
631                 if (DVDRead(&ActivePlayer.fileInfo,
632                             WorkBuffer,
633                             32,
634                             offset) < 0)
635                 {
636 #ifdef _DEBUG
637                     OSReport("Fail to read the offset data from THP file.\n");
638 #endif
639                     return FALSE;
640                 }
641 
642                 // Set starting file offset, frame size, and frame number
643                 ActivePlayer.initOffset    = (s32)(ActivePlayer.header.movieDataOffsets
644                                            + WorkBuffer[0]);
645                 ActivePlayer.initReadFrame = frameNum;
646                 ActivePlayer.initReadSize  = (s32)(WorkBuffer[1] - WorkBuffer[0]);
647             }
648             else
649             {
650 #ifdef _DEBUG
651                 OSReport("Specified frame number is over total frame number\n");
652 #endif
653                 return FALSE;
654             }
655         }
656         // If 0, from beginning
657         else
658         {
659             ActivePlayer.initOffset    = (s32)ActivePlayer.header.movieDataOffsets;
660             ActivePlayer.initReadSize  = (s32)ActivePlayer.header.firstFrameSize;
661             ActivePlayer.initReadFrame = frameNum;
662         }
663 
664         if (ActivePlayer.audioExist)
665         {
666             if (audioTrack < 0 || audioTrack >= ActivePlayer.audioInfo.sndNumTracks)
667             {
668 #ifdef _DEBUG
669             OSReport("Specified audio track number is invalid\n");
670 #endif
671                 return FALSE;
672             }
673             else
674             {
675                 ActivePlayer.curAudioTrack = audioTrack;
676             }
677         }
678 
679         playFlag                     &= THP_PLAY_LOOP;
680         ActivePlayer.playFlag         = (u8)playFlag;
681         ActivePlayer.videoDecodeCount = 0;
682 
683         // If On Memory playback, load all THP movie data to memory
684         if (ActivePlayer.onMemory)
685         {
686             if (DVDRead(&ActivePlayer.fileInfo,
687                         ActivePlayer.movieData,
688                         (s32)ActivePlayer.header.movieDataSize,
689                         (s32)ActivePlayer.header.movieDataOffsets) < 0)
690             {
691 #ifdef _DEBUG
692                 OSReport("Fail to read all movie data from THP file\n");
693 #endif
694                 return FALSE;
695             }
696 
697             ptr = ActivePlayer.movieData + ActivePlayer.initOffset - ActivePlayer.header.movieDataOffsets;
698 
699             // Create video decode thread
700             CreateVideoDecodeThread(VIDEO_THREAD_PRIORITY, ptr);
701 
702             // Create audio decode thread if required
703             if (ActivePlayer.audioExist)
704             {
705                 CreateAudioDecodeThread(AUDIO_THREAD_PRIORITY, ptr);
706             }
707         }
708         // Not On Memory playback
709         else
710         {
711             // Create video decode thread
712             CreateVideoDecodeThread(VIDEO_THREAD_PRIORITY, NULL);
713 
714             // Create audio decode thread if required
715             if (ActivePlayer.audioExist)
716             {
717                 CreateAudioDecodeThread(AUDIO_THREAD_PRIORITY, NULL);
718             }
719 
720             // Create read thread
721             CreateReadThread(READ_THREAD_PRIORITY);
722         }
723 
724         ActivePlayer.curVideoNumber = -1;
725         ActivePlayer.curAudioNumber = 0;
726 
727         // Initialize queues used with various threads
728         InitAllMessageQueue();
729 
730         VideoDecodeThreadStart();
731 
732         if (ActivePlayer.audioExist)
733         {
734             AudioDecodeThreadStart();
735         }
736 
737         if (!ActivePlayer.onMemory)
738         {
739             ReadThreadStart();
740         }
741 
742         // Wait until thread preparation completed.
743         if (WaitUntilPrepare() == FALSE)
744         {
745             return FALSE;
746         }
747 
748         // If preparations complete, state goes to preparations complete
749         ActivePlayer.state = THP_PLAYER_PREPARE;
750         ActivePlayer.internalState = THP_PLAYER_STOP;
751 
752         // Initialize variables
753         ActivePlayer.dispTextureSet  = NULL;
754         ActivePlayer.playAudioBuffer = NULL;
755 
756         if (ActivePlayer.audioExist)
757         {
758             StreamInit();
759         }
760 
761         // Register VI post callback that controls playback
762         OldVIPostCallback = VISetPostRetraceCallback(PlayControl);
763 
764         return TRUE;
765     }
766 
767     return FALSE;
768 }
769 
770 /*---------------------------------------------------------------------------*
771     Name:           THPPlayerPlay
772 
773     Description:    Start of movie playback.
774 
775     Arguments:      None
776 
777     Returns:        Returns TRUE if successful, and FALSE if unsuccessful.
778  *---------------------------------------------------------------------------*/
779 
THPPlayerPlay(void)780 BOOL THPPlayerPlay(void)
781 {
782     if (ActivePlayer.open && ((ActivePlayer.state == THP_PLAYER_PREPARE)
783         || (ActivePlayer.state == THP_PLAYER_PAUSE)))
784     {
785         if (ActivePlayer.state == THP_PLAYER_PAUSE && ActivePlayer.audioExist)
786         {
787             StreamReInit();
788         }
789         ActivePlayer.state        = THP_PLAYER_PLAY;
790         ActivePlayer.prevCount    = 0;
791         ActivePlayer.curCount     = 0;
792         ActivePlayer.retraceCount = -1;
793 
794         return TRUE;
795     }
796 
797     return FALSE;
798 }
799 
800 /*---------------------------------------------------------------------------*
801     Name:           THPPlayerStop
802 
803     Description:    Stop for movie playback.
804                     Returns VI post callback to original state and stops threads.
805 
806     Arguments:      None
807 
808     Returns:        Returns TRUE if successful, and FALSE if unsuccessful.
809  *---------------------------------------------------------------------------*/
810 
THPPlayerStop(void)811 void THPPlayerStop(void)
812 {
813     void *texture;
814 
815     if (ActivePlayer.open && !(ActivePlayer.state == THP_PLAYER_STOP))
816     {
817         ActivePlayer.state = ActivePlayer.internalState = THP_PLAYER_STOP;
818 
819         // Return VI post callback
820         VISetPostRetraceCallback(OldVIPostCallback);
821 
822         // Cancel if stopping threads and loading data
823         if (!ActivePlayer.onMemory)
824         {
825             DVDCancel(&ActivePlayer.fileInfo.cb);
826             ReadThreadCancel();
827         }
828 
829         VideoDecodeThreadCancel();
830 
831         if (ActivePlayer.audioExist)
832         {
833             StreamQuit();
834             AudioDecodeThreadCancel();
835         }
836 
837         // Empty played back texture queues.
838         while (1)
839         {
840             texture = PopUsedTextureSet();
841             if (texture == NULL)
842             {
843                 break;
844             }
845         }
846 
847         // Clear errors
848         ActivePlayer.dvdError   = FALSE;
849         ActivePlayer.videoError = FALSE;
850     }
851 
852     return;
853 }
854 
855 /*---------------------------------------------------------------------------*
856     Name:           THPPlayerPause
857 
858     Description:    Pause movie playback
859 
860     Arguments:      None
861 
862     Returns:        Returns TRUE if successful, and FALSE if unsuccessful.
863  *---------------------------------------------------------------------------*/
864 
THPPlayerPause(void)865 BOOL THPPlayerPause(void)
866 {
867     if (ActivePlayer.open && (ActivePlayer.state == THP_PLAYER_PLAY))
868     {
869         ActivePlayer.state = ActivePlayer.internalState = THP_PLAYER_PAUSE;
870 
871         if (ActivePlayer.audioExist)
872         {
873             StreamPause();
874         }
875 
876         return TRUE;
877     }
878 
879     return FALSE;
880 }
881 
882 /*---------------------------------------------------------------------------*
883     Name:           THPPlayerSkip
884 
885     Description:    Skip movie ahead one frame.
886 
887     Arguments:      None
888 
889     Returns:        Returns TRUE if successful, and FALSE if unsuccessful.
890  *---------------------------------------------------------------------------*/
891 
THPPlayerSkip(void)892 BOOL THPPlayerSkip(void)
893 {
894     s32  frameNumber, audioGet, videoGet;
895 
896     if (ActivePlayer.open && (ActivePlayer.state == THP_PLAYER_PAUSE))
897     {
898         // Function is blocked until decoded THP video data is acquired,
899         // so release the played THP video data in advance.
900         THPPlayerDrawDone();
901 
902         // If have audio
903         if (ActivePlayer.audioExist)
904         {
905             if (StreamInfo.top != StreamInfo.bottom)
906             {
907                 StreamInfo.curSampleNum = StreamInfo.boundary[StreamInfo.top];
908                 StreamInfo.top++;
909                 if (StreamInfo.top >= BOUNDARY_NUM)
910                 {
911                     StreamInfo.top = 0;
912                 }
913 
914                 ActivePlayer.curAudioNumber++;
915                 audioGet = 1;
916             }
917             else
918             {
919                 StreamInfo.curSampleNum = StreamInfo.endSampleNum;
920 
921                 frameNumber = ActivePlayer.curAudioNumber + ActivePlayer.initReadFrame;
922 
923                 // Check if one shot and also if audio has reached end.
924                 if (!(ActivePlayer.playFlag & THP_PLAY_LOOP) && (frameNumber >= ActivePlayer.header.numFrames - 1))
925                 {
926                     if (ActivePlayer.playAudioBuffer)
927                     {
928                         PushFreeAudioBuffer(ActivePlayer.playAudioBuffer);
929                         ActivePlayer.playAudioBuffer = NULL;
930                         ActivePlayer.curAudioNumber++;
931                     }
932                     audioGet = 0;
933                 }
934                 else
935                 {
936                     // Release current audio buffer
937                     if (ActivePlayer.playAudioBuffer)
938                     {
939                         PushFreeAudioBuffer(ActivePlayer.playAudioBuffer);
940                     }
941 
942                     // Wait until get next audio buffer
943                     ActivePlayer.playAudioBuffer = (THPAudioBuffer *)PopDecodedAudioBuffer(OS_MESSAGE_BLOCK);
944                     ActivePlayer.curAudioNumber++;
945 
946                     audioGet = 1;
947                 }
948             }
949         }
950 
951         if (ActivePlayer.dispTextureSet)
952         {
953             frameNumber = ActivePlayer.dispTextureSet->frameNumber + ActivePlayer.initReadFrame;
954         }
955         else
956         {
957             frameNumber = ActivePlayer.initReadFrame - 1;
958         }
959 
960         // Check if one shot and also if video has reached end.
961         if (!(ActivePlayer.playFlag & THP_PLAY_LOOP) && (frameNumber == ActivePlayer.header.numFrames - 1))
962         {
963             videoGet = 0;
964         }
965         else
966         {
967             // Release current texture buffer
968             if (ActivePlayer.dispTextureSet)
969             {
970                 PushFreeTextureSet(ActivePlayer.dispTextureSet);
971             }
972 
973             // Wait until the next texture buffer is acquired
974             ActivePlayer.dispTextureSet = (THPTextureSet *)PopDecodedTextureSet(OS_MESSAGE_BLOCK);
975 
976             if (ActivePlayer.audioExist)
977             {
978                 ActivePlayer.curVideoNumber++;
979             }
980 
981             videoGet = 1;
982         }
983 
984         if (audioGet || videoGet)
985         {
986             return TRUE;
987         }
988         else
989         {
990             return FALSE;
991         }
992     }
993 
994     return FALSE;
995 }
996 
997 /*---------------------------------------------------------------------------*
998     Name:           PlayControl
999 
1000     Description:    Controls movie playback. Gets decoded THP video data at
1001                     appropriate timing.
1002 
1003     Arguments:      retraceCount  Current retrace count
1004 
1005     Returns:        None
1006  *---------------------------------------------------------------------------*/
1007 
PlayControl(u32 retraceCount)1008 static void PlayControl(u32 retraceCount)
1009 {
1010     s32 diff, frameNumber;
1011     THPTextureSet *textureSet;
1012 
1013     if (OldVIPostCallback)
1014     {
1015         OldVIPostCallback(retraceCount);
1016     }
1017 
1018     textureSet = (THPTextureSet *)0xFFFFFFFF;
1019 
1020     if (ActivePlayer.open && (ActivePlayer.state == THP_PLAYER_PLAY))
1021     {
1022         // If an error has occurred, change state to error.
1023         if (ActivePlayer.dvdError || ActivePlayer.videoError)
1024         {
1025             ActivePlayer.state = ActivePlayer.internalState = THP_PLAYER_ERROR;
1026 
1027             return;
1028         }
1029 
1030         ActivePlayer.retraceCount++;
1031 
1032         // When start THP movie playback and when end pause
1033         if (ActivePlayer.retraceCount == 0)
1034         {
1035             // Appropriate timing for start of playback?
1036             if (ProperTimingForStart())
1037             {
1038                 // If THP movie has audio
1039                 if (ActivePlayer.audioExist)
1040                 {
1041                     // Calculate difference between current audio playback frames and current video playback frames
1042                     diff = ActivePlayer.curVideoNumber - ActivePlayer.curAudioNumber;
1043 
1044                     // If audio is not behind video, move video forward
1045                     if (diff <= 1)
1046                     {
1047                         // Get decoded THP video data
1048                         textureSet = (THPTextureSet *)PopDecodedTextureSet(OS_MESSAGE_NOBLOCK);
1049 
1050                         // Increment THP video data number (ideal value)
1051                         ActivePlayer.curVideoNumber++;
1052                     }
1053                     // Allow audio output if slow
1054                     else
1055                     {
1056                         StreamPlay();
1057                         ActivePlayer.internalState = THP_PLAYER_PLAY;
1058                     }
1059                 }
1060                 // If THP movie has no audio
1061                 else
1062                 {
1063                     textureSet = (THPTextureSet *)PopDecodedTextureSet(OS_MESSAGE_NOBLOCK);
1064                 }
1065             }
1066             // If not appropriate timing, wait for next VSYNC.
1067             else
1068             {
1069                 ActivePlayer.retraceCount = -1;
1070             }
1071         }
1072         // During playback
1073         else
1074         {
1075             // Enables audio output after 1 VSYNC to obtain starting THP video
1076             // data.  It is assumed that the movie rendering loop is looping with 1 VSYNC.
1077             // The reason for this is:
1078             //
1079             // [Flow from THPPlayerPlay to display of starting frame]
1080             //
1081             //           <Call THPPlayerPlay>
1082             //  -----------------VSYNC---------------------------
1083             //   <Obtain starting THP video data in VI post-callback>
1084             //   <Render starting THP video data with your rendering loop, and
1085             //    call VISetNextFrameBuffer and VIFlush.>
1086             // ------------------VSYNC----------------------------
1087             // From this point, the movie is shown on TV. Audio output is enabled
1088             // with this timing.
1089             if (ActivePlayer.audioExist && ActivePlayer.retraceCount == 1 && ActivePlayer.internalState != THP_PLAYER_PLAY)
1090             {
1091                 StreamPlay();
1092                 ActivePlayer.internalState = THP_PLAYER_PLAY;
1093             }
1094 
1095             if (ProperTimingForGettingNextFrame())
1096             {
1097                 // If THP movie has audio
1098                 if (ActivePlayer.audioExist)
1099                 {
1100                     // Calculate difference between current audio playback frames and current video playback frames
1101                     diff = ActivePlayer.curVideoNumber - ActivePlayer.curAudioNumber;
1102 
1103                     // If audio is not slower than video, move video ahead
1104                     if (diff <= 1)
1105                     {
1106                         // Get decoded THP video data
1107                         textureSet = (THPTextureSet *)PopDecodedTextureSet(OS_MESSAGE_NOBLOCK);
1108 
1109                         // Increment THP video data number (ideal value)
1110                         ActivePlayer.curVideoNumber++;
1111                     }
1112                 }
1113                 // If THP movie has no audio
1114                 else
1115                 {
1116                     // Acquire decoded video data
1117                     textureSet = (THPTextureSet *)PopDecodedTextureSet(OS_MESSAGE_NOBLOCK);
1118                 }
1119             }
1120         }
1121 
1122         // If decoded THP video data can be acquired, push the THP video data
1123         // that has been held until that point to the cache for data played back.
1124         if (textureSet && (textureSet != (THPTextureSet *)0xFFFFFFFF))
1125         {
1126             if (ActivePlayer.dispTextureSet)
1127             {
1128                 // If you call PushFreeTextureSet here, newly decoded THP video
1129                 // data may be written to the texture buffer that the graphics
1130                 // processor is accessing, so the data is pushed to a temporary
1131                 // cache. After verifying with THPPlayerDrawDone() that access from
1132                 // the graphics processor is done, the actual release is done.
1133                 PushUsedTextureSet(ActivePlayer.dispTextureSet);
1134             }
1135             ActivePlayer.dispTextureSet = textureSet;
1136         }
1137 
1138         // Check if playback has reached end during one shot playback
1139         if (!(ActivePlayer.playFlag & THP_PLAY_LOOP))
1140         {
1141             // If THP movie has audio, check if video and audio has reached end.
1142             if (ActivePlayer.audioExist)
1143             {
1144                 frameNumber = ActivePlayer.curAudioNumber + ActivePlayer.initReadFrame;
1145 
1146                 // If the end has been reached, set state to THP_PLAYER_PLAYED.
1147                 if (frameNumber == ActivePlayer.header.numFrames && ActivePlayer.playAudioBuffer == NULL)
1148                 {
1149                     ActivePlayer.state = ActivePlayer.internalState = THP_PLAYER_PLAYED;
1150                 }
1151             }
1152             // If THP movie has audio, check whether the video has reached the end.
1153             else
1154             {
1155                 if (ActivePlayer.dispTextureSet)
1156                 {
1157                     frameNumber = ActivePlayer.dispTextureSet->frameNumber + ActivePlayer.initReadFrame;
1158                 }
1159                 else
1160                 {
1161                     frameNumber = ActivePlayer.initReadFrame - 1;
1162                 }
1163 
1164                 if ((frameNumber == ActivePlayer.header.numFrames - 1)
1165                      &&
1166                     (textureSet == NULL))
1167                 {
1168                     ActivePlayer.state = ActivePlayer.internalState = THP_PLAYER_PLAYED;
1169                 }
1170             }
1171         }
1172     }
1173 
1174     return;
1175 }
1176 
1177 /*---------------------------------------------------------------------------*
1178     Name:           ProperTimingForStart
1179 
1180     Description:    Check whether the timing is appropriate for movie playback
1181                     start. Movie rendering loop may be looping with 1 VSYNC.
1182 
1183     Arguments:      None
1184 
1185     Returns:        If appropriate timing, returns TRUE. If inappropriate, returns FALSE.
1186  *---------------------------------------------------------------------------*/
1187 
ProperTimingForStart(void)1188 static BOOL ProperTimingForStart(void)
1189 {
1190     if (ActivePlayer.videoInfo.videoType & THP_VIDEO_ODD_INTERLACE)
1191     {
1192         if (VIGetNextField() == VI_FIELD_BELOW)
1193         {
1194             return TRUE;
1195         }
1196     }
1197     else if (ActivePlayer.videoInfo.videoType & THP_VIDEO_EVEN_INTERLACE)
1198     {
1199         if (VIGetNextField() == VI_FIELD_ABOVE)
1200         {
1201             return TRUE;
1202         }
1203     }
1204     else
1205     {
1206         return TRUE;
1207     }
1208 
1209     return FALSE;
1210 }
1211 
1212 /*---------------------------------------------------------------------------*
1213     Name:           ProperTimingForGettingNextFrame
1214 
1215     Description:    Checks whether the timing is appropriate for getting decoded
1216                     THP video data.
1217 
1218     Arguments:      None
1219 
1220     Returns:        If appropriate timing, returns TRUE. If inappropriate, returns FALSE.
1221  *---------------------------------------------------------------------------*/
1222 
ProperTimingForGettingNextFrame(void)1223 static BOOL ProperTimingForGettingNextFrame(void)
1224 {
1225     s32 frameRate;
1226 
1227     if (ActivePlayer.videoInfo.videoType & THP_VIDEO_ODD_INTERLACE)
1228     {
1229         if (VIGetNextField() == VI_FIELD_BELOW)
1230         {
1231             return TRUE;
1232         }
1233     }
1234     else if (ActivePlayer.videoInfo.videoType & THP_VIDEO_EVEN_INTERLACE)
1235     {
1236         if (VIGetNextField() == VI_FIELD_ABOVE)
1237         {
1238             return TRUE;
1239         }
1240     }
1241     else
1242     {
1243         // Convert framerate to an integer
1244         frameRate = (s32)((ActivePlayer.header.frameRate) * 100.0f);
1245 
1246         if (VIGetTvFormat() == VI_PAL)
1247         {
1248             ActivePlayer.curCount = (s32)((ActivePlayer.retraceCount * frameRate) / PAL_RATE);
1249         }
1250         else
1251         {
1252             ActivePlayer.curCount = (s32)((ActivePlayer.retraceCount * frameRate) / NTSC_RATE);
1253         }
1254 
1255         if (ActivePlayer.prevCount != ActivePlayer.curCount)
1256         {
1257             ActivePlayer.prevCount = ActivePlayer.curCount;
1258             return TRUE;
1259         }
1260     }
1261 
1262     return FALSE;
1263 }
1264 
1265 /*---------------------------------------------------------------------------*
1266     Name:           THPPlayerDrawCurrentFrame
1267 
1268     Description:    Draw currently acquired decoded THP video data.
1269                     If none acquired, not displayed.
1270 
1271     Arguments:      rmode  Pointer for currently set GXRenderModeObj
1272                     x        X coordinate of upper left TV screen for THP movie display
1273                     y        Y coordinate of upper left TV screen for THP movie display
1274                     polygonW Width of polygon for THP movie display
1275                     polygonH Height of polygon for THP movie display
1276 
1277     Returns:        If able to draw, returns drawn frame number. If unable to draw, returns -1.
1278  *---------------------------------------------------------------------------*/
1279 
THPPlayerDrawCurrentFrame(GXRenderModeObj * rmode,u32 x,u32 y,u32 polygonW,u32 polygonH)1280 s32 THPPlayerDrawCurrentFrame(GXRenderModeObj *rmode, u32 x, u32 y, u32 polygonW, u32 polygonH)
1281 {
1282     s32 currentFrameNumber;
1283 
1284     if (ActivePlayer.open && !(ActivePlayer.state == THP_PLAYER_STOP) && ActivePlayer.dispTextureSet)
1285     {
1286         THPGXYuv2RgbSetup(rmode);
1287         THPGXYuv2RgbDraw(ActivePlayer.dispTextureSet->ytexture,
1288                          ActivePlayer.dispTextureSet->utexture,
1289                          ActivePlayer.dispTextureSet->vtexture,
1290                          (s16)x, (s16)y,
1291                          (s16)ActivePlayer.videoInfo.xSize, (s16)ActivePlayer.videoInfo.ySize,
1292                          (s16)polygonW, (s16)polygonH);
1293 
1294         THPGXRestore();
1295 
1296         currentFrameNumber = (s32)((ActivePlayer.dispTextureSet->frameNumber + ActivePlayer.initReadFrame)
1297                            % ActivePlayer.header.numFrames);
1298 
1299         return currentFrameNumber;
1300     }
1301 
1302     return -1;
1303 }
1304 
1305 /*---------------------------------------------------------------------------*
1306     Name:           THPPlayerGetVideoInfo
1307 
1308     Description:    Acquire THP movie video data.
1309 
1310     Arguments:      videoInfo  Pointer for THPVideoInfo structure.
1311 
1312     Returns:        Returns TRUE if successful, and FALSE if unsuccessful.
1313  *---------------------------------------------------------------------------*/
1314 
THPPlayerGetVideoInfo(THPVideoInfo * videoInfo)1315 BOOL THPPlayerGetVideoInfo(THPVideoInfo *videoInfo)
1316 {
1317     if (ActivePlayer.open)
1318     {
1319         memcpy(videoInfo, &ActivePlayer.videoInfo, sizeof(THPVideoInfo));
1320 
1321         return TRUE;
1322     }
1323 
1324     return FALSE;
1325 }
1326 
1327 /*---------------------------------------------------------------------------*
1328     Name:           THPPlayerGetAudioInfo
1329 
1330     Description:    Acquire THP movie audio data.
1331 
1332     Arguments:      audioInfo  Pointer for THPAudioInfo structure.
1333 
1334     Returns:        Returns TRUE if successful, and FALSE if unsuccessful.
1335  *---------------------------------------------------------------------------*/
1336 
THPPlayerGetAudioInfo(THPAudioInfo * audioInfo)1337 BOOL THPPlayerGetAudioInfo(THPAudioInfo *audioInfo)
1338 {
1339     if (ActivePlayer.open)
1340     {
1341         memcpy(audioInfo, &ActivePlayer.audioInfo, sizeof(THPAudioInfo));
1342 
1343         return TRUE;
1344     }
1345 
1346     return FALSE;
1347 }
1348 
1349 /*---------------------------------------------------------------------------*
1350     Name:           THPPlayerGetFrameRate
1351 
1352     Description:    Acquire THP movie frame rate
1353 
1354     Arguments:      None
1355 
1356     Returns:        If successful, returns THP movie frame rate. If unsuccessful,  returns 0.0f.
1357  *---------------------------------------------------------------------------*/
1358 
THPPlayerGetFrameRate(void)1359 f32 THPPlayerGetFrameRate(void)
1360 {
1361     if (ActivePlayer.open)
1362     {
1363 
1364         return ActivePlayer.header.frameRate;
1365     }
1366 
1367     return 0.0f;
1368 }
1369 
1370 /*---------------------------------------------------------------------------*
1371     Name:           THPPlayerGetTotalFrame
1372 
1373     Description:    Acquire total frames for THP movie
1374 
1375     Arguments:      None
1376 
1377     Returns:        If successful, returns THP movie total frames. If unsuccessful, returns 0.
1378  *---------------------------------------------------------------------------*/
1379 
THPPlayerGetTotalFrame(void)1380 u32 THPPlayerGetTotalFrame(void)
1381 {
1382     if (ActivePlayer.open)
1383     {
1384         return ActivePlayer.header.numFrames;
1385     }
1386 
1387     return 0;
1388 }
1389 
1390 /*---------------------------------------------------------------------------*
1391     Name:           THPPlayerGetState
1392 
1393     Description:    Acquire current player status.
1394 
1395     Arguments:      None
1396 
1397     Returns:        Player status
1398                     THP_PLAYER_STOP    stopped
1399                     THP_PLAYER_PREPARE preparations completed
1400                     THP_PLAYER_PLAY    playing
1401                     THP_PLAYER_PLAYED  played THP movie to end
1402                     THP_PLAYER_ERROR   error occurred
1403  *---------------------------------------------------------------------------*/
1404 
THPPlayerGetState(void)1405 s32 THPPlayerGetState(void)
1406 {
1407     return ActivePlayer.state;
1408 }
1409 
1410 /*---------------------------------------------------------------------------*
1411     Name:           PushUsedTextureSet
1412 
1413     Description:    Remove played back THP video data from played back THP
1414                     video data queue.
1415 
1416     Arguments:      None
1417 
1418     Returns:        None
1419  *---------------------------------------------------------------------------*/
1420 
PushUsedTextureSet(THPTextureSet * buffer)1421 static void PushUsedTextureSet(THPTextureSet *buffer)
1422 {
1423     OSSendMessage(&UsedTextureSetQueue, buffer, OS_MESSAGE_NOBLOCK);
1424 
1425     return;
1426 }
1427 
1428 /*---------------------------------------------------------------------------*
1429     Name:           PopUsedTextureSet
1430 
1431     Description:    Remove played back THP video data from played back THP
1432                     video data queue.
1433 
1434     Arguments:      None
1435 
1436     Returns:        Pointer for played back THP video data.
1437  *---------------------------------------------------------------------------*/
1438 
PopUsedTextureSet(void)1439 static void *PopUsedTextureSet(void)
1440 {
1441     OSMessage msg;
1442 
1443     if (OSReceiveMessage(&UsedTextureSetQueue, &msg, OS_MESSAGE_NOBLOCK) == TRUE)
1444     {
1445         return msg;
1446     }
1447     else
1448     {
1449         return NULL;
1450     }
1451 }
1452 
1453 /*---------------------------------------------------------------------------*
1454     Name:           THPPlayerDrawDone
1455 
1456     Description:    Function used instead of GXDrawDone to synchronize with
1457                     the graphics processor during movie playback. It waits for
1458                     the graphics processor to complete processing and frees
1459                     internally THP video data determined to be played back.
1460 
1461     Arguments:      None
1462 
1463     Returns:        None
1464  *---------------------------------------------------------------------------*/
1465 
THPPlayerDrawDone(void)1466 void THPPlayerDrawDone(void)
1467 {
1468     void *textureSet;
1469 
1470     GXDrawDone();
1471 
1472     if (Initialized)
1473     {
1474         while(1)
1475         {
1476             textureSet = PopUsedTextureSet();
1477             if (textureSet == NULL)
1478             {
1479                 break;
1480             }
1481             else
1482             {
1483                 PushFreeTextureSet(textureSet);
1484             }
1485         }
1486     }
1487 }
1488 
1489 #ifndef HOLLYWOOD_REV
1490 /*---------------------------------------------------------------------------*
1491     Name:           StreamInit
1492 
1493     Description:    Carries out initialization for using streaming with
1494                     THP audio data playback.
1495 
1496     Arguments:      None
1497 
1498     Returns:        None
1499  *---------------------------------------------------------------------------*/
1500 
StreamInit(void)1501 static BOOL StreamInit(void)
1502 {
1503     AXPBADDR  addr;
1504     u32       aramStartAddr, bufferSize;
1505     u32       aramEndAddr;
1506     OSMessage msg;
1507 
1508     bufferSize = OSRoundUp32B(STREAM_BUFFER_MS * ActivePlayer.audioInfo.sndFrequency / 1000.0f + 0.5f) * 2;
1509 
1510     OSInitMessageQueue(&InitAramTransferQueue, &InitAramTransferMessage, 1);
1511 
1512     // Allocate voice for left channel
1513     StreamL = AXAcquireVoice(AX_PRIORITY_NODROP, NULL, 0);
1514 
1515     if (StreamL == NULL || AmemoryL == 0)
1516     {
1517 #ifdef _DEBUG
1518         OSReport("Couldn't complete the initialization for streaming\n");
1519 #endif
1520         return FALSE;
1521     }
1522 
1523     // Initialize mixer channel
1524     if (ActivePlayer.audioInfo.sndChannels == 2)
1525     {
1526         MIXInitChannel(StreamL, 0, 0, -904, -904, -904, 0, 127, 0);
1527     }
1528     else
1529     {
1530         MIXInitChannel(StreamL, 0, 0, -904, -904, -904, 64, 127, 0);
1531     }
1532 
1533     // Carry out settings for voice for left channel
1534     aramStartAddr = AmemoryL / 2;
1535     aramEndAddr   = ((AmemoryL + bufferSize) / 2) - 1;
1536 
1537     addr.loopFlag         = AXPBADDR_LOOP_ON;
1538     addr.format           = AX_PB_FORMAT_PCM16;
1539     addr.loopAddressHi    = (u16)(aramStartAddr >> 16);
1540     addr.loopAddressLo    = (u16)(aramStartAddr & 0xFFFF);
1541     addr.endAddressHi     = (u16)(aramEndAddr >> 16);
1542     addr.endAddressLo     = (u16)(aramEndAddr & 0xFFFF);
1543     addr.currentAddressHi = (u16)(aramStartAddr >> 16);
1544     addr.currentAddressLo = (u16)(aramStartAddr & 0xFFFF);
1545 
1546     AXSetVoiceAddr(StreamL, &addr);
1547 
1548     if (ActivePlayer.audioInfo.sndFrequency == 32000)
1549     {
1550         AXSetVoiceSrcType(StreamL, AX_SRC_TYPE_NONE);
1551     }
1552     else
1553     {
1554         AXSetVoiceSrcType(StreamL, AX_SRC_TYPE_4TAP_12K);
1555         AXSetVoiceSrcRatio(StreamL, (f32)(ActivePlayer.audioInfo.sndFrequency / 32000.0));
1556     }
1557 
1558     if (ActivePlayer.audioInfo.sndChannels == 2)
1559     {
1560         // Allocate voice for right channel
1561         StreamR = AXAcquireVoice(AX_PRIORITY_NODROP, NULL, 0);
1562 
1563         if (StreamR == NULL || AmemoryR == 0)
1564         {
1565             MIXReleaseChannel(StreamL);
1566             AXFreeVoice(StreamL);
1567             StreamL = NULL;
1568 #ifdef _DEBUG
1569             OSReport("Couldn't complete the initialization for streaming\n");
1570 #endif
1571             return FALSE;
1572         }
1573 
1574         // Initialize mixer channel
1575         MIXInitChannel(StreamR, 0, 0, -904, -904, -904, 127, 127, 0);
1576 
1577         // Carry out settings for voice for right channel
1578         aramStartAddr = AmemoryR / 2;
1579         aramEndAddr   = ((AmemoryR + bufferSize) / 2) - 1;
1580 
1581         addr.loopFlag         = AXPBADDR_LOOP_ON;
1582         addr.format           = AX_PB_FORMAT_PCM16;
1583         addr.loopAddressHi    = (u16)(aramStartAddr >> 16);
1584         addr.loopAddressLo    = (u16)(aramStartAddr & 0xFFFF);
1585         addr.endAddressHi     = (u16)(aramEndAddr >> 16);
1586         addr.endAddressLo     = (u16)(aramEndAddr & 0xFFFF);
1587         addr.currentAddressHi = (u16)(aramStartAddr >> 16);
1588         addr.currentAddressLo = (u16)(aramStartAddr & 0xFFFF);
1589 
1590         AXSetVoiceAddr(StreamR, &addr);
1591         if (ActivePlayer.audioInfo.sndFrequency == 32000)
1592         {
1593             AXSetVoiceSrcType(StreamR, AX_SRC_TYPE_NONE);
1594         }
1595         else
1596         {
1597             AXSetVoiceSrcType(StreamR, AX_SRC_TYPE_4TAP_12K);
1598             AXSetVoiceSrcRatio(StreamR, (f32)(ActivePlayer.audioInfo.sndFrequency / 32000.0));
1599         }
1600     }
1601 
1602     // Initialize structure for control of streaming
1603     StreamInfo.top          = 0;
1604     StreamInfo.bottom       = 0;
1605     StreamInfo.curSampleNum = 0;
1606     StreamInfo.endSampleNum = 0;
1607 
1608     // Store decoded THP audio data in streaming buffer
1609     if (ActivePlayer.audioInfo.sndChannels == 2)
1610     {
1611         FillStreamBuffer(StreamBufferL, StreamBufferR, bufferSize >> 1);
1612     }
1613     else
1614     {
1615         FillStreamBuffer(StreamBufferL, NULL, bufferSize >> 1);
1616     }
1617 
1618     // Transfer to A Memory
1619     if (ActivePlayer.audioInfo.sndChannels == 2)
1620     {
1621         DCFlushRange(StreamBufferR, bufferSize);
1622 
1623         ARQPostRequest(&TaskR,
1624                        0,
1625                        ARQ_TYPE_MRAM_TO_ARAM,
1626                        ARQ_PRIORITY_HIGH,
1627                        (u32)StreamBufferR,
1628                        AmemoryR,
1629                        bufferSize,
1630                        NULL);
1631     }
1632 
1633     DCFlushRange(StreamBufferL, bufferSize);
1634 
1635     ARQPostRequest(&TaskL,
1636                    0,
1637                    ARQ_TYPE_MRAM_TO_ARAM,
1638                    ARQ_PRIORITY_HIGH,
1639                    (u32)StreamBufferL,
1640                    AmemoryL,
1641                    bufferSize,
1642                    InitAramTransferDone);
1643 
1644     OSReceiveMessage(&InitAramTransferQueue, &msg, OS_MESSAGE_BLOCK);
1645 
1646     StreamInfo.lastPos = AmemoryL / 2;
1647 
1648     return TRUE;
1649 }
1650 
1651 /*---------------------------------------------------------------------------*
1652     Name:           InitAramTransferDone
1653 
1654     Description:    Notifies end of transfer of data to ARAM.
1655 
1656     Arguments:      Does not use user.
1657 
1658     Returns:        None
1659  *---------------------------------------------------------------------------*/
1660 
InitAramTransferDone(u32 user)1661 static void InitAramTransferDone(u32 user)
1662 {
1663 #pragma unused(user)
1664 
1665     OSSendMessage(&InitAramTransferQueue, NULL, OS_MESSAGE_NOBLOCK);
1666 
1667     return;
1668 }
1669 
1670 
1671 /*---------------------------------------------------------------------------*
1672     Name:           StreamReInit
1673 
1674     Description:    Rearranges the data in the streaming buffer in order to
1675                     restart streaming from the stopped location during a pause.
1676                     Also updates the list that saves the sample numbers that
1677                     show the boundaries between movie frames.
1678 
1679     Arguments:      None
1680 
1681     Returns:        None
1682  *---------------------------------------------------------------------------*/
1683 
StreamReInit(void)1684 static void StreamReInit(void)
1685 {
1686     u64       tmp;
1687     u32       size, sample, offset1, offset2, bufferSampleNum;
1688     s32       index;
1689     s16       *lsrc, *ldst, *rsrc, *rdst;
1690     OSMessage msg;
1691 
1692     bufferSampleNum = OSRoundUp32B(STREAM_BUFFER_MS * ActivePlayer.audioInfo.sndFrequency / 1000.0f + 0.5f);
1693 
1694     if (StreamInfo.curSampleNum == StreamInfo.endSampleNum)
1695     {
1696         // There is no valid data in the streaming buffer so replace all
1697         // with new data.
1698         StreamInfo.endSampleNum = 0;
1699 
1700         if (ActivePlayer.audioInfo.sndChannels == 2)
1701         {
1702             FillStreamBuffer(StreamBufferL, StreamBufferR, bufferSampleNum);
1703         }
1704         else
1705         {
1706             FillStreamBuffer(StreamBufferL, NULL, bufferSampleNum);
1707         }
1708     }
1709     else
1710     {
1711         // Calculates beginning and end of valid data in streaming buffer
1712         offset1 = (u32)(StreamInfo.curSampleNum % bufferSampleNum);
1713         offset2 = (u32)(StreamInfo.endSampleNum     % bufferSampleNum);
1714 
1715         if (!offset2)
1716         {
1717             offset2 = bufferSampleNum;
1718         }
1719 
1720         if (offset1 < offset2)
1721         {
1722             // Buffer status is as follows:
1723             // |----|==========| Or |---|==|-----|
1724             // - Played back data
1725             // = Not played back data
1726             // Line up data in streaming buffer not played back yet from
1727             // beginning of buffer.
1728 
1729             ldst = StreamBufferL;
1730             lsrc = StreamBufferL + offset1;
1731             size = (offset2 - offset1) << 1;
1732 
1733             memcpy(ldst, lsrc, size);
1734 
1735             if (ActivePlayer.audioInfo.sndChannels == 2)
1736             {
1737                 rdst = StreamBufferR;
1738                 rsrc = StreamBufferR + offset1;
1739                 memcpy(rdst, rsrc, size);
1740             }
1741 
1742             // Updates the list that saves the sample numbers which show the boundaries between movie frames.
1743             index = StreamInfo.top;
1744 
1745             while (index != StreamInfo.bottom)
1746             {
1747                 tmp = StreamInfo.boundary[index] % bufferSampleNum;
1748 
1749                 StreamInfo.boundary[index] = tmp - offset1;
1750 
1751                 index++;
1752                 if (index >= BOUNDARY_NUM)
1753                 {
1754                     index = 0;
1755                 }
1756             }
1757 
1758             ldst   = StreamBufferL  + (size >> 1);
1759             sample = bufferSampleNum - (size >> 1);
1760             StreamInfo.endSampleNum = bufferSampleNum - sample;
1761 
1762             // Fill in open areas of streaming buffer with new data
1763             if (ActivePlayer.audioInfo.sndChannels == 2)
1764             {
1765                 rdst = StreamBufferR + (size >> 1);
1766                 FillStreamBuffer(ldst, rdst, sample);
1767             }
1768             else
1769             {
1770                 FillStreamBuffer(ldst, NULL, sample);
1771             }
1772         }
1773         else
1774         {
1775             // Buffer status is as follows:
1776             // |=====|--|==|
1777             // - Played back data
1778             // = Not played back data
1779             // Line up data in streaming buffer not played back yet from
1780             // beginning of buffer.
1781             memcpy(WorkBuffer, StreamBufferL, bufferSampleNum >> 2);
1782 
1783             ldst = StreamBufferL;
1784             lsrc = StreamBufferL  + offset1;
1785             size = (bufferSampleNum - offset1) << 1;
1786 
1787             memcpy(ldst, lsrc, size);
1788 
1789             ldst = StreamBufferL + (size >> 1);
1790 
1791             memcpy(ldst, WorkBuffer, bufferSampleNum >> 2);
1792 
1793             if (ActivePlayer.audioInfo.sndChannels == 2)
1794             {
1795                 memcpy(WorkBuffer, StreamBufferR, bufferSampleNum >> 2);
1796 
1797                 rdst = StreamBufferR;
1798                 rsrc = StreamBufferR  + offset1;
1799 
1800                 memcpy(rdst, rsrc, size);
1801 
1802                 rdst = StreamBufferR + (size >> 1);
1803 
1804                 memcpy(rdst, WorkBuffer, bufferSampleNum >> 2);
1805             }
1806 
1807             // Updates the list that saves the sample numbers which show the boundaries between movie frames.
1808             index = StreamInfo.top;
1809 
1810             while (index != StreamInfo.bottom)
1811             {
1812                 tmp = StreamInfo.boundary[index] % bufferSampleNum;
1813 
1814                 if (tmp > (bufferSampleNum >> 1))
1815                 {
1816                     StreamInfo.boundary[index] = tmp - offset1;
1817                 }
1818                 else
1819                 {
1820                     StreamInfo.boundary[index] = tmp + (bufferSampleNum - offset1);
1821                 }
1822 
1823                 index++;
1824                 if (index >= BOUNDARY_NUM)
1825                 {
1826                     index = 0;
1827                 }
1828             }
1829 
1830             ldst   = StreamBufferL + bufferSampleNum - offset1 + offset2;
1831             sample = offset1 - offset2;
1832 
1833             StreamInfo.endSampleNum = bufferSampleNum - sample;
1834 
1835             // Fill in open areas of streaming buffer with new data
1836             if (ActivePlayer.audioInfo.sndChannels == 2)
1837             {
1838                 rdst = StreamBufferR + bufferSampleNum - offset1 + offset2;
1839                 FillStreamBuffer(ldst, rdst, sample);
1840             }
1841             else
1842             {
1843                 FillStreamBuffer(ldst, NULL, sample);
1844             }
1845         }
1846     }
1847 
1848     // Reinitializes the structure controlling the streaming
1849     StreamInfo.curSampleNum = 0;
1850 
1851     // Transfer to A Memory
1852     if (ActivePlayer.audioInfo.sndChannels == 2)
1853     {
1854         AXSetVoiceCurrentAddr(StreamR, AmemoryR / 2);
1855 
1856         DCFlushRange(StreamBufferR, bufferSampleNum << 1);
1857 
1858         ARQPostRequest(&TaskR,
1859                        0,
1860                        ARQ_TYPE_MRAM_TO_ARAM,
1861                        ARQ_PRIORITY_HIGH,
1862                        (u32)StreamBufferR,
1863                        AmemoryR,
1864                        bufferSampleNum << 1,
1865                        NULL);
1866     }
1867 
1868     AXSetVoiceCurrentAddr(StreamL, AmemoryL / 2);
1869 
1870     DCFlushRange(StreamBufferL, bufferSampleNum << 1);
1871 
1872     ARQPostRequest(&TaskL,
1873                    0,
1874                    ARQ_TYPE_MRAM_TO_ARAM,
1875                    ARQ_PRIORITY_HIGH,
1876                    (u32)StreamBufferL,
1877                    AmemoryL,
1878                    bufferSampleNum << 1,
1879                    InitAramTransferDone);
1880 
1881     OSReceiveMessage(&InitAramTransferQueue, &msg, OS_MESSAGE_BLOCK);
1882 
1883     StreamInfo.lastPos = AmemoryL / 2;
1884 
1885     return;
1886 }
1887 #else
1888 /*---------------------------------------------------------------------------*
1889     Name:           StreamInit
1890 
1891     Description:    Carries out initialization for using streaming with
1892                     THP audio data playback.
1893 
1894     Arguments:      None
1895 
1896     Returns:        None
1897  *---------------------------------------------------------------------------*/
1898 
StreamInit(void)1899 static BOOL StreamInit(void)
1900 {
1901     AXPBADDR  addr;
1902     u32       bufferSize;
1903     u32       startAddr;
1904     u32       endAddr;
1905 
1906     bufferSize = OSRoundUp32B(STREAM_BUFFER_MS * ActivePlayer.audioInfo.sndFrequency / 1000.0f + 0.5f) * 2;
1907 
1908     // Allocate voice for left channel
1909     StreamL = AXAcquireVoice(AX_PRIORITY_NODROP, NULL, 0);
1910 
1911     if (StreamL == NULL)
1912     {
1913 #ifdef _DEBUG
1914         OSReport("Couldn't complete the initialization for streaming\n");
1915 #endif
1916         return FALSE;
1917     }
1918 
1919     // Initialize mixer channel
1920     if (ActivePlayer.audioInfo.sndChannels == 2)
1921     {
1922         MIXInitChannel(StreamL, 0, 0, -904, -904, -904, 0, 127, 0);
1923     }
1924     else
1925     {
1926         MIXInitChannel(StreamL, 0, 0, -904, -904, -904, 64, 127, 0);
1927     }
1928 
1929     // Carry out settings for voice for left channel
1930     startAddr = OSCachedToPhysical(StreamBufferL) / 2;
1931     endAddr   = ((OSCachedToPhysical(StreamBufferL) + bufferSize) / 2) - 1;
1932 
1933     addr.loopFlag         = AXPBADDR_LOOP_ON;
1934     addr.format           = AX_PB_FORMAT_PCM16;
1935     addr.loopAddressHi    = (u16)(startAddr >> 16);
1936     addr.loopAddressLo    = (u16)(startAddr & 0xFFFF);
1937     addr.endAddressHi     = (u16)(endAddr >> 16);
1938     addr.endAddressLo     = (u16)(endAddr & 0xFFFF);
1939     addr.currentAddressHi = (u16)(startAddr >> 16);
1940     addr.currentAddressLo = (u16)(startAddr & 0xFFFF);
1941 
1942     AXSetVoiceAddr(StreamL, &addr);
1943 
1944     if (ActivePlayer.audioInfo.sndFrequency == 32000)
1945     {
1946         AXSetVoiceSrcType(StreamL, AX_SRC_TYPE_NONE);
1947     }
1948     else
1949     {
1950         AXSetVoiceSrcType(StreamL, AX_SRC_TYPE_4TAP_12K);
1951         AXSetVoiceSrcRatio(StreamL, (f32)(ActivePlayer.audioInfo.sndFrequency / 32000.0));
1952     }
1953 
1954     if (ActivePlayer.audioInfo.sndChannels == 2)
1955     {
1956         // Allocate voice for right channel
1957         StreamR = AXAcquireVoice(AX_PRIORITY_NODROP, NULL, 0);
1958 
1959         if (StreamR == NULL)
1960         {
1961             MIXReleaseChannel(StreamL);
1962             AXFreeVoice(StreamL);
1963             StreamL = NULL;
1964 #ifdef _DEBUG
1965             OSReport("Couldn't complete the initialization for streaming\n");
1966 #endif
1967             return FALSE;
1968         }
1969 
1970         // Initialize mixer channel
1971         MIXInitChannel(StreamR, 0, 0, -904, -904, -904, 127, 127, 0);
1972 
1973         // Carry out settings for voice for right channel
1974         startAddr = OSCachedToPhysical(StreamBufferR) / 2;
1975         endAddr   = ((OSCachedToPhysical(StreamBufferR) + bufferSize) / 2) - 1;
1976 
1977         addr.loopFlag         = AXPBADDR_LOOP_ON;
1978         addr.format           = AX_PB_FORMAT_PCM16;
1979         addr.loopAddressHi    = (u16)(startAddr >> 16);
1980         addr.loopAddressLo    = (u16)(startAddr & 0xFFFF);
1981         addr.endAddressHi     = (u16)(endAddr >> 16);
1982         addr.endAddressLo     = (u16)(endAddr & 0xFFFF);
1983         addr.currentAddressHi = (u16)(startAddr >> 16);
1984         addr.currentAddressLo = (u16)(startAddr & 0xFFFF);
1985 
1986         AXSetVoiceAddr(StreamR, &addr);
1987         if (ActivePlayer.audioInfo.sndFrequency == 32000)
1988         {
1989             AXSetVoiceSrcType(StreamR, AX_SRC_TYPE_NONE);
1990         }
1991         else
1992         {
1993             AXSetVoiceSrcType(StreamR, AX_SRC_TYPE_4TAP_12K);
1994             AXSetVoiceSrcRatio(StreamR, (f32)(ActivePlayer.audioInfo.sndFrequency / 32000.0));
1995         }
1996     }
1997 
1998     // Initialize structure for control of streaming
1999     StreamInfo.top          = 0;
2000     StreamInfo.bottom       = 0;
2001     StreamInfo.curSampleNum = 0;
2002     StreamInfo.endSampleNum = 0;
2003 
2004     // Store decoded THP audio data in streaming buffer
2005     if (ActivePlayer.audioInfo.sndChannels == 2)
2006     {
2007         FillStreamBuffer(StreamBufferL, StreamBufferR, bufferSize >> 1);
2008         DCFlushRange(StreamBufferL, bufferSize);
2009         DCFlushRange(StreamBufferR, bufferSize);
2010     }
2011     else
2012     {
2013         FillStreamBuffer(StreamBufferL, NULL, bufferSize >> 1);
2014         DCFlushRange(StreamBufferL, bufferSize);
2015     }
2016 
2017     StreamInfo.lastPos = OSCachedToPhysical(StreamBufferL) / 2;
2018 
2019     return TRUE;
2020 }
2021 
2022 /*---------------------------------------------------------------------------*
2023     Name:           StreamReInit
2024 
2025     Description:    Rearranges the data in the streaming buffer in order to
2026                     restart streaming from the stopped location during a pause.
2027                     Also updates the list that saves the sample numbers that
2028                     show the boundaries between movie frames.
2029 
2030     Arguments:      None
2031 
2032     Returns:        None
2033  *---------------------------------------------------------------------------*/
2034 
StreamReInit(void)2035 static void StreamReInit(void)
2036 {
2037     u64       tmp;
2038     u32       size, sample, offset1, offset2, bufferSampleNum;
2039     s32       index;
2040     s16       *lsrc, *ldst, *rsrc, *rdst;
2041 
2042     bufferSampleNum = OSRoundUp32B(STREAM_BUFFER_MS * ActivePlayer.audioInfo.sndFrequency / 1000.0f + 0.5f);
2043 
2044     if (StreamInfo.curSampleNum == StreamInfo.endSampleNum)
2045     {
2046         // There is no valid data in the streaming buffer so replace all
2047         // with new data.
2048         StreamInfo.endSampleNum = 0;
2049 
2050         if (ActivePlayer.audioInfo.sndChannels == 2)
2051         {
2052             FillStreamBuffer(StreamBufferL, StreamBufferR, bufferSampleNum);
2053         }
2054         else
2055         {
2056             FillStreamBuffer(StreamBufferL, NULL, bufferSampleNum);
2057         }
2058     }
2059     else
2060     {
2061         // Calculates beginning and end of valid data in streaming buffer
2062         offset1 = (u32)(StreamInfo.curSampleNum % bufferSampleNum);
2063         offset2 = (u32)(StreamInfo.endSampleNum % bufferSampleNum);
2064 
2065         if (!offset2)
2066         {
2067             offset2 = bufferSampleNum;
2068         }
2069 
2070         if (offset1 < offset2)
2071         {
2072             // Buffer status is as follows:
2073             // |----|==========| Or |---|==|-----|
2074             // - Played back data
2075             // = Not played back data
2076             // Line up data in streaming buffer not played back yet from
2077             // beginning of buffer.
2078 
2079             ldst = StreamBufferL;
2080             lsrc = StreamBufferL + offset1;
2081             size = (offset2 - offset1) << 1;
2082 
2083             memcpy(ldst, lsrc, size);
2084 
2085             if (ActivePlayer.audioInfo.sndChannels == 2)
2086             {
2087                 rdst = StreamBufferR;
2088                 rsrc = StreamBufferR + offset1;
2089                 memcpy(rdst, rsrc, size);
2090             }
2091 
2092             // Updates the list that saves the sample numbers which show the boundaries between movie frames.
2093             index = StreamInfo.top;
2094 
2095             while (index != StreamInfo.bottom)
2096             {
2097                 tmp = StreamInfo.boundary[index] % bufferSampleNum;
2098 
2099                 StreamInfo.boundary[index] = tmp - offset1;
2100 
2101                 index++;
2102                 if (index >= BOUNDARY_NUM)
2103                 {
2104                     index = 0;
2105                 }
2106             }
2107 
2108             ldst   = StreamBufferL  + (size >> 1);
2109             sample = bufferSampleNum - (size >> 1);
2110             StreamInfo.endSampleNum = bufferSampleNum - sample;
2111 
2112             // Fill in open areas of streaming buffer with new data
2113             if (ActivePlayer.audioInfo.sndChannels == 2)
2114             {
2115                 rdst = StreamBufferR + (size >> 1);
2116                 FillStreamBuffer(ldst, rdst, sample);
2117             }
2118             else
2119             {
2120                 FillStreamBuffer(ldst, NULL, sample);
2121             }
2122         }
2123         else
2124         {
2125             // Buffer status is as follows:
2126             // |=====|--|==|
2127             // - Played back data
2128             // = Not played back data
2129             // Line up data in streaming buffer not played back yet from
2130             // beginning of buffer.
2131             memcpy(WorkBuffer, StreamBufferL, bufferSampleNum >> 2);
2132 
2133             ldst = StreamBufferL;
2134             lsrc = StreamBufferL  + offset1;
2135             size = (bufferSampleNum - offset1) << 1;
2136 
2137             memcpy(ldst, lsrc, size);
2138 
2139             ldst = StreamBufferL + (size >> 1);
2140 
2141             memcpy(ldst, WorkBuffer, bufferSampleNum >> 2);
2142 
2143             if (ActivePlayer.audioInfo.sndChannels == 2)
2144             {
2145                 memcpy(WorkBuffer, StreamBufferR, bufferSampleNum >> 2);
2146 
2147                 rdst = StreamBufferR;
2148                 rsrc = StreamBufferR  + offset1;
2149 
2150                 memcpy(rdst, rsrc, size);
2151 
2152                 rdst = StreamBufferR + (size >> 1);
2153 
2154                 memcpy(rdst, WorkBuffer, bufferSampleNum >> 2);
2155             }
2156 
2157             // Updates the list that saves the sample numbers which show the boundaries between movie frames.
2158             index = StreamInfo.top;
2159 
2160             while (index != StreamInfo.bottom)
2161             {
2162                 tmp = StreamInfo.boundary[index] % bufferSampleNum;
2163 
2164                 if (tmp > (bufferSampleNum >> 1))
2165                 {
2166                     StreamInfo.boundary[index] = tmp - offset1;
2167                 }
2168                 else
2169                 {
2170                     StreamInfo.boundary[index] = tmp + (bufferSampleNum - offset1);
2171                 }
2172 
2173                 index++;
2174                 if (index >= BOUNDARY_NUM)
2175                 {
2176                     index = 0;
2177                 }
2178             }
2179 
2180             ldst   = StreamBufferL + bufferSampleNum - offset1 + offset2;
2181             sample = offset1 - offset2;
2182 
2183             StreamInfo.endSampleNum = bufferSampleNum - sample;
2184 
2185             // Fill in open areas of streaming buffer with new data
2186             if (ActivePlayer.audioInfo.sndChannels == 2)
2187             {
2188                 rdst = StreamBufferR + bufferSampleNum - offset1 + offset2;
2189                 FillStreamBuffer(ldst, rdst, sample);
2190             }
2191             else
2192             {
2193                 FillStreamBuffer(ldst, NULL, sample);
2194             }
2195         }
2196     }
2197 
2198     // Reinitializes the structure controlling the streaming
2199     StreamInfo.curSampleNum = 0;
2200 
2201     if (ActivePlayer.audioInfo.sndChannels == 2)
2202     {
2203         DCFlushRange(StreamBufferR, bufferSampleNum << 1);
2204         AXSetVoiceCurrentAddr(StreamR, OSCachedToPhysical(StreamBufferR) / 2);
2205 
2206     }
2207 
2208     DCFlushRange(StreamBufferL, bufferSampleNum << 1);
2209     AXSetVoiceCurrentAddr(StreamL, OSCachedToPhysical(StreamBufferL) / 2);
2210 
2211     StreamInfo.lastPos = OSCachedToPhysical(StreamBufferL) / 2;
2212 
2213     return;
2214 }
2215 #endif
2216 
2217 /*---------------------------------------------------------------------------*
2218     Name:           EntryBoundary
2219 
2220     Description:    Saves number of samples that shows the boundaries between movie frames to a list.
2221 
2222     Arguments:      boundarySampleNum    Number of samples that shows the boundaries between movie frames
2223 
2224     Returns:        None
2225  *---------------------------------------------------------------------------*/
2226 
EntryBoundary(u64 boundarySampleNum)2227 static void EntryBoundary(u64 boundarySampleNum)
2228 {
2229     StreamInfo.boundary[StreamInfo.bottom] = boundarySampleNum;
2230     StreamInfo.bottom++;
2231     if (StreamInfo.bottom >= BOUNDARY_NUM)
2232     {
2233         StreamInfo.bottom = 0;
2234     }
2235 
2236     return;
2237 }
2238 
2239 /*---------------------------------------------------------------------------*
2240     Name:           CheckBoundary
2241 
2242     Description:    Checks whether streaming playback location exceeds the boundaries
2243                     between movie frames. If it does, the current audio frame
2244                     number is incremented.
2245 
2246     Arguments:      curSampleNum   Current streaming playback location.
2247 
2248     Returns:        None
2249  *---------------------------------------------------------------------------*/
2250 
CheckBoundary(u64 curSampleNum)2251 static void CheckBoundary(u64 curSampleNum)
2252 {
2253     while (StreamInfo.top != StreamInfo.bottom)
2254     {
2255         if (StreamInfo.boundary[StreamInfo.top] <= curSampleNum)
2256         {
2257             StreamInfo.top++;
2258             if (StreamInfo.top >= BOUNDARY_NUM)
2259             {
2260                 StreamInfo.top = 0;
2261             }
2262             ActivePlayer.curAudioNumber++;
2263         }
2264         else
2265         {
2266             break;
2267         }
2268     }
2269 
2270     return;
2271 }
2272 
2273 /*---------------------------------------------------------------------------*
2274     Name:           GetAudioSample
2275 
2276     Description:    Copies decoded data to THP audio data buffer specified.
2277 
2278     Arguments:      left   Pointer to memory that copies left channel data.
2279                     right  Pointer to memory that copies right channel data.
2280                     sample  Number of samples copied. (Stereo Samples)
2281                     reason  Pointer to variable to store error code if number
2282                     of samples copied does not equal the specified number.
2283 
2284     Returns:        Actual number of samples copied.
2285  *---------------------------------------------------------------------------*/
2286 
GetAudioSample(s16 * left,s16 * right,u32 sample,s32 * reason)2287 static u32 GetAudioSample(s16 *left, s16 *right, u32 sample, s32 *reason)
2288 {
2289     u32 sampleNum, i;
2290     s16 *src;
2291 
2292     if (ActivePlayer.playAudioBuffer == NULL)
2293     {
2294         if ((ActivePlayer.playAudioBuffer = (THPAudioBuffer *)PopDecodedAudioBuffer(OS_MESSAGE_NOBLOCK)) == NULL)
2295         {
2296             *reason = EMPTY_AUDIO_DATA;
2297             return 0;
2298         }
2299     }
2300 
2301     if (ActivePlayer.playAudioBuffer->validSample)
2302     {
2303         if (ActivePlayer.playAudioBuffer->validSample >= sample)
2304         {
2305             sampleNum = sample;
2306         }
2307         else
2308         {
2309             sampleNum = ActivePlayer.playAudioBuffer->validSample;
2310         }
2311 
2312         src = ActivePlayer.playAudioBuffer->curPtr;
2313 
2314         // Monaural
2315         if (right == NULL)
2316         {
2317             for (i = 0 ; i < sampleNum ; i++)
2318             {
2319                 src++;
2320                 *left  = *src;
2321                 src++;
2322                 left++;
2323             }
2324         }
2325         // Stereo
2326         else
2327         {
2328             for (i = 0 ; i < sampleNum ; i++)
2329             {
2330                 *right = *src;
2331                 src++;
2332                 *left  = *src;
2333                 src++;
2334                 right++;
2335                 left++;
2336             }
2337         }
2338 
2339         ActivePlayer.playAudioBuffer->validSample -= sampleNum;
2340         ActivePlayer.playAudioBuffer->curPtr       = src;
2341 
2342         if (ActivePlayer.playAudioBuffer->validSample == 0)
2343         {
2344             // Free used THP audio data
2345             PushFreeAudioBuffer(ActivePlayer.playAudioBuffer);
2346             ActivePlayer.playAudioBuffer = NULL;
2347             *reason = EMPTY_AUDIO_BUFFER;
2348         }
2349         else
2350         {
2351             *reason = SUCCESS;
2352         }
2353     }
2354 
2355     return sampleNum;
2356 }
2357 
2358 /*---------------------------------------------------------------------------*
2359     Name:           FillStreamBuffer
2360 
2361     Description:    Fill in specified buffer with decoded THP audio data.
2362                     If boundaries between movie frames appear when filling in,
2363                     save the sample number that displays this boundaries to a list.
2364                     If the decoded THP audio data does not equal the specified
2365                     sample number, fill in boundaries with buffer.
2366 
2367     Arguments:      left   Pointer to memory that copies left channel data.
2368                     right  Pointer to memory that copies right channel data.
2369                     sample  Number of samples copied. (Stereo Samples)
2370 
2371     Returns:        None
2372  *---------------------------------------------------------------------------*/
2373 
FillStreamBuffer(s16 * left,s16 * right,u32 sample)2374 static void FillStreamBuffer(s16 *left, s16 *right, u32 sample)
2375 {
2376     u64 tmp;
2377     u32 actualSample, requestSample;
2378     s32 reason;
2379     s16 *l, *r;
2380 
2381     requestSample = sample;
2382     l             = left;
2383     r             = right;
2384 
2385     tmp = StreamInfo.endSampleNum;
2386 
2387     while(1)
2388     {
2389         actualSample = GetAudioSample(l, r, requestSample, &reason);
2390         tmp         += actualSample;
2391 
2392         // Copied all of specified sample number to designated buffer
2393         if (reason == SUCCESS)
2394         {
2395             break;
2396         }
2397         // If boundaries between movie frames appears when copying to specified buffer
2398         else if (reason == EMPTY_AUDIO_BUFFER)
2399         {
2400             requestSample -= actualSample;
2401             l             += actualSample;
2402             if (r)
2403             {
2404                 r += actualSample;
2405             }
2406             // Save number of samples that shows the boundaries between movie frames to a list
2407             EntryBoundary(tmp);
2408         }
2409         // No more decoded THP audio data (decode did not finish in time)
2410         else
2411         {
2412             memset(l, 0, requestSample << 1);
2413             if (r)
2414             {
2415                 memset(r, 0, requestSample << 1);
2416             }
2417 
2418             break;
2419         }
2420     }
2421 
2422     StreamInfo.endSampleNum += sample;
2423 
2424     return;
2425 }
2426 
2427 /*---------------------------------------------------------------------------*
2428     Name:           THPPlayerStreamUpdate
2429 
2430     Description:    Calls from AX user callback, and checks status of
2431                     streaming buffer. If need to update, updates buffer.
2432 
2433     Arguments:      None
2434 
2435     Returns:        None
2436  *---------------------------------------------------------------------------*/
2437 #ifndef HOLLYWOOD_REV
THPPlayerStreamUpdate(void)2438 void THPPlayerStreamUpdate(void)
2439 {
2440     u32 currentPosition, bufferSampleNum, diff;
2441     u32 aramHalfAddr, aramStartAddr, aramEndAddr;
2442 
2443     if (Initialized && (StreamL || StreamR) & (ActivePlayer.internalState == THP_PLAYER_PLAY))
2444     {
2445         bufferSampleNum = OSRoundUp32B(STREAM_BUFFER_MS * ActivePlayer.audioInfo.sndFrequency / 1000.0f + 0.5f);
2446 
2447         currentPosition = (u32)(StreamL->pb.addr.currentAddressHi << 16) | (StreamL->pb.addr.currentAddressLo);
2448 
2449         if (currentPosition >= StreamInfo.lastPos)
2450         {
2451             diff = currentPosition - StreamInfo.lastPos;
2452         }
2453         else
2454         {
2455             aramStartAddr = AmemoryL / 2;
2456             aramEndAddr   = aramStartAddr + bufferSampleNum;
2457 
2458             diff  = aramEndAddr - StreamInfo.lastPos;
2459             diff += currentPosition - aramStartAddr;
2460         }
2461 
2462         StreamInfo.curSampleNum += diff;
2463 
2464         // Check if streaming data exceeds boundaries between movie frames
2465         CheckBoundary(StreamInfo.curSampleNum);
2466 
2467         aramHalfAddr = AmemoryL / 2 + bufferSampleNum / 2;
2468 
2469         // Check if streaming buffer needs update.  If so, updates.
2470         if (currentPosition < StreamInfo.lastPos)
2471         {
2472             TransferStreamData(1);
2473         }
2474 
2475         if ((currentPosition >= aramHalfAddr) && (StreamInfo.lastPos < aramHalfAddr))
2476         {
2477             TransferStreamData(0);
2478         }
2479 
2480         StreamInfo.lastPos = currentPosition;
2481     }
2482 }
2483 #else
THPPlayerStreamUpdate(void)2484 void THPPlayerStreamUpdate(void)
2485 {
2486     u32  bufferSampleNum;
2487     u32  currentPosition;
2488     u32  diff;
2489     u32  halfPosition;
2490 
2491     if (Initialized && (StreamL || StreamR) & (ActivePlayer.internalState == THP_PLAYER_PLAY))
2492     {
2493         bufferSampleNum = OSRoundUp32B(STREAM_BUFFER_MS * ActivePlayer.audioInfo.sndFrequency / 1000.0f + 0.5f);
2494 
2495         currentPosition = (u32)(StreamL->pb.addr.currentAddressHi << 16) | (StreamL->pb.addr.currentAddressLo);
2496 
2497         if (currentPosition >= StreamInfo.lastPos)
2498         {
2499             diff = currentPosition - StreamInfo.lastPos;
2500         }
2501         else
2502         {
2503             u32 startAddr;
2504             u32 endAddr;
2505 
2506             startAddr = OSCachedToPhysical(StreamBufferL) / 2;
2507             endAddr   = startAddr + bufferSampleNum;
2508 
2509             diff  = endAddr - StreamInfo.lastPos;
2510             diff += currentPosition - startAddr;
2511         }
2512 
2513         StreamInfo.curSampleNum += diff;
2514 
2515         // Check if streaming data exceeds boundaries between movie frames
2516         CheckBoundary(StreamInfo.curSampleNum);
2517 
2518         halfPosition = OSCachedToPhysical(StreamBufferL) / 2 + bufferSampleNum / 2;
2519 
2520         // Check if streaming buffer needs update.  If so, updates.
2521         if (currentPosition < StreamInfo.lastPos)
2522         {
2523             TransferStreamData(1);
2524         }
2525 
2526         if ((currentPosition >= halfPosition) && (StreamInfo.lastPos < halfPosition))
2527         {
2528             TransferStreamData(0);
2529         }
2530 
2531         StreamInfo.lastPos = currentPosition;
2532     }
2533 }
2534 #endif
2535 
2536 /*---------------------------------------------------------------------------*
2537     Name:           TransferStreamData
2538 
2539     Description:    Updates streaming buffer. Using argument, flag, specifies
2540                     location to update streaming buffer (first half or second half).
2541 
2542     Arguments:      flag 1 is update of second half
2543                          0 is update of first half
2544 
2545     Returns:        None
2546  *---------------------------------------------------------------------------*/
2547 #ifndef HOLLYWOOD_REV
TransferStreamData(s32 flag)2548 static void TransferStreamData(s32 flag)
2549 {
2550     s16 *srcMainBufferL, *srcMainBufferR;
2551     u32 destAmemoryL, destAmemoryR;
2552     u32 bufferSampleHalfNum;
2553 
2554     bufferSampleHalfNum = OSRoundUp32B(STREAM_BUFFER_MS * ActivePlayer.audioInfo.sndFrequency / 1000.0f + 0.5f) / 2;
2555 
2556     if (flag)
2557     {
2558         srcMainBufferL = StreamBufferL + bufferSampleHalfNum;
2559         srcMainBufferR = StreamBufferR + bufferSampleHalfNum;
2560         destAmemoryL   = AmemoryL   + (bufferSampleHalfNum << 1);
2561         destAmemoryR   = AmemoryR   + (bufferSampleHalfNum << 1);
2562     }
2563     else
2564     {
2565         srcMainBufferL = StreamBufferL;
2566         srcMainBufferR = StreamBufferR;
2567         destAmemoryL   = AmemoryL;
2568         destAmemoryR   = AmemoryR;
2569     }
2570 
2571     if (ActivePlayer.audioInfo.sndChannels == 2)
2572     {
2573         FillStreamBuffer(srcMainBufferL,
2574                          srcMainBufferR,
2575                          bufferSampleHalfNum);
2576     }
2577     else
2578     {
2579         FillStreamBuffer(srcMainBufferL,
2580                          NULL,
2581                          bufferSampleHalfNum);
2582     }
2583 
2584     DCFlushRange(srcMainBufferL, bufferSampleHalfNum << 1);
2585 
2586     ARQPostRequest(&TaskL,
2587                    0,
2588                    ARQ_TYPE_MRAM_TO_ARAM,
2589                    ARQ_PRIORITY_HIGH,
2590                    (u32)srcMainBufferL,
2591                    destAmemoryL,
2592                    bufferSampleHalfNum << 1,
2593                    NULL);
2594 
2595     if (ActivePlayer.audioInfo.sndChannels == 2)
2596     {
2597         DCFlushRange(srcMainBufferR, bufferSampleHalfNum << 1);
2598 
2599         ARQPostRequest(&TaskR,
2600                        0,
2601                        ARQ_TYPE_MRAM_TO_ARAM,
2602                        ARQ_PRIORITY_HIGH,
2603                        (u32)srcMainBufferR,
2604                        destAmemoryR,
2605                        bufferSampleHalfNum << 1,
2606                        NULL);
2607     }
2608 
2609     return;
2610 }
2611 #else
TransferStreamData(s32 flag)2612 static void TransferStreamData(s32 flag)
2613 {
2614     s16  *destBufferL;
2615     s16  *destBufferR;
2616     u32  bufferSampleHalfNum;
2617 
2618     bufferSampleHalfNum = OSRoundUp32B(STREAM_BUFFER_MS * ActivePlayer.audioInfo.sndFrequency / 1000.0f + 0.5f) / 2;
2619 
2620     if (flag)
2621     {
2622         destBufferL = StreamBufferL + bufferSampleHalfNum;
2623         destBufferR = StreamBufferR + bufferSampleHalfNum;
2624     }
2625     else
2626     {
2627         destBufferL = StreamBufferL;
2628         destBufferR = StreamBufferR;
2629     }
2630 
2631     if (ActivePlayer.audioInfo.sndChannels == 2)
2632     {
2633         FillStreamBuffer(destBufferL,
2634                          destBufferR,
2635                          bufferSampleHalfNum);
2636         DCFlushRange(destBufferL, bufferSampleHalfNum << 1);
2637         DCFlushRange(destBufferR, bufferSampleHalfNum << 1);
2638     }
2639     else
2640     {
2641         FillStreamBuffer(destBufferL,
2642                          NULL,
2643                          bufferSampleHalfNum);
2644         DCFlushRange(destBufferL, bufferSampleHalfNum << 1);
2645     }
2646 
2647     return;
2648 }
2649 #endif
2650 
2651 /*---------------------------------------------------------------------------*
2652     Name:           StreamPlay
2653 
2654     Description:    Start streaming
2655 
2656     Arguments:      None
2657 
2658     Returns:        None
2659  *---------------------------------------------------------------------------*/
2660 
StreamPlay(void)2661 static void StreamPlay(void)
2662 {
2663     if (StreamL)
2664     {
2665         AXSetVoiceState(StreamL, AX_PB_STATE_RUN);
2666     }
2667 
2668     if (StreamR)
2669     {
2670         AXSetVoiceState(StreamR, AX_PB_STATE_RUN);
2671     }
2672 
2673     return;
2674 }
2675 
2676 /*---------------------------------------------------------------------------*
2677     Name:           StreamPause
2678 
2679     Description:    Pause streaming
2680 
2681     Arguments:      None
2682 
2683     Returns:        None
2684  *---------------------------------------------------------------------------*/
2685 
StreamPause(void)2686 static void StreamPause(void)
2687 {
2688     if (StreamL)
2689     {
2690         AXSetVoiceState(StreamL, AX_PB_STATE_STOP);
2691     }
2692 
2693     if (StreamR)
2694     {
2695         AXSetVoiceState(StreamR, AX_PB_STATE_STOP);
2696     }
2697 
2698     return;
2699 }
2700 
2701 /*---------------------------------------------------------------------------*
2702     Name:           StreamQuit
2703 
2704     Description:    Stop streaming
2705 
2706     Arguments:      None
2707 
2708     Returns:        None
2709  *---------------------------------------------------------------------------*/
2710 
StreamQuit(void)2711 static void StreamQuit(void)
2712 {
2713     if (StreamL)
2714     {
2715         MIXReleaseChannel(StreamL);
2716         AXFreeVoice(StreamL);
2717         StreamL = NULL;
2718     }
2719 
2720     if (StreamR)
2721     {
2722         MIXReleaseChannel(StreamR);
2723         AXFreeVoice(StreamR);
2724         StreamR = NULL;
2725     }
2726 
2727     return;
2728 }
2729 
2730 #ifndef HOLLYWOOD_REV
2731 /*---------------------------------------------------------------------------*
2732     Name:           THPPlayerCalcNeedAmemory
2733 
2734     Description:    Calculates A Memory for THP movie playback
2735 
2736     Arguments:      None
2737 
2738     Returns:        If successful, returns memory size needed.  If unsuccessful, returns 0.
2739  *---------------------------------------------------------------------------*/
2740 
THPPlayerCalcNeedAmemory(void)2741 u32 THPPlayerCalcNeedAmemory(void)
2742 {
2743     u32 size;
2744 
2745     if (ActivePlayer.open && ActivePlayer.audioExist)
2746     {
2747         size = (OSRoundUp32B(STREAM_BUFFER_MS * ActivePlayer.audioInfo.sndFrequency / 1000.0f + 0.5f) * 2
2748              * ActivePlayer.audioInfo.sndChannels);
2749 
2750         return size;
2751     }
2752 
2753     return 0;
2754 }
2755 
2756 /*---------------------------------------------------------------------------*
2757     Name:           THPPlayerSetAmemory
2758 
2759     Description:    Allocates A memory for THP movie playback
2760 
2761     Arguments:      addr  Address of A memory set aside externally
2762 
2763     Returns:        Returns TRUE if successful, and FALSE if unsuccessful.
2764  *---------------------------------------------------------------------------*/
2765 
THPPlayerSetAmemory(u32 addr)2766 BOOL THPPlayerSetAmemory(u32 addr)
2767 {
2768     if (ActivePlayer.open && (ActivePlayer.state == THP_PLAYER_STOP))
2769     {
2770         AmemoryL = addr;
2771         addr += (OSRoundUp32B(STREAM_BUFFER_MS * ActivePlayer.audioInfo.sndFrequency / 1000.0f + 0.5f) * 2);
2772         if (ActivePlayer.audioInfo.sndChannels == 2)
2773         {
2774             AmemoryR = addr;
2775         }
2776 
2777         return TRUE;
2778     }
2779 
2780     return FALSE;
2781 }
2782 #endif
2783 
2784 /*---------------------------------------------------------------------------*
2785     Name:           THPPlayerGetStreamAXPB
2786 
2787     Description:    Acquires AXVPB pointer set aside internally
2788 
2789     Arguments:      left  Pointer to pointer variable to save left channel
2790                           AXVPB pointer.
2791                     right Pointer to pointer variable to save right channel
2792                           AXVPB pointer.
2793 
2794     Returns:        None
2795  *---------------------------------------------------------------------------*/
2796 
THPPlayerGetStreamAXPB(AXVPB ** left,AXVPB ** right)2797 void THPPlayerGetStreamAXPB(AXVPB **left, AXVPB **right)
2798 {
2799     *left  = StreamL;
2800     *right = StreamR;
2801 
2802     return;
2803 }
2804