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.

This commit is contained in:
rdb 2013-08-22 18:20:10 +00:00
parent 90770727c0
commit 03e96d8c4a
8 changed files with 182 additions and 141 deletions

View File

@ -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

View File

@ -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]

View File

@ -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

View File

@ -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();

View File

@ -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++) { for (int i = 0; i < (int)_format_ctx->nb_streams; i++) {
if(_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { 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 #elif LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53, 25, 0)
AVPacket pkt; // We should technically also consider resampling in this case,
av_init_packet(&pkt); // 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 #endif
{
bufsize = _frame->linesize[0];
memcpy(_buffer, _frame->data[0], bufsize);
}
}
av_frame_unref(_frame);
#endif
if (len < 0) { if (len < 0) {
return false; return false;
} else if (len == 0){ } else if (len == 0){

View File

@ -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;

View File

@ -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 _buffer = (unsigned char*) av_malloc(_buffer_size);
// of low-level stream analysis calls that really should be _io_context = avio_alloc_context(_buffer, _buffer_size, 0, (void*) this,
// automatic (and are automatic in av_open_input_file()), and (b) &read_packet, 0, &seek);
// 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.
// Nowadays we synthesize a "url" that references this pointer. _format_context = avformat_alloc_context();
ostringstream strm; _format_context->pb = _io_context;
strm << "pandavfs://" << (void *)this;
string url = strm.str();
// 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 _buffer = (unsigned char*) av_malloc(_buffer_size);
// of low-level ffmpeg calls that really shouldn't be part of the _io_context = avio_alloc_context(_buffer, _buffer_size, 0, (void*) this,
// public API (and which aren't necessary with av_open_input_file() &read_packet, 0, &seek);
// 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 _format_context = avformat_alloc_context();
// pointer, then open that url. This calls pandavfs_open(), which _format_context->pb = _io_context;
// decodes the pointer and stores it for future callbacks.
ostringstream strm;
strm << "pandavfs://" << (void *)this;
string url = strm.str();
// 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 // Function: FfmpegVirtualFile::read_packet
// 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
// 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 // Function: FfmpegVirtualFile::seek
// 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
// 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) { seek(void *opaque, int64_t pos, int whence) {
FfmpegVirtualFile *self = (FfmpegVirtualFile *)(h->priv_data); FfmpegVirtualFile *self = (FfmpegVirtualFile *) opaque;
istream *in = self->_in; istream *in = self->_in;
switch(whence) { switch (whence) {
case SEEK_SET: case SEEK_SET:
in->seekg(self->_start + (streampos)pos, ios::beg); in->seekg(self->_start + (streampos)pos, ios::beg);
break; break;
case SEEK_CUR: case SEEK_CUR:
in->seekg(pos, ios::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: case AVSEEK_SIZE:
return self->_size; return self->_size;
default: default:
ffmpeg_cat.error() ffmpeg_cat.error()
<< "Illegal parameter to seek in ffmpegVirtualFile\n"; << "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

View File

@ -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); // These are callbacks passed to ffmpeg and cannot change signature.
static int pandavfs_read(URLContext *h, unsigned char *buf, int size); static int read_packet(void *opaque, uint8_t *buf, int buf_size);
static int pandavfs_write(URLContext *h, const unsigned char *buf, int size); static int64_t seek(void *opaque, int64_t offset, int whence);
static int64_t pandavfs_seek(URLContext *h, int64_t pos, int whence);
static int pandavfs_close(URLContext *h);
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