annotate data/fileio/VideoFileReader.cpp @ 150:c946c19e6329

(none)
author ivand_qmul
date Wed, 14 Nov 2007 15:11:46 +0000
parents e63e8272dcb0
children 2ac52ea3c1c4
rev   line source
ivand_qmul@125 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
ivand_qmul@125 2
ivand_qmul@125 3 /*
ivand_qmul@125 4 Sound Access
ivand_qmul@125 5 EASAIER client application.
ivand_qmul@125 6 Queen Mary 2007. Ivan Damnjanovic.
ivand_qmul@125 7
ivand_qmul@125 8 This program is free software; you can redistribute it and/or
ivand_qmul@125 9 modify it under the terms of the GNU General Public License as
ivand_qmul@125 10 published by the Free Software Foundation; either version 2 of the
ivand_qmul@125 11 License, or (at your option) any later version. See the file
ivand_qmul@125 12 COPYING included with this distribution for more information.
ivand_qmul@125 13 */
ivand_qmul@125 14
ivand_qmul@125 15 #ifdef HAVE_FFMPEG
ivand_qmul@125 16
ivand_qmul@125 17
ivand_qmul@125 18 //#include "system/System.h"
ivand_qmul@125 19
ivand_qmul@125 20 #include <sys/types.h>
ivand_qmul@125 21 #include <sys/stat.h>
ivand_qmul@125 22 #include <fcntl.h>
ivand_qmul@125 23
ivand_qmul@125 24 #include <iostream>
ivand_qmul@125 25
ivand_qmul@125 26 #include <QApplication>
ivand_qmul@125 27 #include <QFileInfo>
ivand_qmul@125 28 #include <QProgressDialog>
ivand_qmul@125 29
ivand_qmul@125 30 #include "VideoFileReader.h"
ivand_qmul@125 31
ivand_qmul@129 32 #ifdef WIN32
ivand_qmul@129 33 #include <Windows.h>
ivand_qmul@129 34 #endif
ivand_qmul@150 35 extern float zoomFivan;
ivand_qmul@129 36 long long countFreq;
ivand_qmul@138 37 int Videow=320;
ivand_qmul@138 38 int Videoh=240;
ivand_qmul@125 39 VideoFileReader::VideoFileReader(QString path, bool showProgress, CacheMode mode) :
ivand_qmul@125 40 CodedAudioFileReader(mode),
ivand_qmul@125 41 m_path(path)
ivand_qmul@125 42 {
ivand_qmul@125 43 m_frameCount = 0;
ivand_qmul@125 44 m_channelCount = 0;
ivand_qmul@125 45 m_sampleRate = 0;
ivand_qmul@125 46 m_fileSize = 0;
ivand_qmul@125 47 m_bitrateNum = 0;
ivand_qmul@125 48 m_bitrateDenom = 0;
ivand_qmul@125 49 m_cancelled = false;
ivand_qmul@125 50
ivand_qmul@125 51 struct stat stat;
ivand_qmul@125 52 if (::stat(path.toLocal8Bit().data(), &stat) == -1 || stat.st_size == 0) {
ivand_qmul@125 53 m_error = QString("File %1 does not exist.").arg(path);
ivand_qmul@125 54 return;
ivand_qmul@125 55 }
ivand_qmul@125 56
ivand_qmul@125 57 // standard SDL initialization stuff
ivand_qmul@125 58 if(SDL_Init(SDL_INIT_VIDEO|SDL_DOUBLEBUF|SDL_INIT_AUDIO) < 0) {
ivand_qmul@125 59 m_error = QString("Failed to open file %1 for reading.").arg(SDL_GetError());
ivand_qmul@125 60 return;
ivand_qmul@125 61 }
ivand_qmul@125 62 m_fileSize = stat.st_size;
ivand_qmul@125 63
ivand_qmul@125 64
ivand_qmul@125 65 // open file from arg[1]
ivand_qmul@125 66 film = SDL_ffmpegOpen(path.toLocal8Bit().data());
ivand_qmul@125 67 if (path.endsWith("mpg")) film->delay=1;
ivand_qmul@125 68 if (path.endsWith("divx")) film->delay=1;
ivand_qmul@125 69 if(!film)
ivand_qmul@125 70 {
ivand_qmul@125 71 m_error = QString("Failed to open file %1 for reading.").arg(path);
ivand_qmul@125 72 return;
ivand_qmul@125 73 }
ivand_qmul@125 74 // print some info on detected stream to output
ivand_qmul@125 75 film->skipAudio=0;
ivand_qmul@125 76 film->skipVideo=0;
ivand_qmul@125 77 int s;
ivand_qmul@125 78 SDL_ffmpegStream *str;
ivand_qmul@125 79 for(s = 0; s<film->VStreams; s++)
ivand_qmul@125 80 str = SDL_ffmpegGetVideoStream(film, s);
ivand_qmul@125 81 SDL_ffmpegSelectVideoStream(film, 0);
ivand_qmul@125 82 film->skipVideo=1;
ivand_qmul@125 83 for(s = 0; s<film->AStreams; s++)
ivand_qmul@125 84 str = SDL_ffmpegGetAudioStream(film, s);
ivand_qmul@125 85
ivand_qmul@125 86 SDL_ffmpegSelectAudioStream(film, 0);
ivand_qmul@125 87
ivand_qmul@125 88
ivand_qmul@125 89 if (showProgress) {
ivand_qmul@125 90 m_progress = new QProgressDialog
ivand_qmul@125 91 (QObject::tr("Decoding %1...").arg(QFileInfo(path).fileName()),
ivand_qmul@125 92 QObject::tr("Stop"), 0, 100);
ivand_qmul@125 93 m_progress->hide();
ivand_qmul@125 94 }
ivand_qmul@125 95
ivand_qmul@125 96 m_sampleRate=str->sampleRate;
ivand_qmul@125 97 int channels=str->channels;
ivand_qmul@125 98 m_channelCount=channels;
ivand_qmul@125 99 SDL_ffmpegPause(film, 0);
ivand_qmul@125 100 SDL_ffmpegStartDecoding(film);
ivand_qmul@125 101
ivand_qmul@125 102 if (!decodeAudio(film)) {
ivand_qmul@125 103 m_error = QString("Failed to decode audio from file %1 for reading.").arg(path);
ivand_qmul@125 104 return;
ivand_qmul@125 105 }
ivand_qmul@125 106 film->skipAudio=1;
ivand_qmul@125 107 //SDL_ffmpegSeek(film, 0);
ivand_qmul@125 108 //SDL_ffmpegStopDecoding(film);
ivand_qmul@125 109 SDL_Delay(5);
ivand_qmul@125 110 film->skipVideo=0;
ivand_qmul@125 111
ivand_qmul@125 112 film->videoThread=SDL_CreateThread(videoPlayCall,this);
ivand_qmul@125 113
ivand_qmul@125 114
ivand_qmul@125 115
ivand_qmul@125 116
ivand_qmul@125 117
ivand_qmul@125 118 if (showProgress) {
ivand_qmul@125 119 delete m_progress;
ivand_qmul@125 120 m_progress = 0;
ivand_qmul@125 121 }
ivand_qmul@125 122
ivand_qmul@125 123 //delete[] filebuffer;
ivand_qmul@125 124 }
ivand_qmul@125 125
ivand_qmul@125 126
ivand_qmul@125 127 VideoFileReader::~VideoFileReader()
ivand_qmul@125 128 {
ivand_qmul@125 129 film->videoThreadActive = 0;
ivand_qmul@125 130 if(film->videoThread) SDL_WaitThread(film->videoThread, 0);
ivand_qmul@125 131 }
ivand_qmul@125 132 bool
ivand_qmul@125 133 VideoFileReader::decodeAudio(SDL_ffmpegFile* file)
ivand_qmul@125 134 {
ivand_qmul@125 135
ivand_qmul@125 136
ivand_qmul@125 137 int64_t duration=((AVFormatContext *)file->_ffmpeg)->duration;
ivand_qmul@125 138 double elapsed = 0;
ivand_qmul@125 139 m_cancelled=false;
ivand_qmul@125 140 int audio_ends=0;
ivand_qmul@125 141 while((elapsed < duration)&&!m_cancelled ) {
ivand_qmul@125 142
ivand_qmul@125 143 elapsed = double(m_frameCount)*1000000 /(m_channelCount*m_sampleRate);
ivand_qmul@125 144 double percent = (elapsed * 100) / duration;
ivand_qmul@125 145 int progress = int(percent);
ivand_qmul@125 146 if (progress < 1) progress = 1;
ivand_qmul@125 147 if (progress > 99) progress = 99;
ivand_qmul@125 148 if (progress > m_progress->value()) {
ivand_qmul@125 149 m_progress->setValue(progress);
ivand_qmul@125 150 m_progress->show();
ivand_qmul@125 151 m_progress->raise();
ivand_qmul@125 152 qApp->processEvents();
ivand_qmul@125 153 if (m_progress->wasCanceled()) {
ivand_qmul@125 154 m_cancelled = true;
ivand_qmul@125 155 }
ivand_qmul@125 156 }
ivand_qmul@125 157
ivand_qmul@125 158 // we tell SDL_ffmpegGetAudio how many bytes we need, the function then
ivand_qmul@125 159 // fills this pointer with the amount of bytes it could actually give
ivand_qmul@125 160 int gotLength = 100000;
ivand_qmul@125 161 if (!isDecodeCacheInitialised()) {
ivand_qmul@125 162 initialiseDecodeCache();
ivand_qmul@125 163 }
ivand_qmul@125 164 // we try to get some data from our file
ivand_qmul@125 165 // important! this call is paired with SDL_ffmpegReleaseAudio
ivand_qmul@125 166 int16_t* audio =(int16_t *) SDL_ffmpegGetAudio(file, &gotLength);
ivand_qmul@125 167 for (int i=0; i<gotLength/2;i++)
ivand_qmul@125 168 {
ivand_qmul@125 169 float sample=float(*audio++)/float(2*32768);
ivand_qmul@125 170 addSampleToDecodeCache(sample);
ivand_qmul@125 171 }
ivand_qmul@125 172 // copy the bytes we got to audiocard
ivand_qmul@125 173 // if(audio) memcpy(stream, audio, gotLength);
ivand_qmul@125 174
ivand_qmul@125 175 // we release our audio data, so the decode thread can fill it again
ivand_qmul@125 176 // we also inform this function of the amount of bytes we used, so it can
ivand_qmul@125 177 // move the buffer accordingly
ivand_qmul@125 178 // important! this call is paired with SDL_ffmpegGetAudio
ivand_qmul@125 179 SDL_ffmpegReleaseAudio(file, gotLength);
ivand_qmul@125 180 //decode_audio(film, 1000000);
ivand_qmul@125 181 m_frameCount+=gotLength/2;
ivand_qmul@125 182 if ((progress > 97)&&(gotLength<=0)) audio_ends++;
ivand_qmul@125 183 if (audio_ends>=2000) m_cancelled = true;
ivand_qmul@125 184 }
ivand_qmul@125 185 m_frameCount/=m_channelCount;
ivand_qmul@125 186 if (isDecodeCacheInitialised()) finishDecodeCache();
ivand_qmul@125 187 return true;
ivand_qmul@125 188 }
ivand_qmul@125 189 bool
ivand_qmul@125 190 VideoFileReader::videoInit(SDL_ffmpegFile* file)
ivand_qmul@125 191 {
ivand_qmul@125 192 int w,h;
ivand_qmul@125 193 // we get the size from our active video stream, if no active video stream
ivand_qmul@125 194 // exists, width and height are set to default values (320x240)
ivand_qmul@125 195 SDL_ffmpegGetVideoSize(file, &w, &h);
benoitrigolleau@145 196
benoitrigolleau@145 197 MainWindow * MWins=MainWindow::instance();
benoitrigolleau@145 198 MWins->setSDLInitSize(w,h);
benoitrigolleau@145 199
benoitrigolleau@145 200
benoitrigolleau@130 201 SDL_Init(SDL_INIT_VIDEO);
ivand_qmul@150 202 Videow=w=320*zoomFivan;
ivand_qmul@150 203 Videoh=h=240*zoomFivan;
ivand_qmul@125 204 // Open the Video device
ivand_qmul@150 205 screen = SDL_SetVideoMode(w, h, 0, SDL_DOUBLEBUF|SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
benoitrigolleau@130 206 //SDL_WM_SetCaption("EASAIER Video Player", "EASAIER Video Player");
ivand_qmul@125 207 if(!screen) {
ivand_qmul@125 208 printf("Couldn't open video: %s\n", SDL_GetError());
ivand_qmul@125 209 return false;
ivand_qmul@125 210 }
ivand_qmul@125 211 return true;
ivand_qmul@125 212 }
ivand_qmul@125 213
ivand_qmul@125 214 int VideoFileReader::videoPlayCall(void *t)
ivand_qmul@125 215 {
ivand_qmul@125 216 return ((VideoFileReader *)t)->videoPlay();
ivand_qmul@125 217 }
ivand_qmul@125 218
ivand_qmul@125 219 int
ivand_qmul@125 220 VideoFileReader::videoPlay()
ivand_qmul@125 221 {
ivand_qmul@125 222
ivand_qmul@125 223
ivand_qmul@125 224 film->videoThreadActive = 1;
ivand_qmul@125 225 MainWindow * MWins=MainWindow::instance();
ivand_qmul@125 226
ivand_qmul@125 227 if (!videoInit(film)) {
ivand_qmul@125 228 m_error = QString("Failed to failed to initalized video file for reading.");
ivand_qmul@125 229 return 0;
ivand_qmul@125 230 }
ivand_qmul@125 231 //const SDL_VideoInfo * vid=SDL_GetVideoInfo();
ivand_qmul@125 232 film->audioTime =0;
ivand_qmul@125 233 int w,h;
ivand_qmul@125 234 SDL_ffmpegGetVideoSize(film, &w, &h);
ivand_qmul@125 235 //SDL_ffmpegStartDecoding(film);
ivand_qmul@125 236 SDL_Delay(1000);
ivand_qmul@129 237 QueryPerformanceFrequency((LARGE_INTEGER *)(&countFreq));
ivand_qmul@129 238 countFreq/=1000;
ivand_qmul@129 239 film->countFreq=countFreq;
ivand_qmul@129 240 QueryPerformanceCounter((LARGE_INTEGER *)(&film->timer));
ivand_qmul@129 241 film->timer=film->timer/(film->countFreq);
ivand_qmul@129 242 film->timebase=1;
ivand_qmul@129 243 film->vs[film->videoStream]->lastTimeStamp=0;
ivand_qmul@125 244 while( film->videoThreadActive ) {
ivand_qmul@125 245
ivand_qmul@150 246 if (!(w==(int)(320*zoomFivan))){
ivand_qmul@150 247 w=320*zoomFivan;
ivand_qmul@150 248 h=240*zoomFivan;
ivand_qmul@150 249 // Open the Video device
ivand_qmul@150 250 screen = SDL_SetVideoMode(w, h, 0, SDL_DOUBLEBUF|SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
ivand_qmul@150 251 }
ivand_qmul@125 252 if (MWins->isAudioPlaying())
ivand_qmul@125 253 {
ivand_qmul@125 254 if ((SDL_ffmpegGetState(film))||((long)(abs((long)(film->audioTime - (int64_t)(MWins->Get_CurAudioTime()))))>=1000))
ivand_qmul@125 255 {
ivand_qmul@125 256 //SDL_Delay(1000);
ivand_qmul@125 257 film->audioTime = MWins->Get_CurAudioTime();
ivand_qmul@125 258 SDL_ffmpegSeek(film, film->audioTime);
ivand_qmul@125 259 SDL_ffmpegPause(film, 0);
ivand_qmul@125 260 }
ivand_qmul@125 261 else
ivand_qmul@125 262 film->audioTime = MWins->Get_CurAudioTime();
ivand_qmul@125 263 }
ivand_qmul@125 264 else
ivand_qmul@125 265 {
ivand_qmul@125 266 SDL_ffmpegPause(film, 1);
ivand_qmul@125 267
ivand_qmul@125 268 }
ivand_qmul@125 269
ivand_qmul@125 270 // we retrieve the current image from the file
ivand_qmul@125 271 // we get 0 if no file could be retrieved
ivand_qmul@125 272 // important! please note this call should be paired with SDL_ffmpegReleaseVideo
ivand_qmul@125 273 SDL_Surface* bmp = SDL_ffmpegGetVideo((SDL_ffmpegFile *)film);
ivand_qmul@125 274
ivand_qmul@125 275 if(bmp) {
ivand_qmul@125 276
ivand_qmul@125 277
ivand_qmul@125 278 // we got a frame, so we better show this one
ivand_qmul@125 279 SDL_BlitSurface(bmp, 0, screen, 0);
ivand_qmul@125 280
ivand_qmul@125 281 // we flip the double buffered screen so we might actually see something
ivand_qmul@125 282 SDL_Flip(screen);
ivand_qmul@125 283
ivand_qmul@125 284 // After releasing bmp, you can no longer use it.
ivand_qmul@125 285 // you should call this function every time you get a frame!
ivand_qmul@125 286 SDL_ffmpegReleaseVideo((SDL_ffmpegFile *)film, bmp);
ivand_qmul@125 287 }
ivand_qmul@125 288
ivand_qmul@125 289 // we wish not to kill our poor cpu, so we give it some timeoff
ivand_qmul@129 290 // SDL_Delay(1);
ivand_qmul@125 291 }
ivand_qmul@125 292 // after all is said and done, we should call this
ivand_qmul@125 293 SDL_ffmpegFree(film);
ivand_qmul@125 294 return 0;
ivand_qmul@125 295 }
ivand_qmul@125 296
ivand_qmul@125 297 void
ivand_qmul@125 298 VideoFileReader::getSupportedExtensions(std::set<QString> &extensions)
ivand_qmul@125 299 {
ivand_qmul@125 300 extensions.insert("mpg");
ivand_qmul@125 301 extensions.insert("avi");
ivand_qmul@125 302 extensions.insert("divx");
ivand_qmul@125 303 extensions.insert("mov");
ivand_qmul@125 304 }
ivand_qmul@125 305
ivand_qmul@125 306 #endif