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