diff --git a/panda/src/grutil/movieTexture.cxx b/panda/src/grutil/movieTexture.cxx index bdba0f7ca6..3cc7223b15 100644 --- a/panda/src/grutil/movieTexture.cxx +++ b/panda/src/grutil/movieTexture.cxx @@ -24,6 +24,7 @@ #include "config_gobj.h" #include "config_grutil.h" #include "bamCacheRecord.h" +#include "math.h" TypeHandle MovieTexture::_type_handle; @@ -48,7 +49,9 @@ MovieTexture:: MovieTexture(PT(MovieVideo) video) : Texture(video->get_name()) { - do_load_one(video, NULL, 0); + // It is necessary to copy the video, because + // the cull thread will be accessing it. + do_load_one(video->make_copy(), NULL, 0); } //////////////////////////////////////////////////////////////////// @@ -57,7 +60,14 @@ MovieTexture(PT(MovieVideo) video) : // Description: xxx //////////////////////////////////////////////////////////////////// MovieTexture::CData:: -CData() +CData() : + _video_width(1), + _video_height(1), + _video_length(1.0), + _playing(false), + _clock(0.0), + _play_rate(1.0), + _loop_count(1) { } @@ -70,7 +80,12 @@ MovieTexture::CData:: CData(const CData ©) : _pages(copy._pages), _video_width(copy._video_width), - _video_height(copy._video_height) + _video_height(copy._video_height), + _video_length(copy._video_length), + _playing(false), + _clock(0.0), + _play_rate(1.0), + _loop_count(1.0) { } @@ -120,6 +135,7 @@ MovieTexture(const MovieTexture ©) : cdata->_pages[i]._alpha = color[i]->make_copy(); } } + recalculate_image_properties(cdata); } } @@ -183,27 +199,31 @@ VideoPage() : //////////////////////////////////////////////////////////////////// void MovieTexture:: recalculate_image_properties(CDWriter &cdata) { - int x_max = 0; - int y_max = 0; + int x_max = 1; + int y_max = 1; bool alpha = false; + double len = 0.0; for (int i=0; i<_z_size; i++) { MovieVideo *t = cdata->_pages[i]._color; if (t) { if (t->size_x() > x_max) x_max = t->size_x(); if (t->size_y() > y_max) y_max = t->size_y(); + if (t->length() > len) len = t->length(); if (t->get_num_components() == 4) alpha=true; } t = cdata->_pages[i]._alpha; if (t) { if (t->size_x() > x_max) x_max = t->size_x(); if (t->size_y() > y_max) y_max = t->size_y(); + if (t->length() > len) len = t->length(); alpha = true; } } cdata->_video_width = x_max; cdata->_video_height = y_max; + cdata->_video_length = len; if (get_texture_type() == TT_cube_map) { // Texture must be square. @@ -269,9 +289,13 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath, _primary_file_num_channels = primary_file_num_channels; _alpha_file_channel = alpha_file_channel; - return do_load_one(color, alpha, z); - + if (!do_load_one(color, alpha, z)) { + return false; + } + set_loaded_from_image(); + set_loop(true); + play(); } //////////////////////////////////////////////////////////////////// @@ -287,7 +311,6 @@ do_load_one(PT(MovieVideo) color, PT(MovieVideo) alpha, int z) { cdata->_pages.resize(z+1); cdata->_pages[z]._color = color; cdata->_pages[z]._alpha = alpha; - cdata->_pages[z]._base_clock = ClockObject::get_global_clock()->get_frame_time(); recalculate_image_properties(cdata); } @@ -353,25 +376,36 @@ has_cull_callback() const { bool MovieTexture:: cull_callback(CullTraverser *, const CullTraverserData &) const { CDReader cdata(_cycler); + + // Calculate the cursor position modulo the length of the movie. double now = ClockObject::get_global_clock()->get_frame_time(); + double clock = cdata->_clock; + if (cdata->_playing) { + clock += now * cdata->_play_rate; + } + double offset; + if (clock >= cdata->_video_length * cdata->_loop_count) { + offset = cdata->_video_length; + } else { + offset = fmod(clock, cdata->_video_length); + } + for (int i=0; i<((int)(cdata->_pages.size())); i++) { - double delta = now - cdata->_pages[i]._base_clock; MovieVideo *color = cdata->_pages[i]._color; MovieVideo *alpha = cdata->_pages[i]._alpha; - if (color) { - double offset = delta; - if ((offset < color->last_start()) || (offset >= color->next_start())) { - if (alpha) { - color->fetch_into_texture_rgb(offset, (MovieTexture*)this, i); - } else { - color->fetch_into_texture(offset, (MovieTexture*)this, i); - } + if (color && alpha) { + if ((offset >= color->next_start())|| + ((offset < color->last_start()) && (color->can_seek()))) { + color->fetch_into_texture_rgb(offset, (MovieTexture*)this, i); } - } - if (alpha) { - double offset = delta; - if ((offset < alpha->last_start()) || (offset >= alpha->next_start())) { - alpha->fetch_into_texture_alpha(offset, (MovieTexture*)this, i, _alpha_file_channel); + if ((offset >= alpha->next_start())|| + ((offset < alpha->last_start()) && (alpha->can_seek()))) { + alpha->fetch_into_texture_alpha(offset, (MovieTexture*)this, i, _alpha_file_channel); + } + } else if (color) { + if ((offset >= color->next_start())|| + ((offset < color->last_start()) && (color->can_seek()))) { + color->fetch_into_texture(offset, (MovieTexture*)this, i); } } } @@ -404,3 +438,186 @@ reload_ram_image() { // Therefore, this is not needed. } +//////////////////////////////////////////////////////////////////// +// Function: MovieTexture::restart +// Access: Published +// Description: Start playing the movie from where it was last +// paused. Has no effect if the movie is not paused, +// or if the movie's cursor is already at the end. +//////////////////////////////////////////////////////////////////// +void MovieTexture:: +restart() { + CDWriter cdata(_cycler); + if (!cdata->_playing) { + double now = ClockObject::get_global_clock()->get_frame_time(); + cdata->_clock = cdata->_clock - (now * cdata->_play_rate); + cdata->_playing = true; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: MovieTexture::stop +// Access: Published +// Description: Stops a currently playing or looping movie right +// where it is. The movie's cursor remains frozen at +// the point where it was stopped. +//////////////////////////////////////////////////////////////////// +void MovieTexture:: +stop() { + CDWriter cdata(_cycler); + if (cdata->_playing) { + double now = ClockObject::get_global_clock()->get_frame_time(); + cdata->_clock = cdata->_clock + (now * cdata->_play_rate); + cdata->_playing = false; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: MovieTexture::play +// Access: Published +// Description: Plays the movie from the beginning. +//////////////////////////////////////////////////////////////////// +void MovieTexture:: +play() { + CDWriter cdata(_cycler); + double now = ClockObject::get_global_clock()->get_frame_time(); + cdata->_clock = 0.0 - (now * cdata->_play_rate); + cdata->_playing = true; +} + +//////////////////////////////////////////////////////////////////// +// Function: MovieTexture::set_time +// Access: Published +// Description: Sets the movie's cursor. If the movie's loop count +// count is greater than one, then its length is +// effectively multiplied for the purposes of this +// function. In other words, you can set a value in +// the range 0.0 to (length * loopcount). +//////////////////////////////////////////////////////////////////// +void MovieTexture:: +set_time(double t) { + CDWriter cdata(_cycler); + t = min(cdata->_video_length * cdata->_loop_count, max(0.0, t)); + if (cdata->_playing) { + double now = ClockObject::get_global_clock()->get_frame_time(); + cdata->_clock = t - (now * cdata->_play_rate); + } else { + cdata->_clock = t; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: MovieTexture::get_time +// Access: Published +// Description: Returns the current value of the movie's cursor. +// If the movie's loop count is greater than one, then +// its length is effectively multiplied for the +// purposes of this function. In other words, +// the return value will be in the range 0.0 +// to (length * loopcount). +//////////////////////////////////////////////////////////////////// +double MovieTexture:: +get_time() const { + CDReader cdata(_cycler); + double clock = cdata->_clock; + if (cdata->_playing) { + double now = ClockObject::get_global_clock()->get_frame_time(); + clock += (now * cdata->_play_rate); + } + return min(cdata->_video_length * cdata->_loop_count, clock); +} + +//////////////////////////////////////////////////////////////////// +// Function: MovieTexture::set_loop +// Access: Published +// Description: If true, sets the movie's loop count to 1 billion. +// If false, sets the movie's loop count to one. +//////////////////////////////////////////////////////////////////// +void MovieTexture:: +set_loop(bool loop) { + CDWriter cdata(_cycler); + if (loop) { + cdata->_loop_count = 1000000000; + } else { + cdata->_loop_count = 1; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: MovieTexture::get_loop +// Access: Published +// Description: Returns true if the movie's loop count is not equal +// to one. +//////////////////////////////////////////////////////////////////// +bool MovieTexture:: +get_loop() const { + CDReader cdata(_cycler); + return (cdata->_loop_count != 1); +} + +//////////////////////////////////////////////////////////////////// +// Function: MovieTexture::set_loop_count +// Access: Published +// Description: Sets the movie's loop count to the desired value. +//////////////////////////////////////////////////////////////////// +void MovieTexture:: +set_loop_count(int n) { + CDWriter cdata(_cycler); + if (n < 1) n = 1; + if (n > 1000000000) n = 1000000000; + cdata->_loop_count = n; +} + +//////////////////////////////////////////////////////////////////// +// Function: MovieTexture::get_loop_count +// Access: Published +// Description: Returns the movie's loop count. +//////////////////////////////////////////////////////////////////// +int MovieTexture:: +get_loop_count() const { + CDReader cdata(_cycler); + return cdata->_loop_count; +} + +//////////////////////////////////////////////////////////////////// +// Function: MovieTexture::set_play_rate +// Access: Published +// Description: Sets the movie's play-rate. This is the speed at +// which the movie's cursor advances. The default is +// to advance 1.0 movie-seconds per real-time second. +//////////////////////////////////////////////////////////////////// +void MovieTexture:: +set_play_rate(double rate) { + CDWriter cdata(_cycler); + if (cdata->_playing) { + double now = ClockObject::get_global_clock()->get_frame_time(); + cdata->_clock += (now * cdata->_play_rate); + cdata->_play_rate = rate; + cdata->_clock -= (now * cdata->_play_rate); + } else { + cdata->_play_rate = rate; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: MovieTexture::get_play_rate +// Access: Published +// Description: Gets the movie's play-rate. +//////////////////////////////////////////////////////////////////// +double MovieTexture:: +get_play_rate() const { + CDReader cdata(_cycler); + return cdata->_play_rate; +} + +//////////////////////////////////////////////////////////////////// +// Function: MovieTexture::is_playing +// Access: Published +// Description: Returns true if the movie's cursor is advancing. +//////////////////////////////////////////////////////////////////// +bool MovieTexture:: +is_playing() const { + CDReader cdata(_cycler); + return cdata->_playing; +} + diff --git a/panda/src/grutil/movieTexture.h b/panda/src/grutil/movieTexture.h index 495952dabc..f7bcd3a3ab 100644 --- a/panda/src/grutil/movieTexture.h +++ b/panda/src/grutil/movieTexture.h @@ -42,6 +42,19 @@ PUBLISHED: INLINE int get_video_height() const; INLINE LVecBase2f get_tex_scale() const; + void restart(); + void stop(); + void play(); + void set_time(double t); + double get_time() const; + void set_loop(bool enable); + bool get_loop() const; + void set_loop_count(int count); + int get_loop_count() const; + void set_play_rate(double play_rate); + double get_play_rate() const; + bool is_playing() const; + public: static PT(Texture) make_texture(); virtual bool has_cull_callback() const; @@ -62,7 +75,6 @@ protected: VideoPage(); PT(MovieVideo) _color; PT(MovieVideo) _alpha; - double _base_clock; }; typedef pvector Pages; @@ -75,10 +87,16 @@ protected: virtual TypeHandle get_parent_type() const { return MovieTexture::get_class_type(); } - + Pages _pages; int _video_width; int _video_height; + double _video_length; + + double _clock; + bool _playing; + int _loop_count; + double _play_rate; }; PipelineCycler _cycler; diff --git a/panda/src/movies/ffmpegVideo.cxx b/panda/src/movies/ffmpegVideo.cxx index 7a76b920cf..f565e371fe 100644 --- a/panda/src/movies/ffmpegVideo.cxx +++ b/panda/src/movies/ffmpegVideo.cxx @@ -60,12 +60,12 @@ FfmpegVideo(const Filename &name) : if(_format_ctx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) { _video_index = i; _video_ctx = _format_ctx->streams[i]->codec; - _video_timebase = av_q2d(_video_ctx->time_base); + _video_timebase = av_q2d(_format_ctx->streams[i]->time_base); } if(_format_ctx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO) { _audio_index = i; _audio_ctx = _format_ctx->streams[i]->codec; - _audio_timebase = av_q2d(_audio_ctx->time_base); + _audio_timebase = av_q2d(_format_ctx->streams[i]->time_base); } } @@ -86,7 +86,7 @@ FfmpegVideo(const Filename &name) : _size_x = _video_ctx->width; _size_y = _video_ctx->height; - _num_components = (_video_ctx->pix_fmt==PIX_FMT_RGBA32) ? 4:3; + _num_components = 3; // Don't know how to implement RGBA movies yet. if (_audio_ctx) { AVCodec *pAudioCodec=avcodec_find_decoder(_audio_ctx->codec_id); @@ -100,10 +100,10 @@ FfmpegVideo(const Filename &name) : } } } - + _length = (_format_ctx->duration * 1.0) / AV_TIME_BASE; _can_seek = true; - _can_seek_zero = true; + _can_seek_fast = true; memset(_time_corrections, 0, sizeof(_time_corrections)); @@ -135,6 +135,7 @@ FfmpegVideo:: //////////////////////////////////////////////////////////////////// void FfmpegVideo:: cleanup() { + _frame_out->data[0] = 0; if (_format_ctx) { av_close_input_file(_format_ctx); _format_ctx = 0; @@ -217,12 +218,13 @@ read_ahead() { } } - cerr << "Audio: " << dts << " " << real << "\n"; + cerr << "Audio: " << pkt.dts << "(" << dts << ") " << real << "\n"; } av_free_packet(&pkt); } + cerr << "Synthesized dummy frame.\n"; _next_start = _next_start + 1.0; } @@ -232,11 +234,13 @@ read_ahead() { // Description: See MovieVideo::fetch_into_buffer. //////////////////////////////////////////////////////////////////// void FfmpegVideo:: -fetch_into_buffer(double time, unsigned char *data, bool rgba) { +fetch_into_buffer(double time, unsigned char *data, bool bgra) { // If there was an error at any point, fetch black. if (_format_ctx==0) { - memset(data,0,size_x()*size_y()*(rgba?4:3)); + memset(data,0,size_x()*size_y()*(bgra?4:3)); + _last_start = _next_start; + _next_start += 1.0; return; } @@ -244,13 +248,15 @@ fetch_into_buffer(double time, unsigned char *data, bool rgba) { nassertv(ctx->width == size_x()); nassertv(ctx->height == size_y()); - if (rgba) { - avpicture_fill((AVPicture *)_frame_out, data, PIX_FMT_RGBA32, ctx->width, ctx->height); - img_convert((AVPicture *)_frame_out, PIX_FMT_RGBA32, + if (bgra) { + _frame_out->data[0] = data + ((ctx->height-1) * ctx->width * 4); + _frame_out->linesize[0] = ctx->width * -4; + img_convert((AVPicture *)_frame_out, PIX_FMT_BGRA, (AVPicture *)_frame, ctx->pix_fmt, ctx->width, ctx->height); } else { - avpicture_fill((AVPicture *)_frame_out, data, PIX_FMT_RGB24, ctx->width, ctx->height); - img_convert((AVPicture *)_frame_out, PIX_FMT_RGB24, + _frame_out->data[0] = data + ((ctx->height-1) * ctx->width * 3); + _frame_out->linesize[0] = ctx->width * -3; + img_convert((AVPicture *)_frame_out, PIX_FMT_BGR24, (AVPicture *)_frame, ctx->pix_fmt, ctx->width, ctx->height); } diff --git a/panda/src/movies/inkblotVideo.cxx b/panda/src/movies/inkblotVideo.cxx index 350394f5c9..7b18d9592e 100644 --- a/panda/src/movies/inkblotVideo.cxx +++ b/panda/src/movies/inkblotVideo.cxx @@ -72,7 +72,8 @@ InkblotVideo(int x, int y, int fps) : _cells2 = new unsigned char[padx * pady]; memset(_cells, 255, padx * pady); memset(_cells2, 255, padx * pady); - + _can_seek = true; + _can_seek_fast = false; _frames_read = 0; } @@ -93,12 +94,12 @@ InkblotVideo:: // Description: See MovieVideo::fetch_into_buffer. //////////////////////////////////////////////////////////////////// void InkblotVideo:: -fetch_into_buffer(double time, unsigned char *data, bool rgba) { +fetch_into_buffer(double time, unsigned char *data, bool bgra) { int padx = size_x() + 2; int pady = size_y() + 2; - if ((time == 0.0)&&(_next_start != 0.0)) { + if (time < _next_start) { // Rewind to beginning. memset(_cells, 255, padx * pady); memset(_cells2, 255, padx * pady); @@ -139,10 +140,10 @@ fetch_into_buffer(double time, unsigned char *data, bool rgba) { color &c1 = colormap[(val>>4)+0]; color &c2 = colormap[(val>>4)+1]; int lerp = val & 15; - data[0] = (c1.r * (16-lerp) + c2.r * lerp) / 16; + data[0] = (c1.b * (16-lerp) + c2.b * lerp) / 16; data[1] = (c1.g * (16-lerp) + c2.g * lerp) / 16; - data[2] = (c1.b * (16-lerp) + c2.b * lerp) / 16; - if (rgba) { + data[2] = (c1.r * (16-lerp) + c2.r * lerp) / 16; + if (bgra) { data[3] = 255; data += 4; } else { diff --git a/panda/src/movies/movieAudio.I b/panda/src/movies/movieAudio.I index 2043bf8dc1..5d69d00751 100644 --- a/panda/src/movies/movieAudio.I +++ b/panda/src/movies/movieAudio.I @@ -76,7 +76,14 @@ length() const { //////////////////////////////////////////////////////////////////// // Function: MovieAudio::can_seek // Access: Public -// Description: See method 'seek' for an explanation. +// Description: Returns true if the movie can seek. If this is +// true, seeking is still not guaranteed to be fast: +// for some movies, seeking is implemented by rewinding +// to the beginning and then fast-forwarding to the +// desired location. Even if the movie cannot seek, +// the seek method can still advance to an arbitrary +// location by reading samples and discarding them. +// However, to move backward, can_seek must return true. //////////////////////////////////////////////////////////////////// INLINE bool MovieAudio:: can_seek() const { @@ -84,13 +91,13 @@ can_seek() const { } //////////////////////////////////////////////////////////////////// -// Function: MovieAudio::can_seek_zero +// Function: MovieAudio::can_seek_fast // Access: Public -// Description: See method 'seek' for an explanation. +// Description: Returns true if seek operations are constant time. //////////////////////////////////////////////////////////////////// INLINE bool MovieAudio:: -can_seek_zero() const { - return _can_seek_zero; +can_seek_fast() const { + return _can_seek_fast; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/movies/movieAudio.cxx b/panda/src/movies/movieAudio.cxx index 6ad8b62db2..ff99acdb2c 100644 --- a/panda/src/movies/movieAudio.cxx +++ b/panda/src/movies/movieAudio.cxx @@ -35,7 +35,7 @@ MovieAudio(const string &name) : _audio_channels(1), _length(1.0E10), _can_seek(true), - _can_seek_zero(true), + _can_seek_fast(true), _aborted(false), _samples_read(0) { @@ -77,22 +77,26 @@ read_samples(int n, PN_int16 *data) { //////////////////////////////////////////////////////////////////// // Function: MovieAudio::seek // Access: Published, Virtual -// Description: Skips to the specified point in the movie. After +// Description: Skips to the specified sample number. After // calling seek, samples_read will be equal to the -// offset times the sample rate. +// specified value. If the movie reports that it +// cannot seek, then this method can still advance +// by reading samples and discarding them. However, +// to move backward, can_seek must be true. +// +// If the movie reports that it can_seek, it doesn't +// mean that it can do so quickly. It may have to +// rewind the movie and then fast forward to the +// desired location. Only if can_seek_fast returns +// true can seek operations be done in constant time. // // Seeking may not be precise, because AVI files // often have inaccurate indices. However, it is // usually pretty close (ie, 0.05 seconds). -// -// It is an error to call seek with a nonzero offset -// if can_seek() reports false. It is an error to -// call seek with a zero offset if can_seek_zero -// reports false. //////////////////////////////////////////////////////////////////// void MovieAudio:: -seek(double offset) { - _samples_read = offset * audio_rate(); +seek(int sr) { + _samples_read = sr; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/movies/movieAudio.h b/panda/src/movies/movieAudio.h index 5417d8a11f..4adafab129 100644 --- a/panda/src/movies/movieAudio.h +++ b/panda/src/movies/movieAudio.h @@ -45,11 +45,11 @@ PUBLISHED: INLINE int audio_channels() const; INLINE double length() const; INLINE bool can_seek() const; - INLINE bool can_seek_zero() const; + INLINE bool can_seek_fast() const; INLINE bool aborted() const; INLINE int samples_read() const; INLINE void skip_samples(int n); - virtual void seek(double offset); + virtual void seek(int sr); virtual PT(MovieAudio) make_copy() const; static PT(MovieAudio) load(const Filename &name); @@ -61,7 +61,7 @@ protected: int _audio_channels; double _length; bool _can_seek; - bool _can_seek_zero; + bool _can_seek_fast; bool _aborted; int _samples_read; diff --git a/panda/src/movies/movieVideo.I b/panda/src/movies/movieVideo.I index 4f4f246fd0..558f4789ee 100644 --- a/panda/src/movies/movieVideo.I +++ b/panda/src/movies/movieVideo.I @@ -86,7 +86,14 @@ length() const { //////////////////////////////////////////////////////////////////// // Function: MovieVideo::can_seek // Access: Published -// Description: See explanation in fetch_to_buffer. +// Description: Returns true if the movie can seek. If this is +// true, seeking is still not guaranteed to be fast: +// for some movies, seeking is implemented by rewinding +// to the beginning and then fast-forwarding to the +// desired location. Even if the movie cannot seek, +// the fetch methods can still advance to an arbitrary +// location by reading frames and discarding them. +// However, to move backward, can_seek must return true. //////////////////////////////////////////////////////////////////// INLINE bool MovieVideo:: can_seek() const { @@ -94,13 +101,13 @@ can_seek() const { } //////////////////////////////////////////////////////////////////// -// Function: MovieVideo::can_seek_zero +// Function: MovieVideo::can_seek_fast // Access: Published -// Description: See explanation in fetch_to_buffer. +// Description: Returns true if seek operations are constant time. //////////////////////////////////////////////////////////////////// INLINE bool MovieVideo:: -can_seek_zero() const { - return _can_seek_zero; +can_seek_fast() const { + return _can_seek_fast; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/movies/movieVideo.cxx b/panda/src/movies/movieVideo.cxx index fa913f280a..b59de83e4a 100644 --- a/panda/src/movies/movieVideo.cxx +++ b/panda/src/movies/movieVideo.cxx @@ -38,7 +38,7 @@ MovieVideo(const string &name) : _num_components(3), _length(1.0E10), _can_seek(true), - _can_seek_zero(true), + _can_seek_fast(true), _aborted(false), _last_start(-1.0), _next_start(0.0) @@ -242,19 +242,22 @@ fetch_into_texture_rgb(double time, Texture *t, int page) { // Function: MovieVideo::fetch_into_buffer // Access: Published, Virtual // Description: Reads the specified video frame into the supplied -// RGB8 or RGBA8 buffer. The frame's begin and end +// BGR or BGRA buffer. The frame's begin and end // times are stored in last_start and next_start. // -// You may always specify a timestamp greater than or -// equal to next_start --- ie, read forward through the -// movie. If the movie reports that it can_seek_zero, -// you may also specify a timestamp of 0.0 --- ie, -// rewind the movie. If the movie reports that it -// can_seek, you may specify any timestamp. It is -// generally much faster to read frames sequentially. +// If the movie reports that it can_seek, you may +// also specify a timestamp less than next_start. +// Otherwise, you may only specify a timestamp +// greater than or equal to next_start. +// +// If the movie reports that it can_seek, it doesn't +// mean that it can do so quickly. It may have to +// rewind the movie and then fast forward to the +// desired location. Only if can_seek_fast returns +// true can it seek rapidly. //////////////////////////////////////////////////////////////////// void MovieVideo:: -fetch_into_buffer(double time, unsigned char *data, bool rgba) { +fetch_into_buffer(double time, unsigned char *data, bool bgra) { // The following is the implementation of the null video stream, ie, // a stream of blinking red and blue frames. This method must be @@ -272,7 +275,7 @@ fetch_into_buffer(double time, unsigned char *data, bool rgba) { data[1] = 128; data[2] = 255; } - if (rgba) { + if (bgra) { data[3] = 255; } } diff --git a/panda/src/movies/movieVideo.h b/panda/src/movies/movieVideo.h index a337525e53..ae1b1adb01 100644 --- a/panda/src/movies/movieVideo.h +++ b/panda/src/movies/movieVideo.h @@ -45,7 +45,7 @@ class EXPCL_PANDA_MOVIES MovieVideo : public TypedWritableReferenceCount, public INLINE int get_num_components() const; INLINE int length() const; INLINE bool can_seek() const; - INLINE bool can_seek_zero() const; + INLINE bool can_seek_fast() const; INLINE bool aborted() const; INLINE double last_start() const; INLINE double next_start() const; @@ -57,7 +57,7 @@ class EXPCL_PANDA_MOVIES MovieVideo : public TypedWritableReferenceCount, public static PT(MovieVideo) load(const Filename &name); public: - virtual void fetch_into_buffer(double time, unsigned char *block, bool rgba); + virtual void fetch_into_buffer(double time, unsigned char *block, bool bgra); private: void allocate_conversion_buffer(); @@ -69,7 +69,7 @@ class EXPCL_PANDA_MOVIES MovieVideo : public TypedWritableReferenceCount, public int _num_components; double _length; bool _can_seek; - bool _can_seek_zero; + bool _can_seek_fast; bool _aborted; double _last_start; double _next_start;