mirror of
https://github.com/Fledge68/WiiFlow_Lite.git
synced 2024-12-11 20:44:21 +01:00
353 lines
8.0 KiB
C++
353 lines
8.0 KiB
C++
/***************************************************************************
|
|
* Copyright (C) 2010
|
|
* by Dimok
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any
|
|
* damages arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any
|
|
* purpose, including commercial applications, and to alter it and
|
|
* redistribute it freely, subject to the following restrictions:
|
|
*
|
|
* 1. The origin of this software must not be misrepresented; you
|
|
* must not claim that you wrote the original software. If you use
|
|
* this software in a product, an acknowledgment in the product
|
|
* documentation would be appreciated but is not required.
|
|
*
|
|
* 2. Altered source versions must be plainly marked as such, and
|
|
* must not be misrepresented as being the original software.
|
|
*
|
|
* 3. This notice may not be removed or altered from any source
|
|
* distribution.
|
|
*
|
|
* WiiMovie.cpp
|
|
*
|
|
* for WiiXplorer 2010
|
|
***************************************************************************/
|
|
#include <unistd.h>
|
|
#include <asndlib.h>
|
|
#include <wiiuse/wpad.h>
|
|
|
|
#include "WiiMovie.hpp"
|
|
#include "musicplayer.h"
|
|
#include "gecko.h"
|
|
|
|
#define SND_BUFFERS 8
|
|
#define FRAME_BUFFERS 8
|
|
|
|
static BufferCircle * soundBuffer = NULL;
|
|
|
|
WiiMovie::WiiMovie(const char * filepath)
|
|
{
|
|
VideoFrameCount = 0;
|
|
fps = 0.0f;
|
|
ExitRequested = false;
|
|
fullScreen = false;
|
|
Playing = false;
|
|
volume = 128;
|
|
ThreadStack = NULL;
|
|
PlayThread = LWP_THREAD_NULL;
|
|
|
|
gprintf("Opening video '%s'\n", filepath);
|
|
|
|
string file(filepath);
|
|
Video = openVideo(file);
|
|
if(!Video)
|
|
{
|
|
gprintf("Open video failed\n");
|
|
ExitRequested = true;
|
|
return;
|
|
}
|
|
|
|
SndChannels = (Video->getNumChannels() == 2) ? VOICE_STEREO_16BIT : VOICE_MONO_16BIT;
|
|
SndFrequence = Video->getFrequency();
|
|
fps = Video->getFps();
|
|
maxSoundSize = Video->getMaxAudioSamples()*Video->getNumChannels()*2;
|
|
gprintf("Open video succeeded: sound channels: %d, Frequency: %d, FPS: %4.3f\n", SndChannels, SndFrequence, fps);
|
|
|
|
if (Video->hasSound())
|
|
{
|
|
gprintf("Video has sound\n");
|
|
soundBuffer = &SoundBuffer;
|
|
soundBuffer->Resize(SND_BUFFERS);
|
|
soundBuffer->SetBufferBlockSize(maxSoundSize * FRAME_BUFFERS);
|
|
}
|
|
|
|
PlayThreadStack = NULL;
|
|
ThreadStack = (u8 *) memalign(32, 32768);
|
|
if (!ThreadStack)
|
|
return;
|
|
|
|
LWP_MutexInit(&mutex, true);
|
|
LWP_CreateThread (&ReadThread, UpdateThread, this, ThreadStack, 32768, LWP_PRIO_HIGHEST);
|
|
gprintf("Reading frames thread started\n");
|
|
}
|
|
|
|
WiiMovie::~WiiMovie()
|
|
{
|
|
gprintf("Destructing WiiMovie object\n");
|
|
Playing = true;
|
|
ExitRequested = true;
|
|
|
|
Stop();
|
|
|
|
LWP_ResumeThread(ReadThread);
|
|
LWP_JoinThread(ReadThread, NULL);
|
|
LWP_MutexDestroy(mutex);
|
|
|
|
ASND_StopVoice(10);
|
|
MusicPlayer::Instance()->Play();
|
|
|
|
if (ReadThread != LWP_THREAD_NULL)
|
|
{
|
|
LWP_ResumeThread(ReadThread);
|
|
LWP_JoinThread(ReadThread, NULL);
|
|
}
|
|
if (mutex != LWP_MUTEX_NULL)
|
|
{
|
|
LWP_MutexUnlock(mutex);
|
|
LWP_MutexDestroy(mutex);
|
|
}
|
|
if (ThreadStack != NULL)
|
|
{
|
|
SAFE_FREE(ThreadStack);
|
|
ThreadStack = NULL;
|
|
}
|
|
|
|
soundBuffer = NULL;
|
|
|
|
Frames.clear();
|
|
|
|
if(Video)
|
|
closeVideo(Video);
|
|
}
|
|
|
|
bool WiiMovie::Play(bool loop)
|
|
{
|
|
if(!Video) return false;
|
|
|
|
gprintf("Start playing video\n");
|
|
|
|
PlayThreadStack = (u8 *) memalign(32, 32768);
|
|
if (PlayThreadStack == NULL) return false;
|
|
|
|
Playing = true;
|
|
PlayTime.reset();
|
|
|
|
Video->loop = loop;
|
|
|
|
gprintf("Start playing thread\n");
|
|
|
|
LWP_ResumeThread(ReadThread);
|
|
LWP_CreateThread(&PlayThread, PlayingThread, this, PlayThreadStack, 32768, 70);
|
|
|
|
return true;
|
|
}
|
|
|
|
void WiiMovie::Stop()
|
|
{
|
|
gprintf("Stopping WiiMovie video\n");
|
|
ExitRequested = true;
|
|
if (PlayThread != LWP_THREAD_NULL)
|
|
{
|
|
LWP_JoinThread(PlayThread, NULL);
|
|
}
|
|
PlayThread = LWP_THREAD_NULL;
|
|
gprintf("Playing thread stopped\n");
|
|
|
|
SAFE_FREE(PlayThreadStack);
|
|
}
|
|
|
|
void WiiMovie::SetVolume(int vol)
|
|
{
|
|
volume = 255 * vol/100;
|
|
ASND_ChangeVolumeVoice(10, volume, volume);
|
|
}
|
|
|
|
void WiiMovie::SetScreenSize(int width, int height, int top, int left)
|
|
{
|
|
screenwidth = width;
|
|
screenheight = height;
|
|
screenleft = left;
|
|
screentop = top;
|
|
}
|
|
|
|
void WiiMovie::SetFullscreen()
|
|
{
|
|
if(!Video) return;
|
|
|
|
float newscale = 1000.0f;
|
|
|
|
float vidwidth = (float) width * 1.0f;
|
|
float vidheight = (float) height * 1.0f;
|
|
int retries = 100;
|
|
fullScreen = true;
|
|
|
|
while(vidheight * newscale > screenheight || vidwidth * newscale > screenwidth)
|
|
{
|
|
if(vidheight * newscale > screenheight)
|
|
newscale = screenheight/vidheight;
|
|
if(vidwidth * newscale > screenwidth)
|
|
newscale = screenwidth/vidwidth;
|
|
|
|
retries--;
|
|
if(retries == 0)
|
|
{
|
|
newscale = 1.0f;
|
|
break;
|
|
}
|
|
}
|
|
|
|
scaleX = scaleY = newscale;
|
|
}
|
|
|
|
void WiiMovie::SetFrameSize(int w, int h)
|
|
{
|
|
if(!Video) return;
|
|
|
|
scaleX = (float) w /(float) width;
|
|
scaleY = (float) h /(float) height;
|
|
}
|
|
|
|
void WiiMovie::SetAspectRatio(float Aspect)
|
|
{
|
|
if(!Video) return;
|
|
|
|
float vidwidth = (float) height*scaleY*Aspect;
|
|
|
|
scaleX = (float) width/vidwidth;
|
|
}
|
|
|
|
extern "C" void THPSoundCallback(int voice)
|
|
{
|
|
if (!soundBuffer || !soundBuffer->IsBufferReady()) return;
|
|
|
|
if(ASND_AddVoice(voice, soundBuffer->GetBuffer(), soundBuffer->GetBufferSize()) != SND_OK)
|
|
return;
|
|
|
|
soundBuffer->LoadNext();
|
|
}
|
|
|
|
void WiiMovie::FrameLoadLoop()
|
|
{
|
|
while (!ExitRequested)
|
|
{
|
|
LoadNextFrame();
|
|
|
|
while (Frames.size() > FRAME_BUFFERS && !ExitRequested)
|
|
usleep(100);
|
|
}
|
|
}
|
|
|
|
void * WiiMovie::UpdateThread(void *arg)
|
|
{
|
|
WiiMovie *movie = static_cast<WiiMovie *>(arg);
|
|
while (!movie->ExitRequested)
|
|
{
|
|
movie->ReadNextFrame();
|
|
usleep(100);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void * WiiMovie::PlayingThread(void *arg)
|
|
{
|
|
WiiMovie *movie = static_cast<WiiMovie *>(arg);
|
|
movie->FrameLoadLoop();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void WiiMovie::ReadNextFrame()
|
|
{
|
|
if(!Playing) LWP_SuspendThread(ReadThread);
|
|
|
|
u32 FramesNeeded = (u32) (PlayTime.elapsed()*fps);
|
|
|
|
gprintf("Reading needed frames: %d\n", FramesNeeded);
|
|
|
|
while(VideoFrameCount < FramesNeeded)
|
|
{
|
|
LWP_MutexLock(mutex);
|
|
Video->loadNextFrame();
|
|
LWP_MutexUnlock(mutex);
|
|
|
|
++VideoFrameCount;
|
|
|
|
gprintf("Loaded video frame: %d\n", VideoFrameCount);
|
|
|
|
if(Video->hasSound())
|
|
{
|
|
u32 newWhich = SoundBuffer.Which();
|
|
int i = 0;
|
|
for (i = 0; i < SoundBuffer.Size()-2; ++i)
|
|
{
|
|
if (!SoundBuffer.IsBufferReady(newWhich)) break;
|
|
|
|
newWhich = (newWhich + 1) % SoundBuffer.Size();
|
|
}
|
|
|
|
if (i == SoundBuffer.Size() - 2) return;
|
|
|
|
int currentSize = SoundBuffer.GetBufferSize(newWhich);
|
|
currentSize += Video->getCurrentBuffer((s16 *) (&SoundBuffer.GetBuffer(newWhich)[currentSize]))*SndChannels*2;
|
|
SoundBuffer.SetBufferSize(newWhich, currentSize);
|
|
|
|
if(currentSize >= (FRAME_BUFFERS-1)*maxSoundSize)
|
|
SoundBuffer.SetBufferReady(newWhich, true);
|
|
|
|
if(ASND_StatusVoice(10) == SND_UNUSED && SoundBuffer.IsBufferReady())
|
|
{
|
|
ASND_StopVoice(10);
|
|
ASND_SetVoice(10, SndChannels == 2 ? VOICE_STEREO_16BIT : VOICE_MONO_16BIT, SndFrequence, 0, SoundBuffer.GetBuffer(), SoundBuffer.GetBufferSize(), volume, volume, THPSoundCallback);
|
|
SoundBuffer.LoadNext();
|
|
}
|
|
}
|
|
}
|
|
|
|
// usleep(100);
|
|
}
|
|
|
|
void WiiMovie::LoadNextFrame()
|
|
{
|
|
if(!Video || !Playing)
|
|
{
|
|
return;
|
|
}
|
|
|
|
VideoFrame VideoF;
|
|
LWP_MutexLock(mutex);
|
|
Video->getCurrentFrame(VideoF);
|
|
LWP_MutexUnlock(mutex);
|
|
|
|
if(!VideoF.getData()) return;
|
|
|
|
if(width != VideoF.getWidth())
|
|
{
|
|
width = VideoF.getWidth();
|
|
height = VideoF.getHeight();
|
|
if (fullScreen)
|
|
SetFullscreen();
|
|
else
|
|
{
|
|
// Calculate new top and left
|
|
screenleft = (screenwidth - width) / 2;
|
|
screentop = (screenheight - height) / 2;
|
|
}
|
|
}
|
|
|
|
STexture frame;
|
|
if (frame.fromRAW(VideoF.getData(), VideoF.getWidth(), VideoF.getHeight()) == STexture::TE_OK)
|
|
Frames.push_back(frame);
|
|
}
|
|
|
|
bool WiiMovie::GetNextFrame(STexture *tex)
|
|
{
|
|
if (!Video || Frames.size() == 0) return false;
|
|
|
|
*tex = Frames.at(0);
|
|
Frames.erase(Frames.begin());
|
|
return true;
|
|
}
|