xoreos  0.0.5
decoder.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include <cassert>
26 
27 #include <boost/pointer_cast.hpp>
28 
29 #include "src/common/error.h"
31 #include "src/common/threads.h"
32 #include "src/common/debug.h"
33 
34 #include "src/events/events.h"
35 
36 #include "src/graphics/graphics.h"
37 
39 
40 #include "src/video/decoder.h"
41 
42 #include "src/sound/sound.h"
43 #include "src/sound/audiostream.h"
44 #include "src/sound/decoders/pcm.h"
45 
46 namespace Video {
47 
49  _needCopy(false),
50  _texture(0),
51  _textureWidth(0.0f), _textureHeight(0.0f), _scale(kScaleNone),
52  _startTime(0), _pauseLevel(0), _pauseStartTime(0) {
53 
54 }
55 
57  deinit();
58 
59  if (_texture != 0)
60  GfxMan.abandon(&_texture, 1);
61 
62  stopAudio();
63 }
64 
66  hide();
67 
68  GLContainer::removeFromQueue(Graphics::kQueueGLContainer);
69 }
70 
72  uint32 width = getWidth();
73  uint32 height = getHeight();
74 
75  // The real texture dimensions. Have to be a power of 2
76  int realWidth = NEXTPOWER2(width);
77  int realHeight = NEXTPOWER2(height);
78 
79  // Dimensions of the actual video part of texture
80  _textureWidth = ((float) width ) / ((float) realWidth );
81  _textureHeight = ((float) height) / ((float) realHeight);
82 
83  _surface.reset(new Graphics::Surface(realWidth, realHeight));
84 
85  _surface->fill(0, 0, 0, 0);
86 
87  rebuild();
88 }
89 
91  for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
92  if ((*it)->getTrackType() == Track::kTrackTypeVideo)
93  return boost::static_pointer_cast<const VideoTrack>(*it)->getWidth();
94 
95  return 0;
96 }
97 
99  for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
100  if ((*it)->getTrackType() == Track::kTrackTypeVideo)
101  return boost::static_pointer_cast<const VideoTrack>(*it)->getHeight();
102 
103  return 0;
104 }
105 
107  for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
108  if (!(*it)->endOfTrack())
109  return false;
110 
111  return true;
112 }
113 
115  for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
116  if ((*it)->getTrackType() == Track::kTrackTypeVideo && !(*it)->endOfTrack())
117  return false;
118 
119  return true;
120 }
121 
123  return !endOfVideoTracks() && getTimeToNextFrame() == 0;
124 }
125 
126 void VideoDecoder::pauseVideo(bool pause) {
127  if (pause) {
128  _pauseLevel++;
129 
130  // We can't go negative
131  } else if (_pauseLevel) {
132  _pauseLevel--;
133 
134  // Do nothing
135  } else {
136  return;
137  }
138 
139  if (_pauseLevel == 1 && pause) {
140  _pauseStartTime = EventMan.getTimestamp(); // Store the starting time from pausing to keep it for later
141 
142  for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
143  (*it)->pause(true);
144  } else if (_pauseLevel == 0) {
145  for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
146  (*it)->pause(false);
147 
148  _startTime += (EventMan.getTimestamp() - _pauseStartTime);
149  }
150 }
151 
152 void VideoDecoder::addTrack(Track *track, bool isExternal) {
153  TrackPtr owned(track);
154  _tracks.push_back(owned);
155 
156  if (isExternal)
157  _externalTracks.push_back(owned);
158  else
159  _internalTracks.push_back(owned);
160 
161  if (track->getTrackType() == Track::kTrackTypeAudio) {
162  // Update volume settings if it's an audio track
163  // TODO: Make this setting available via an external interface
164  boost::static_pointer_cast<AudioTrack>(owned)->setGain(1.0f);
165  } else if (track->getTrackType() == Track::kTrackTypeVideo) {
166  // If this track has a better time, update _nextVideoTrack
167  VideoTrackPtr videoTrack = boost::static_pointer_cast<VideoTrack>(owned);
168  if (!_nextVideoTrack || videoTrack->getNextFrameStartTime() < _nextVideoTrack->getNextFrameStartTime())
169  _nextVideoTrack = videoTrack;
170  }
171 
172  // Keep the track paused if we're paused
173  if (isPaused())
174  track->pause(true);
175 
176  // Start the track if we're playing
177  if (isPlaying() && track->getTrackType() == Track::kTrackTypeAudio)
178  boost::static_pointer_cast<AudioTrack>(owned)->start();
179 }
180 
182  if (track > _internalTracks.size())
183  return VideoDecoder::TrackPtr();
184 
185  return _internalTracks[track];
186 }
187 
189  if (track > _internalTracks.size())
191 
192  return _internalTracks[track];
193 }
194 
196  _nextVideoTrack.reset();
197  Common::Timestamp bestTime(0xFFFFFFFF);
198 
199  for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) {
200  if ((*it)->getTrackType() == Track::kTrackTypeVideo && !(*it)->endOfTrack()) {
201  VideoTrackPtr track = boost::static_pointer_cast<VideoTrack>(*it);
202  Common::Timestamp time = track->getNextFrameStartTime();
203 
204  if (time < bestTime) {
205  bestTime = time;
206  _nextVideoTrack = track;
207  }
208  }
209  }
210 
211  return _nextVideoTrack;
212 }
213 
215  ConstTrackList tracks;
216 
217  for (TrackList::const_iterator it = _internalTracks.begin(); it != _internalTracks.end(); it++)
218  tracks.push_back(*it);
219 
220  return tracks;
221 }
222 
224  for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
225  if ((*it)->getTrackType() == Track::kTrackTypeAudio)
226  boost::static_pointer_cast<AudioTrack>(*it)->start();
227 }
228 
230  for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++)
231  if ((*it)->getTrackType() == Track::kTrackTypeAudio)
232  boost::static_pointer_cast<AudioTrack>(*it)->stop();
233 }
234 
236  for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
237  if ((*it)->getTrackType() == Track::kTrackTypeAudio)
238  return true;
239 
240  return false;
241 }
242 
244  if (!_surface)
245  return;
246 
247  // Generate the texture ID
248  glGenTextures(1, &_texture);
249 
250  glBindTexture(GL_TEXTURE_2D, _texture);
251 
252  // Texture clamping
253  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
254  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
255  // No filtering
256  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
257  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
258  glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
259 
260  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, _surface->getWidth(), _surface->getHeight(),
261  0, GL_BGRA, GL_UNSIGNED_BYTE, _surface->getData());
262 }
263 
265  if (_texture == 0)
266  return;
267 
268  glDeleteTextures(1, &_texture);
269 
270  _texture = 0;
271 }
272 
274  if (!_needCopy)
275  return;
276 
277  if (!_surface)
278  throw Common::Exception("No video data while trying to copy");
279  if (_texture == 0)
280  throw Common::Exception("No texture while trying to copy");
281 
282  glBindTexture(GL_TEXTURE_2D, _texture);
283  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _surface->getWidth(), _surface->getHeight(),
284  GL_BGRA, GL_UNSIGNED_BYTE, _surface->getData());
285 
286  _needCopy = false;
287 }
288 
290  _scale = scale;
291 }
292 
294  if (_startTime == 0)
295  return false;
296 
297  for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++)
298  if (!(*it)->endOfTrack())
299  return true;
300 
301  return false;
302 }
303 
305  if (!needsUpdate() || !_nextVideoTrack)
306  return;
307 
308  debugC(Common::kDebugVideo, 9, "New video frame");
309 
310  // Actually decode the frame for the track
312 
313  // Copy the data to the screen
314  copyData();
315 
316  // Look for the next video track here for the next decode.
318 
319  // Figure out how much audio we need
320  Common::Timestamp audioNeeded;
321  if (_nextVideoTrack)
322  audioNeeded = _nextVideoTrack->getNextFrameStartTime().addMsecs(500);
323  else
324  audioNeeded = Common::Timestamp(0xFFFFFFFF);
325 
326  // Ensure we have enough audio by the time we get to the next frame
327  for (TrackList::iterator it = _internalTracks.begin(); it != _internalTracks.end(); it++)
328  if ((*it)->getTrackType() == Track::kTrackTypeAudio && boost::static_pointer_cast<AudioTrack>(*it)->canBufferData())
329  checkAudioBuffer(static_cast<AudioTrack&>(**it), audioNeeded);
330 }
331 
332 void VideoDecoder::getQuadDimensions(float &width, float &height) const {
333  width = getWidth();
334  height = getHeight();
335 
336  if (_scale == kScaleNone)
337  // No scaling requested
338  return;
339 
340  float screenWidth = WindowMan.getWindowWidth();
341  float screenHeight = WindowMan.getWindowHeight();
342 
343  if ((_scale == kScaleUp) && (width <= screenWidth) && (height <= screenHeight))
344  // Only upscaling requested, but not necessary
345  return;
346 
347  if ((_scale == kScaleDown) && (width >= screenWidth) && (height >= screenHeight))
348  // Only downscaling requested, but not necessary
349  return;
350 
351  float ratio = width / height;
352 
353  width = screenWidth;
354  height = screenWidth / ratio;
355  if (height <= screenHeight)
356  return;
357 
358  height = screenHeight;
359  width = screenHeight * ratio;
360 }
361 
363 }
364 
367  return;
368 
369  if (!isPlaying() || _texture == 0)
370  return;
371 
372  // Process and copy the next frame data, if necessary
373  update();
374 
375  // Get the dimensions of the video surface we want, depending on the scaling requested
376  float width, height;
377  getQuadDimensions(width, height);
378 
379  // Create a textured quad with those dimensions
380 
381  float hWidth = width / 2.0f;
382  float hHeight = height / 2.0f;
383 
384  glBindTexture(GL_TEXTURE_2D, _texture);
385  glBegin(GL_QUADS);
386  glTexCoord2f(0.0f, 0.0f);
387  glVertex3f(-hWidth, -hHeight, -1.0f);
388  glTexCoord2f(_textureWidth, 0.0f);
389  glVertex3f( hWidth, -hHeight, -1.0f);
390  glTexCoord2f(_textureWidth, _textureHeight);
391  glVertex3f( hWidth, hHeight, -1.0f);
392  glTexCoord2f(0.0f, _textureHeight);
393  glVertex3f(-hWidth, hHeight, -1.0f);
394  glEnd();
395 }
396 
398  _startTime = EventMan.getTimestamp();
399 
400  startAudio();
401 
402  show();
403 }
404 
406  hide();
407 
408  stopAudio();
409 }
410 
412  if (!isPlaying())
413  return 0;
414 
415  if (isPaused())
416  return _pauseStartTime - _startTime;
417 
418  // TODO: Use the sound time if possible
419 
420  return EventMan.getTimestamp() - _startTime;
421 }
422 
424  if (!_nextVideoTrack || endOfVideo())
425  return 0;
426 
427  uint32 currentTime = getTime();
428  uint32 nextFrameStartTime = _nextVideoTrack->getNextFrameStartTime().msecs();
429 
430  if (nextFrameStartTime <= currentTime)
431  return 0;
432 
433  return nextFrameStartTime - currentTime;
434 }
435 
437 }
438 
440  // New API only
441  Common::Timestamp maxDuration(0, 1000);
442 
443  for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) {
444  Common::Timestamp duration = (*it)->getDuration();
445 
446  if (duration > maxDuration)
447  maxDuration = duration;
448  }
449 
450  return maxDuration;
451 }
452 
454  _paused = false;
455 }
456 
457 void VideoDecoder::Track::pause(bool shouldPause) {
458  _paused = shouldPause;
459  pauseIntern(shouldPause);
460 }
461 
462 void VideoDecoder::Track::pauseIntern(bool UNUSED(shouldPause)) {
463 }
464 
466  return Common::Timestamp(0, 1000);
467 }
468 
469 VideoDecoder::AudioTrack::AudioTrack() : _gain(1.0f), _muted(false) {
470 }
471 
473  return !getAudioStream() || !SoundMan.isPlaying(_handle);
474 }
475 
477  _gain = gain;
478 
479  if (SoundMan.isPlaying(_handle))
480  SoundMan.setChannelGain(_handle, _muted ? 0.0f : _gain);
481 }
482 
484  stop();
485 
486  Sound::AudioStream *stream = getAudioStream();
487  assert(stream);
488 
489  _handle = SoundMan.playAudioStream(stream, Sound::kSoundTypeVideo, false);
490 
491  // Apply the gain
492  SoundMan.setChannelGain(_handle, _muted ? 0.0f : _gain);
493 
494  // Pause the audio again if we're still paused
495  if (isPaused())
496  SoundMan.pauseChannel(_handle, true);
497 
498  // Actually start playback of the channel
499  SoundMan.startChannel(_handle);
500 }
501 
503  SoundMan.stopChannel(_handle);
504 }
505 
507  if (SoundMan.isPlaying(_handle))
508  return (uint32)SoundMan.getChannelDurationPlayed(_handle);
509 
510  return 0;
511 }
512 
514  // Update the mute settings, if required
515  if (_muted != mute) {
516  _muted = mute;
517 
518  if (SoundMan.isPlaying(_handle))
519  SoundMan.setChannelGain(_handle, _muted ? 0.0f : _gain);
520  }
521 }
522 
524  if (SoundMan.isPlaying(_handle))
525  SoundMan.pauseChannel(_handle, shouldPause);
526 }
527 
529  return getCurFrame() >= (getFrameCount() - 1);
530 }
531 
533  // Default implementation: Return an invalid (negative) number
534  return Common::Timestamp().addFrames(-1);
535 }
536 
538  if (endOfTrack() || getCurFrame() < 0)
539  return Common::Timestamp();
540 
541  return getFrameTime(getCurFrame() + 1);
542 }
543 
545  return Common::Timestamp(0, frame, getFrameRate());
546 }
547 
549  Common::Rational frameRate = getFrameRate();
550 
551  // Easy conversion
552  if (frameRate == time.framerate())
553  return time.totalNumberOfFrames();
554 
555  // Create the rational based on the time first to hopefully cancel out
556  // *something* when multiplying by the frameRate (which can be large in
557  // some AVI videos).
558  return (Common::Rational(time.totalNumberOfFrames(), time.framerate()) * frameRate).toInt();
559 }
560 
562  return getFrameTime(getFrameCount());
563 }
564 
565 } // End of namespace Video
Common::ScopedPtr< Graphics::Surface > _surface
The video&#39;s surface.
Definition: decoder.h:393
uint32 getTimeToNextFrame() const
Return the time, in milliseconds, to the next frame.
Definition: decoder.cpp:423
virtual void show()
Show the object.
Definition: renderable.cpp:114
Only scale the video up, if necessary.
Definition: decoder.h:59
virtual void pauseIntern(bool shouldPause)
Function called by pause() for subclasses to implement.
Definition: decoder.cpp:462
Only render transparent parts.
Definition: types.h:99
int64 totalNumberOfFrames() const
Return the time in frames described by this timestamp.
Definition: timestamp.h:209
The global graphics manager.
Don&#39;t scale the video.
Definition: decoder.h:58
virtual void hide()
Hide the object.
Definition: renderable.cpp:123
An abstract representation of an audio track.
Definition: decoder.h:302
void debugC(Common::DebugChannel channel, uint32 level, const char *s,...)
Definition: debug.cpp:34
The track is a video track.
Definition: decoder.h:181
An object containing OpenGL structures.
Definition: types.h:84
boost::shared_ptr< const Track > ConstTrackPtr
A const Track pointer.
Definition: decoder.h:369
A simple rational class that holds fractions.
Definition: rational.h:56
void reset(PointerType o=0)
Resets the pointer with the new value.
Definition: scopedptr.h:87
Utility functions for debug output.
uint64 framerate() const
Return the framerate used by this timestamp.
Definition: timestamp.h:223
void addTrack(Track *track, bool isExternal=false)
Define a track to be used by this class.
Definition: decoder.cpp:152
bool hasAudio() const
Definition: decoder.cpp:235
bool _needCopy
Is new frame content available that needs to by copied?
Definition: decoder.h:391
virtual void decodeNextTrackFrame(VideoTrack &track)=0
Decode enough data for the next frame.
Graphics::TextureID _texture
Definition: decoder.h:479
void setMute(bool mute)
Mute the track.
Definition: decoder.cpp:513
Implementing the reading stream interfaces for plain memory blocks.
virtual Common::Timestamp getDuration() const
Get the duration of the track.
Definition: decoder.cpp:465
static uint32 NEXTPOWER2(uint32 x)
Round up to the next power of 2.
Definition: util.h:84
Decoding PCM (Pulse Code Modulation).
TrackPtr getTrack(uint track)
Get the given internal track based on its index.
Definition: decoder.cpp:181
virtual bool canBufferData() const =0
Can more audio data be buffered?
The track is an audio track.
Definition: decoder.h:176
void update()
Update the video, if necessary.
Definition: decoder.cpp:304
void setScale(Scale scale)
Definition: decoder.cpp:289
virtual uint32 getHeight() const
Returns the height of the video&#39;s frames.
Definition: decoder.cpp:98
Common::Timestamp getFrameTime(uint frame) const
Get the time the given frame should be shown.
Definition: decoder.cpp:544
void initVideo()
Create a surface for video of these dimensions.
Definition: decoder.cpp:71
bool needsUpdate() const
Check whether a new frame should be decoded, i.e.
Definition: decoder.cpp:122
virtual Common::Timestamp getDuration() const
Get the duration of the track.
Definition: decoder.cpp:561
TrackList getInternalTracks()
Get a copy of the internal tracks.
Definition: decoder.h:461
virtual TrackType getTrackType() const =0
Get the type of track.
void render(Graphics::RenderPass pass)
Render the object.
Definition: decoder.cpp:365
Basic exceptions to throw.
Threading system helpers.
uint32 _pauseLevel
The pause level of the video; 0 for not paused.
Definition: decoder.h:491
VideoTrackPtr _nextVideoTrack
The next video track that needs to display.
Definition: decoder.h:473
RenderPass
Definition: types.h:97
boost::shared_ptr< VideoTrack > VideoTrackPtr
A VideoTrack pointer.
Definition: decoder.h:379
Common::Timestamp getNextFrameStartTime() const
Get the start time of the next frame since the start of the video.
Definition: decoder.cpp:537
VideoTrackPtr findNextVideoTrack()
Set _nextVideoTrack to the video track with the lowest start time for the next frame.
Definition: decoder.cpp:195
void start()
Start playing this track.
Definition: decoder.cpp:483
void pauseVideo(bool pause)
Pause or resume the video.
Definition: decoder.cpp:126
void start()
Start playing the video.
Definition: decoder.cpp:397
#define UNUSED(x)
Definition: system.h:170
"GVideo", global, non-engine video (movies).
Definition: debugman.h:44
void stopAudio()
Stop all audio tracks.
Definition: decoder.cpp:229
bool endOfTrack() const
Return if the track has finished.
Definition: decoder.cpp:472
std::vector< ConstTrackPtr > ConstTrackList
A list of const tracks.
Definition: decoder.h:389
The global events manager.
bool isPlaying() const
Is the video currently playing?
Definition: decoder.cpp:293
void pause(bool shouldPause)
Set the pause status of the track.
Definition: decoder.cpp:457
void getQuadDimensions(float &width, float &height) const
Get the dimensions of the quad to draw the texture on.
Definition: decoder.cpp:332
bool _paused
Is the track paused?
Definition: decoder.h:220
The global sound manager, handling all sound output.
Video/Movie.
Definition: types.h:47
TrackList _internalTracks
Tracks internal to this VideoDecoder.
Definition: decoder.h:470
#define SoundMan
Shortcut for accessing the sound manager.
Definition: sound.h:293
StackException Exception
Definition: error.h:59
An abstract representation of a video track.
Definition: decoder.h:226
void setGain(float gain)
Set the gain for this track.
Definition: decoder.cpp:476
bool endOfVideo() const
Returns if the video has reached the end or not.
Definition: decoder.cpp:106
void calculateDistance()
Calculate the object&#39;s distance.
Definition: decoder.cpp:362
#define EventMan
Shortcut for accessing the events manager.
Definition: events.h:210
bool isPaused() const
Return whether the video is currently paused or not.
Definition: decoder.h:152
Generic audio input stream.
Definition: audiostream.h:70
uint32 getTime() const
Returns the time position (in ms) of the current video.
Definition: decoder.cpp:411
void abort()
Abort the playing of the video.
Definition: decoder.cpp:405
#define WindowMan
Shortcut for accessing the window manager.
Definition: windowman.h:137
virtual void checkAudioBuffer(AudioTrack &track, const Common::Timestamp &endTime)
Ensure that there is enough audio buffered in the given track to reach the given timestamp.
Definition: decoder.cpp:436
boost::shared_ptr< Track > TrackPtr
A Track pointer.
Definition: decoder.h:364
uint getFrameAtTime(const Common::Timestamp &time) const
Get the frame that should be displaying at the given time.
Definition: decoder.cpp:548
void pauseIntern(bool shouldPause)
Function called by pause() for subclasses to implement.
Definition: decoder.cpp:523
An image surface, in BGRA format.
uint32 getRunningTime() const
Get the time the AudioStream behind this track has been running.
Definition: decoder.cpp:506
virtual bool endOfTrack() const
Return if the track has finished.
Definition: decoder.cpp:528
uint32_t uint32
Definition: types.h:204
bool endOfVideoTracks() const
Have all video tracks finished?
Definition: decoder.cpp:114
virtual uint32 getWidth() const
Returns the width of the video&#39;s frames.
Definition: decoder.cpp:90
virtual Common::Timestamp getDuration() const
Get the duration of the video.
Definition: decoder.cpp:439
Timestamps allow specifying points in time and measuring time intervals with a sub-millisecond granul...
Definition: timestamp.h:108
float _textureHeight
Definition: decoder.h:482
An abstract representation of a track in a movie.
Definition: decoder.h:159
#define pass
Definition: fft.cpp:257
virtual Common::Timestamp getFrameTime(uint frame) const
Get the time the given frame should be shown.
Definition: decoder.cpp:532
void copyData()
Copy the video image data to the texture.
Definition: decoder.cpp:273
TrackList _externalTracks
Tracks loaded from externals files.
Definition: decoder.h:471
void startAudio()
Start the designated internal audio track and any external audio tracks.
Definition: decoder.cpp:223
TrackList _tracks
Tracks owned by this VideoDecoder (both internal and external).
Definition: decoder.h:469
Timestamp addFrames(int64 frames) const
Returns a new timestamp, which corresponds to the time encoded by this timestamp with the given numbe...
Definition: timestamp.cpp:179
uint32 _startTime
The start time of the video, or -1 for not set.
Definition: decoder.h:488
Only scale the video down, if necessary.
Definition: decoder.h:60
Streaming audio.
void stop()
Stop playing this track.
Definition: decoder.cpp:502
#define GfxMan
Shortcut for accessing the graphics manager.
Definition: graphics.h:299
unsigned int uint
Definition: types.h:211
Generic video decoder interface.
uint32 _pauseStartTime
The time when the track was first paused.
Definition: decoder.h:494