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