Browse Source

Uff, this should bring Panda up to date with the latest version of ffmpeg. We now use AVIOContext instead of URLProtocol, avcodec_decode_audio4 instead of 3, and add support for libswresample to resample the input data to 16-bits signed int since some codecs now give float data. If this breaks anyone's build, please, just consider updating your ffmpeg version.

rdb 12 years ago
parent
commit
03e96d8c4a

+ 2 - 1
dtool/Config.pp

@@ -804,10 +804,11 @@
 // Is FFMPEG installed, and where?
 // Is FFMPEG installed, and where?
 #define FFMPEG_IPATH /usr/include/ffmpeg
 #define FFMPEG_IPATH /usr/include/ffmpeg
 #define FFMPEG_LPATH
 #define FFMPEG_LPATH
-#define FFMPEG_LIBS $[if $[WINDOWS_PLATFORM],libavcodec.lib libavformat.lib libavutil.lib libgcc.lib libswscale.lib,avcodec avformat avutil swscale]
+#define FFMPEG_LIBS $[if $[WINDOWS_PLATFORM],libavcodec.lib libavformat.lib libavutil.lib libgcc.lib libswscale.lib libswresample.lib,avcodec avformat avutil swscale swresample]
 #defer HAVE_FFMPEG $[libtest $[FFMPEG_LPATH],$[FFMPEG_LIBS]]
 #defer HAVE_FFMPEG $[libtest $[FFMPEG_LPATH],$[FFMPEG_LIBS]]
 // Define this if you compiled ffmpeg with libswscale enabled.
 // Define this if you compiled ffmpeg with libswscale enabled.
 #define HAVE_SWSCALE 1
 #define HAVE_SWSCALE 1
+#define HAVE_SWRESAMPLE 1
 
 
 // Is ODE installed, and where?
 // Is ODE installed, and where?
 #define ODE_IPATH
 #define ODE_IPATH

+ 1 - 4
dtool/LocalSetup.pp

@@ -187,11 +187,7 @@
 #print - Did not find OpenCV
 #print - Did not find OpenCV
 #endif
 #endif
 #if $[HAVE_FFMPEG]
 #if $[HAVE_FFMPEG]
-#if $[HAVE_SWSCALE]
-#print + FFMPEG, with libswscale
-#else
 #print + FFMPEG
 #print + FFMPEG
-#endif
 #else
 #else
 #print - Did not find FFMPEG
 #print - Did not find FFMPEG
 #endif
 #endif
@@ -428,6 +424,7 @@ $[cdefine OPENCV_VER_23]
 /* Define if we have FFMPEG installed and want to build for FFMPEG.  */
 /* Define if we have FFMPEG installed and want to build for FFMPEG.  */
 $[cdefine HAVE_FFMPEG]
 $[cdefine HAVE_FFMPEG]
 $[cdefine HAVE_SWSCALE]
 $[cdefine HAVE_SWSCALE]
+$[cdefine HAVE_SWRESAMPLE]
 
 
 /* Define if we have ODE installed and want to build for ODE.  */
 /* Define if we have ODE installed and want to build for ODE.  */
 $[cdefine HAVE_ODE]
 $[cdefine HAVE_ODE]

+ 6 - 0
panda/src/movies/config_movies.cxx

@@ -81,6 +81,12 @@ ConfigVariableEnum<ThreadPriority> ffmpeg_thread_priority
  PRC_DESC("The default thread priority at which to start ffmpeg decoder "
  PRC_DESC("The default thread priority at which to start ffmpeg decoder "
           "threads."));
           "threads."));
 
 
+ConfigVariableInt ffmpeg_read_buffer_size
+("ffmpeg-read-buffer-size", 4096,
+ PRC_DESC("The size in bytes of the buffer used when reading input files. "
+          "This is important for performance.  A typical size is that of a "
+          "cache page, e.g. 4kb."));
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: init_libmovies
 //     Function: init_libmovies
 //  Description: Initializes the library.  This must be called at
 //  Description: Initializes the library.  This must be called at

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

@@ -32,6 +32,7 @@ extern ConfigVariableBool ffmpeg_show_seek_frames;
 extern ConfigVariableBool ffmpeg_support_seek;
 extern ConfigVariableBool ffmpeg_support_seek;
 extern ConfigVariableBool ffmpeg_global_lock;
 extern ConfigVariableBool ffmpeg_global_lock;
 extern ConfigVariableEnum<ThreadPriority> ffmpeg_thread_priority;
 extern ConfigVariableEnum<ThreadPriority> ffmpeg_thread_priority;
+extern ConfigVariableInt ffmpeg_read_buffer_size;
 
 
 extern EXPCL_PANDA_MOVIES void init_libmovies();
 extern EXPCL_PANDA_MOVIES void init_libmovies();
 
 

+ 104 - 10
panda/src/movies/ffmpegAudioCursor.cxx

@@ -18,16 +18,29 @@
 
 
 #include "ffmpegAudio.h"
 #include "ffmpegAudio.h"
 extern "C" {
 extern "C" {
+  #include "libavutil/dict.h"
+  #include "libavutil/opt.h"
   #include "libavcodec/avcodec.h"
   #include "libavcodec/avcodec.h"
   #include "libavformat/avformat.h"
   #include "libavformat/avformat.h"
 }
 }
 
 
+#ifdef HAVE_SWRESAMPLE
+extern "C" {
+  #include "libswresample/swresample.h"
+}
+#endif
+
 TypeHandle FfmpegAudioCursor::_type_handle;
 TypeHandle FfmpegAudioCursor::_type_handle;
 
 
 #if LIBAVFORMAT_VERSION_MAJOR < 53
 #if LIBAVFORMAT_VERSION_MAJOR < 53
   #define AVMEDIA_TYPE_AUDIO CODEC_TYPE_AUDIO
   #define AVMEDIA_TYPE_AUDIO CODEC_TYPE_AUDIO
 #endif
 #endif
 
 
+#ifndef AVCODEC_MAX_AUDIO_FRAME_SIZE
+// More recent versions of ffmpeg no longer define this.
+#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000
+#endif
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: FfmpegAudioCursor::Constructor
 //     Function: FfmpegAudioCursor::Constructor
 //       Access: Protected
 //       Access: Protected
@@ -42,7 +55,8 @@ FfmpegAudioCursor(FfmpegAudio *src) :
   _format_ctx(0),
   _format_ctx(0),
   _audio_ctx(0),
   _audio_ctx(0),
   _buffer(0),
   _buffer(0),
-  _buffer_alloc(0)
+  _buffer_alloc(0),
+  _resample_ctx(0)
 {
 {
   if (!_ffvfile.open_vfs(_filename)) {
   if (!_ffvfile.open_vfs(_filename)) {
     cleanup();
     cleanup();
@@ -62,8 +76,8 @@ FfmpegAudioCursor(FfmpegAudio *src) :
   }
   }
 
 
   // Find the audio stream
   // Find the audio stream
-  for(int i = 0; i < (int)_format_ctx->nb_streams; i++) {
-    if(_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+  for (int i = 0; i < (int)_format_ctx->nb_streams; i++) {
+    if (_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
       _audio_index = i;
       _audio_index = i;
       _audio_ctx = _format_ctx->streams[i]->codec;
       _audio_ctx = _format_ctx->streams[i]->codec;
       _audio_timebase = av_q2d(_format_ctx->streams[i]->time_base);
       _audio_timebase = av_q2d(_format_ctx->streams[i]->time_base);
@@ -84,6 +98,8 @@ FfmpegAudioCursor(FfmpegAudio *src) :
   }
   }
 
 
 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)
 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)
+  AVDictionary *opts = NULL;
+  av_dict_set(&opts, "request_sample_fmt", "s16", 0);
   if (avcodec_open2(_audio_ctx, pAudioCodec, NULL) < 0) {
   if (avcodec_open2(_audio_ctx, pAudioCodec, NULL) < 0) {
 #else
 #else
   if (avcodec_open(_audio_ctx, pAudioCodec) < 0) {
   if (avcodec_open(_audio_ctx, pAudioCodec) < 0) {
@@ -92,23 +108,61 @@ FfmpegAudioCursor(FfmpegAudio *src) :
     return;
     return;
   }
   }
 
 
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 8, 0)
+  av_dict_free(&opts);
+#endif
+
+  // Set up the resample context if necessary.
+  if (_audio_ctx->sample_fmt != AV_SAMPLE_FMT_S16) {
+#ifdef HAVE_SWRESAMPLE
+#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53, 25, 0)
+    movies_cat.error()
+      << "Codec does not use signed 16-bit sample format.  Upgrade libavcodec to 53.25.0 or higher.\n";
+#else
+    movies_cat.debug()
+      << "Codec does not use signed 16-bit sample format.  Setting up swresample context.\n";
+#endif
+
+    _resample_ctx = swr_alloc();
+    av_opt_set_int(_resample_ctx, "in_channel_layout", _audio_ctx->channel_layout, 0);
+    av_opt_set_int(_resample_ctx, "out_channel_layout", _audio_ctx->channel_layout, 0);
+    av_opt_set_int(_resample_ctx, "in_sample_rate", _audio_ctx->sample_rate, 0);
+    av_opt_set_int(_resample_ctx, "out_sample_rate", _audio_ctx->sample_rate, 0);
+    av_opt_set_sample_fmt(_resample_ctx, "in_sample_fmt", _audio_ctx->sample_fmt, 0);
+    av_opt_set_sample_fmt(_resample_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
+
+    if (swr_init(_resample_ctx) != 0) {
+      movies_cat.error()
+        << "Failed to set up resample context.\n";
+      _resample_ctx = NULL;
+    }
+#else
+    movies_cat.error()
+      << "Codec does not use signed 16-bit sample format, but support for libswresample has not been enabled.\n";
+#endif
+  }
+
   _length = (_format_ctx->duration * 1.0) / AV_TIME_BASE;
   _length = (_format_ctx->duration * 1.0) / AV_TIME_BASE;
   _can_seek = true;
   _can_seek = true;
   _can_seek_fast = true;
   _can_seek_fast = true;
 
 
+  _frame = av_frame_alloc();
+
   _packet = new AVPacket;
   _packet = new AVPacket;
   _buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE / 2;
   _buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE / 2;
-  _buffer_alloc = new PN_int16[_buffer_size + 128];
+  _buffer_alloc = new PN_int16[_buffer_size + 64];
+
+  // Allocate enough space for 1024 samples per channel.
   if ((_packet == 0)||(_buffer_alloc == 0)) {
   if ((_packet == 0)||(_buffer_alloc == 0)) {
     cleanup();
     cleanup();
     return;
     return;
   }
   }
   memset(_packet, 0, sizeof(AVPacket));
   memset(_packet, 0, sizeof(AVPacket));
 
 
-  // Align the buffer to a 16-byte boundary
+  // Align the buffer to a 64-byte boundary
   // The ffmpeg codec likes this, because it uses SSE/SSE2.
   // The ffmpeg codec likes this, because it uses SSE/SSE2.
   _buffer = _buffer_alloc;
   _buffer = _buffer_alloc;
-  while (((size_t)_buffer) & 15) {
+  while (((size_t)_buffer) & 31) {
     _buffer += 1;
     _buffer += 1;
   }
   }
 
 
@@ -137,6 +191,11 @@ FfmpegAudioCursor::
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void FfmpegAudioCursor::
 void FfmpegAudioCursor::
 cleanup() {
 cleanup() {
+  if (_frame) {
+    av_frame_free(&_frame);
+    _frame = NULL;
+  }
+
   if (_packet) {
   if (_packet) {
     if (_packet->data) {
     if (_packet->data) {
       av_free_packet(_packet);
       av_free_packet(_packet);
@@ -161,6 +220,13 @@ cleanup() {
     _format_ctx = NULL;
     _format_ctx = NULL;
   }
   }
 
 
+#ifdef HAVE_SWRESAMPLE
+  if (_resample_ctx) {
+    swr_free(&_resample_ctx);
+    _resample_ctx = NULL;
+  }
+#endif
+
   _audio_index = -1;
   _audio_index = -1;
 }
 }
 
 
@@ -199,7 +265,6 @@ fetch_packet() {
 bool FfmpegAudioCursor::
 bool FfmpegAudioCursor::
 reload_buffer() {
 reload_buffer() {
 
 
-
   while (_buffer_head == _buffer_tail) {
   while (_buffer_head == _buffer_tail) {
     // If we're out of packets, generate silence.
     // If we're out of packets, generate silence.
     if (_packet->data == 0) {
     if (_packet->data == 0) {
@@ -217,15 +282,44 @@ reload_buffer() {
       int len = avcodec_decode_audio2(_audio_ctx, _buffer, &bufsize,
       int len = avcodec_decode_audio2(_audio_ctx, _buffer, &bufsize,
                                       _packet_data, _packet_size);
                                       _packet_data, _packet_size);
       movies_debug("avcodec_decode_audio2 returned " << len);
       movies_debug("avcodec_decode_audio2 returned " << len);
-#else
-      AVPacket pkt; 
-      av_init_packet(&pkt); 
+#elif LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53, 25, 0)
+      // We should technically also consider resampling in this case,
+      // but whatever.  Just upgrade your ffmpeg version if you get garbage.
+      AVPacket pkt;
+      av_init_packet(&pkt);
       pkt.data = _packet_data;
       pkt.data = _packet_data;
       pkt.size = _packet_size;
       pkt.size = _packet_size;
       int len = avcodec_decode_audio3(_audio_ctx, _buffer, &bufsize, &pkt);
       int len = avcodec_decode_audio3(_audio_ctx, _buffer, &bufsize, &pkt);
       movies_debug("avcodec_decode_audio3 returned " << len);
       movies_debug("avcodec_decode_audio3 returned " << len);
       av_free_packet(&pkt);
       av_free_packet(&pkt);
+#else
+      int got_frame;
+      AVPacket pkt;
+      av_init_packet(&pkt);
+      pkt.data = _packet_data;
+      pkt.size = _packet_size;
+      int len = avcodec_decode_audio4(_audio_ctx, _frame, &got_frame, &pkt);
+      movies_debug("avcodec_decode_audio4 returned " << len);
+      av_free_packet(&pkt);
+
+      bufsize = 0;
+      if (got_frame) {
+#ifdef HAVE_SWRESAMPLE
+        if (_resample_ctx) {
+          // Resample the data to signed 16-bit sample format.
+          uint8_t* out[SWR_CH_MAX] = {(uint8_t*) _buffer, NULL};
+          bufsize = swr_convert(_resample_ctx, out, _buffer_size / 2, (const uint8_t**)_frame->extended_data, _frame->nb_samples);
+          bufsize *= _audio_channels * 2;
+        } else
+#endif
+        {
+          bufsize = _frame->linesize[0];
+          memcpy(_buffer, _frame->data[0], bufsize);
+        }
+      }
+      av_frame_unref(_frame);
 #endif
 #endif
+
       if (len < 0) {
       if (len < 0) {
         return false;
         return false;
       } else if (len == 0){
       } else if (len == 0){

+ 14 - 1
panda/src/movies/ffmpegAudioCursor.h

@@ -25,12 +25,20 @@
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "ffmpegVirtualFile.h"
 #include "ffmpegVirtualFile.h"
 
 
+extern "C" {
+  #include "libavcodec/avcodec.h"
+}
+
 class FfmpegAudio;
 class FfmpegAudio;
 struct AVFormatContext;
 struct AVFormatContext;
 struct AVCodecContext;
 struct AVCodecContext;
 struct AVStream;
 struct AVStream;
 struct AVPacket;
 struct AVPacket;
 
 
+#ifdef HAVE_SWRESAMPLE
+struct SwrContext;
+#endif
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : FfmpegAudioCursor
 //       Class : FfmpegAudioCursor
 // Description : A stream that generates a sequence of audio samples.
 // Description : A stream that generates a sequence of audio samples.
@@ -61,12 +69,17 @@ protected:
   int _audio_index;
   int _audio_index;
   double _audio_timebase;
   double _audio_timebase;
 
 
+  AVFrame  *_frame;
   PN_int16 *_buffer;
   PN_int16 *_buffer;
   int       _buffer_size;
   int       _buffer_size;
   PN_int16 *_buffer_alloc;
   PN_int16 *_buffer_alloc;
   int       _buffer_head;
   int       _buffer_head;
   int       _buffer_tail;
   int       _buffer_tail;
-  
+
+#ifdef HAVE_SWRESAMPLE
+  SwrContext *_resample_ctx;
+#endif
+
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;

+ 49 - 120
panda/src/movies/ffmpegVirtualFile.cxx

@@ -33,12 +33,15 @@ extern "C" {
 //     Function: FfmpegVirtualFile::Constructor
 //     Function: FfmpegVirtualFile::Constructor
 //       Access: Public
 //       Access: Public
 //  Description: 
 //  Description: 
-////////////////////////////////////////////////////////////////////
+///////////////////////////////p/////////////////////////////////////
 FfmpegVirtualFile::
 FfmpegVirtualFile::
-FfmpegVirtualFile() : 
+FfmpegVirtualFile() :
+  _io_context(NULL),
   _format_context(NULL),
   _format_context(NULL),
   _in(NULL),
   _in(NULL),
-  _owns_in(false)
+  _owns_in(false),
+  _buffer(NULL),
+  _buffer_size(ffmpeg_read_buffer_size)
 {
 {
 }
 }
 
 
@@ -105,28 +108,21 @@ open_vfs(const Filename &filename) {
   _start = 0;
   _start = 0;
   _size = vfile->get_file_size(_in);
   _size = vfile->get_file_size(_in);
 
 
-  // I tried to use av_open_input_stream(), but it (a) required a lot
-  // of low-level stream analysis calls that really should be
-  // automatic (and are automatic in av_open_input_file()), and (b)
-  // was broken on the ffmpeg build I happened to grab.  Screw it,
-  // clearly av_open_input_file() is the preferred and more
-  // heavily-exercised interface.  So we'll continue to use url
-  // synthesis as a hacky hook into this interface.
+  _buffer = (unsigned char*) av_malloc(_buffer_size);
+  _io_context = avio_alloc_context(_buffer, _buffer_size, 0, (void*) this,
+                                   &read_packet, 0, &seek);
 
 
-  // Nowadays we synthesize a "url" that references this pointer.
-  ostringstream strm;
-  strm << "pandavfs://" << (void *)this;
-  string url = strm.str();
+  _format_context = avformat_alloc_context();
+  _format_context->pb = _io_context;
 
 
   // Now we can open the stream.
   // Now we can open the stream.
   int result =
   int result =
 #if LIBAVFORMAT_VERSION_INT > AV_VERSION_INT(53, 3, 0)
 #if LIBAVFORMAT_VERSION_INT > AV_VERSION_INT(53, 3, 0)
-    avformat_open_input(&_format_context, url.c_str(), NULL, NULL);
+    avformat_open_input(&_format_context, "", NULL, NULL);
 #else
 #else
-    av_open_input_file(&_format_context, url.c_str(), NULL, 0, NULL);
+    av_open_input_file(&_format_context, "", NULL, 0, NULL);
 #endif
 #endif
   if (result < 0) {
   if (result < 0) {
-    _format_context = NULL;
     close();
     close();
     return false;
     return false;
   }
   }
@@ -163,31 +159,21 @@ open_subfile(const SubfileInfo &info) {
 
 
   _in->seekg(_start);
   _in->seekg(_start);
 
 
-  // I tried to use av_open_input_stream(), but it (a) required a lot
-  // of low-level ffmpeg calls that really shouldn't be part of the
-  // public API (and which aren't necessary with av_open_input_file()
-  // because they happen implicitly there), and (b) was completely
-  // broken on the ffmpeg build I happened to grab.  Screw it; clearly
-  // av_open_input_file() is the preferred and more heavily-exercised
-  // interface.  So we'll use it, even though it requires a bit of a
-  // hack.
-
-  // The hack is that we synthesize a "url" that references this
-  // pointer, then open that url.  This calls pandavfs_open(), which
-  // decodes the pointer and stores it for future callbacks.
-  ostringstream strm;
-  strm << "pandavfs://" << (void *)this;
-  string url = strm.str();
+  _buffer = (unsigned char*) av_malloc(_buffer_size);
+  _io_context = avio_alloc_context(_buffer, _buffer_size, 0, (void*) this,
+                                   &read_packet, 0, &seek);
+
+  _format_context = avformat_alloc_context();
+  _format_context->pb = _io_context;
 
 
   // Now we can open the stream.
   // Now we can open the stream.
   int result =
   int result =
 #if LIBAVFORMAT_VERSION_INT > AV_VERSION_INT(53, 3, 0)
 #if LIBAVFORMAT_VERSION_INT > AV_VERSION_INT(53, 3, 0)
-    avformat_open_input(&_format_context, url.c_str(), NULL, NULL);
+    avformat_open_input(&_format_context, fname.c_str(), NULL, NULL);
 #else
 #else
-    av_open_input_file(&_format_context, url.c_str(), NULL, 0, NULL);
+    av_open_input_file(&_format_context, fname.c_str(), NULL, 0, NULL);
 #endif
 #endif
   if (result < 0) {
   if (result < 0) {
-    _format_context = NULL;
     close();
     close();
     return false;
     return false;
   }
   }
@@ -212,6 +198,16 @@ close() {
 #endif
 #endif
   }
   }
 
 
+  if (_io_context != NULL) {
+    av_free(_io_context);
+    _io_context = NULL;
+  }
+
+  if (_buffer != NULL) {
+    av_free(_buffer);
+    _buffer = NULL;
+  }
+
   if (_owns_in) {
   if (_owns_in) {
     nassertv(_in != NULL);
     nassertv(_in != NULL);
     VirtualFileSystem::close_read_file(_in);
     VirtualFileSystem::close_read_file(_in);
@@ -236,65 +232,25 @@ register_protocol() {
   // Here's a good place to call this global ffmpeg initialization
   // Here's a good place to call this global ffmpeg initialization
   // function.
   // function.
   av_register_all();
   av_register_all();
-  
+
   // And this one.
   // And this one.
 #if LIBAVFORMAT_VERSION_INT >= 0x351400
 #if LIBAVFORMAT_VERSION_INT >= 0x351400
   avformat_network_init();
   avformat_network_init();
 #endif
 #endif
 
 
-  static URLProtocol protocol;
-  protocol.name = "pandavfs";
-  protocol.url_open  = pandavfs_open;
-  protocol.url_read  = pandavfs_read;
-
-#if LIBAVFORMAT_VERSION_INT < 3425280
-  protocol.url_write = (int (*)(URLContext *, unsigned char *, int))pandavfs_write;
-#else
-  protocol.url_write = pandavfs_write;
-#endif
-
-  protocol.url_seek  = pandavfs_seek;
-  protocol.url_close = pandavfs_close;
-#if LIBAVFORMAT_VERSION_INT < 3415296
-  ::register_protocol(&protocol);
-#elif LIBAVFORMAT_VERSION_MAJOR < 53
-  av_register_protocol(&protocol);
-#else
-  av_register_protocol2(&protocol, sizeof(protocol));
-#endif
-
   // Let's also register the logging to Panda's notify callback.
   // Let's also register the logging to Panda's notify callback.
   av_log_set_callback(&log_callback);
   av_log_set_callback(&log_callback);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: FfmpegVirtualFile::pandavfs_open
-//       Access: Private, Static
-//  Description: A callback to "open" a virtual file.  Actually, all
-//               this does is assign the pointer back to the
-//               FfmpegVirtualFile instance.
-////////////////////////////////////////////////////////////////////
-int FfmpegVirtualFile::
-pandavfs_open(URLContext *h, const char *filename, int flags) {
-  filename += 11; // Skip over "pandavfs://"
-  istringstream strm(filename);
-  void *ptr = 0;
-  strm >> ptr;
-
-  FfmpegVirtualFile *self = (FfmpegVirtualFile *)ptr;
-  h->priv_data = self;
-  return 0;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FfmpegVirtualFile::pandavfs_read
+//     Function: FfmpegVirtualFile::read_packet
 //       Access: Private, Static
 //       Access: Private, Static
 //  Description: A callback to read a virtual file.
 //  Description: A callback to read a virtual file.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int FfmpegVirtualFile::
 int FfmpegVirtualFile::
-pandavfs_read(URLContext *h, unsigned char *buf, int size) {
+read_packet(void *opaque, uint8_t *buf, int size) {
   streampos ssize = (streampos)size;
   streampos ssize = (streampos)size;
-  FfmpegVirtualFile *self = (FfmpegVirtualFile *)(h->priv_data);
+  FfmpegVirtualFile *self = (FfmpegVirtualFile *) opaque;
   istream *in = self->_in;
   istream *in = self->_in;
 
 
   // Since we may be simulating a subset of the opened stream, don't
   // Since we may be simulating a subset of the opened stream, don't
@@ -316,50 +272,36 @@ pandavfs_read(URLContext *h, unsigned char *buf, int size) {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: FfmpegVirtualFile::pandavfs_write
-//       Access: Private, Static
-//  Description: A callback to write a virtual file.  Unimplemented,
-//               because we use ffmpeg for playback only, not for
-//               encoding video streams.
-////////////////////////////////////////////////////////////////////
-int FfmpegVirtualFile::
-pandavfs_write(URLContext *h, const unsigned char *buf, int size) {
-  ffmpeg_cat.warning()
-    << "ffmpeg is trying to write to the VFS.\n";
-  return -1;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FfmpegVirtualFile::pandavfs_seek
+//     Function: FfmpegVirtualFile::seek
 //       Access: Private, Static
 //       Access: Private, Static
 //  Description: A callback to change the read position on an istream.
 //  Description: A callback to change the read position on an istream.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int64_t FfmpegVirtualFile::
 int64_t FfmpegVirtualFile::
-pandavfs_seek(URLContext *h, int64_t pos, int whence) {
-  FfmpegVirtualFile *self = (FfmpegVirtualFile *)(h->priv_data);
+seek(void *opaque, int64_t pos, int whence) {
+  FfmpegVirtualFile *self = (FfmpegVirtualFile *) opaque;
   istream *in = self->_in;
   istream *in = self->_in;
 
 
-  switch(whence) {
-  case SEEK_SET: 
-    in->seekg(self->_start + (streampos)pos, ios::beg); 
+  switch (whence) {
+  case SEEK_SET:
+    in->seekg(self->_start + (streampos)pos, ios::beg);
     break;
     break;
 
 
-  case SEEK_CUR: 
-    in->seekg(pos, ios::cur); 
+  case SEEK_CUR:
+    in->seekg(pos, ios::cur);
     break;
     break;
 
 
-  case SEEK_END: 
+  case SEEK_END:
     // For seeks relative to the end, we actually compute the end
     // For seeks relative to the end, we actually compute the end
     // based on _start + _size, and then use ios::beg.
     // based on _start + _size, and then use ios::beg.
-    in->seekg(self->_start + (streampos)self->_size + (streampos)pos, ios::beg); 
+    in->seekg(self->_start + (streampos)self->_size + (streampos)pos, ios::beg);
     break;
     break;
 
 
-  case AVSEEK_SIZE: 
-    return self->_size; 
+  case AVSEEK_SIZE:
+    return self->_size;
 
 
   default:
   default:
-    ffmpeg_cat.error() 
-      << "Illegal parameter to seek in ffmpegVirtualFile\n";
+    ffmpeg_cat.error()
+      << "Illegal parameter to seek in FfmpegVirtualFile\n";
     in->clear();
     in->clear();
     return -1;
     return -1;
   }
   }
@@ -368,19 +310,6 @@ pandavfs_seek(URLContext *h, int64_t pos, int whence) {
   return in->tellg() - self->_start;
   return in->tellg() - self->_start;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: FfmpegVirtualFile::pandavfs_close
-//       Access: Private, Static
-//  Description: A hook to "close" a panda VFS file.  Actually it only
-//               clears the associated pointer.
-////////////////////////////////////////////////////////////////////
-int FfmpegVirtualFile::
-pandavfs_close(URLContext *h) {
-  //FfmpegVirtualFile *self = (FfmpegVirtualFile *)(h->priv_data);
-  h->priv_data = 0;
-  return 0;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: FfmpegVirtualFile::log_callback
 //     Function: FfmpegVirtualFile::log_callback
 //       Access: Private, Static
 //       Access: Private, Static

+ 6 - 6
panda/src/movies/ffmpegVirtualFile.h

@@ -56,25 +56,25 @@ public:
   static void register_protocol();
   static void register_protocol();
 
 
 private:
 private:
-  static int pandavfs_open(URLContext *h, const char *filename, int flags);
-  static int pandavfs_read(URLContext *h, unsigned char *buf, int size);
-  static int pandavfs_write(URLContext *h, const unsigned char *buf, int size);
-  static int64_t pandavfs_seek(URLContext *h, int64_t pos, int whence);
-  static int pandavfs_close(URLContext *h);
+  // These are callbacks passed to ffmpeg and cannot change signature.
+  static int read_packet(void *opaque, uint8_t *buf, int buf_size);
+  static int64_t seek(void *opaque, int64_t offset, int whence);
 
 
   static void log_callback(void *ptr, int level, const char *fmt, va_list v1);
   static void log_callback(void *ptr, int level, const char *fmt, va_list v1);
 
 
 private:
 private:
+  AVIOContext *_io_context;
   AVFormatContext *_format_context;
   AVFormatContext *_format_context;
   streampos _start;
   streampos _start;
   streamsize _size;
   streamsize _size;
   istream *_in;
   istream *_in;
   pifstream _file_in;
   pifstream _file_in;
   bool _owns_in;
   bool _owns_in;
+  unsigned char *_buffer;
+  int _buffer_size;
 };
 };
 
 
 #include "ffmpegVirtualFile.I"
 #include "ffmpegVirtualFile.I"
 
 
 #endif // HAVE_FFMPEG
 #endif // HAVE_FFMPEG
 #endif // FFMPEGVIRTUALFILE_H
 #endif // FFMPEGVIRTUALFILE_H
-