Browse Source

Restructured to eliminate Movie class

Josh Yelon 18 years ago
parent
commit
dfac5cacb3

+ 0 - 7
panda/src/movies/Sources.pp

@@ -14,9 +14,7 @@
 	movie.h movie.I \
 	movieAudio.h movieAudio.I \
 	movieVideo.h movieVideo.I \
-        inkblotMovie.h inkblotMovie.I \
         inkblotVideo.h inkblotVideo.I \
-        ffmpegMovie.h ffmpegMovie.I \
         ffmpegVideo.h ffmpegVideo.I \
         ffmpegAudio.h ffmpegAudio.I \
 	config_movies.h
@@ -24,21 +22,16 @@
   #define INCLUDED_SOURCES \
         movieVideo.cxx \
         movieAudio.cxx \
-        movie.cxx \
         inkblotVideo.cxx \
-        inkblotMovie.cxx \
         ffmpegVideo.cxx \
         ffmpegAudio.cxx \
-        ffmpegMovie.cxx \
         config_movies.cxx
     
   #define INSTALL_HEADERS \
 	movie.h movie.I \
 	movieAudio.h movieAudio.I \
 	movieVideo.h movieVideo.I \
-        inkblotMovie.h inkblotMovie.I \
         inkblotVideo.h inkblotVideo.I \
-        ffmpegMovie.h ffmpegMovie.I \
         ffmpegVideo.h ffmpegVideo.I \
         ffmpegAudio.h ffmpegAudio.I \
 	config_movies.h

+ 9 - 5
panda/src/movies/config_movies.cxx

@@ -19,6 +19,10 @@
 #include "config_movies.h"
 #include "dconfig.h"
 
+#ifdef HAVE_FFMPEG
+#include "avcodec.h"
+#endif
+
 ConfigureDef(config_movies);
 NotifyCategoryDef(movies, "");
 
@@ -44,11 +48,11 @@ init_libmovies() {
 
   MovieVideo::init_type();
   MovieAudio::init_type();
-  Movie::init_type();
   InkblotVideo::init_type();
-  InkblotMovie::init_type();
-  FfmpegVideo::init_type();
-  FfmpegAudio::init_type();
-  FfmpegMovie::init_type();
+#ifdef HAVE_FFMPEG
+  //  FfmpegVideo::init_type();
+  //  FfmpegAudio::init_type();
+  av_register_all();
+#endif
 }
 

+ 2 - 1
panda/src/movies/config_movies.h

@@ -24,10 +24,11 @@
 #include "configVariableEnum.h"
 #include "configVariableDouble.h"
 #include "dconfig.h"
-#include "movie.h"
 #include "movieVideo.h"
 #include "movieAudio.h"
 #include "inkblotVideo.h"
+#include "ffmpegVideo.h"
+#include "ffmpegAudio.h"
 
 ConfigureDecl(config_movies, EXPCL_PANDA_MOVIES, EXPTP_PANDA_MOVIES);
 NotifyCategoryDecl(movies, EXPCL_PANDA_MOVIES, EXPTP_PANDA_MOVIES);

+ 20 - 3
panda/src/movies/ffmpegAudio.cxx

@@ -16,7 +16,11 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+#ifdef HAVE_FFMPEG
+
 #include "ffmpegAudio.h"
+#include "avcodec.h"
+#include "avformat.h"
 
 TypeHandle FfmpegAudio::_type_handle;
 
@@ -26,9 +30,9 @@ TypeHandle FfmpegAudio::_type_handle;
 //  Description: xxx
 ////////////////////////////////////////////////////////////////////
 FfmpegAudio::
-FfmpegAudio(CPT(FfmpegMovie) source, double offset) :
-  MovieAudio((const FfmpegMovie *)source),
-  _sourcep(source)
+FfmpegAudio(const Filename &name) :
+  MovieAudio(name),
+  _filename(name)
 {
 }
 
@@ -65,3 +69,16 @@ read_samples(int n, PN_int16 *data) {
   _samples_read += n;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FfmpegAudio::make_copy
+//       Access: Published, Virtual
+//  Description: Make a copy of this MovieAudio with its own cursor.
+////////////////////////////////////////////////////////////////////
+PT(MovieAudio) FfmpegAudio::
+make_copy() const {
+  return new FfmpegAudio(_filename);
+}
+
+////////////////////////////////////////////////////////////////////
+
+#endif // HAVE_FFMPEG

+ 9 - 5
panda/src/movies/ffmpegAudio.h

@@ -18,12 +18,12 @@
 
 #ifndef FFMPEGAUDIO_H
 #define FFMPEGAUDIO_H
+#ifdef HAVE_FFMPEG
 
 #include "pandabase.h"
 #include "namable.h"
 #include "texture.h"
 #include "pointerTo.h"
-#include "ffmpegMovie.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : FfmpegAudio
@@ -31,13 +31,16 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_MOVIES FfmpegAudio : public MovieAudio {
 
-public:
-  FfmpegAudio(CPT(FfmpegMovie) source, double offset);
+PUBLISHED:
+  FfmpegAudio(const Filename &name);
   virtual ~FfmpegAudio();
+  virtual PT(MovieAudio) make_copy() const;
+
+public:
   virtual void read_samples(int n, PN_int16 *data);
   
 protected:
-  const FfmpegMovie *_sourcep;
+  Filename _filename;
   
 public:
   static TypeHandle get_class_type() {
@@ -59,4 +62,5 @@ private:
 
 #include "ffmpegAudio.I"
 
-#endif
+#endif // HAVE_FFMPEG
+#endif // FFMPEG_AUDIO.H

+ 0 - 18
panda/src/movies/ffmpegMovie.I

@@ -1,18 +0,0 @@
-// Filename: ffmpegMovie.I
-// Created by: jyelon (01Aug2007)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-

+ 0 - 66
panda/src/movies/ffmpegMovie.cxx

@@ -1,66 +0,0 @@
-// Filename: ffmpegMovie.cxx
-// Created by: jyelon (01Aug2007)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2007, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "ffmpegVideo.h"
-#include "ffmpegAudio.h"
-#include "ffmpegMovie.h"
-#include "config_movies.h"
-
-TypeHandle FfmpegMovie::_type_handle;
-
-////////////////////////////////////////////////////////////////////
-//     Function: FfmpegMovie::Constructor
-//       Access: Published
-//  Description: xxx
-////////////////////////////////////////////////////////////////////
-FfmpegMovie::
-FfmpegMovie(const string &filename) :
-  Movie(filename,1.0)
-{
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::get_video
-//       Access: Published, Virtual
-//  Description: Fetch a video stream.  Always constructs a new
-//               MovieVideo or subclass of MovieVideo.
-////////////////////////////////////////////////////////////////////
-PT(MovieVideo) FfmpegMovie::
-get_video(double offset) const {
-  if (_dummy_video) {
-    return new MovieVideo(this);
-  } else {
-    return new FfmpegVideo(this, offset);
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::get_audio
-//       Access: Published, Virtual
-//  Description: Fetch an audio stream.  Always constructs a new
-//               MovieAudio or subclass of MovieAudio.
-////////////////////////////////////////////////////////////////////
-PT(MovieAudio) FfmpegMovie::
-get_audio(double offset) const {
-  if (_dummy_audio) {
-    return new MovieAudio(this);
-  } else {
-    return new FfmpegAudio(this, offset);
-  }
-}
-

+ 0 - 65
panda/src/movies/ffmpegMovie.h

@@ -1,65 +0,0 @@
-// Filename: ffmpegMovie.h
-// Created by: jyelon (01Aug2007)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef FFMPEGMOVIE_H
-#define FFMPEGMOVIE_H
-
-#include "pandabase.h"
-#include "texture.h"
-#include "pointerTo.h"
-#include "movie.h"
-
-class FfmpegVideo;
-class FfmpegAudio;
-
-////////////////////////////////////////////////////////////////////
-//       Class : FfmpegMovie
-// Description : A Movie loader class that uses FFMPEG as its
-//               underlying decoder.
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_MOVIES FfmpegMovie : public Movie {
-
-PUBLISHED:
-  FfmpegMovie(const string &filename);
-
-  virtual PT(MovieVideo) get_video(double offset=0.0) const;
-  virtual PT(MovieAudio) get_audio(double offset=0.0) const;
-
-public:
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type() {
-    Movie::init_type();
-    register_type(_type_handle, "FfmpegMovie",
-                  Movie::get_class_type());
-  }
-  virtual TypeHandle get_type() const {
-    return get_class_type();
-  }
-  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-
-private:
-  static TypeHandle _type_handle;
-  friend class FfmpegVideo;
-  friend class FfmpegAudio;
-};
-
-#include "ffmpegMovie.I"
-
-#endif

+ 39 - 0
panda/src/movies/ffmpegVideo.I

@@ -16,3 +16,42 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+////////////////////////////////////////////////////////////////////
+//     Function: FfmpegVideo::get_time_correction
+//       Access: Private
+//  Description: The timestamps of packets in AVI files are often
+//               really inaccurate.  This returns a small heuristic
+//               correction based on analysis of the audio packets.
+////////////////////////////////////////////////////////////////////
+
+INLINE double FfmpegVideo::
+get_time_correction() {
+  // The idea here is simple.  For audio packets it
+  // is possible to calculate an accurate time by counting
+  // the audio samples.  It is then possible to measure
+  // the difference between the reported time and the
+  // actual time of the audio packet.  We average this 
+  // difference over the last few audio packets.  We then
+  // assume that the video packets are off by the same amount.
+
+  double correction = 0.0;
+  for (int i=0; i<_time_correction_window; i++) {
+    correction += _time_corrections[i];
+  }
+  correction /= _time_correction_window;
+  return correction;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FfmpegVideo::update_time_correction
+//       Access: Private
+//  Description: The timestamps of packets in AVI files are often
+//               really inaccurate.  This records some data which
+//               is needed to calculate a heuristic correction factor.
+////////////////////////////////////////////////////////////////////
+INLINE void FfmpegVideo::
+update_time_correction(double diff) {
+  _time_corrections[_time_correction_next % _time_correction_window] = diff;
+  _time_correction_next += 1;
+}
+

+ 225 - 6
panda/src/movies/ffmpegVideo.cxx

@@ -16,9 +16,12 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+#ifdef HAVE_FFMPEG
+
 #include "ffmpegVideo.h"
-#include "ffmpegMovie.h"
 #include "config_movies.h"
+#include "avcodec.h"
+#include "avformat.h"
 
 TypeHandle FfmpegVideo::_type_handle;
 
@@ -28,19 +31,199 @@ TypeHandle FfmpegVideo::_type_handle;
 //  Description: xxx
 ////////////////////////////////////////////////////////////////////
 FfmpegVideo::
-FfmpegVideo(CPT(FfmpegMovie) source, double offset) :
-  MovieVideo((const FfmpegMovie *)source),
-  _sourcep(source)
+FfmpegVideo(const Filename &name) :
+  MovieVideo(name),
+  _filename(name),
+  _samples_read(0),
+  _format_ctx(0),
+  _video_index(-1),
+  _audio_index(-1),
+  _video_ctx(0),
+  _audio_ctx(0),
+  _frame(0),
+  _frame_out(0),
+  _time_correction_next(0)
 {
+  string osname = _filename.to_os_specific();
+  if (av_open_input_file(&_format_ctx, osname.c_str(), NULL, 0, NULL)!=0) {
+    cleanup();
+    return;
+  }
+  
+  if (av_find_stream_info(_format_ctx)<0) {
+    cleanup();
+    return;
+  }
+  
+  // Find the video and audio streams
+  for(int i=0; i<_format_ctx->nb_streams; i++) {
+    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);
+    }
+    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);
+    }
+  }
+  
+  if (_video_ctx == 0) {
+    cleanup();
+    return;
+  }
+
+  AVCodec *pVideoCodec=avcodec_find_decoder(_video_ctx->codec_id);
+  if(pVideoCodec == 0) {
+    cleanup();
+    return;
+  }
+  if(avcodec_open(_video_ctx, pVideoCodec)<0) {
+    cleanup();
+    return;
+  }
+
+  _size_x = _video_ctx->width;
+  _size_y = _video_ctx->height;
+  _num_components = (_video_ctx->pix_fmt==PIX_FMT_RGBA32) ? 4:3;
+  
+  if (_audio_ctx) {
+    AVCodec *pAudioCodec=avcodec_find_decoder(_audio_ctx->codec_id);
+    if (pAudioCodec == 0) {
+      _audio_ctx = 0;
+      _audio_index = -1;
+    } else {
+      if (avcodec_open(_audio_ctx, pAudioCodec)<0) {
+        _audio_ctx = 0;
+        _audio_index = -1;
+      }
+    }
+  }
+  
+  _length = (_format_ctx->duration * 1.0) / AV_TIME_BASE;
+  _can_seek = true;
+  _can_seek_zero = true;
+
+  memset(_time_corrections, 0, sizeof(_time_corrections));
+  
+  _frame = avcodec_alloc_frame();
+  _frame_out = avcodec_alloc_frame();
+  if ((_frame == 0)||(_frame_out == 0)) {
+    cleanup();
+    return;
+  }
+  
+  read_ahead();
+  _next_start = 0.0;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: FfmpegVideo::Destructor
-//       Access: Public, Virtual
-//  Description: 
+//       Access: Public
+//  Description: xxx
 ////////////////////////////////////////////////////////////////////
 FfmpegVideo::
 ~FfmpegVideo() {
+  cleanup();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FfmpegVideo::cleanup
+//       Access: Public
+//  Description: Reset to a standard inactive state.
+////////////////////////////////////////////////////////////////////
+void FfmpegVideo::
+cleanup() {
+  if (_format_ctx) {
+    av_close_input_file(_format_ctx);
+    _format_ctx = 0;
+  }
+  if (_frame) {
+    av_free(_frame);
+    _frame = 0;
+  }
+  if (_frame_out) {
+    av_free(_frame_out);
+    _frame_out = 0;
+  }
+  _video_ctx = 0;
+  _audio_ctx = 0;
+  _video_index = -1;
+  _audio_index = -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FfmpegVideo::read_ahead
+//       Access: Protected
+//  Description: The video prefetches the next video frame in order
+//               to be able to implement the next_start query.
+//               This function skips over audio packets, but in the
+//               process, it updates the time_correction value.
+//               If the stream is out of video packets, the packet
+//               is empty.
+////////////////////////////////////////////////////////////////////
+void FfmpegVideo::
+read_ahead() {
+  if (_format_ctx == 0) {
+    return;
+  }
+  
+  AVPacket pkt;
+
+  while(av_read_frame(_format_ctx, &pkt)>=0) {
+    
+    // Is this a packet from the video stream?
+    // If so, store corrected timestamp and return.
+    
+    if (pkt.stream_index== _video_index) {
+      double dts = pkt.dts * _video_timebase;
+      double correction = get_time_correction();
+      _next_start = dts + correction;
+      cerr << "Video: " << dts << " " << dts+correction << "\n";
+      if (_next_start < _last_start) {
+        _next_start = _last_start;
+      }
+      int finished = 0;
+      avcodec_decode_video(_video_ctx, _frame,
+                           &finished, pkt.data, pkt.size);
+      if (finished) {
+        return;
+      }
+    }
+    
+    // Is this a packet from the audio stream?
+    // If so, use it to calibrate the time correction value.
+    
+    if (pkt.stream_index== _audio_index) {
+      double dts = pkt.dts * _audio_timebase;
+      double real = (_samples_read * 1.0) / _audio_ctx->sample_rate;
+      update_time_correction(real - dts);
+
+      int16_t buffer[4096];
+      uint8_t *audio_pkt_data = pkt.data;
+      int audio_pkt_size = pkt.size;
+      while(audio_pkt_size > 0) {
+        int data_size = sizeof(buffer);
+        int decoded = avcodec_decode_audio(_audio_ctx, buffer, &data_size,
+                                           audio_pkt_data, audio_pkt_size);
+        if(decoded <= 0) {
+          break;
+        }
+        audio_pkt_data += decoded;
+        audio_pkt_size -= decoded;
+        if (data_size > 0) {
+          _samples_read += data_size / (2 * _audio_ctx->channels);
+        }
+      }
+
+      cerr << "Audio: " << dts << " " << real << "\n";
+    }
+    
+    av_free_packet(&pkt);
+  }
+  
+  _next_start = _next_start + 1.0;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -50,5 +233,41 @@ FfmpegVideo::
 ////////////////////////////////////////////////////////////////////
 void FfmpegVideo::
 fetch_into_buffer(double time, unsigned char *data, bool rgba) {
+
+  // If there was an error at any point, fetch black.
+  if (_format_ctx==0) {
+    memset(data,0,size_x()*size_y()*(rgba?4:3));
+    return;
+  }
+  
+  AVCodecContext *ctx = _format_ctx->streams[_video_index]->codec;
+  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, 
+                (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, 
+                (AVPicture *)_frame, ctx->pix_fmt, ctx->width, ctx->height);
+  }
+
+  _last_start = _next_start;
+  read_ahead();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FfmpegVideo::make_copy
+//       Access: Published, Virtual
+//  Description: Make a copy of this MovieVideo with its own cursor.
+////////////////////////////////////////////////////////////////////
+PT(MovieVideo) FfmpegVideo::
+make_copy() const {
+  return new FfmpegVideo(_filename);
+}
+
+////////////////////////////////////////////////////////////////////
+
+#endif // HAVE_FFMPEG

+ 35 - 7
panda/src/movies/ffmpegVideo.h

@@ -18,26 +18,53 @@
 
 #ifndef FFMPEGVIDEO_H
 #define FFMPEGVIDEO_H
+#ifdef HAVE_FFMPEG
 
 #include "pandabase.h"
 #include "texture.h"
 #include "pointerTo.h"
-#include "ffmpegMovie.h"
+
+struct AVFormatContext;
+struct AVCodecContext;
+struct AVStream;
+struct AVPacket;
+struct AVFrame;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : FfmpegVideo
-// Description : A cellular automaton that generates an amusing
-//               pattern of swirling colors.
+// Description : 
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_MOVIES FfmpegVideo : public MovieVideo {
 
- public:
-  FfmpegVideo(CPT(FfmpegMovie) source, double offset);
+ PUBLISHED:
+  FfmpegVideo(const Filename &name);
   virtual ~FfmpegVideo();
+  virtual PT(MovieVideo) make_copy() const;
+  
+ public:
   virtual void fetch_into_buffer(double time, unsigned char *block, bool rgba);
 
  protected:
-  const FfmpegMovie *_sourcep;
+  INLINE double get_time_correction();
+  INLINE void update_time_correction(double diff);
+  void read_ahead();
+  void cleanup();
+  
+  static const int _time_correction_window = 4;
+  double _time_corrections[_time_correction_window];
+  int _time_correction_next;
+
+  Filename _filename;
+  AVFormatContext *_format_ctx;
+  AVCodecContext *_video_ctx;
+  AVCodecContext *_audio_ctx;
+  int _video_index;
+  int _audio_index;
+  double _video_timebase;
+  double _audio_timebase;
+  AVFrame *_frame;
+  AVFrame *_frame_out;
+  int _samples_read;
   
 public:
   static TypeHandle get_class_type() {
@@ -59,4 +86,5 @@ private:
 
 #include "ffmpegVideo.I"
 
-#endif
+#endif // HAVE_FFMPEG
+#endif // FFMPEGVIDEO_H

+ 0 - 28
panda/src/movies/inkblotMovie.I

@@ -1,28 +0,0 @@
-// Filename: inkblotMovie.I
-// Created by: jyelon (02Jul07)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-////////////////////////////////////////////////////////////////////
-//     Function: InkblotMovie::get_fps
-//       Access: Published
-//  Description: Get the frame rate of the inkblot movie.
-////////////////////////////////////////////////////////////////////
-INLINE int InkblotMovie::
-get_fps() const {
-  return _fps;
-}
-

+ 0 - 65
panda/src/movies/inkblotMovie.cxx

@@ -1,65 +0,0 @@
-// Filename: inkblotMovie.cxx
-// Created by: jyelon (02Jul07)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2007, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "inkblotVideo.h"
-#include "inkblotMovie.h"
-#include "config_movies.h"
-
-TypeHandle InkblotMovie::_type_handle;
-
-////////////////////////////////////////////////////////////////////
-//     Function: InkblotMovie::Constructor
-//       Access: Published
-//  Description: xxx
-////////////////////////////////////////////////////////////////////
-InkblotMovie::
-InkblotMovie(const string &name, double len, int sizex, int sizey, int fps) :
-  Movie(name,len)
-{
-  _ignores_offset = true;
-  if (sizex < 1) sizex=1;
-  if (sizey < 1) sizey=1;
-  if (fps < 1) fps=1;
-  _size_x = sizex;
-  _size_y = sizey;
-  _fps = fps;
-  _dummy_video = false;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::get_video
-//       Access: Published, Virtual
-//  Description: Fetch a video stream.  Always constructs a new
-//               MovieVideo or subclass of MovieVideo.
-////////////////////////////////////////////////////////////////////
-PT(MovieVideo) InkblotMovie::
-get_video(double offset) const {
-  return new InkblotVideo(this);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::get_audio
-//       Access: Published, Virtual
-//  Description: Fetch an audio stream.  Always constructs a new
-//               MovieAudio or subclass of MovieAudio.
-////////////////////////////////////////////////////////////////////
-PT(MovieAudio) InkblotMovie::
-get_audio(double offset) const {
-  return new MovieAudio(this);
-}
-

+ 0 - 80
panda/src/movies/inkblotMovie.h

@@ -1,80 +0,0 @@
-// Filename: inkblotMovie.h
-// Created by: jyelon (02Jul07)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef INKBLOTMOVIE_H
-#define INKBLOTMOVIE_H
-
-#include "pandabase.h"
-#include "texture.h"
-#include "pointerTo.h"
-#include "movie.h"
-
-////////////////////////////////////////////////////////////////////
-//       Class : InkblotMovie
-// Description : This cellular automaton generates an attractive
-//               pattern of swirling colors.  It is called "Digital
-//               Inkblots," it was invented by Jason Rampe, who in
-//               turn based it on Rudy Rucker's automaton "Rug."
-//               Both automata were included in the program "Mirek's
-//               Cellebration," which is a fantastic exploration
-//               of different kinds of cellular automata.  I
-//               encourage anyone to download it, it's a blast.
-//               I find that 128x128 at about 15 fps is just right
-//               for this automaton.
-//
-//               I have included a cellular automaton here mainly
-//               as a simple example of how to derive from class
-//               Movie, and to demonstrate that a "Movie" can be
-//               anything that generates a series of video frames,
-//               not just an AVI file.
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_MOVIES InkblotMovie : public Movie {
-
-PUBLISHED:
-  InkblotMovie(const string &name, double len,
-               int sizex=256, int sizey=256, int fps=10);
-
-  INLINE int get_fps() const;
-  virtual PT(MovieVideo) get_video(double offset=0.0) const;
-  virtual PT(MovieAudio) get_audio(double offset=0.0) const;
-
-protected:
-  int _fps;
-
-public:
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type() {
-    Movie::init_type();
-    register_type(_type_handle, "InkblotMovie",
-                  Movie::get_class_type());
-  }
-  virtual TypeHandle get_type() const {
-    return get_class_type();
-  }
-  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-
-private:
-  static TypeHandle _type_handle;
-  friend class FfmpegVideo;
-};
-
-#include "inkblotMovie.I"
-
-#endif

+ 34 - 11
panda/src/movies/inkblotVideo.cxx

@@ -17,7 +17,6 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "inkblotVideo.h"
-#include "inkblotMovie.h"
 #include "config_movies.h"
 
 TypeHandle InkblotVideo::_type_handle;
@@ -57,16 +56,23 @@ static color colormap[17] = {
 //  Description: xxx
 ////////////////////////////////////////////////////////////////////
 InkblotVideo::
-InkblotVideo(CPT(InkblotMovie) source) :
-  MovieVideo((const InkblotMovie *)source)
+InkblotVideo(int x, int y, int fps) :
+  MovieVideo("inkblot")
 {
-  _sourcep = source;
-  int padx = size_x() + 2;
-  int pady = size_y() + 2;
+  if (x < 1) x=1;
+  if (y < 1) y=1;
+  if (fps < 1) fps=1;
+  _size_x = x;
+  _size_y = y;
+  _fps = fps;
+  
+  int padx = x + 2;
+  int pady = y + 2;
   _cells = new unsigned char[padx * pady];
   _cells2 = new unsigned char[padx * pady];
   memset(_cells, 255, padx * pady);
   memset(_cells2, 255, padx * pady);
+  
   _frames_read = 0;
 }
 
@@ -89,16 +95,24 @@ InkblotVideo::
 void InkblotVideo::
 fetch_into_buffer(double time, unsigned char *data, bool rgba) {
 
-  nassertv(time >= _next_start);
-  
   int padx = size_x() + 2;
   int pady = size_y() + 2;
-  int fps = _sourcep->get_fps();
+  
+  if ((time == 0.0)&&(_next_start != 0.0)) {
+    // Rewind to beginning.
+    memset(_cells, 255, padx * pady);
+    memset(_cells2, 255, padx * pady);
+    _last_start = -1.0;
+    _next_start = 0.0;
+    _frames_read = 0;
+  }
+  
+  nassertv(time >= _next_start);
   
   while (_next_start <= time) {
-    _last_start = (_frames_read * 1.0) / fps;
+    _last_start = (_frames_read * 1.0) / _fps;
     _frames_read += 1;
-    _next_start = (_frames_read * 1.0) / fps;
+    _next_start = (_frames_read * 1.0) / _fps;
     for (int y=1; y<pady-1; y++) {
       for (int x=1; x<padx-1; x++) {
         int tot =
@@ -138,3 +152,12 @@ fetch_into_buffer(double time, unsigned char *data, bool rgba) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: InkblotVideo::make_copy
+//       Access: Published, Virtual
+//  Description: Make a copy of this video with a separate cursor.
+////////////////////////////////////////////////////////////////////
+PT(MovieVideo) InkblotVideo::
+make_copy() const {
+  return new InkblotVideo(_size_x, _size_y, _fps);
+}

+ 5 - 4
panda/src/movies/inkblotVideo.h

@@ -22,7 +22,6 @@
 #include "pandabase.h"
 #include "texture.h"
 #include "pointerTo.h"
-#include "inkblotMovie.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : InkblotVideo
@@ -31,13 +30,15 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_MOVIES InkblotVideo : public MovieVideo {
 
- public:
-  InkblotVideo(CPT(InkblotMovie) source);
+ PUBLISHED:
+  InkblotVideo(int x, int y, int fps);
   virtual ~InkblotVideo();
+  virtual PT(MovieVideo) make_copy() const;
+  
+ public:
   virtual void fetch_into_buffer(double time, unsigned char *block, bool rgba);
   
  protected:
-  const InkblotMovie *_sourcep;
   unsigned char *_cells;
   unsigned char *_cells2;
   int _fps;

+ 0 - 147
panda/src/movies/movie.I

@@ -1,147 +0,0 @@
-// Filename: movie.I
-// Created by: jyelon (02Jul07)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::size_x
-//       Access: Published
-//  Description: Get the horizontal size of the movie.
-////////////////////////////////////////////////////////////////////
-INLINE int Movie::
-size_x() const {
-  return _size_x;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::size_y
-//       Access: Published
-//  Description: Get the vertical size of the movie.
-////////////////////////////////////////////////////////////////////
-INLINE int Movie::
-size_y() const {
-  return _size_y;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::get_num_components
-//       Access: Published
-//  Description: Indicates whether the movie is monochrome, color,
-//               or color-plus-alpha.
-//
-//               You can fetch the movie's contents into any texture,
-//               regardless of the texture's format.  However, it may
-//               be faster if the texture matches the movie.
-////////////////////////////////////////////////////////////////////
-INLINE int Movie::
-get_num_components() const {
-  return _num_components;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::length
-//       Access: Published
-//  Description: Returns the length of the movie.
-//
-//               Some kinds of Movie, such as internet TV station, 
-//               might not have a predictable length.  In that case,
-//               the length will be set to a very large number: 1.0E10.
-//               If the internet TV station goes offline, the video
-//               or audio stream will set its abort flag.  Reaching the
-//               end of the movie (ie, the specified length) normally
-//               does not cause the abort flag to be set.
-//
-//               The video and audio streams produced by get_video and
-//               get_audio are always of unlimited duration - you can
-//               always read another video frame or another audio
-//               sample.  This is true even if the specified length
-//               is reached, or an abort is flagged. If either stream
-//               runs out of data, it will synthesize blank video
-//               frames and silent audio samples as necessary to
-//               satisfy read requests.
-//
-//               Some AVI files have incorrect length values encoded
-//               into them - usually, they're a second or two long or
-//               short.  When playing such an AVI using the Movie class,
-//               you may see a slightly truncated video, or a slightly
-//               elongated video (padded with black frames).  There are
-//               utilities out there to fix the length values in AVI
-//               files.
-//
-////////////////////////////////////////////////////////////////////
-INLINE double Movie::
-length() const {
-  return _length;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::audio_rate
-//       Access: Public
-//  Description: Returns the audio sample rate, in samples per sec.
-////////////////////////////////////////////////////////////////////
-INLINE int Movie::
-audio_rate() const {
-  return _audio_rate;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::audio_channels
-//       Access: Public
-//  Description: Returns the number of audio channels.  Ie, 1 for
-//               mono, 2 for stereo.
-////////////////////////////////////////////////////////////////////
-INLINE int Movie::
-audio_channels() const {
-  return _audio_channels;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::ignores_offset
-//       Access: Published
-//  Description: The methods get_video and get_audio both accept
-//               an offset parameter, which allow you to seek
-//               to a particular location within the movie.  Not
-//               all movies can do this, though.  For instance, an
-//               internet TV station cannot be fast-forwarded.  In
-//               these cases, the offset parameter is ignored.
-////////////////////////////////////////////////////////////////////
-INLINE bool Movie::
-ignores_offset() const {
-  return _ignores_offset;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::dummy_video
-//       Access: Published
-//  Description: If you open a sound file as a movie, a dummy video
-//               stream will be synthesized.  Returns true in this case.
-////////////////////////////////////////////////////////////////////
-INLINE bool Movie::
-dummy_video() const {
-  return _dummy_video;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::dummy_audio
-//       Access: Published
-//  Description: If you open a movie with no sound, a dummy sound
-//               stream will be synthesized.  Returns true in this case.
-////////////////////////////////////////////////////////////////////
-INLINE bool Movie::
-dummy_audio() const {
-  return _dummy_audio;
-}
-

+ 0 - 89
panda/src/movies/movie.cxx

@@ -1,89 +0,0 @@
-// Filename: movie.cxx
-// Created by: jyelon (02Jul07)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2007, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "movieVideo.h"
-#include "movieAudio.h"
-#include "movie.h"
-#include "config_movies.h"
-
-TypeHandle Movie::_type_handle;
-
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::Constructor
-//       Access: Published
-//  Description: This constructor returns a null/dummy movie --- 
-//               the video is flashing blue/white, and the audio is
-//               silent.  To get more interesting movie, you need to
-//               construct a subclass of this class.
-////////////////////////////////////////////////////////////////////
-Movie::
-Movie(const string &name, double len) :
-  Namable(name),
-  _size_x(1),
-  _size_y(1),
-  _num_components(3),
-  _length(len),
-  _audio_rate(8000),
-  _audio_channels(1),
-  _ignores_offset(true),
-  _dummy_video(true),
-  _dummy_audio(true)
-{
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::Destructor
-//       Access: Published, Virtual
-//  Description: 
-////////////////////////////////////////////////////////////////////
-Movie::
-~Movie() {
-}
- 
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::get_video
-//       Access: Published, Virtual
-//  Description: Fetch a video stream.  Always constructs a new
-//               MovieVideo or subclass of MovieVideo.
-////////////////////////////////////////////////////////////////////
-PT(MovieVideo) Movie::
-get_video(double offset) const {
-  return new MovieVideo(this);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::get_audio
-//       Access: Published, Virtual
-//  Description: Fetch an audio stream.  Always constructs a new
-//               MovieAudio or subclass of MovieAudio.
-////////////////////////////////////////////////////////////////////
-PT(MovieAudio) Movie::
-get_audio(double offset) const {
-  return new MovieAudio(this);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Movie::load
-//       Access: Published, Static
-//  Description: Loads a movie from a file.
-////////////////////////////////////////////////////////////////////
-CPT(Movie) Movie::
-load(const Filename &path) {
-  // For now, just return a dummy movie.
-  return new Movie("dummy",30.0);
-}

+ 0 - 95
panda/src/movies/movie.h

@@ -1,95 +0,0 @@
-// Filename: movie.h
-// Created by: jyelon (02Jul07)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef MOVIE_H
-#define MOVIE_H
-
-#include "pandabase.h"
-#include "texture.h"
-#include "pointerTo.h"
-
-class MovieVideo;
-class MovieAudio;
-
-////////////////////////////////////////////////////////////////////
-//       Class : Movie
-// Description : A "movie" is actually any source that provides
-//               an audio and a video stream.  So that could include
-//               an AVI file, or an internet TV station.  It could
-//               also be an MP3 file paired with a dummy video stream.
-//
-//               Class Movie and anything derived from Movie must be
-//               immutable, for thread-safety reasons.  (However, the
-//               MovieVideo and MovieAudio objects constructed by
-//               get_video and get_audio do not need to be immutable
-//               or thread-safe).
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_MOVIES Movie : public TypedWritableReferenceCount, public Namable{
-
-PUBLISHED:
-  Movie(const string &name, double len);
-  
-  INLINE int size_x() const;
-  INLINE int size_y() const;
-  INLINE int get_num_components() const;
-  INLINE double length() const;
-  INLINE int audio_rate() const;
-  INLINE int audio_channels() const;
-  INLINE bool ignores_offset() const;
-  INLINE bool dummy_video() const;
-  INLINE bool dummy_audio() const;
-
-  virtual PT(MovieVideo) get_video(double offset=0.0) const;
-  virtual PT(MovieAudio) get_audio(double offset=0.0) const;
-  static CPT(Movie) load(const Filename &path);
-  
-public:
-  virtual ~Movie();
-
-protected:
-  int _size_x;
-  int _size_y;
-  int _num_components;
-  double _length;
-  int _audio_rate;
-  int _audio_channels;
-  bool _ignores_offset;
-  bool _dummy_video;
-  bool _dummy_audio;
-  
-public:
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type() {
-    TypedWritableReferenceCount::init_type();
-    register_type(_type_handle, "Movie",
-                  TypedWritableReferenceCount::get_class_type());
-  }
-  virtual TypeHandle get_type() const {
-    return get_class_type();
-  }
-  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-
-private:
-  static TypeHandle _type_handle;
-};
-
-#include "movie.I"
-
-#endif

+ 67 - 16
panda/src/movies/movieAudio.I

@@ -16,44 +16,95 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-////////////////////////////////////////////////////////////////////
-//     Function: MovieAudio::get_source
-//       Access: Public
-//  Description: Returns the source Movie.
-////////////////////////////////////////////////////////////////////
-INLINE CPT(Movie) MovieAudio::
-get_source() const {
-  return _source;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: MovieAudio::audio_rate
 //       Access: Public
-//  Description: See Movie::audio_rate.
+//  Description: Returns the audio sample rate.
 ////////////////////////////////////////////////////////////////////
 INLINE int MovieAudio::
 audio_rate() const {
-  return _source->audio_rate();
+  return _audio_rate;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: MovieAudio::audio_channels
 //       Access: Public
-//  Description: See Movie::audio_channels.
+//  Description: Returns the number of audio channels (ie, two for
+//               stereo, one for mono).
 ////////////////////////////////////////////////////////////////////
 INLINE int MovieAudio::
 audio_channels() const {
-  return _source->audio_channels();
+  return _audio_channels;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: MovieAudio::length
 //       Access: Public
-//  Description: See Movie::length.
+//  Description: Returns the length of the movie.
+//
+//               Some kinds of Movie, such as internet TV station, 
+//               might not have a predictable length.  In that case,
+//               the length will be set to a very large number: 1.0E10.
+//               If the internet TV station goes offline, the video
+//               or audio stream will set its abort flag.  Reaching the
+//               end of the movie (ie, the specified length) normally
+//               does not cause the abort flag to be set.
+//
+//               The video and audio streams produced by get_video and
+//               get_audio are always of unlimited duration - you can
+//               always read another video frame or another audio
+//               sample.  This is true even if the specified length
+//               is reached, or an abort is flagged. If either stream
+//               runs out of data, it will synthesize blank video
+//               frames and silent audio samples as necessary to
+//               satisfy read requests.
+//
+//               Some AVI files have incorrect length values encoded
+//               into them - usually, they're a second or two long or
+//               short.  When playing such an AVI using the Movie class,
+//               you may see a slightly truncated video, or a slightly
+//               elongated video (padded with black frames).  There are
+//               utilities out there to fix the length values in AVI
+//               files.
+//
 ////////////////////////////////////////////////////////////////////
 INLINE double MovieAudio::
 length() const {
-  return _source->length();
+  return _length;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MovieAudio::can_seek
+//       Access: Public
+//  Description: See method 'seek' for an explanation.
+////////////////////////////////////////////////////////////////////
+INLINE bool MovieAudio::
+can_seek() const {
+  return _can_seek;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MovieAudio::can_seek_zero
+//       Access: Public
+//  Description: See method 'seek' for an explanation.
+////////////////////////////////////////////////////////////////////
+INLINE bool MovieAudio::
+can_seek_zero() const {
+  return _can_seek_zero;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MovieAudio::aborted
+//       Access: Public
+//  Description: Returns true if the audio has aborted prematurely.
+//               For example, this could occur if the Movie was actually
+//               an internet TV station, and the connection was lost.
+//               Reaching the normal end of the audio does not
+//               constitute an 'abort' condition.
+////////////////////////////////////////////////////////////////////
+INLINE bool MovieAudio::
+aborted() const {
+  return _aborted;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 50 - 3
panda/src/movies/movieAudio.cxx

@@ -29,9 +29,14 @@ TypeHandle MovieAudio::_type_handle;
 //               a subclass of this class.
 ////////////////////////////////////////////////////////////////////
 MovieAudio::
-MovieAudio(CPT(Movie) source) :
-  Namable(source->get_name()),
-  _source(source),
+MovieAudio(const string &name) :
+  Namable(name),
+  _audio_rate(8000),
+  _audio_channels(1),
+  _length(1.0E10),
+  _can_seek(true),
+  _can_seek_zero(true),
+  _aborted(false),
   _samples_read(0)
 {
 }
@@ -69,3 +74,45 @@ read_samples(int n, PN_int16 *data) {
   _samples_read += n;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: MovieAudio::seek
+//       Access: Published, Virtual
+//  Description: Skips to the specified point in the movie. After
+//               calling seek, samples_read will be equal to the
+//               offset times the sample rate.
+//
+//               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();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MovieAudio::make_copy
+//       Access: Published, Virtual
+//  Description: Make a copy of this MovieAudio with its own cursor.
+////////////////////////////////////////////////////////////////////
+PT(MovieAudio) MovieAudio::
+make_copy() const {
+  return new MovieAudio();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MovieAudio::load
+//       Access: Published, Static
+//  Description: Load a movie from a file.
+////////////////////////////////////////////////////////////////////
+PT(MovieAudio) MovieAudio::
+load(const Filename &name) {
+  // Someday, I'll probably put a dispatcher here.
+  // But for now, just hardwire it to go to FFMPEG.
+  return new FfmpegAudio(name);
+}

+ 24 - 7
panda/src/movies/movieAudio.h

@@ -23,29 +23,46 @@
 #include "namable.h"
 #include "texture.h"
 #include "pointerTo.h"
-#include "movie.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : MovieAudio
-// Description : A stream that generates a sequence of audio samples.
+// Description : A MovieAudio is actually any source that provides
+//               a sequence of audio samples.  That could include an
+//               AVI file, a microphone, or an internet TV station.
+//
+//               Thread safety: each individual MovieAudio
+//               must be owned and accessed by a single thread.
+//               It is OK for two different threads to open
+//               the same file at the same time, as long as they
+//               use separate MovieAudio objects.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_MOVIES MovieAudio : public TypedWritableReferenceCount, public Namable {
 
 PUBLISHED:
-  INLINE CPT(Movie) get_source() const;
+  MovieAudio(const string &name = "Blank Audio");
+  virtual ~MovieAudio();
   INLINE int audio_rate() const;
   INLINE int audio_channels() const;
   INLINE double length() const;
+  INLINE bool can_seek() const;
+  INLINE bool can_seek_zero() const;
+  INLINE bool aborted() const;
   INLINE int samples_read() const;
   INLINE void skip_samples(int n);
-  
+  virtual void seek(double offset);
+  virtual PT(MovieAudio) make_copy() const;
+  static PT(MovieAudio) load(const Filename &name);
+
 public:
-  MovieAudio(CPT(Movie) source);
-  virtual ~MovieAudio();
   virtual void read_samples(int n, PN_int16 *data);
   
 protected:
-  CPT(Movie) _source;
+  int _audio_rate;
+  int _audio_channels;
+  double _length;
+  bool _can_seek;
+  bool _can_seek_zero;
+  bool _aborted;
   int _samples_read;
   
 public:

+ 55 - 18
panda/src/movies/movieVideo.I

@@ -16,54 +16,91 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-////////////////////////////////////////////////////////////////////
-//     Function: MovieVideo::get_source
-//       Access: Published
-//  Description: Returns a pointer to the source Movie.
-////////////////////////////////////////////////////////////////////
-INLINE CPT(Movie) MovieVideo::
-get_source() const {
-  return _source;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: MovieVideo::size_x
 //       Access: Published
-//  Description: See Movie::size_x
+//  Description: Get the horizontal size of the movie.
 ////////////////////////////////////////////////////////////////////
 INLINE int MovieVideo::
 size_x() const {
-  return _source->size_x();
+  return _size_x;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: MovieVideo::size_y
 //       Access: Published
-//  Description: See Movie::size_y
+//  Description: Get the vertical size of the movie.
 ////////////////////////////////////////////////////////////////////
 INLINE int MovieVideo::
 size_y() const {
-  return _source->size_y();
+  return _size_y;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: MovieVideo::get_num_components
 //       Access: Published
-//  Description: See Movie::get_num_components
+//  Description: Returns 4 if the movie has an alpha
+//               channel, 3 otherwise.
 ////////////////////////////////////////////////////////////////////
 INLINE int MovieVideo::
 get_num_components() const {
-  return _source->get_num_components();
+  return _num_components;
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: MovieVideo::length
 //       Access: Published
-//  Description: See Movie::length
+//  Description: Returns the length of the movie.
+//
+//               Some kinds of Movie, such as internet TV station, 
+//               might not have a predictable length.  In that case,
+//               the length will be set to a very large number: 1.0E10.
+//               If the internet TV station goes offline, the video
+//               or audio stream will set its abort flag.  Reaching the
+//               end of the movie (ie, the specified length) normally
+//               does not cause the abort flag to be set.
+//
+//               The video and audio streams produced by get_video and
+//               get_audio are always of unlimited duration - you can
+//               always read another video frame or another audio
+//               sample.  This is true even if the specified length
+//               is reached, or an abort is flagged. If either stream
+//               runs out of data, it will synthesize blank video
+//               frames and silent audio samples as necessary to
+//               satisfy read requests.
+//
+//               Some AVI files have incorrect length values encoded
+//               into them - usually, they're a second or two long or
+//               short.  When playing such an AVI using the Movie class,
+//               you may see a slightly truncated video, or a slightly
+//               elongated video (padded with black frames).  There are
+//               utilities out there to fix the length values in AVI
+//               files.
+//
 ////////////////////////////////////////////////////////////////////
 INLINE int MovieVideo::
 length() const {
-  return _source->length();
+  return _length;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MovieVideo::can_seek
+//       Access: Published
+//  Description: See explanation in fetch_to_buffer.
+////////////////////////////////////////////////////////////////////
+INLINE bool MovieVideo::
+can_seek() const {
+  return _can_seek;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MovieVideo::can_seek_zero
+//       Access: Published
+//  Description: See explanation in fetch_to_buffer.
+////////////////////////////////////////////////////////////////////
+INLINE bool MovieVideo::
+can_seek_zero() const {
+  return _can_seek_zero;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 68 - 31
panda/src/movies/movieVideo.cxx

@@ -17,6 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "movieVideo.h"
+#include "ffmpegVideo.h"
 #include "config_movies.h"
 
 TypeHandle MovieVideo::_type_handle;
@@ -30,9 +31,14 @@ TypeHandle MovieVideo::_type_handle;
 //               to construct a subclass of this class.
 ////////////////////////////////////////////////////////////////////
 MovieVideo::
-MovieVideo(CPT(Movie) source) :
-  Namable(source->get_name()),
-  _source(source),
+MovieVideo(const string &name) :
+  Namable(name),
+  _size_x(1),
+  _size_y(1),
+  _num_components(3),
+  _length(1.0E10),
+  _can_seek(true),
+  _can_seek_zero(true),
   _aborted(false),
   _last_start(-1.0),
   _next_start(0.0)
@@ -65,12 +71,32 @@ allocate_conversion_buffer() {
   }
 }
   
+////////////////////////////////////////////////////////////////////
+//     Function: MovieVideo::fetch_into_bitbucket
+//       Access: Published, Virtual
+//  Description: Discards the next video frame.  Still sets
+//               last_start and next_start.
+//
+//               See fetch_into_buffer for more details.
+////////////////////////////////////////////////////////////////////
+void MovieVideo::
+fetch_into_bitbucket(double time) {
+
+  // This generic implementation is layered on fetch_into_buffer.
+  // It will work for any derived class, so it is never necessary to
+  // redefine this.  It is probably possible to make a faster
+  // implementation, but since this function is rarely used, it
+  // probably isn't worth the trouble.
+
+  allocate_conversion_buffer();
+  fetch_into_buffer(time, _conversion_buffer, false);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: MovieVideo::fetch_into_texture
 //       Access: Published, Virtual
-//  Description: Reads frames from the stream until the specified 
-//               time is reached.  The last frame read is stored in
-//               the supplied texture.
+//  Description: Reads the specified video frame into 
+//               the specified texture.
 //
 //               See fetch_into_buffer for more details.
 ////////////////////////////////////////////////////////////////////
@@ -112,8 +138,7 @@ fetch_into_texture(double time, Texture *t, int page) {
 ////////////////////////////////////////////////////////////////////
 //     Function: MovieVideo::fetch_into_texture_alpha
 //       Access: Published, Virtual
-//  Description: Reads frames from the stream until the specified 
-//               time is reached.  The last frame read is stored in
+//  Description: Reads the specified video frame into 
 //               the alpha channel of the supplied texture.  The
 //               RGB channels of the texture are not touched.
 //
@@ -170,8 +195,7 @@ fetch_into_texture_alpha(double time, Texture *t, int page, int alpha_src) {
 ////////////////////////////////////////////////////////////////////
 //     Function: MovieVideo::fetch_into_texture_rgb
 //       Access: Published, Virtual
-//  Description: Reads frames from the stream until the specified 
-//               time is reached.  The last frame read is stored in
+//  Description: Reads the specified video frame into
 //               the RGB channels of the supplied texture.  The alpha
 //               channel of the texture is not touched.
 //
@@ -217,21 +241,17 @@ fetch_into_texture_rgb(double time, Texture *t, int page) {
 ////////////////////////////////////////////////////////////////////
 //     Function: MovieVideo::fetch_into_buffer
 //       Access: Published, Virtual
-//  Description: Reads frames from the stream until the specified 
-//               time is reached.  The last frame read is stored in
-//               the supplied RGB8 or RGBA8 buffer.
+//  Description: Reads the specified video frame into the supplied
+//               RGB8 or RGBA8 buffer.  The frame's begin and end
+//               times are stored in last_start and next_start.
 //
-//               The fetch methods do not seek: they just reads frames
-//               from the stream.  Therefore, they cannot move backward.
-//               If you specify a time value less than next_start, they
-//               will just read one frame and return.
-//
-//               To truly seek, you must call get_video with an
-//               offset.  This is sometimes inaccurate, because AVI
-//               file indices often contain errors.  Therefore, it
-//               is sometimes advantageous to use fetch methods to 
-//               just read frames from the stream until you get
-//               to the target location.
+//               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.
 ////////////////////////////////////////////////////////////////////
 void MovieVideo::
 fetch_into_buffer(double time, unsigned char *data, bool rgba) {
@@ -239,16 +259,11 @@ fetch_into_buffer(double time, unsigned char *data, bool rgba) {
   // The following is the implementation of the null video stream, ie,
   // a stream of blinking red and blue frames.  This method must be
   // overridden by the subclass.
-
-  if (time < _next_start) time = _next_start;
+  
   _last_start = floor(time);
   _next_start = _last_start + 1;
 
-  if (_last_start >= length()) {
-    data[0] = 0;
-    data[1] = 0;
-    data[2] = 0;
-  } else if (((int)_last_start) & 1) {
+  if (((int)_last_start) & 1) {
     data[0] = 255;
     data[1] = 128;
     data[2] = 128;
@@ -262,3 +277,25 @@ fetch_into_buffer(double time, unsigned char *data, bool rgba) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: MovieVideo::make_copy
+//       Access: Published, Virtual
+//  Description: Make a copy of this video with a separate cursor.
+////////////////////////////////////////////////////////////////////
+PT(MovieVideo) MovieVideo::
+make_copy() const {
+  return new MovieVideo();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MovieVideo::load
+//       Access: Published, Static
+//  Description: Load a movie from a file.
+////////////////////////////////////////////////////////////////////
+PT(MovieVideo) MovieVideo::
+load(const Filename &name) {
+  // Someday, I'll probably put a dispatcher here.
+  // But for now, just hardwire it to go to FFMPEG.
+  return new FfmpegVideo(name);
+}
+

+ 22 - 6
panda/src/movies/movieVideo.h

@@ -22,30 +22,41 @@
 #include "pandabase.h"
 #include "texture.h"
 #include "pointerTo.h"
-#include "movie.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : MovieVideo
-// Description : A stream that generates a series of images.
+// Description : A MovieVideo is actually any source that provides
+//               a sequence of video frames.  That could include an
+//               AVI file, a digital camera, or an internet TV station.
+//
+//               Thread safety: each individual MovieVideo or
+//               must be owned and accessed by a single thread.
+//               It is OK for two different threads to open
+//               the same file at the same time, as long as they
+//               use separate MovieVideo objects.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_MOVIES MovieVideo : public TypedWritableReferenceCount, public Namable {
 
  PUBLISHED:
-  INLINE CPT(Movie) get_source() const;
+  MovieVideo(const string &name = "Blank Video");
+  virtual ~MovieVideo();
   INLINE int size_x() const;
   INLINE int size_y() const;
   INLINE int get_num_components() const;
   INLINE int length() const;
+  INLINE bool can_seek() const;
+  INLINE bool can_seek_zero() const;
   INLINE bool aborted() const;
   INLINE double last_start() const;
   INLINE double next_start() const;
+  virtual void fetch_into_bitbucket(double time);
   virtual void fetch_into_texture(double time, Texture *t, int page);
   virtual void fetch_into_texture_rgb(double time, Texture *t, int page);
   virtual void fetch_into_texture_alpha(double time, Texture *t, int page, int alpha_src);
+  virtual PT(MovieVideo) make_copy() const;
+  static PT(MovieVideo) load(const Filename &name);
 
  public:
-  MovieVideo(CPT(Movie) source);
-  virtual ~MovieVideo();
   virtual void fetch_into_buffer(double time, unsigned char *block, bool rgba);
   
  private:
@@ -53,7 +64,12 @@ class EXPCL_PANDA_MOVIES MovieVideo : public TypedWritableReferenceCount, public
   unsigned char *_conversion_buffer;
   
  protected:
-  CPT(Movie) _source;
+  int _size_x;
+  int _size_y;
+  int _num_components;
+  double _length;
+  bool _can_seek;
+  bool _can_seek_zero;
   bool _aborted;
   double _last_start;
   double _next_start;

+ 0 - 3
panda/src/movies/movies_composite1.cxx

@@ -1,9 +1,6 @@
-#include "movie.cxx"
 #include "movieVideo.cxx"
 #include "movieAudio.cxx"
-#include "inkblotMovie.cxx"
 #include "inkblotVideo.cxx"
-#include "ffmpegMovie.cxx"
 #include "ffmpegAudio.cxx"
 #include "ffmpegVideo.cxx"
 #include "config_movies.cxx"