Mercurial > hg > easaier-soundaccess
view data/fileio/VideoFileReader.cpp @ 150:c946c19e6329
(none)
author | ivand_qmul |
---|---|
date | Wed, 14 Nov 2007 15:11:46 +0000 |
parents | e63e8272dcb0 |
children | 2ac52ea3c1c4 |
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ /* Sound Access EASAIER client application. Queen Mary 2007. Ivan Damnjanovic. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See the file COPYING included with this distribution for more information. */ #ifdef HAVE_FFMPEG //#include "system/System.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <iostream> #include <QApplication> #include <QFileInfo> #include <QProgressDialog> #include "VideoFileReader.h" #ifdef WIN32 #include <Windows.h> #endif extern float zoomFivan; long long countFreq; int Videow=320; int Videoh=240; VideoFileReader::VideoFileReader(QString path, bool showProgress, CacheMode mode) : CodedAudioFileReader(mode), m_path(path) { m_frameCount = 0; m_channelCount = 0; m_sampleRate = 0; m_fileSize = 0; m_bitrateNum = 0; m_bitrateDenom = 0; m_cancelled = false; struct stat stat; if (::stat(path.toLocal8Bit().data(), &stat) == -1 || stat.st_size == 0) { m_error = QString("File %1 does not exist.").arg(path); return; } // standard SDL initialization stuff if(SDL_Init(SDL_INIT_VIDEO|SDL_DOUBLEBUF|SDL_INIT_AUDIO) < 0) { m_error = QString("Failed to open file %1 for reading.").arg(SDL_GetError()); return; } m_fileSize = stat.st_size; // open file from arg[1] film = SDL_ffmpegOpen(path.toLocal8Bit().data()); if (path.endsWith("mpg")) film->delay=1; if (path.endsWith("divx")) film->delay=1; if(!film) { m_error = QString("Failed to open file %1 for reading.").arg(path); return; } // print some info on detected stream to output film->skipAudio=0; film->skipVideo=0; int s; SDL_ffmpegStream *str; for(s = 0; s<film->VStreams; s++) str = SDL_ffmpegGetVideoStream(film, s); SDL_ffmpegSelectVideoStream(film, 0); film->skipVideo=1; for(s = 0; s<film->AStreams; s++) str = SDL_ffmpegGetAudioStream(film, s); SDL_ffmpegSelectAudioStream(film, 0); if (showProgress) { m_progress = new QProgressDialog (QObject::tr("Decoding %1...").arg(QFileInfo(path).fileName()), QObject::tr("Stop"), 0, 100); m_progress->hide(); } m_sampleRate=str->sampleRate; int channels=str->channels; m_channelCount=channels; SDL_ffmpegPause(film, 0); SDL_ffmpegStartDecoding(film); if (!decodeAudio(film)) { m_error = QString("Failed to decode audio from file %1 for reading.").arg(path); return; } film->skipAudio=1; //SDL_ffmpegSeek(film, 0); //SDL_ffmpegStopDecoding(film); SDL_Delay(5); film->skipVideo=0; film->videoThread=SDL_CreateThread(videoPlayCall,this); if (showProgress) { delete m_progress; m_progress = 0; } //delete[] filebuffer; } VideoFileReader::~VideoFileReader() { film->videoThreadActive = 0; if(film->videoThread) SDL_WaitThread(film->videoThread, 0); } bool VideoFileReader::decodeAudio(SDL_ffmpegFile* file) { int64_t duration=((AVFormatContext *)file->_ffmpeg)->duration; double elapsed = 0; m_cancelled=false; int audio_ends=0; while((elapsed < duration)&&!m_cancelled ) { elapsed = double(m_frameCount)*1000000 /(m_channelCount*m_sampleRate); double percent = (elapsed * 100) / duration; int progress = int(percent); if (progress < 1) progress = 1; if (progress > 99) progress = 99; if (progress > m_progress->value()) { m_progress->setValue(progress); m_progress->show(); m_progress->raise(); qApp->processEvents(); if (m_progress->wasCanceled()) { m_cancelled = true; } } // we tell SDL_ffmpegGetAudio how many bytes we need, the function then // fills this pointer with the amount of bytes it could actually give int gotLength = 100000; if (!isDecodeCacheInitialised()) { initialiseDecodeCache(); } // we try to get some data from our file // important! this call is paired with SDL_ffmpegReleaseAudio int16_t* audio =(int16_t *) SDL_ffmpegGetAudio(file, &gotLength); for (int i=0; i<gotLength/2;i++) { float sample=float(*audio++)/float(2*32768); addSampleToDecodeCache(sample); } // copy the bytes we got to audiocard // if(audio) memcpy(stream, audio, gotLength); // we release our audio data, so the decode thread can fill it again // we also inform this function of the amount of bytes we used, so it can // move the buffer accordingly // important! this call is paired with SDL_ffmpegGetAudio SDL_ffmpegReleaseAudio(file, gotLength); //decode_audio(film, 1000000); m_frameCount+=gotLength/2; if ((progress > 97)&&(gotLength<=0)) audio_ends++; if (audio_ends>=2000) m_cancelled = true; } m_frameCount/=m_channelCount; if (isDecodeCacheInitialised()) finishDecodeCache(); return true; } bool VideoFileReader::videoInit(SDL_ffmpegFile* file) { int w,h; // we get the size from our active video stream, if no active video stream // exists, width and height are set to default values (320x240) SDL_ffmpegGetVideoSize(file, &w, &h); MainWindow * MWins=MainWindow::instance(); MWins->setSDLInitSize(w,h); SDL_Init(SDL_INIT_VIDEO); Videow=w=320*zoomFivan; Videoh=h=240*zoomFivan; // Open the Video device screen = SDL_SetVideoMode(w, h, 0, SDL_DOUBLEBUF|SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL); //SDL_WM_SetCaption("EASAIER Video Player", "EASAIER Video Player"); if(!screen) { printf("Couldn't open video: %s\n", SDL_GetError()); return false; } return true; } int VideoFileReader::videoPlayCall(void *t) { return ((VideoFileReader *)t)->videoPlay(); } int VideoFileReader::videoPlay() { film->videoThreadActive = 1; MainWindow * MWins=MainWindow::instance(); if (!videoInit(film)) { m_error = QString("Failed to failed to initalized video file for reading."); return 0; } //const SDL_VideoInfo * vid=SDL_GetVideoInfo(); film->audioTime =0; int w,h; SDL_ffmpegGetVideoSize(film, &w, &h); //SDL_ffmpegStartDecoding(film); SDL_Delay(1000); QueryPerformanceFrequency((LARGE_INTEGER *)(&countFreq)); countFreq/=1000; film->countFreq=countFreq; QueryPerformanceCounter((LARGE_INTEGER *)(&film->timer)); film->timer=film->timer/(film->countFreq); film->timebase=1; film->vs[film->videoStream]->lastTimeStamp=0; while( film->videoThreadActive ) { if (!(w==(int)(320*zoomFivan))){ w=320*zoomFivan; h=240*zoomFivan; // Open the Video device screen = SDL_SetVideoMode(w, h, 0, SDL_DOUBLEBUF|SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL); } if (MWins->isAudioPlaying()) { if ((SDL_ffmpegGetState(film))||((long)(abs((long)(film->audioTime - (int64_t)(MWins->Get_CurAudioTime()))))>=1000)) { //SDL_Delay(1000); film->audioTime = MWins->Get_CurAudioTime(); SDL_ffmpegSeek(film, film->audioTime); SDL_ffmpegPause(film, 0); } else film->audioTime = MWins->Get_CurAudioTime(); } else { SDL_ffmpegPause(film, 1); } // we retrieve the current image from the file // we get 0 if no file could be retrieved // important! please note this call should be paired with SDL_ffmpegReleaseVideo SDL_Surface* bmp = SDL_ffmpegGetVideo((SDL_ffmpegFile *)film); if(bmp) { // we got a frame, so we better show this one SDL_BlitSurface(bmp, 0, screen, 0); // we flip the double buffered screen so we might actually see something SDL_Flip(screen); // After releasing bmp, you can no longer use it. // you should call this function every time you get a frame! SDL_ffmpegReleaseVideo((SDL_ffmpegFile *)film, bmp); } // we wish not to kill our poor cpu, so we give it some timeoff // SDL_Delay(1); } // after all is said and done, we should call this SDL_ffmpegFree(film); return 0; } void VideoFileReader::getSupportedExtensions(std::set<QString> &extensions) { extensions.insert("mpg"); extensions.insert("avi"); extensions.insert("divx"); extensions.insert("mov"); } #endif