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