/*---------------------------------------------------------------------------* Project: THP Player File: THPVideoDecode.c Copyright (C)2002-2006 Nintendo All Rights Reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Log: THPVideoDecode.c,v $ Revision 1.1 02/03/2006 10:01:27 aka Imported from Dolphin tree. 4 03/11/25 11:24 Dante Japanese to English translation of comments and text strings 3 03/09/24 9:09a Akagi Added explicit cast. 2 03/09/16 15:50:00 Suzuki changed the process which skips to decode when decoding is delay. 1 02/05/14 11:30a Suzuki Initial check-in. $NoKeywords: $ *---------------------------------------------------------------------------*/ #include #include "THPPlayerStrmAX.h" #include "THPVideoDecode.h" #include "THPRead.h" /*---------------------------------------------------------------------------* External Function *---------------------------------------------------------------------------*/ extern void PrepareReady(BOOL flag); /*---------------------------------------------------------------------------* Static Function *---------------------------------------------------------------------------*/ static void *VideoDecoder(void *ptr); static void *VideoDecoderForOnMemory(void *ptr); static u32 VideoDecode(THPReadBuffer *readBuffer); /*---------------------------------------------------------------------------* Global Variable *---------------------------------------------------------------------------*/ extern THPPlayer ActivePlayer; /*---------------------------------------------------------------------------* Static Variable *---------------------------------------------------------------------------*/ static s32 VideoDecodeThreadCreated = 0; static OSThread VideoDecodeThread; static u8 VideoDecodeThreadStack[4*1024]; static OSMessageQueue FreeTextureSetQueue; static OSMessageQueue DecodedTextureSetQueue; static OSMessage FreeTextureSetMessage[DECODE_VIDEO_BUFFER_NUM]; static OSMessage DecodedTextureSetMessage[DECODE_VIDEO_BUFFER_NUM]; static s32 First; /*---------------------------------------------------------------------------* Name: CreateVideoDecodeThread Description: Create video decode thread Arguments: priority Thread priority ptr Pointer to memory where THP movie start data is for OnMemory playback. Returns: If thread creation succeeds returns TRUE. If fails, returns FALSE. *---------------------------------------------------------------------------*/ BOOL CreateVideoDecodeThread(OSPriority priority, u8 *ptr) { if (ptr) { if (OSCreateThread(&VideoDecodeThread, VideoDecoderForOnMemory, ptr, VideoDecodeThreadStack + sizeof(VideoDecodeThreadStack), sizeof(VideoDecodeThreadStack), priority, OS_THREAD_ATTR_DETACH) == FALSE) { #ifdef _DEBUG OSReport("Can't create video decode thread\n"); #endif return FALSE; } } else { if (OSCreateThread(&VideoDecodeThread, VideoDecoder, NULL, VideoDecodeThreadStack + sizeof(VideoDecodeThreadStack), sizeof(VideoDecodeThreadStack), priority, OS_THREAD_ATTR_DETACH) == FALSE) { #ifdef _DEBUG OSReport("Can't create video decode thread\n"); #endif return FALSE; } } OSInitMessageQueue(&FreeTextureSetQueue, FreeTextureSetMessage, DECODE_VIDEO_BUFFER_NUM); OSInitMessageQueue(&DecodedTextureSetQueue, DecodedTextureSetMessage, DECODE_VIDEO_BUFFER_NUM); VideoDecodeThreadCreated = 1; First = 1; return TRUE; } /*---------------------------------------------------------------------------* Name: VideoDecodeThreadStart Description: Start of video decode thread Arguments: None Returns: None *---------------------------------------------------------------------------*/ void VideoDecodeThreadStart(void) { if (VideoDecodeThreadCreated) { OSResumeThread(&VideoDecodeThread); } return; } /*---------------------------------------------------------------------------* Name: VideoDecodeThreadCancel Description: Cancel video decode thread Arguments: None Returns: None *---------------------------------------------------------------------------*/ void VideoDecodeThreadCancel(void) { if (VideoDecodeThreadCreated) { OSCancelThread(&VideoDecodeThread); VideoDecodeThreadCreated = 0; } return; } /*---------------------------------------------------------------------------* Name: VideoDecoder Description: Video decoder streaming playback Arguments: None Returns: None *---------------------------------------------------------------------------*/ static void *VideoDecoder(void *ptr) { #pragma unused(ptr) THPReadBuffer *readBuffer; s32 frameNumber; u32 skipCount = 0; while (1) { if (ActivePlayer.audioExist) { // Skip decoding if video decoding is delayed while (skipCount) { readBuffer = (THPReadBuffer *)PopReadedBuffer2(); frameNumber = (s32)((readBuffer->frameNumber + ActivePlayer.initReadFrame) % ActivePlayer.header.numFrames); // Always decode last frame with one-shot playback if (frameNumber == ActivePlayer.header.numFrames - 1) { if (!(ActivePlayer.playFlag & THP_PLAY_LOOP)) { VideoDecode(readBuffer); } } PushFreeReadBuffer(readBuffer); skipCount--; // Increment as decoded ActivePlayer.videoDecodeCount++; } } if (ActivePlayer.audioExist) { readBuffer = (THPReadBuffer *)PopReadedBuffer2(); } else { readBuffer = (THPReadBuffer *)PopReadedBuffer(); } skipCount = VideoDecode(readBuffer); PushFreeReadBuffer(readBuffer); } return NULL; } /*---------------------------------------------------------------------------* Name: VideoDecoderForOnMemory Description: Video decoder for OnMemory playback Arguments: None Returns: None *---------------------------------------------------------------------------*/ static void *VideoDecoderForOnMemory(void *ptr) { THPReadBuffer readBuffer; s32 tmp, size, readFrame, frameNumber; u32 skipCount; size = ActivePlayer.initReadSize; readBuffer.ptr = (u8 *)ptr; readFrame = 0; skipCount = 0; while(1) { if (ActivePlayer.audioExist) { // Skip decoding if video decoding is delayed while (skipCount) { skipCount--; // Increment as decoded ActivePlayer.videoDecodeCount++; frameNumber = (s32)((readFrame + ActivePlayer.initReadFrame) % ActivePlayer.header.numFrames); // Check THP movie end if (frameNumber == ActivePlayer.header.numFrames - 1) { // If loop playback, at beginning of THP movie if (ActivePlayer.playFlag & THP_PLAY_LOOP) { size = *(s32 *)(readBuffer.ptr); readBuffer.ptr = ActivePlayer.movieData; } // Always decode last frame with one-shot playback else { break; } } // If not last, move pointer to next frame else { tmp = *(s32 *)(readBuffer.ptr); readBuffer.ptr += size; size = tmp; } readFrame++; } } readBuffer.frameNumber = readFrame; skipCount = VideoDecode(&readBuffer); frameNumber = (s32)((readFrame + ActivePlayer.initReadFrame) % ActivePlayer.header.numFrames); // Check THP movie end if (frameNumber == ActivePlayer.header.numFrames - 1) { // If loop playback, at beginning of THP movie if (ActivePlayer.playFlag & THP_PLAY_LOOP) { size = *(s32 *)(readBuffer.ptr); readBuffer.ptr = ActivePlayer.movieData; } // If one-shot playback, stop decoding else { OSSuspendThread(&VideoDecodeThread); } } // If not last, move pointer to next frame else { tmp = *(s32 *)(readBuffer.ptr); readBuffer.ptr += size; size = tmp; } readFrame++; } return NULL; } /*---------------------------------------------------------------------------* Name: VideoDecode Description: Decode THP video data Arguments: readBuffer: Pointer to buffer where THP frame stored. Returns: Frame number to show decode delay *---------------------------------------------------------------------------*/ static u32 VideoDecode(THPReadBuffer *readBuffer) { THPTextureSet *textureSet; u32 i; u32 ret = 0; u32 *compSizePtr; u8 *ptr; compSizePtr = (u32 *)(readBuffer->ptr + 8); ptr = readBuffer->ptr + ActivePlayer.compInfo.numComponents * 4 + 8; textureSet = (THPTextureSet *)PopFreeTextureSet(); for (i = 0 ; i < ActivePlayer.compInfo.numComponents ; i++) { switch (ActivePlayer.compInfo.frameComp[i]) { case THP_VIDEO_COMP: if ((ActivePlayer.videoError = THPVideoDecode(ptr, textureSet->ytexture, textureSet->utexture, textureSet->vtexture, ActivePlayer.thpWork)) != THP_OK) { if (First) { PrepareReady(FALSE); First = 0; } OSSuspendThread(&VideoDecodeThread); } textureSet->frameNumber = readBuffer->frameNumber; PushDecodedTextureSet(textureSet); // Check decode delay // curVideoNumber displays current ideal video number. Since // video number starts from 0, add 1 when comparing with videoDecodeCount if (ActivePlayer.curVideoNumber + 1 > ActivePlayer.videoDecodeCount) { // Calculate delayed frame number ret = (u32)(ActivePlayer.curVideoNumber + 1 - ActivePlayer.videoDecodeCount); } else { ret = 0; } // Increment decoded THP video data count ActivePlayer.videoDecodeCount++; break; } ptr += *compSizePtr; compSizePtr++; } if (First) { PrepareReady(TRUE); First = 0; } return ret; } /*---------------------------------------------------------------------------* Name: PopFreeTextureSet Description: Acquire free texture buffers Arguments: None Returns: Pointer for texture buffers not used. *---------------------------------------------------------------------------*/ void *PopFreeTextureSet() { OSMessage msg; OSReceiveMessage(&FreeTextureSetQueue, &msg, OS_MESSAGE_BLOCK); return msg; } /*---------------------------------------------------------------------------* Name: PushFreeTextureSet Description: Free played back THP video data. Arguments: buffer: Pointer for played back THP video data. Returns: None *---------------------------------------------------------------------------*/ void PushFreeTextureSet(void *buffer) { OSSendMessage(&FreeTextureSetQueue, buffer, OS_MESSAGE_NOBLOCK); return; } /*---------------------------------------------------------------------------* Name: PopDecodedTextureSet Description: Acquire decoded THP video data Arguments: flag: If OS_MESSAGE_BLOCK, block until can get decoded THP video data. If OS_MESSAGE_NOBLOCK, do not block. Returns: If successful, return pointer to texture buffer. If unsuccessful, return NULL. *---------------------------------------------------------------------------*/ void *PopDecodedTextureSet(s32 flag) { OSMessage msg; if (OSReceiveMessage(&DecodedTextureSetQueue, &msg, flag) == TRUE) { return msg; } else { return NULL; } } /*---------------------------------------------------------------------------* Name: PushDecodedTextureSet Description: Push decoded THP video data to queue. Arguments: buffer Pointer for decoded THP video data. Returns: None *---------------------------------------------------------------------------*/ void PushDecodedTextureSet(void *buffer) { OSSendMessage(&DecodedTextureSetQueue, buffer, OS_MESSAGE_BLOCK); return; }