annotate data/fileio/VideoFileReader.cpp @ 167:2ac52ea3c1c4

video mouse events are in SDL now. The code is really better now, but there is a display bug when you zoom in, zoom out
author benoitrigolleau
date Fri, 16 Nov 2007 15:18:44 +0000
parents c946c19e6329
children be6d31baecb9
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>
benoitrigolleau@167 23 #include <cassert>
ivand_qmul@125 24
ivand_qmul@125 25 #include <iostream>
ivand_qmul@125 26
ivand_qmul@125 27 #include <QApplication>
ivand_qmul@125 28 #include <QFileInfo>
ivand_qmul@125 29 #include <QProgressDialog>
ivand_qmul@125 30
ivand_qmul@125 31 #include "VideoFileReader.h"
ivand_qmul@125 32
ivand_qmul@129 33 #ifdef WIN32
ivand_qmul@129 34 #include <Windows.h>
ivand_qmul@129 35 #endif
ivand_qmul@129 36 long long countFreq;
ivand_qmul@138 37 int Videow=320;
ivand_qmul@138 38 int Videoh=240;
benoitrigolleau@167 39 float zoomFivan=1;
ivand_qmul@125 40 VideoFileReader::VideoFileReader(QString path, bool showProgress, CacheMode mode) :
ivand_qmul@125 41 CodedAudioFileReader(mode),
ivand_qmul@125 42 m_path(path)
ivand_qmul@125 43 {
ivand_qmul@125 44 m_frameCount = 0;
ivand_qmul@125 45 m_channelCount = 0;
ivand_qmul@125 46 m_sampleRate = 0;
ivand_qmul@125 47 m_fileSize = 0;
ivand_qmul@125 48 m_bitrateNum = 0;
ivand_qmul@125 49 m_bitrateDenom = 0;
ivand_qmul@125 50 m_cancelled = false;
benoitrigolleau@167 51 m_zoomfactor = 1;
ivand_qmul@125 52
ivand_qmul@125 53 struct stat stat;
ivand_qmul@125 54 if (::stat(path.toLocal8Bit().data(), &stat) == -1 || stat.st_size == 0) {
ivand_qmul@125 55 m_error = QString("File %1 does not exist.").arg(path);
ivand_qmul@125 56 return;
ivand_qmul@125 57 }
ivand_qmul@125 58
ivand_qmul@125 59 // standard SDL initialization stuff
ivand_qmul@125 60 if(SDL_Init(SDL_INIT_VIDEO|SDL_DOUBLEBUF|SDL_INIT_AUDIO) < 0) {
ivand_qmul@125 61 m_error = QString("Failed to open file %1 for reading.").arg(SDL_GetError());
ivand_qmul@125 62 return;
ivand_qmul@125 63 }
ivand_qmul@125 64 m_fileSize = stat.st_size;
ivand_qmul@125 65
ivand_qmul@125 66
ivand_qmul@125 67 // open file from arg[1]
ivand_qmul@125 68 film = SDL_ffmpegOpen(path.toLocal8Bit().data());
ivand_qmul@125 69 if (path.endsWith("mpg")) film->delay=1;
ivand_qmul@125 70 if (path.endsWith("divx")) film->delay=1;
ivand_qmul@125 71 if(!film)
ivand_qmul@125 72 {
ivand_qmul@125 73 m_error = QString("Failed to open file %1 for reading.").arg(path);
ivand_qmul@125 74 return;
ivand_qmul@125 75 }
ivand_qmul@125 76 // print some info on detected stream to output
ivand_qmul@125 77 film->skipAudio=0;
ivand_qmul@125 78 film->skipVideo=0;
ivand_qmul@125 79 int s;
ivand_qmul@125 80 SDL_ffmpegStream *str;
ivand_qmul@125 81 for(s = 0; s<film->VStreams; s++)
ivand_qmul@125 82 str = SDL_ffmpegGetVideoStream(film, s);
ivand_qmul@125 83 SDL_ffmpegSelectVideoStream(film, 0);
ivand_qmul@125 84 film->skipVideo=1;
ivand_qmul@125 85 for(s = 0; s<film->AStreams; s++)
ivand_qmul@125 86 str = SDL_ffmpegGetAudioStream(film, s);
ivand_qmul@125 87
ivand_qmul@125 88 SDL_ffmpegSelectAudioStream(film, 0);
ivand_qmul@125 89
ivand_qmul@125 90
ivand_qmul@125 91 if (showProgress) {
ivand_qmul@125 92 m_progress = new QProgressDialog
ivand_qmul@125 93 (QObject::tr("Decoding %1...").arg(QFileInfo(path).fileName()),
ivand_qmul@125 94 QObject::tr("Stop"), 0, 100);
ivand_qmul@125 95 m_progress->hide();
ivand_qmul@125 96 }
ivand_qmul@125 97
ivand_qmul@125 98 m_sampleRate=str->sampleRate;
ivand_qmul@125 99 int channels=str->channels;
ivand_qmul@125 100 m_channelCount=channels;
ivand_qmul@125 101 SDL_ffmpegPause(film, 0);
ivand_qmul@125 102 SDL_ffmpegStartDecoding(film);
ivand_qmul@125 103
ivand_qmul@125 104 if (!decodeAudio(film)) {
ivand_qmul@125 105 m_error = QString("Failed to decode audio from file %1 for reading.").arg(path);
ivand_qmul@125 106 return;
ivand_qmul@125 107 }
ivand_qmul@125 108 film->skipAudio=1;
ivand_qmul@125 109 //SDL_ffmpegSeek(film, 0);
ivand_qmul@125 110 //SDL_ffmpegStopDecoding(film);
ivand_qmul@125 111 SDL_Delay(5);
ivand_qmul@125 112 film->skipVideo=0;
ivand_qmul@125 113
ivand_qmul@125 114 film->videoThread=SDL_CreateThread(videoPlayCall,this);
ivand_qmul@125 115
ivand_qmul@125 116
ivand_qmul@125 117
ivand_qmul@125 118
ivand_qmul@125 119
ivand_qmul@125 120 if (showProgress) {
ivand_qmul@125 121 delete m_progress;
ivand_qmul@125 122 m_progress = 0;
ivand_qmul@125 123 }
ivand_qmul@125 124
ivand_qmul@125 125 //delete[] filebuffer;
ivand_qmul@125 126 }
ivand_qmul@125 127
ivand_qmul@125 128
ivand_qmul@125 129 VideoFileReader::~VideoFileReader()
ivand_qmul@125 130 {
ivand_qmul@125 131 film->videoThreadActive = 0;
ivand_qmul@125 132 if(film->videoThread) SDL_WaitThread(film->videoThread, 0);
ivand_qmul@125 133 }
ivand_qmul@125 134 bool
ivand_qmul@125 135 VideoFileReader::decodeAudio(SDL_ffmpegFile* file)
ivand_qmul@125 136 {
ivand_qmul@125 137
ivand_qmul@125 138
ivand_qmul@125 139 int64_t duration=((AVFormatContext *)file->_ffmpeg)->duration;
ivand_qmul@125 140 double elapsed = 0;
ivand_qmul@125 141 m_cancelled=false;
ivand_qmul@125 142 int audio_ends=0;
ivand_qmul@125 143 while((elapsed < duration)&&!m_cancelled ) {
ivand_qmul@125 144
ivand_qmul@125 145 elapsed = double(m_frameCount)*1000000 /(m_channelCount*m_sampleRate);
ivand_qmul@125 146 double percent = (elapsed * 100) / duration;
ivand_qmul@125 147 int progress = int(percent);
ivand_qmul@125 148 if (progress < 1) progress = 1;
ivand_qmul@125 149 if (progress > 99) progress = 99;
ivand_qmul@125 150 if (progress > m_progress->value()) {
ivand_qmul@125 151 m_progress->setValue(progress);
ivand_qmul@125 152 m_progress->show();
ivand_qmul@125 153 m_progress->raise();
ivand_qmul@125 154 qApp->processEvents();
ivand_qmul@125 155 if (m_progress->wasCanceled()) {
ivand_qmul@125 156 m_cancelled = true;
ivand_qmul@125 157 }
ivand_qmul@125 158 }
ivand_qmul@125 159
ivand_qmul@125 160 // we tell SDL_ffmpegGetAudio how many bytes we need, the function then
ivand_qmul@125 161 // fills this pointer with the amount of bytes it could actually give
ivand_qmul@125 162 int gotLength = 100000;
ivand_qmul@125 163 if (!isDecodeCacheInitialised()) {
ivand_qmul@125 164 initialiseDecodeCache();
ivand_qmul@125 165 }
ivand_qmul@125 166 // we try to get some data from our file
ivand_qmul@125 167 // important! this call is paired with SDL_ffmpegReleaseAudio
ivand_qmul@125 168 int16_t* audio =(int16_t *) SDL_ffmpegGetAudio(file, &gotLength);
ivand_qmul@125 169 for (int i=0; i<gotLength/2;i++)
ivand_qmul@125 170 {
ivand_qmul@125 171 float sample=float(*audio++)/float(2*32768);
ivand_qmul@125 172 addSampleToDecodeCache(sample);
ivand_qmul@125 173 }
ivand_qmul@125 174 // copy the bytes we got to audiocard
ivand_qmul@125 175 // if(audio) memcpy(stream, audio, gotLength);
ivand_qmul@125 176
ivand_qmul@125 177 // we release our audio data, so the decode thread can fill it again
ivand_qmul@125 178 // we also inform this function of the amount of bytes we used, so it can
ivand_qmul@125 179 // move the buffer accordingly
ivand_qmul@125 180 // important! this call is paired with SDL_ffmpegGetAudio
ivand_qmul@125 181 SDL_ffmpegReleaseAudio(file, gotLength);
ivand_qmul@125 182 //decode_audio(film, 1000000);
ivand_qmul@125 183 m_frameCount+=gotLength/2;
ivand_qmul@125 184 if ((progress > 97)&&(gotLength<=0)) audio_ends++;
ivand_qmul@125 185 if (audio_ends>=2000) m_cancelled = true;
ivand_qmul@125 186 }
ivand_qmul@125 187 m_frameCount/=m_channelCount;
ivand_qmul@125 188 if (isDecodeCacheInitialised()) finishDecodeCache();
ivand_qmul@125 189 return true;
ivand_qmul@125 190 }
ivand_qmul@125 191 bool
ivand_qmul@125 192 VideoFileReader::videoInit(SDL_ffmpegFile* file)
ivand_qmul@125 193 {
ivand_qmul@125 194 int w,h;
ivand_qmul@125 195 // we get the size from our active video stream, if no active video stream
ivand_qmul@125 196 // exists, width and height are set to default values (320x240)
ivand_qmul@125 197 SDL_ffmpegGetVideoSize(file, &w, &h);
benoitrigolleau@145 198
benoitrigolleau@145 199 MainWindow * MWins=MainWindow::instance();
benoitrigolleau@167 200
benoitrigolleau@145 201
benoitrigolleau@145 202
benoitrigolleau@130 203 SDL_Init(SDL_INIT_VIDEO);
benoitrigolleau@167 204 Videow=w;//=320*m_zoomfactor;
benoitrigolleau@167 205 Videoh=h;//=240*m_zoomfactor;
benoitrigolleau@167 206
benoitrigolleau@167 207 //TODO update the size according to the component size
benoitrigolleau@167 208 // this will not work if video size is bigger than window size.
benoitrigolleau@167 209 m_width =w;
benoitrigolleau@167 210 m_height =h;
benoitrigolleau@167 211
benoitrigolleau@167 212 MWins->setSDLInitSize(w,h);
ivand_qmul@125 213 // Open the Video device
ivand_qmul@150 214 screen = SDL_SetVideoMode(w, h, 0, SDL_DOUBLEBUF|SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
benoitrigolleau@130 215 //SDL_WM_SetCaption("EASAIER Video Player", "EASAIER Video Player");
ivand_qmul@125 216 if(!screen) {
benoitrigolleau@167 217 fprintf(stderr, "Couldn't open video: %s\n", SDL_GetError());
ivand_qmul@125 218 return false;
ivand_qmul@125 219 }
ivand_qmul@125 220 return true;
ivand_qmul@125 221 }
ivand_qmul@125 222
ivand_qmul@125 223 int VideoFileReader::videoPlayCall(void *t)
ivand_qmul@125 224 {
ivand_qmul@125 225 return ((VideoFileReader *)t)->videoPlay();
ivand_qmul@125 226 }
ivand_qmul@125 227
benoitrigolleau@167 228 void VideoFileReader::processEvents()
benoitrigolleau@167 229 {
benoitrigolleau@167 230 SDL_Event event;
benoitrigolleau@167 231
benoitrigolleau@167 232 while (SDL_PollEvent(&event))
benoitrigolleau@167 233 {
benoitrigolleau@167 234 float signe = 1;
benoitrigolleau@167 235 switch (event.type)
benoitrigolleau@167 236 {
benoitrigolleau@167 237 case SDL_MOUSEMOTION:
benoitrigolleau@167 238 break;
benoitrigolleau@167 239 case SDL_MOUSEBUTTONDOWN:
benoitrigolleau@167 240 switch(event.button.button){
benoitrigolleau@167 241 case SDL_BUTTON_LEFT :
benoitrigolleau@167 242 break;
benoitrigolleau@167 243 case SDL_BUTTON_MIDDLE:
benoitrigolleau@167 244 break;
benoitrigolleau@167 245 case SDL_BUTTON_RIGHT:
benoitrigolleau@167 246 break;
benoitrigolleau@167 247 default:
benoitrigolleau@167 248 break;
benoitrigolleau@167 249 }
benoitrigolleau@167 250 break;
benoitrigolleau@167 251 case SDL_MOUSEBUTTONUP:
benoitrigolleau@167 252
benoitrigolleau@167 253 switch(event.button.button){
benoitrigolleau@167 254 case SDL_BUTTON_LEFT :
benoitrigolleau@167 255 break;
benoitrigolleau@167 256 case SDL_BUTTON_MIDDLE:
benoitrigolleau@167 257 break;
benoitrigolleau@167 258 case SDL_BUTTON_RIGHT:
benoitrigolleau@167 259 break;
benoitrigolleau@167 260 case SDL_BUTTON_WHEELDOWN:
benoitrigolleau@167 261 signe = -1;
benoitrigolleau@167 262 case SDL_BUTTON_WHEELUP:
benoitrigolleau@167 263 float f,f2;
benoitrigolleau@167 264 f = m_zoomfactor + signe * 0.1;
benoitrigolleau@167 265 f2 = f;
benoitrigolleau@167 266 if((int)(m_width*f+0.5)%4){
benoitrigolleau@167 267 f = (m_width*f - (int)(m_width*f+0.5)%4)/m_width;
benoitrigolleau@167 268 }
benoitrigolleau@167 269 m_zoomfactor=f;
benoitrigolleau@167 270
benoitrigolleau@167 271 break;
benoitrigolleau@167 272 default:
benoitrigolleau@167 273 break;
benoitrigolleau@167 274 }
benoitrigolleau@167 275 break;
benoitrigolleau@167 276
benoitrigolleau@167 277 default:
benoitrigolleau@167 278 break;
benoitrigolleau@167 279 }
benoitrigolleau@167 280 }
benoitrigolleau@167 281 }
benoitrigolleau@167 282
ivand_qmul@125 283 int
ivand_qmul@125 284 VideoFileReader::videoPlay()
ivand_qmul@125 285 {
ivand_qmul@125 286
ivand_qmul@125 287
ivand_qmul@125 288 film->videoThreadActive = 1;
ivand_qmul@125 289 MainWindow * MWins=MainWindow::instance();
ivand_qmul@125 290
ivand_qmul@125 291 if (!videoInit(film)) {
ivand_qmul@125 292 m_error = QString("Failed to failed to initalized video file for reading.");
ivand_qmul@125 293 return 0;
ivand_qmul@125 294 }
ivand_qmul@125 295 //const SDL_VideoInfo * vid=SDL_GetVideoInfo();
ivand_qmul@125 296 film->audioTime =0;
ivand_qmul@125 297 int w,h;
ivand_qmul@125 298 SDL_ffmpegGetVideoSize(film, &w, &h);
ivand_qmul@125 299 //SDL_ffmpegStartDecoding(film);
ivand_qmul@125 300 SDL_Delay(1000);
ivand_qmul@129 301 QueryPerformanceFrequency((LARGE_INTEGER *)(&countFreq));
ivand_qmul@129 302 countFreq/=1000;
ivand_qmul@129 303 film->countFreq=countFreq;
ivand_qmul@129 304 QueryPerformanceCounter((LARGE_INTEGER *)(&film->timer));
ivand_qmul@129 305 film->timer=film->timer/(film->countFreq);
ivand_qmul@129 306 film->timebase=1;
ivand_qmul@129 307 film->vs[film->videoStream]->lastTimeStamp=0;
ivand_qmul@125 308 while( film->videoThreadActive ) {
ivand_qmul@125 309
benoitrigolleau@167 310 if (!(w==(int)(Videow*m_zoomfactor))){
benoitrigolleau@167 311 w=Videow*m_zoomfactor;
benoitrigolleau@167 312 h=Videoh*m_zoomfactor;
benoitrigolleau@167 313 if (w<80 || h<60){
benoitrigolleau@167 314 w=80;
benoitrigolleau@167 315 h=60;
benoitrigolleau@167 316 m_zoomfactor = 80.0/Videow;
benoitrigolleau@167 317 }
benoitrigolleau@167 318 // Open the Video device
benoitrigolleau@167 319 zoomFivan = m_zoomfactor;
benoitrigolleau@167 320 screen = SDL_SetVideoMode(w, h, 0, SDL_DOUBLEBUF|SDL_HWSURFACE|SDL_RESIZABLE|SDL_ASYNCBLIT|SDL_HWACCEL);
benoitrigolleau@167 321 MWins->setSDLInitSize(w,h);
benoitrigolleau@167 322 m_width =w;
benoitrigolleau@167 323 m_height =h;
benoitrigolleau@167 324
ivand_qmul@150 325 }
benoitrigolleau@167 326 // calls process events function, to take in account the user input
benoitrigolleau@167 327 processEvents();
ivand_qmul@125 328 if (MWins->isAudioPlaying())
ivand_qmul@125 329 {
ivand_qmul@125 330 if ((SDL_ffmpegGetState(film))||((long)(abs((long)(film->audioTime - (int64_t)(MWins->Get_CurAudioTime()))))>=1000))
ivand_qmul@125 331 {
ivand_qmul@125 332 //SDL_Delay(1000);
ivand_qmul@125 333 film->audioTime = MWins->Get_CurAudioTime();
ivand_qmul@125 334 SDL_ffmpegSeek(film, film->audioTime);
ivand_qmul@125 335 SDL_ffmpegPause(film, 0);
ivand_qmul@125 336 }
ivand_qmul@125 337 else
ivand_qmul@125 338 film->audioTime = MWins->Get_CurAudioTime();
ivand_qmul@125 339 }
ivand_qmul@125 340 else
ivand_qmul@125 341 {
ivand_qmul@125 342 SDL_ffmpegPause(film, 1);
ivand_qmul@125 343
ivand_qmul@125 344 }
ivand_qmul@125 345
ivand_qmul@125 346 // we retrieve the current image from the file
ivand_qmul@125 347 // we get 0 if no file could be retrieved
ivand_qmul@125 348 // important! please note this call should be paired with SDL_ffmpegReleaseVideo
ivand_qmul@125 349 SDL_Surface* bmp = SDL_ffmpegGetVideo((SDL_ffmpegFile *)film);
ivand_qmul@125 350
ivand_qmul@125 351 if(bmp) {
ivand_qmul@125 352
ivand_qmul@125 353
ivand_qmul@125 354 // we got a frame, so we better show this one
ivand_qmul@125 355 SDL_BlitSurface(bmp, 0, screen, 0);
ivand_qmul@125 356
ivand_qmul@125 357 // we flip the double buffered screen so we might actually see something
ivand_qmul@125 358 SDL_Flip(screen);
ivand_qmul@125 359
ivand_qmul@125 360 // After releasing bmp, you can no longer use it.
ivand_qmul@125 361 // you should call this function every time you get a frame!
ivand_qmul@125 362 SDL_ffmpegReleaseVideo((SDL_ffmpegFile *)film, bmp);
ivand_qmul@125 363 }
ivand_qmul@125 364
ivand_qmul@125 365 // we wish not to kill our poor cpu, so we give it some timeoff
ivand_qmul@129 366 // SDL_Delay(1);
ivand_qmul@125 367 }
ivand_qmul@125 368 // after all is said and done, we should call this
ivand_qmul@125 369 SDL_ffmpegFree(film);
ivand_qmul@125 370 return 0;
ivand_qmul@125 371 }
ivand_qmul@125 372
ivand_qmul@125 373 void
ivand_qmul@125 374 VideoFileReader::getSupportedExtensions(std::set<QString> &extensions)
ivand_qmul@125 375 {
ivand_qmul@125 376 extensions.insert("mpg");
ivand_qmul@125 377 extensions.insert("avi");
ivand_qmul@125 378 extensions.insert("divx");
ivand_qmul@125 379 extensions.insert("mov");
ivand_qmul@125 380 }
ivand_qmul@125 381
ivand_qmul@125 382 #endif