wiiqt6/thp_player/thpwindow.cpp

379 lines
9.6 KiB
C++

#include "thpwindow.h"
#include "ui_thpwindow.h"
#include "../WiiQt/tools.h"
#define MAX_BUFFERS 50 //in frames
#define BUFFER_DELAY 200 //time to wait between checking buffer size ( msecs )
ThpWindow::ThpWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::ThpWindow)
{
ui->setupUi( this );
ui->mainToolBar->setVisible( false );
ui->label_fName->clear();
ui->label_fpsT->clear();
ui->label_itemNo->clear();
ui->label_sizeT->clear();
ui->label_timeCur->clear();
ui->label_timeFull->clear();
ui->label_video->clear();
ui->scrollArea->setWidgetResizable( false );
EnableGui( false );
ui->statusBar->addPermanentWidget( ui->label_fName, 0 );
ui->statusBar->addPermanentWidget( ui->label_itemNo, 0 );
AudioOutputDevice = NULL;
AudioOutput = NULL;
videoFile = NULL;
dontBuffer = false;
//currentDir = QDir::currentPath();
currentDir = "/media/Jenna/jenna/c/gui_fork/SSBB_JAP/DATA/files/movie";
//workaround for some bullshit bug in the Qt libs
foreach( const QAudioDeviceInfo &deviceInfo, QAudioDeviceInfo::availableDevices( QAudio::AudioOutput ) )
{
qDebug() << "l:" << deviceInfo.deviceName();
}
connect( &timer, SIGNAL( timeout() ), this, SLOT( ShowNextFrame() ) );
}
ThpWindow::~ThpWindow()
{
dontBuffer = true;
timer.stop();
delete ui;
if(videoFile)
{
closeVideo( videoFile );
videoFile = NULL;
}
if( AudioOutput )
{
AudioOutput->stop();
delete AudioOutput;
AudioOutput = NULL;
}
}
//open file
void ThpWindow::on_actionOpen_triggered()
{
timer.stop();
dontBuffer = true;
playList.clear();
curPlayListPos = 0;
QStringList fNames = QFileDialog::getOpenFileNames( this, tr("Open Files"), currentDir, tr("Wii/GC Videos (*.thp *.mth)") );
if( fNames.isEmpty() )
return;
foreach( QString str, fNames )
playList << str;
currentDir = QFileInfo( playList.at( 0 ) ).absolutePath();
PlayPlayListItem( 0 );
}
//open folder
void ThpWindow::on_actionOpen_Folder_triggered()
{
timer.stop();
dontBuffer = true;
playList.clear();
curPlayListPos = 0;
QString dirName = QFileDialog::getExistingDirectory( this, tr( "Open Folder" ), currentDir );
if( dirName.isEmpty() )
return;
currentDir = dirName;
QDir dir( dirName );
QFileInfoList fil = dir.entryInfoList( QStringList() << "*.thp" << "*.mth" , QDir::Files );
//qDebug() << "found" << fil.size() << "items";
foreach( QFileInfo fi, fil )
playList << fi.absoluteFilePath();
PlayPlayListItem( 0 );
}
void ThpWindow::PlayPlayListItem( quint32 i )
{
//qDebug() << "ThpWindow::PlayPlayListItem" << i;
if( !playList.size() ) //no videos to play
{
ui->label_itemNo->clear();
return;
}
if( i >= (quint32)playList.size() ) //all videos are played
{
curPlayListPos = 0; //skip back to beginning
if( !ui->pushButton_loop->isChecked() ) //dont loop
{
ui->pushButton_playPause->setChecked( false );
timer.stop();
dontBuffer = true;
}
}
ui->label_itemNo->setText( QString( "%1 / %2").arg( curPlayListPos + 1 ).arg( playList.size() ) );
LoadVideo( playList.at( curPlayListPos ) );
}
void ThpWindow::LoadVideo( const QString &path )
{
//qDebug() << "ThpWindow::LoadVideo" << path;
EnableGui( false );
std::string filepath = path.toUtf8().constData();
ui->progressBar_buffer->setValue( 0 );
//stop current video
timer.stop();
if( videoFile )
{
closeVideo( videoFile );
videoFile = NULL;
}
Frames.clear();
SoundBuffers.clear();
videoFile = openVideo( filepath );
if( !videoFile )
{
QMessageBox::information( this, tr("Player"), tr("Cannot load %1.").arg( path ) );
return;
}
//dontBuffer = false;
ui->label_video->setFixedSize( videoFile->getWidth(), videoFile->getHeight() );
frameCnt = videoFile->getFrameCount();
curFrame = 0;
for( quint8 i = 0; i < 3; i++ )
LoadNextFrame();
CreateAudioOutput();
//show some info in the gui
ui->label_fpsT->setText( QString( "%1" ).arg( videoFile->getFps(), 0, 'f', 3 ) );
ui->label_sizeT->setText( QString( "%1 x %2" ).arg( videoFile->getWidth() ).arg( videoFile->getHeight() ) );
ui->label_fName->setText( QFileInfo( path ).fileName() );
ui->horizontalSlider_pos->setMaximum( frameCnt );
//set timer for animation
qDebug() << "fps" << QString( "%1" ).arg( videoFile->getFps(), 0, 'f', 3 );
qreal delay = 1000.0f/videoFile->getFps();
qDebug() << "delay" << QString( "%1" ).arg( delay, 0, 'f', 3 );
ui->label_timeFull->setText( TimeTxt( delay * videoFile->getFrameCount() ));
timer.setInterval( delay );
//if play button is clicked, just play
if( ui->pushButton_playPause->isChecked() )
timer.start();
//otherwise just load the first frame
else
ShowNextFrame();
//allow the buttons to work
EnableGui( true );
}
QString ThpWindow::TimeTxt( quint64 msecs )
{
quint32 hours = msecs / 3600000;
msecs -= ( hours * 3600000 );
quint32 minutes = msecs / 60000;
msecs -= ( minutes * 60000 );
quint32 seconds = msecs / 1000;
msecs -= ( seconds * 1000 );
return QString( "%1:%2:%3.%4" ).arg( hours, 2, 10, QChar( '0' ) )
.arg( minutes, 2, 10, QChar( '0' ) )
.arg( seconds, 2, 10, QChar( '0' ) )
.arg( msecs, 3, 10, QChar( '0' ) );
}
void ThpWindow::LoadNextFrame()
{
//qDebug() << "ThpWindow::LoadNextFrame()";
VideoFrame VideoF;
videoFile->loadNextFrame();
videoFile->getCurrentFrame(VideoF);
QImage image(VideoF.getData(), VideoF.getWidth(), VideoF.getHeight(), QImage::Format_RGB888);
if (image.isNull())
return;
Frames.push_back(QPixmap::fromImage(image));
int SoundPos = SoundBuffers.size();
SoundBuffers.resize(SoundBuffers.size()+1);
SoundBuffers[SoundPos].Buffer.resize(videoFile->getMaxAudioSamples()*2);
SoundBuffers[SoundPos].Size = videoFile->getCurrentBuffer(&SoundBuffers[SoundPos].Buffer[0])*2*2;
}
void ThpWindow::ShowNextFrame()
{
//qDebug() << "ThpWindow::ShowNextFrame()" << Frames.size() << curFrame << frameCnt;
if( Frames.size() < 3 )
{
BufferIfNeeded();
return;
}
if( ++curFrame >= frameCnt ) //end of video
{
PlayPlayListItem( ++curPlayListPos );
return;
}
ui->horizontalSlider_pos->setValue( curFrame );
qreal delay = 1000.0f/videoFile->getFps();
ui->label_timeCur->setText( TimeTxt( delay * videoFile->getCurrentFrameNr() ) );
ui->label_video->setPixmap(Frames[2]);
//ui->label_video->setPixmap(Frames[0]);
if( AudioOutputDevice && ui->pushButton_vol->isChecked() )
//&& SoundBuffers.size() > 2
//&& SoundBuffers[ 2 ].Buffer.size()
//&& SoundBuffers[ 2 ].Size )
AudioOutputDevice->write((char *) &SoundBuffers[2].Buffer[0], SoundBuffers[2].Size);
Frames.erase(Frames.begin());
SoundBuffers.erase(SoundBuffers.begin());
}
void ThpWindow::BufferIfNeeded()
{
if( dontBuffer )
return; //break the buffer loop
if( Frames.size() < MAX_BUFFERS )//we need to read a frame
{
LoadNextFrame();
}
//show buffer in the gui
int b = ((float)Frames.size() / (float)MAX_BUFFERS) * 100.0f;
ui->progressBar_buffer->setValue( b );
//wait a bit and call this function again
QTimer::singleShot( BUFFER_DELAY, this, SLOT( BufferIfNeeded() ) );
}
void ThpWindow::CreateAudioOutput()
{
//qDebug() << "ThpWindow::CreateAudioOutput()" << timer.isActive();
if( AudioOutput )
{
AudioOutput->stop();
delete AudioOutput;
AudioOutput = NULL;
}
AudioOutputDevice = NULL;
AudioFormat.setFrequency( videoFile->getFrequency() );
AudioFormat.setChannels( videoFile->getNumChannels() );
AudioFormat.setSampleSize( 16 );
AudioFormat.setCodec( "audio/pcm" );
AudioFormat.setByteOrder( QAudioFormat::LittleEndian );
AudioFormat.setSampleType( QAudioFormat::SignedInt );
QAudioDeviceInfo info( QAudioDeviceInfo::defaultOutputDevice() );
if( !info.isFormatSupported( AudioFormat ) )
{
AudioFormat = info.nearestFormat( AudioFormat );//try to find a usable audio playback format
if( !info.isFormatSupported( AudioFormat ) )
{
qWarning() << "unsupported audio format: can't play anything";
ui->statusBar->showMessage( tr( "Can't find suitable audio format" ), 5000 );
return;
}
}
AudioOutput = new QAudioOutput( AudioFormat, this );
if( !AudioOutput )
{
ui->statusBar->showMessage( tr( "Audio output error" ), 5000 );
qWarning() << "!AudioOutput";
return;
}
AudioOutputDevice = AudioOutput->start();
if( AudioOutput->error() )
{
ui->statusBar->showMessage( tr( "Audio output error" ), 5000 );
qWarning() << "AudioOutput->error()" << AudioOutput->error();
AudioOutput->stop();
AudioOutputDevice = NULL;
}
}
//enable/disable buttons
void ThpWindow::EnableGui( bool enable )
{
ui->pushButton_ffw->setEnabled( enable );
ui->pushButton_loop->setEnabled( enable );
ui->pushButton_next->setEnabled( enable );
ui->pushButton_playPause->setEnabled( enable );
ui->pushButton_prev->setEnabled( enable );
ui->pushButton_rewind->setEnabled( enable );
ui->pushButton_stop->setEnabled( enable );
ui->pushButton_vol->setEnabled( enable );
}
//play button
void ThpWindow::on_pushButton_playPause_clicked()
{
if( ui->pushButton_playPause->isChecked() )
{
dontBuffer = false;//start buffering again after stopped
timer.start();
}
else
{
//dontBuffer = true;//ok to buffer while paused
timer.stop();
}
}
//next button
void ThpWindow::on_pushButton_next_clicked()
{
PlayPlayListItem( ++curPlayListPos );
}
//prev button
void ThpWindow::on_pushButton_prev_clicked()
{
if( !curPlayListPos )
curPlayListPos = playList.size();
PlayPlayListItem( --curPlayListPos );
}
//stop button
void ThpWindow::on_pushButton_stop_clicked()
{
//stop playback
timer.stop();
ui->pushButton_playPause->setChecked( false );
//clear buffer
dontBuffer = true;
Frames.clear();
SoundBuffers.clear();
ui->progressBar_buffer->setValue( 0 );
//set video to first frame
videoFile->SetFrameNo( 0 );
//read a few frames into buffer
curFrame = 0;
for( quint8 i = 0; i < 3; i++ )
LoadNextFrame();
//show first frame in gui
ShowNextFrame();
}