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. lbajardsilogic@191: */ lbajardsilogic@191: lbajardsilogic@191: #ifdef HAVE_FFMPEG lbajardsilogic@191: lbajardsilogic@191: lbajardsilogic@191: //#include "system/System.h" lbajardsilogic@191: lbajardsilogic@191: #include lbajardsilogic@191: #include lbajardsilogic@191: #include lbajardsilogic@191: #include lbajardsilogic@191: lbajardsilogic@191: #include lbajardsilogic@191: lbajardsilogic@191: #include lbajardsilogic@191: #include lbajardsilogic@191: #include lbajardsilogic@191: lbajardsilogic@191: #include lbajardsilogic@191: lbajardsilogic@191: #include "VideoFileReader.h" lbajardsilogic@191: ivand_qmul@129: #ifdef WIN32 ivand_qmul@129: #include lbajardsilogic@191: #endif lbajardsilogic@191: long long countFreq; lbajardsilogic@191: int Videow=320; lbajardsilogic@191: int Videoh=240; benoitrigolleau@256: int zoomWivan=320; benoitrigolleau@256: int zoomHivan=240; benoitrigolleau@256: int haveFilm=0; benoitrigolleau@256: lbajardsilogic@191: VideoFileReader::VideoFileReader(QString path, bool showProgress, CacheMode mode) : lbajardsilogic@191: CodedAudioFileReader(mode), lbajardsilogic@191: m_path(path) lbajardsilogic@191: { lbajardsilogic@191: m_frameCount = 0; lbajardsilogic@191: m_channelCount = 0; lbajardsilogic@191: m_sampleRate = 0; lbajardsilogic@191: m_fileSize = 0; lbajardsilogic@191: m_bitrateNum = 0; lbajardsilogic@191: m_bitrateDenom = 0; lbajardsilogic@191: m_cancelled = false; lbajardsilogic@191: m_zoomfactor = 1; lbajardsilogic@191: lbajardsilogic@191: struct stat stat; lbajardsilogic@191: if (::stat(path.toLocal8Bit().data(), &stat) == -1 || stat.st_size == 0) { lbajardsilogic@191: m_error = QString("File %1 does not exist.").arg(path); lbajardsilogic@191: return; lbajardsilogic@191: } 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; lbajardsilogic@191: } lbajardsilogic@191: m_fileSize = stat.st_size; lbajardsilogic@191: benoitrigolleau@256: if (haveFilm) benoitrigolleau@256: { benoitrigolleau@256: haveFilm=1; benoitrigolleau@256: SDL_ffmpegFree(film); benoitrigolleau@256: } 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) lbajardsilogic@191: { lbajardsilogic@191: m_error = QString("Failed to open file %1 for reading.").arg(path); lbajardsilogic@191: return; lbajardsilogic@191: } 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); lbajardsilogic@191: lbajardsilogic@191: SDL_ffmpegSelectAudioStream(film, 0); lbajardsilogic@191: lbajardsilogic@191: lbajardsilogic@191: if (showProgress) { lbajardsilogic@191: m_progress = new QProgressDialog lbajardsilogic@191: (QObject::tr("Decoding %1...").arg(QFileInfo(path).fileName()), lbajardsilogic@191: QObject::tr("Stop"), 0, 100); lbajardsilogic@191: m_progress->hide(); lbajardsilogic@191: } lbajardsilogic@191: 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: lbajardsilogic@191: if (!decodeAudio(film)) { lbajardsilogic@191: m_error = QString("Failed to decode audio from file %1 for reading.").arg(path); lbajardsilogic@191: 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); lbajardsilogic@191: lbajardsilogic@191: lbajardsilogic@191: lbajardsilogic@191: lbajardsilogic@191: lbajardsilogic@191: if (showProgress) { lbajardsilogic@191: delete m_progress; lbajardsilogic@191: m_progress = 0; lbajardsilogic@191: } lbajardsilogic@191: lbajardsilogic@191: //delete[] filebuffer; lbajardsilogic@191: } lbajardsilogic@191: lbajardsilogic@191: lbajardsilogic@191: VideoFileReader::~VideoFileReader() lbajardsilogic@191: { lbajardsilogic@191: film->videoThreadActive = 0; lbajardsilogic@191: if(film->videoThread) SDL_WaitThread(film->videoThread, 0); lbajardsilogic@191: } lbajardsilogic@191: bool lbajardsilogic@191: VideoFileReader::decodeAudio(SDL_ffmpegFile* file) lbajardsilogic@191: { 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 ) { lbajardsilogic@191: lbajardsilogic@191: elapsed = double(m_frameCount)*1000000 /(m_channelCount*m_sampleRate); lbajardsilogic@191: double percent = (elapsed * 100) / duration; lbajardsilogic@191: int progress = int(percent); lbajardsilogic@191: if (progress < 1) progress = 1; lbajardsilogic@191: if (progress > 99) progress = 99; lbajardsilogic@191: if (progress > m_progress->value()) { lbajardsilogic@191: m_progress->setValue(progress); lbajardsilogic@191: m_progress->show(); lbajardsilogic@191: m_progress->raise(); lbajardsilogic@191: qApp->processEvents(); lbajardsilogic@191: if (m_progress->wasCanceled()) { lbajardsilogic@191: m_cancelled = true; lbajardsilogic@191: } lbajardsilogic@191: } lbajardsilogic@191: 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; lbajardsilogic@191: if (!isDecodeCacheInitialised()) { lbajardsilogic@191: 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(); lbajardsilogic@191: return true; lbajardsilogic@191: } lbajardsilogic@191: bool lbajardsilogic@191: VideoFileReader::videoInit(SDL_ffmpegFile* file) lbajardsilogic@191: { 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@145: benoitrigolleau@145: MainWindow * MWins=MainWindow::instance(); benoitrigolleau@167: benoitrigolleau@145: benoitrigolleau@145: benoitrigolleau@130: SDL_Init(SDL_INIT_VIDEO); benoitrigolleau@167: Videow=w;//=320*m_zoomfactor; benoitrigolleau@167: Videoh=h;//=240*m_zoomfactor; benoitrigolleau@167: benoitrigolleau@167: //TODO update the size according to the component size benoitrigolleau@167: // this will not work if video size is bigger than window size. benoitrigolleau@167: m_width =w; benoitrigolleau@167: m_height =h; benoitrigolleau@256: zoomWivan =w; benoitrigolleau@256: zoomHivan =h; benoitrigolleau@167: MWins->setSDLInitSize(w,h); ivand_qmul@125: // Open the Video device ivand_qmul@150: screen = SDL_SetVideoMode(w, h, 0, SDL_DOUBLEBUF|SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL); benoitrigolleau@130: //SDL_WM_SetCaption("EASAIER Video Player", "EASAIER Video Player"); ivand_qmul@125: if(!screen) { benoitrigolleau@167: fprintf(stderr, "Couldn't open video: %s\n", SDL_GetError()); ivand_qmul@125: return false; lbajardsilogic@191: } lbajardsilogic@191: return true; lbajardsilogic@191: } lbajardsilogic@191: ivand_qmul@125: int VideoFileReader::videoPlayCall(void *t) ivand_qmul@125: { ivand_qmul@125: return ((VideoFileReader *)t)->videoPlay(); lbajardsilogic@191: } lbajardsilogic@191: benoitrigolleau@167: void VideoFileReader::processEvents() benoitrigolleau@167: { benoitrigolleau@167: SDL_Event event; benoitrigolleau@167: benoitrigolleau@167: while (SDL_PollEvent(&event)) benoitrigolleau@167: { benoitrigolleau@167: float signe = 1; benoitrigolleau@167: switch (event.type) benoitrigolleau@167: { benoitrigolleau@167: case SDL_MOUSEMOTION: benoitrigolleau@167: break; benoitrigolleau@167: case SDL_MOUSEBUTTONDOWN: benoitrigolleau@167: switch(event.button.button){ benoitrigolleau@167: case SDL_BUTTON_LEFT : benoitrigolleau@167: break; benoitrigolleau@167: case SDL_BUTTON_MIDDLE: benoitrigolleau@167: break; benoitrigolleau@167: case SDL_BUTTON_RIGHT: benoitrigolleau@167: break; benoitrigolleau@167: default: benoitrigolleau@167: break; benoitrigolleau@167: } benoitrigolleau@167: break; benoitrigolleau@167: case SDL_MOUSEBUTTONUP: benoitrigolleau@167: benoitrigolleau@167: switch(event.button.button){ benoitrigolleau@167: case SDL_BUTTON_LEFT : benoitrigolleau@167: break; benoitrigolleau@167: case SDL_BUTTON_MIDDLE: benoitrigolleau@167: break; benoitrigolleau@167: case SDL_BUTTON_RIGHT: benoitrigolleau@167: break; benoitrigolleau@167: case SDL_BUTTON_WHEELDOWN: benoitrigolleau@167: signe = -1; benoitrigolleau@167: case SDL_BUTTON_WHEELUP: benoitrigolleau@167: float f,f2; benoitrigolleau@167: f = m_zoomfactor + signe * 0.1; benoitrigolleau@167: f2 = f; benoitrigolleau@167: if((int)(m_width*f+0.5)%4){ benoitrigolleau@167: f = (m_width*f - (int)(m_width*f+0.5)%4)/m_width; benoitrigolleau@167: } benoitrigolleau@167: m_zoomfactor=f; benoitrigolleau@167: benoitrigolleau@167: break; benoitrigolleau@167: default: benoitrigolleau@167: break; benoitrigolleau@167: } benoitrigolleau@167: break; benoitrigolleau@167: benoitrigolleau@167: default: benoitrigolleau@167: break; benoitrigolleau@167: } benoitrigolleau@167: } lbajardsilogic@191: } lbajardsilogic@191: lbajardsilogic@191: int lbajardsilogic@191: VideoFileReader::videoPlay() lbajardsilogic@191: { 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)) { lbajardsilogic@191: m_error = QString("Failed to failed to initalized video file for reading."); lbajardsilogic@191: 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: benoitrigolleau@167: if (!(w==(int)(Videow*m_zoomfactor))){ benoitrigolleau@167: w=Videow*m_zoomfactor; benoitrigolleau@167: h=Videoh*m_zoomfactor; benoitrigolleau@167: if (w<80 || h<60){ benoitrigolleau@167: w=80; benoitrigolleau@167: h=60; benoitrigolleau@167: m_zoomfactor = 80.0/Videow; benoitrigolleau@167: } benoitrigolleau@167: // Open the Video device benoitrigolleau@256: //zoomFivan = m_zoomfactor; benoitrigolleau@167: screen = SDL_SetVideoMode(w, h, 0, SDL_DOUBLEBUF|SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL); benoitrigolleau@167: MWins->setSDLInitSize(w,h); benoitrigolleau@167: m_width =w; benoitrigolleau@167: m_height =h; benoitrigolleau@256: zoomWivan =w; benoitrigolleau@256: zoomHivan =h; benoitrigolleau@167: ivand_qmul@150: } benoitrigolleau@167: // calls process events function, to take in account the user input benoitrigolleau@167: processEvents(); 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); lbajardsilogic@191: } ivand_qmul@125: // after all is said and done, we should call this lbajardsilogic@191: SDL_ffmpegFree(film); lbajardsilogic@191: return 0; lbajardsilogic@191: } lbajardsilogic@191: lbajardsilogic@191: void lbajardsilogic@191: VideoFileReader::getSupportedExtensions(std::set &extensions) lbajardsilogic@191: { lbajardsilogic@191: extensions.insert("mpg"); lbajardsilogic@191: extensions.insert("avi"); lbajardsilogic@191: extensions.insert("divx"); lbajardsilogic@191: extensions.insert("mov"); lbajardsilogic@191: } lbajardsilogic@191: lbajardsilogic@191: #endif