annotate data/fileio/VideoFileReader.cpp @ 145:e63e8272dcb0

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