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