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