annotate data/fileio/VideoFileReader.cpp @ 191:be6d31baecb9

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