Browse Source

Getting closer to functional

Josh Yelon 18 years ago
parent
commit
b1d7446c27

+ 239 - 22
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 &copy) :
   _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 &copy) :
         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;
+}
+

+ 20 - 2
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<VideoPage> 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<CData> _cycler;

+ 19 - 13
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);
   }
 

+ 7 - 6
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 {

+ 12 - 5
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;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 14 - 10
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;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 3 - 3
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;
   

+ 12 - 5
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;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 14 - 11
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;
   }
 }

+ 3 - 3
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;