annotate data/fileio/VideoFileReader.cpp @ 130:b3df8b8185db

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