support caching movie files in the model-cache-dir and in a txo file

This commit is contained in:
David Rose 2011-06-29 20:33:34 +00:00
parent b00edc02d4
commit 285d70c29e
78 changed files with 3114 additions and 1025 deletions

View File

@ -25,7 +25,7 @@
#include "config_audio.h"
#include "fmodAudioSound.h"
#include "string_utils.h"
#include "fileSystemInfo.h"
#include "subfileInfo.h"
TypeHandle FmodAudioSound::_type_handle;
@ -104,9 +104,10 @@ FmodAudioSound(AudioManager *manager, Filename file_name, bool positional) {
}
const char *name_or_data = _file_name.c_str();
string os_filename;
pvector<unsigned char> mem_buffer;
FileSystemInfo info;
SubfileInfo info;
if (preload) {
// Pre-read the file right now, and pass it in as a memory
// buffer. This avoids threading issues completely, because all
@ -129,9 +130,10 @@ FmodAudioSound(AudioManager *manager, Filename file_name, bool positional) {
// This is also safe, because FMod uses its own I/O operations
// that don't involve Panda, so this can safely happen in an
// FMod thread.
name_or_data = info.get_os_file_name().c_str();
sound_info.fileoffset = (unsigned int)info.get_file_start();
sound_info.length = (unsigned int)info.get_file_size();
os_filename = info.get_filename().to_os_specific();
name_or_data = os_filename.c_str();
sound_info.fileoffset = (unsigned int)info.get_start();
sound_info.length = (unsigned int)info.get_size();
flags |= FMOD_CREATESTREAM;
if (fmodAudio_cat.is_debug()) {
fmodAudio_cat.debug()
@ -144,7 +146,7 @@ FmodAudioSound(AudioManager *manager, Filename file_name, bool positional) {
// Otherwise, if the Panda threading system is compiled in, we
// can assign callbacks to read the file through the VFS.
name_or_data = (const char *)file.p();
sound_info.length = (unsigned int)info.get_file_size();
sound_info.length = (unsigned int)info.get_size();
sound_info.useropen = open_callback;
sound_info.userclose = close_callback;
sound_info.userread = read_callback;

View File

@ -13,8 +13,8 @@
ca_bundle_data_src.c \
checksumHashGenerator.I checksumHashGenerator.h circBuffer.I \
circBuffer.h \
config_express.h \
compress_string.h \
config_express.h \
copy_stream.h \
datagram.I datagram.h datagramGenerator.I \
datagramGenerator.h \
@ -23,7 +23,7 @@
encrypt_string.h \
error_utils.h \
export_dtool.h \
fileSystemInfo.h fileSystemInfo.I \
fileReference.h fileReference.I \
hashGeneratorBase.I hashGeneratorBase.h \
hashVal.I hashVal.h \
indirectLess.I indirectLess.h \
@ -34,11 +34,12 @@
multifile.I multifile.h \
namable.I \
namable.h \
nodePointerToBase.h nodePointerToBase.I \
nodePointerTo.h nodePointerTo.I \
nodePointerToBase.h nodePointerToBase.I \
nodeReferenceCount.h nodeReferenceCount.I \
openSSLWrapper.h openSSLWrapper.I \
ordered_vector.h ordered_vector.I ordered_vector.T \
pStatCollectorForwardBase.h \
password_hash.h \
patchfile.I patchfile.h \
pointerTo.I pointerTo.h \
@ -47,13 +48,14 @@
pointerToBase.I pointerToBase.h \
pointerToVoid.I pointerToVoid.h \
profileTimer.I profileTimer.h \
pStatCollectorForwardBase.h \
pta_uchar.h pta_float.h \
pta_int.h \
pta_uchar.h pta_float.h \
ramfile.I ramfile.h \
referenceCount.I referenceCount.h \
stringDecoder.h stringDecoder.I \
subStream.I subStream.h subStreamBuf.h \
subfileInfo.h subfileInfo.I \
temporaryFile.h temporaryFile.I \
textEncoder.h textEncoder.I \
threadSafePointerTo.I threadSafePointerTo.h \
threadSafePointerToBase.I threadSafePointerToBase.h \
@ -61,8 +63,8 @@
typedReferenceCount.I typedReferenceCount.h typedef.h \
unicodeLatinMap.h \
vector_uchar.h vector_float.h \
virtualFileComposite.h virtualFileComposite.I virtualFile.h \
virtualFile.I virtualFileList.I virtualFileList.h virtualFileMount.h \
virtualFileComposite.h virtualFileComposite.I virtualFile.h \
virtualFileMount.I virtualFileMountMultifile.h \
virtualFileMountMultifile.I virtualFileMountSystem.h \
virtualFileMountSystem.I virtualFileSimple.h virtualFileSimple.I \
@ -77,24 +79,25 @@
#define INCLUDED_SOURCES \
buffer.cxx checksumHashGenerator.cxx \
config_express.cxx \
compress_string.cxx \
config_express.cxx \
copy_stream.cxx \
datagram.cxx datagramGenerator.cxx \
datagramIterator.cxx \
datagramSink.cxx dcast.cxx \
encrypt_string.cxx \
error_utils.cxx \
fileSystemInfo.cxx \
fileReference.cxx \
hashGeneratorBase.cxx hashVal.cxx \
memoryInfo.cxx memoryUsage.cxx memoryUsagePointerCounts.cxx \
memoryUsagePointers.cxx multifile.cxx \
namable.cxx \
nodePointerToBase.cxx \
nodePointerTo.cxx \
nodePointerToBase.cxx \
nodeReferenceCount.cxx \
openSSLWrapper.cxx \
ordered_vector.cxx \
pStatCollectorForwardBase.cxx \
password_hash.cxx \
patchfile.cxx \
pointerTo.cxx \
@ -102,13 +105,14 @@
pointerToBase.cxx \
pointerToVoid.cxx \
profileTimer.cxx \
pStatCollectorForwardBase.cxx \
pta_uchar.cxx pta_float.cxx \
pta_int.cxx \
pta_uchar.cxx pta_float.cxx \
ramfile.cxx \
referenceCount.cxx \
stringDecoder.cxx \
subStream.cxx subStreamBuf.cxx \
subfileInfo.cxx \
temporaryFile.cxx \
textEncoder.cxx \
threadSafePointerTo.cxx \
threadSafePointerToBase.cxx \
@ -133,8 +137,8 @@
ca_bundle_data_src.c \
checksumHashGenerator.I checksumHashGenerator.h circBuffer.I \
circBuffer.h \
config_express.h \
compress_string.h \
config_express.h \
copy_stream.h \
datagram.I datagram.h datagramGenerator.I \
datagramGenerator.h \
@ -142,7 +146,7 @@
dcast.T dcast.h \
encrypt_string.h \
error_utils.h \
fileSystemInfo.h fileSystemInfo.I \
fileReference.h fileReference.I \
hashGeneratorBase.I hashGeneratorBase.h \
hashVal.I hashVal.h \
indirectLess.I indirectLess.h \
@ -153,11 +157,12 @@
multifile.I multifile.h \
namable.I \
namable.h \
nodePointerToBase.h nodePointerToBase.I \
nodePointerTo.h nodePointerTo.I \
nodePointerToBase.h nodePointerToBase.I \
nodeReferenceCount.h nodeReferenceCount.I \
openSSLWrapper.h openSSLWrapper.I \
ordered_vector.h ordered_vector.I ordered_vector.T \
pStatCollectorForwardBase.h \
password_hash.h \
patchfile.I patchfile.h \
pointerTo.I pointerTo.h \
@ -166,13 +171,14 @@
pointerToBase.I pointerToBase.h \
pointerToVoid.I pointerToVoid.h \
profileTimer.I profileTimer.h \
pStatCollectorForwardBase.h \
pta_uchar.h pta_float.h \
pta_int.h \
pta_uchar.h pta_float.h \
ramfile.I ramfile.h \
referenceCount.I referenceCount.h \
stringDecoder.h stringDecoder.I \
subStream.I subStream.h subStreamBuf.h \
subfileInfo.h subfileInfo.I \
temporaryFile.h temporaryFile.I \
textEncoder.h textEncoder.I \
threadSafePointerTo.I threadSafePointerTo.h \
threadSafePointerToBase.I threadSafePointerToBase.h \
@ -180,8 +186,8 @@
typedReferenceCount.I typedReferenceCount.h typedef.h \
unicodeLatinMap.h \
vector_uchar.h vector_float.h \
virtualFileComposite.h virtualFileComposite.I virtualFile.h \
virtualFile.I virtualFileList.I virtualFileList.h virtualFileMount.h \
virtualFileComposite.h virtualFileComposite.I virtualFile.h \
virtualFileMount.I virtualFileMountMultifile.h \
virtualFileMountMultifile.I virtualFileMountSystem.h \
virtualFileMountSystem.I virtualFileSimple.h virtualFileSimple.I \

View File

@ -25,6 +25,8 @@
#include "virtualFileMountMultifile.h"
#include "virtualFileMountSystem.h"
#include "virtualFileSimple.h"
#include "fileReference.h"
#include "temporaryFile.h"
#include "pandaSystem.h"
#include "numeric_types.h"
#include "namable.h"
@ -98,6 +100,8 @@ init_libexpress() {
VirtualFileMountMultifile::init_type();
VirtualFileMountSystem::init_type();
VirtualFileSimple::init_type();
FileReference::init_type();
TemporaryFile::init_type();
init_system_type_handles();

View File

@ -15,11 +15,10 @@
////////////////////////////////////////////////////////////////////
// Function: DatagramGenerator::Constructor
// Access: Public
// Access: Published
// Description: Does nothing since this is class is just
// the definition of an interface
////////////////////////////////////////////////////////////////////
INLINE DatagramGenerator::DatagramGenerator(){
INLINE DatagramGenerator::
DatagramGenerator() {
}

View File

@ -16,10 +16,11 @@
#include "pandabase.h"
#include "datagramGenerator.h"
#include "temporaryFile.h"
////////////////////////////////////////////////////////////////////
// Function: DatagramGenerator::Destructor
// Access: Public, Virtual
// Access: Published, Virtual
// Description: Does nothing since this is class is just
// the definition of an interface
////////////////////////////////////////////////////////////////////
@ -28,20 +29,67 @@ DatagramGenerator::
}
////////////////////////////////////////////////////////////////////
// Function: DatagramGenerator::get_file
// Access: Public, Virtual
// Description: Returns the VirtualFile that provides the source for
// these datagrams, if any, or NULL if the datagrams do
// not originate from a VirtualFile.
// Function: DatagramGenerator::save_datagram
// Access: Published, Virtual
// Description: Skips over the next datagram without extracting it,
// but saves the relevant file information in the
// SubfileInfo object so that its data may be read
// later. For non-file-based datagram generators, this
// may mean creating a temporary file and copying the
// contents of the datagram to disk.
//
// Returns true on success, false on failure or if this
// method is unimplemented.
////////////////////////////////////////////////////////////////////
VirtualFile *DatagramGenerator::
bool DatagramGenerator::
save_datagram(SubfileInfo &info) {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramGenerator::get_filename
// Access: Published, Virtual
// Description: Returns the filename that provides the source for
// these datagrams, if any, or empty string if the
// datagrams do not originate from a file on disk.
////////////////////////////////////////////////////////////////////
const Filename &DatagramGenerator::
get_filename() {
const FileReference *file = get_file();
if (file != (FileReference *)NULL) {
return file->get_filename();
}
static const Filename empty_filename;
return empty_filename;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramGenerator::get_file
// Access: Published, Virtual
// Description: Returns the FileReference that provides the source for
// these datagrams, if any, or NULL if the datagrams do
// not originate from a file on disk.
////////////////////////////////////////////////////////////////////
const FileReference *DatagramGenerator::
get_file() {
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramGenerator::get_vfile
// Access: Published, Virtual
// Description: Returns the VirtualFile that provides the source for
// these datagrams, if any, or NULL if the datagrams do
// not originate from a VirtualFile.
////////////////////////////////////////////////////////////////////
VirtualFile *DatagramGenerator::
get_vfile() {
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramGenerator::get_file_pos
// Access: Public, Virtual
// Access: Published, Virtual
// Description: Returns the current file position within the data
// stream, if any, or 0 if the file position is not
// meaningful or cannot be determined.

View File

@ -19,13 +19,16 @@
#include "datagram.h"
class SubfileInfo;
class FileReference;
class Filename;
class VirtualFile;
////////////////////////////////////////////////////////////////////
// Class : DatagramGenerator
// Description : This class defines the abstract interace to any
// source of datagrams, whether it be from a file or
// from the net
// from the net.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS DatagramGenerator {
PUBLISHED:
@ -33,10 +36,13 @@ PUBLISHED:
virtual ~DatagramGenerator();
virtual bool get_datagram(Datagram &data) = 0;
virtual bool save_datagram(SubfileInfo &info);
virtual bool is_eof() = 0;
virtual bool is_error() = 0;
virtual VirtualFile *get_file();
virtual const Filename &get_filename();
virtual const FileReference *get_file();
virtual VirtualFile *get_vfile();
virtual streampos get_file_pos();
};

View File

@ -13,6 +13,7 @@
////////////////////////////////////////////////////////////////////
#include "datagramSink.h"
#include "fileReference.h"
////////////////////////////////////////////////////////////////////
// Function: DatagramSink::Destructor
@ -21,5 +22,86 @@
// the definition of an interface
////////////////////////////////////////////////////////////////////
DatagramSink::
~DatagramSink(){
~DatagramSink() {
}
////////////////////////////////////////////////////////////////////
// Function: DatagramSink::copy_datagram
// Access: Published, Virtual
// Description: Copies the file data from the entire indicated
// file (via the vfs) as the next datagram. This is
// intended to support potentially very large datagrams.
//
// Returns true on success, false on failure or if this
// method is unimplemented. On true, fills "result"
// with the information that references the copied file,
// if possible.
////////////////////////////////////////////////////////////////////
bool DatagramSink::
copy_datagram(SubfileInfo &result, const Filename &filename) {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramSink::copy_datagram
// Access: Published, Virtual
// Description: Copies the file data from the range of the indicated
// file (outside of the vfs) as the next datagram. This
// is intended to support potentially very large
// datagrams.
//
// Returns true on success, false on failure or if this
// method is unimplemented. On true, fills "result"
// with the information that references the copied file,
// if possible.
////////////////////////////////////////////////////////////////////
bool DatagramSink::
copy_datagram(SubfileInfo &result, const SubfileInfo &source) {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramSink::get_filename
// Access: Published, Virtual
// Description: Returns the filename that provides the target for
// these datagrams, if any, or empty string if the
// datagrams do not get written to a file on disk.
////////////////////////////////////////////////////////////////////
const Filename &DatagramSink::
get_filename() {
const FileReference *file = get_file();
if (file != (FileReference *)NULL) {
return file->get_filename();
}
static const Filename empty_filename;
return empty_filename;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramSink::get_file
// Access: Published, Virtual
// Description: Returns the FileReference that provides the target for
// these datagrams, if any, or NULL if the datagrams do
// not written to a file on disk.
////////////////////////////////////////////////////////////////////
const FileReference *DatagramSink::
get_file() {
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramSink::get_file_pos
// Access: Published, Virtual
// Description: Returns the current file position within the data
// stream, if any, or 0 if the file position is not
// meaningful or cannot be determined.
//
// For DatagramSinks that return a meaningful file
// position, this will be pointing to the first byte
// following the datagram returned after a call to
// put_datagram().
////////////////////////////////////////////////////////////////////
streampos DatagramSink::
get_file_pos() {
return 0;
}

View File

@ -19,6 +19,10 @@
#include "datagram.h"
class SubfileInfo;
class FileReference;
class Filename;
////////////////////////////////////////////////////////////////////
// Class : DatagramSink
// Description : This class defines the abstract interface to sending
@ -31,8 +35,14 @@ PUBLISHED:
virtual ~DatagramSink();
virtual bool put_datagram(const Datagram &data) = 0;
virtual bool copy_datagram(SubfileInfo &result, const Filename &filename);
virtual bool copy_datagram(SubfileInfo &result, const SubfileInfo &source);
virtual bool is_error() = 0;
virtual void flush() = 0;
virtual const Filename &get_filename();
virtual const FileReference *get_file();
virtual streampos get_file_pos();
};
#include "datagramSink.I"

View File

@ -10,7 +10,7 @@
#include "dcast.cxx"
#include "encrypt_string.cxx"
#include "error_utils.cxx"
#include "fileSystemInfo.cxx"
#include "fileReference.cxx"
#include "hashGeneratorBase.cxx"
#include "hashVal.cxx"
#include "memoryInfo.cxx"

View File

@ -4,8 +4,10 @@
#include "ramfile.cxx"
#include "referenceCount.cxx"
#include "stringDecoder.cxx"
#include "subfileInfo.cxx"
#include "subStream.cxx"
#include "subStreamBuf.cxx"
#include "temporaryFile.cxx"
#include "textEncoder.cxx"
#include "threadSafePointerTo.cxx"
#include "threadSafePointerToBase.cxx"

View File

@ -0,0 +1,33 @@
// Filename: fileReference.I
// Created by: drose (23Jun11)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: FileReference::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE FileReference::
FileReference(const Filename &filename) : _filename(filename) {
}
////////////////////////////////////////////////////////////////////
// Function: FileReference::get_filename
// Access: Published
// Description: Returns the filename of the reference.
////////////////////////////////////////////////////////////////////
INLINE const Filename &FileReference::
get_filename() const {
return _filename;
}

View File

@ -0,0 +1,17 @@
// Filename: fileReference.cxx
// Created by: drose (23Jun11)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "fileReference.h"
TypeHandle FileReference::_type_handle;

View File

@ -0,0 +1,57 @@
// Filename: fileReference.h
// Created by: drose (23Jun11)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef FILEREFERENCE_H
#define FILEREFERENCE_H
#include "pandabase.h"
#include "typedReferenceCount.h"
#include "filename.h"
////////////////////////////////////////////////////////////////////
// Class : FileReference
// Description : Keeps a reference-counted pointer to a file on disk.
// As long as the FileReference is held, someone
// presumably has a use for this file.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS FileReference : public TypedReferenceCount {
PUBLISHED:
INLINE FileReference(const Filename &filename);
INLINE const Filename &get_filename() const;
protected:
Filename _filename;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
TypedReferenceCount::init_type();
register_type(_type_handle, "FileReference",
TypedReferenceCount::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 "fileReference.I"
#endif

View File

@ -1,103 +0,0 @@
// Filename: fileSystemInfo.I
// Created by: drose (20Jun11)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: FileSystemInfo::Default Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE FileSystemInfo::
FileSystemInfo() :
_file_start(0),
_file_size(0)
{
}
////////////////////////////////////////////////////////////////////
// Function: FileSystemInfo::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE FileSystemInfo::
FileSystemInfo(const string &os_file_name, streampos file_start, streamsize file_size) :
_os_file_name(os_file_name),
_file_start(file_start),
_file_size(file_size)
{
}
////////////////////////////////////////////////////////////////////
// Function: FileSystemInfo::Copy Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE FileSystemInfo::
FileSystemInfo(const FileSystemInfo &copy) :
_os_file_name(copy._os_file_name),
_file_start(copy._file_start),
_file_size(copy._file_size)
{
}
////////////////////////////////////////////////////////////////////
// Function: FileSystemInfo::Copy Assignment Operator
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void FileSystemInfo::
operator = (const FileSystemInfo &copy) {
_os_file_name = copy._os_file_name;
_file_start = copy._file_start;
_file_size = copy._file_size;
}
////////////////////////////////////////////////////////////////////
// Function: FileSystemInfo::get_os_file_name
// Access: Published
// Description: Returns the os-specific filename that may be used to
// open this file.
////////////////////////////////////////////////////////////////////
INLINE const string &FileSystemInfo::
get_os_file_name() const {
return _os_file_name;
}
////////////////////////////////////////////////////////////////////
// Function: FileSystemInfo::get_file_start
// Access: Published
// Description: Returns the offset within the file at which this file
// data begins.
////////////////////////////////////////////////////////////////////
INLINE streampos FileSystemInfo::
get_file_start() const {
return _file_start;
}
////////////////////////////////////////////////////////////////////
// Function: FileSystemInfo::get_file_size
// Access: Published
// Description: Returns the number of consecutive bytes, beginning at
// get_file_start(), that correspond to this file data.
////////////////////////////////////////////////////////////////////
INLINE streamsize FileSystemInfo::
get_file_size() const {
return _file_size;
}
INLINE ostream &
operator << (ostream &out, const FileSystemInfo &info) {
info.output(out);
return out;
}

View File

@ -1,48 +0,0 @@
// Filename: fileSystemInfo.h
// Created by: drose (20Jun11)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef FILESYSTEMINFO_H
#define FILESYSTEMINFO_H
#include "pandabase.h"
////////////////////////////////////////////////////////////////////
// Class : FileSystemInfo
// Description : This class is used to return data about an actual
// file on disk by VirtualFile::get_system_info().
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS FileSystemInfo {
PUBLISHED:
INLINE FileSystemInfo();
INLINE FileSystemInfo(const string &os_file_name, streampos file_start, streamsize file_size);
INLINE FileSystemInfo(const FileSystemInfo &copy);
INLINE void operator = (const FileSystemInfo &copy);
INLINE const string &get_os_file_name() const;
INLINE streampos get_file_start() const;
INLINE streamsize get_file_size() const;
void output(ostream &out) const;
private:
string _os_file_name;
streampos _file_start;
streamsize _file_size;
};
INLINE ostream &operator << (ostream &out, const FileSystemInfo &info);
#include "fileSystemInfo.I"
#endif

View File

@ -26,7 +26,6 @@
#include "referenceCount.h"
#include "pvector.h"
#include "openSSLWrapper.h"
#include "fileSystemInfo.h"
////////////////////////////////////////////////////////////////////
// Class : Multifile

View File

@ -0,0 +1,140 @@
// Filename: subfileInfo.I
// Created by: drose (20Jun11)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: SubfileInfo::Default Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SubfileInfo::
SubfileInfo() :
_start(0),
_size(0)
{
}
////////////////////////////////////////////////////////////////////
// Function: SubfileInfo::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SubfileInfo::
SubfileInfo(const FileReference *file, streampos start, streamsize size) :
_file(file),
_start(start),
_size(size)
{
}
////////////////////////////////////////////////////////////////////
// Function: SubfileInfo::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SubfileInfo::
SubfileInfo(const Filename &filename, streampos start, streamsize size) :
_file(new FileReference(filename)),
_start(start),
_size(size)
{
}
////////////////////////////////////////////////////////////////////
// Function: SubfileInfo::Copy Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE SubfileInfo::
SubfileInfo(const SubfileInfo &copy) :
_file(copy._file),
_start(copy._start),
_size(copy._size)
{
}
////////////////////////////////////////////////////////////////////
// Function: SubfileInfo::Copy Assignment Operator
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void SubfileInfo::
operator = (const SubfileInfo &copy) {
_file = copy._file;
_start = copy._start;
_size = copy._size;
}
////////////////////////////////////////////////////////////////////
// Function: SubfileInfo::is_empty
// Access: Published
// Description: Returns true if this SubfileInfo doesn't define any
// file, false if it has real data.
////////////////////////////////////////////////////////////////////
INLINE bool SubfileInfo::
is_empty() const {
return _file == (FileReference *)NULL;
}
////////////////////////////////////////////////////////////////////
// Function: SubfileInfo::get_file
// Access: Published
// Description: Returns the FileReference that represents this file.
////////////////////////////////////////////////////////////////////
INLINE const FileReference *SubfileInfo::
get_file() const {
return _file;
}
////////////////////////////////////////////////////////////////////
// Function: SubfileInfo::get_filename
// Access: Published
// Description: A shortcut to the filename.
////////////////////////////////////////////////////////////////////
INLINE const Filename &SubfileInfo::
get_filename() const {
if (_file != (FileReference *)NULL) {
return _file->get_filename();
}
static const Filename empty_filename;
return empty_filename;
}
////////////////////////////////////////////////////////////////////
// Function: SubfileInfo::get_start
// Access: Published
// Description: Returns the offset within the file at which this file
// data begins.
////////////////////////////////////////////////////////////////////
INLINE streampos SubfileInfo::
get_start() const {
return _start;
}
////////////////////////////////////////////////////////////////////
// Function: SubfileInfo::get_size
// Access: Published
// Description: Returns the number of consecutive bytes, beginning at
// get_start(), that correspond to this file data.
////////////////////////////////////////////////////////////////////
INLINE streamsize SubfileInfo::
get_size() const {
return _size;
}
INLINE ostream &
operator << (ostream &out, const SubfileInfo &info) {
info.output(out);
return out;
}

View File

@ -1,4 +1,4 @@
// Filename: fileSystemInfo.cxx
// Filename: subfileInfo.cxx
// Created by: drose (20Jun11)
//
////////////////////////////////////////////////////////////////////
@ -12,15 +12,14 @@
//
////////////////////////////////////////////////////////////////////
#include "fileSystemInfo.h"
#include "subfileInfo.h"
////////////////////////////////////////////////////////////////////
// Function: FileSystemInfo::output
// Function: SubfileInfo::output
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void FileSystemInfo::
void SubfileInfo::
output(ostream &out) const {
out << "FileSystemInfo(" << _os_file_name << ", " << _file_start
<< ", " << _file_size << ")";
out << "SubfileInfo(" << get_filename() << ", " << _start << ", " << _size << ")";
}

View File

@ -0,0 +1,56 @@
// Filename: subfileInfo.h
// Created by: drose (20Jun11)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef SUBFILEINFO_H
#define SUBFILEINFO_H
#include "pandabase.h"
#include "fileReference.h"
#include "pointerTo.h"
////////////////////////////////////////////////////////////////////
// Class : SubfileInfo
// Description : This class records a particular byte sub-range within
// an existing file on disk. Generally, the filename is
// understood as a physical file on disk, and not to be
// looked up via the vfs.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS SubfileInfo {
PUBLISHED:
INLINE SubfileInfo();
INLINE SubfileInfo(const FileReference *file, streampos start, streamsize size);
INLINE SubfileInfo(const Filename &filename, streampos start, streamsize size);
INLINE SubfileInfo(const SubfileInfo &copy);
INLINE void operator = (const SubfileInfo &copy);
INLINE bool is_empty() const;
INLINE const FileReference *get_file() const;
INLINE const Filename &get_filename() const;
INLINE streampos get_start() const;
INLINE streamsize get_size() const;
void output(ostream &out) const;
private:
CPT(FileReference) _file;
streampos _start;
streamsize _size;
};
INLINE ostream &operator << (ostream &out, const SubfileInfo &info);
#include "subfileInfo.I"
#endif

View File

@ -0,0 +1,23 @@
// Filename: temporaryFile.I
// Created by: drose (23Jun11)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: TemporaryFile::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE TemporaryFile::
TemporaryFile(const Filename &filename) : FileReference(filename) {
}

View File

@ -0,0 +1,28 @@
// Filename: temporaryFile.cxx
// Created by: drose (23Jun11)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "temporaryFile.h"
TypeHandle TemporaryFile::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: TemporaryFile::Destructor
// Access: Published, Virtual
// Description: The destructor is responsible for removing the file
// if it exists.
////////////////////////////////////////////////////////////////////
TemporaryFile::
~TemporaryFile() {
_filename.unlink();
}

View File

@ -0,0 +1,54 @@
// Filename: temporaryFile.h
// Created by: drose (23Jun11)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef TEMPORARYFILE_H
#define TEMPORARYFILE_H
#include "pandabase.h"
#include "fileReference.h"
////////////////////////////////////////////////////////////////////
// Class : TemporaryFile
// Description : This is a special kind of FileReference class that
// automatically deletes the file in question when it is
// deleted. It is not responsible for creating,
// opening, or closing the file, however.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS TemporaryFile : public FileReference {
PUBLISHED:
INLINE TemporaryFile(const Filename &filename);
virtual ~TemporaryFile();
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
FileReference::init_type();
register_type(_type_handle, "TemporaryFile",
FileReference::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 "temporaryFile.I"
#endif

View File

@ -216,7 +216,7 @@ get_timestamp() const {
////////////////////////////////////////////////////////////////////
// Function: VirtualFile::get_system_info
// Access: Published, Virtual
// Description: Populates the FileSystemInfo structure with the data
// Description: Populates the SubfileInfo structure with the data
// representing where the file actually resides on disk,
// if this is knowable. Returns true if the file might
// reside on disk, and the info is populated, or false
@ -224,7 +224,7 @@ get_timestamp() const {
// resides), in which case the info is meaningless.
////////////////////////////////////////////////////////////////////
bool VirtualFile::
get_system_info(FileSystemInfo &info) {
get_system_info(SubfileInfo &info) {
return false;
}

View File

@ -18,7 +18,7 @@
#include "pandabase.h"
#include "filename.h"
#include "fileSystemInfo.h"
#include "subfileInfo.h"
#include "pointerTo.h"
#include "typedReferenceCount.h"
#include "ordered_vector.h"
@ -61,7 +61,7 @@ PUBLISHED:
BLOCKING virtual off_t get_file_size() const;
BLOCKING virtual time_t get_timestamp() const;
virtual bool get_system_info(FileSystemInfo &info);
virtual bool get_system_info(SubfileInfo &info);
public:
INLINE void set_original_filename(const Filename &filename);

View File

@ -143,7 +143,7 @@ close_read_file(istream *stream) const {
////////////////////////////////////////////////////////////////////
// Function: VirtualFileMount::get_system_info
// Access: Public, Virtual
// Description: Populates the FileSystemInfo structure with the data
// Description: Populates the SubfileInfo structure with the data
// representing where the file actually resides on disk,
// if this is knowable. Returns true if the file might
// reside on disk, and the info is populated, or false
@ -151,7 +151,7 @@ close_read_file(istream *stream) const {
// resides), in which case the info is meaningless.
////////////////////////////////////////////////////////////////////
bool VirtualFileMount::
get_system_info(const Filename &file, FileSystemInfo &info) {
get_system_info(const Filename &file, SubfileInfo &info) {
return false;
}

View File

@ -58,7 +58,7 @@ public:
virtual off_t get_file_size(const Filename &file, istream *stream) const=0;
virtual off_t get_file_size(const Filename &file) const=0;
virtual time_t get_timestamp(const Filename &file) const=0;
virtual bool get_system_info(const Filename &file, FileSystemInfo &info);
virtual bool get_system_info(const Filename &file, SubfileInfo &info);
virtual bool scan_directory(vector_string &contents,
const Filename &dir) const=0;

View File

@ -174,7 +174,7 @@ get_timestamp(const Filename &file) const {
////////////////////////////////////////////////////////////////////
// Function: VirtualFileMountMultifile::get_system_info
// Access: Public, Virtual
// Description: Populates the FileSystemInfo structure with the data
// Description: Populates the SubfileInfo structure with the data
// representing where the file actually resides on disk,
// if this is knowable. Returns true if the file might
// reside on disk, and the info is populated, or false
@ -182,7 +182,7 @@ get_timestamp(const Filename &file) const {
// resides), in which case the info is meaningless.
////////////////////////////////////////////////////////////////////
bool VirtualFileMountMultifile::
get_system_info(const Filename &file, FileSystemInfo &info) {
get_system_info(const Filename &file, SubfileInfo &info) {
Filename multifile_name = _multifile->get_multifile_name();
if (multifile_name.empty()) {
return false;
@ -199,7 +199,7 @@ get_system_info(const Filename &file, FileSystemInfo &info) {
streampos start = _multifile->get_subfile_internal_start(subfile_index);
size_t length = _multifile->get_subfile_internal_length(subfile_index);
info = FileSystemInfo(multifile_name.to_os_specific(), start, length);
info = SubfileInfo(multifile_name, start, length);
return true;
}

View File

@ -45,7 +45,7 @@ public:
virtual off_t get_file_size(const Filename &file, istream *stream) const;
virtual off_t get_file_size(const Filename &file) const;
virtual time_t get_timestamp(const Filename &file) const;
virtual bool get_system_info(const Filename &file, FileSystemInfo &info);
virtual bool get_system_info(const Filename &file, SubfileInfo &info);
virtual bool scan_directory(vector_string &contents,
const Filename &dir) const;

View File

@ -184,7 +184,7 @@ get_timestamp(const Filename &file) const {
////////////////////////////////////////////////////////////////////
// Function: VirtualFileMountSystem::get_system_info
// Access: Public, Virtual
// Description: Populates the FileSystemInfo structure with the data
// Description: Populates the SubfileInfo structure with the data
// representing where the file actually resides on disk,
// if this is knowable. Returns true if the file might
// reside on disk, and the info is populated, or false
@ -192,9 +192,9 @@ get_timestamp(const Filename &file) const {
// resides), in which case the info is meaningless.
////////////////////////////////////////////////////////////////////
bool VirtualFileMountSystem::
get_system_info(const Filename &file, FileSystemInfo &info) {
get_system_info(const Filename &file, SubfileInfo &info) {
Filename pathname(_physical_filename, file);
info = FileSystemInfo(pathname.to_os_specific(), 0, pathname.get_file_size());
info = SubfileInfo(pathname, 0, pathname.get_file_size());
return true;
}

View File

@ -39,7 +39,7 @@ public:
virtual off_t get_file_size(const Filename &file, istream *stream) const;
virtual off_t get_file_size(const Filename &file) const;
virtual time_t get_timestamp(const Filename &file) const;
virtual bool get_system_info(const Filename &file, FileSystemInfo &info);
virtual bool get_system_info(const Filename &file, SubfileInfo &info);
virtual bool scan_directory(vector_string &contents,
const Filename &dir) const;

View File

@ -163,7 +163,7 @@ get_timestamp() const {
////////////////////////////////////////////////////////////////////
// Function: VirtualFileSimple::get_system_info
// Access: Published, Virtual
// Description: Populates the FileSystemInfo structure with the data
// Description: Populates the SubfileInfo structure with the data
// representing where the file actually resides on disk,
// if this is knowable. Returns true if the file might
// reside on disk, and the info is populated, or false
@ -171,7 +171,7 @@ get_timestamp() const {
// resides), in which case the info is meaningless.
////////////////////////////////////////////////////////////////////
bool VirtualFileSimple::
get_system_info(FileSystemInfo &info) {
get_system_info(SubfileInfo &info) {
return _mount->get_system_info(_local_filename, info);
}

View File

@ -46,7 +46,7 @@ PUBLISHED:
virtual off_t get_file_size(istream *stream) const;
virtual off_t get_file_size() const;
virtual time_t get_timestamp() const;
virtual bool get_system_info(FileSystemInfo &info);
virtual bool get_system_info(SubfileInfo &info);
public:
virtual bool read_file(pvector<unsigned char> &result, bool auto_unwrap) const;

View File

@ -680,8 +680,12 @@ get_aux_data(const string &key) const {
// Description: Reads the texture from a Panda texture object. This
// defines the complete Texture specification, including
// the image data as well as all texture properties.
// This only works if the txo file contains a static
// Texture image, as opposed to a subclass of Texture
// such as a movie texture.
//
// The filename is just for reference.
// Pass a real filename if it is available, or empty
// string if it is not.
////////////////////////////////////////////////////////////////////
bool Texture::
read_txo(istream &in, const string &filename) {
@ -691,6 +695,79 @@ read_txo(istream &in, const string &filename) {
return do_read_txo(in, filename);
}
////////////////////////////////////////////////////////////////////
// Function: Texture::make_from_txo
// Access: Published, Static
// Description: Constructs a new Texture object from the txo file.
// This is similar to Texture::read_txo(), but it
// constructs and returns a new object, which allows it
// to return a subclass of Texture (for instance, a
// movie texture).
//
// Pass a real filename if it is available, or empty
// string if it is not.
////////////////////////////////////////////////////////////////////
PT(Texture) Texture::
make_from_txo(istream &in, const string &filename) {
DatagramInputFile din;
if (!din.open(in, filename)) {
gobj_cat.error()
<< "Could not read texture object: " << filename << "\n";
return NULL;
}
string head;
if (!din.read_header(head, _bam_header.size())) {
gobj_cat.error()
<< filename << " is not a texture object file.\n";
return NULL;
}
if (head != _bam_header) {
gobj_cat.error()
<< filename << " is not a texture object file.\n";
return NULL;
}
BamReader reader(&din);
if (!reader.init()) {
return NULL;
}
TypedWritable *object = reader.read_object();
if (object != (TypedWritable *)NULL &&
object->is_exact_type(BamCacheRecord::get_class_type())) {
// Here's a special case: if the first object in the file is a
// BamCacheRecord, it's really a cache data file and not a true
// txo file; but skip over the cache data record and let the user
// treat it like an ordinary txo file.
object = reader.read_object();
}
if (object == (TypedWritable *)NULL) {
gobj_cat.error()
<< "Texture object " << filename << " is empty.\n";
return NULL;
} else if (!object->is_of_type(Texture::get_class_type())) {
gobj_cat.error()
<< "Texture object " << filename << " contains a "
<< object->get_type() << ", not a Texture.\n";
return NULL;
}
PT(Texture) other = DCAST(Texture, object);
if (!reader.resolve()) {
gobj_cat.error()
<< "Unable to fully resolve texture object file.\n";
return NULL;
}
return other;
}
////////////////////////////////////////////////////////////////////
// Function: Texture::write_txo
// Access: Published
@ -990,6 +1067,20 @@ get_keep_ram_image() const {
return _keep_ram_image;
}
////////////////////////////////////////////////////////////////////
// Function: Texture::is_cacheable
// Access: Published, Virtual
// Description: Returns true if there is enough information in this
// Texture object to write it to the bam cache
// successfully, false otherwise. For most textures,
// this is the same as has_ram_image().
////////////////////////////////////////////////////////////////////
bool Texture::
is_cacheable() const {
MutexHolder holder(_lock);
return do_has_bam_rawdata();
}
////////////////////////////////////////////////////////////////////
// Function: Texture::get_num_loadable_ram_mipmap_images
// Access: Published
@ -3110,59 +3201,8 @@ do_read_txo_file(const Filename &fullpath) {
////////////////////////////////////////////////////////////////////
bool Texture::
do_read_txo(istream &in, const string &filename) {
DatagramInputFile din;
if (!din.open(in)) {
gobj_cat.error()
<< "Could not read texture object: " << filename << "\n";
return false;
}
string head;
if (!din.read_header(head, _bam_header.size())) {
gobj_cat.error()
<< filename << " is not a texture object file.\n";
return false;
}
if (head != _bam_header) {
gobj_cat.error()
<< filename << " is not a texture object file.\n";
return false;
}
BamReader reader(&din, filename);
if (!reader.init()) {
return false;
}
TypedWritable *object = reader.read_object();
if (object != (TypedWritable *)NULL &&
object->is_exact_type(BamCacheRecord::get_class_type())) {
// Here's a special case: if the first object in the file is a
// BamCacheRecord, it's really a cache data file and not a true
// txo file; but skip over the cache data record and let the user
// treat it like an ordinary txo file.
object = reader.read_object();
}
if (object == (TypedWritable *)NULL) {
gobj_cat.error()
<< "Texture object " << filename << " is empty.\n";
return false;
} else if (!object->is_of_type(Texture::get_class_type())) {
gobj_cat.error()
<< "Texture object " << filename << " contains a "
<< object->get_type() << ", not a Texture.\n";
return false;
}
PT(Texture) other = DCAST(Texture, object);
if (!reader.resolve()) {
gobj_cat.error()
<< "Unable to fully resolve texture object file.\n";
PT(Texture) other = make_from_txo(in, filename);
if (other == (Texture *)NULL) {
return false;
}
@ -3506,10 +3546,10 @@ do_read_dds(istream &in, const string &filename, bool header_only) {
bool Texture::
do_write(const Filename &fullpath, int z, int n, bool write_pages, bool write_mipmaps) const {
if (is_txo_filename(fullpath)) {
if (!do_has_ram_image()) {
((Texture *)this)->do_get_ram_image();
if (!do_has_bam_rawdata()) {
((Texture *)this)->do_get_bam_rawdata();
}
nassertr(do_has_ram_image(), false);
nassertr(do_has_bam_rawdata(), false);
return do_write_txo_file(fullpath);
}
@ -3671,7 +3711,7 @@ bool Texture::
do_write_txo(ostream &out, const string &filename) const {
DatagramOutputFile dout;
if (!dout.open(out)) {
if (!dout.open(out, filename)) {
gobj_cat.error()
<< "Could not write texture object: " << filename << "\n";
return false;
@ -3683,7 +3723,7 @@ do_write_txo(ostream &out, const string &filename) const {
return false;
}
BamWriter writer(&dout, filename);
BamWriter writer(&dout);
if (!writer.init()) {
return false;
}
@ -3700,7 +3740,7 @@ do_write_txo(ostream &out, const string &filename) const {
}
_lock.acquire();
if (!do_has_ram_image()) {
if (!do_has_bam_rawdata()) {
gobj_cat.error()
<< get_name() << " does not have ram image\n";
return false;
@ -5368,6 +5408,31 @@ do_reload() {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: Texture::do_has_bam_rawdata
// Access: Protected, Virtual
// Description: Returns true if there is a rawdata image that we have
// available to write to the bam stream. For a normal
// Texture, this is the same thing as
// do_has_ram_image(), but a movie texture might define
// it differently.
////////////////////////////////////////////////////////////////////
bool Texture::
do_has_bam_rawdata() const {
return do_has_ram_image();
}
////////////////////////////////////////////////////////////////////
// Function: Texture::do_get_bam_rawdata
// Access: Protected, Virtual
// Description: If do_has_bam_rawdata() returned false, this attempts
// to reload the rawdata image if possible.
////////////////////////////////////////////////////////////////////
void Texture::
do_get_bam_rawdata() {
do_get_ram_image();
}
////////////////////////////////////////////////////////////////////
// Function: Texture::convert_from_pnmimage
// Access: Private, Static
@ -6727,277 +6792,9 @@ register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
////////////////////////////////////////////////////////////////////
// Function: Texture::make_from_bam
// Access: Protected, Static
// Description: Factory method to generate a Texture object
////////////////////////////////////////////////////////////////////
TypedWritable *Texture::
make_from_bam(const FactoryParams &params) {
// The process of making a texture is slightly different than making
// other TypedWritable objects. That is because all creation of
// Textures should be done through calls to TexturePool, which
// ensures that any loads of the same filename refer to the same
// memory.
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
// Get the filenames and texture type so we can look up the file on
// disk first.
string name = scan.get_string();
Filename filename = scan.get_string();
Filename alpha_filename = scan.get_string();
int primary_file_num_channels = scan.get_uint8();
int alpha_file_channel = scan.get_uint8();
bool has_rawdata = scan.get_bool();
TextureType texture_type = (TextureType)scan.get_uint8();
Texture *me = NULL;
if (has_rawdata) {
// If the raw image data is included, then just create a Texture
// and don't load from the file.
me = new Texture(name);
me->_filename = filename;
me->_alpha_filename = alpha_filename;
me->_primary_file_num_channels = primary_file_num_channels;
me->_alpha_file_channel = alpha_file_channel;
me->_texture_type = texture_type;
// Read the texture attributes directly from the bam stream.
me->fillin(scan, manager, has_rawdata);
} else {
// Now create a temporary Texture object to read all the
// attributes from the bam stream.
PT(Texture) dummy = new Texture("");
dummy->fillin(scan, manager, has_rawdata);
if (filename.empty()) {
// This texture has no filename; since we don't have an image to
// load, we can't actually create the texture.
gobj_cat.info()
<< "Cannot create texture '" << name << "' with no filename.\n";
} else {
// This texture does have a filename, so try to load it from disk.
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
if (!manager->get_filename().empty()) {
// If texture filename was given relative to the bam filename,
// expand it now.
Filename bam_dir = manager->get_filename().get_dirname();
vfs->resolve_filename(filename, bam_dir);
if (!alpha_filename.empty()) {
vfs->resolve_filename(alpha_filename, bam_dir);
}
}
LoaderOptions options = manager->get_loader_options();
if (dummy->uses_mipmaps()) {
options.set_texture_flags(options.get_texture_flags() | LoaderOptions::TF_generate_mipmaps);
}
switch (texture_type) {
case TT_1d_texture:
case TT_2d_texture:
if (alpha_filename.empty()) {
me = TexturePool::load_texture(filename, primary_file_num_channels,
false, options);
} else {
me = TexturePool::load_texture(filename, alpha_filename,
primary_file_num_channels,
alpha_file_channel,
false, options);
}
break;
case TT_3d_texture:
me = TexturePool::load_3d_texture(filename, false, options);
break;
case TT_2d_texture_array:
me = TexturePool::load_2d_texture_array(filename, false, options);
break;
case TT_cube_map:
me = TexturePool::load_cube_map(filename, false, options);
break;
}
}
if (me != (Texture *)NULL) {
me->fillin_from(dummy);
me->set_name(name);
}
}
return me;
}
////////////////////////////////////////////////////////////////////
// Function: Texture::fillin
// Access: Protected
// Description: Function that reads out of the datagram (or asks
// manager to read) all of the data that is needed to
// re-create this object and stores it in the appropiate
// place
////////////////////////////////////////////////////////////////////
void Texture::
fillin(DatagramIterator &scan, BamReader *manager, bool has_rawdata) {
// We have already read in the filenames; don't read them again.
_wrap_u = (WrapMode)scan.get_uint8();
_wrap_v = (WrapMode)scan.get_uint8();
_wrap_w = (WrapMode)scan.get_uint8();
_minfilter = (FilterType)scan.get_uint8();
_magfilter = (FilterType)scan.get_uint8();
_anisotropic_degree = scan.get_int16();
_border_color.read_datagram(scan);
if (manager->get_file_minor_ver() >= 1) {
_compression = (CompressionMode)scan.get_uint8();
}
if (manager->get_file_minor_ver() >= 16) {
_quality_level = (QualityLevel)scan.get_uint8();
}
_format = (Format)scan.get_uint8();
_num_components = scan.get_uint8();
++_properties_modified;
bool has_simple_ram_image = false;
if (manager->get_file_minor_ver() >= 18) {
_orig_file_x_size = scan.get_uint32();
_orig_file_y_size = scan.get_uint32();
has_simple_ram_image = scan.get_bool();
}
if (has_simple_ram_image) {
_simple_x_size = scan.get_uint32();
_simple_y_size = scan.get_uint32();
_simple_image_date_generated = scan.get_int32();
size_t u_size = scan.get_uint32();
PTA_uchar image = PTA_uchar::empty_array(u_size, get_class_type());
for (size_t u_idx = 0; u_idx < u_size; ++u_idx) {
image[(int)u_idx] = scan.get_uint8();
}
_simple_ram_image._image = image;
_simple_ram_image._page_size = u_size;
++_simple_image_modified;
}
if (has_rawdata) {
_x_size = scan.get_uint32();
_y_size = scan.get_uint32();
_z_size = scan.get_uint32();
_component_type = (ComponentType)scan.get_uint8();
_component_width = scan.get_uint8();
_ram_image_compression = CM_off;
if (manager->get_file_minor_ver() >= 1) {
_ram_image_compression = (CompressionMode)scan.get_uint8();
}
int num_ram_images = 1;
if (manager->get_file_minor_ver() >= 3) {
num_ram_images = scan.get_uint8();
}
_ram_images.clear();
_ram_images.reserve(num_ram_images);
for (int n = 0; n < num_ram_images; ++n) {
_ram_images.push_back(RamImage());
_ram_images[n]._page_size = get_expected_ram_page_size();
if (manager->get_file_minor_ver() >= 1) {
_ram_images[n]._page_size = scan.get_uint32();
}
size_t u_size = scan.get_uint32();
// fill the _image buffer with image data
PTA_uchar image = PTA_uchar::empty_array(u_size, get_class_type());
for (size_t u_idx = 0; u_idx < u_size; ++u_idx) {
image[(int)u_idx] = scan.get_uint8();
}
_ram_images[n]._image = image;
}
_loaded_from_image = true;
do_set_pad_size(0, 0, 0);
++_image_modified;
}
}
////////////////////////////////////////////////////////////////////
// Function: Texture::fillin_from
// Access: Protected
// Description: Called in make_from_bam(), this method properly
// copies the attributes from the bam stream (as stored
// in dummy) into this texture, updating the modified
// flags appropriately.
////////////////////////////////////////////////////////////////////
void Texture::
fillin_from(Texture *dummy) {
MutexHolder holder(_lock);
// Use the setters instead of setting these directly, so we can
// correctly avoid incrementing _properties_modified if none of
// these actually change. (Otherwise, we'd have to reload the
// texture to the GSG every time we loaded a new bam file that
// reference the texture, since each bam file reference passes
// through this function.)
do_set_wrap_u(dummy->get_wrap_u());
do_set_wrap_v(dummy->get_wrap_v());
do_set_wrap_w(dummy->get_wrap_w());
do_set_border_color(dummy->get_border_color());
if (dummy->get_minfilter() != FT_default) {
do_set_minfilter(dummy->get_minfilter());
}
if (dummy->get_magfilter() != FT_default) {
do_set_magfilter(dummy->get_magfilter());
}
if (dummy->get_anisotropic_degree() != 0) {
do_set_anisotropic_degree(dummy->get_anisotropic_degree());
}
if (dummy->get_compression() != CM_default) {
do_set_compression(dummy->get_compression());
}
if (dummy->get_quality_level() != QL_default) {
do_set_quality_level(dummy->get_quality_level());
}
Format format = dummy->get_format();
int num_components = dummy->get_num_components();
if (num_components == _num_components) {
// Only reset the format if the number of components hasn't
// changed, since if the number of components has changed our
// texture no longer matches what it was when the bam was
// written.
do_set_format(format);
}
if (dummy->has_simple_ram_image()) {
// Only replace the simple ram image if it was generated more
// recently than the one we already have.
if (_simple_ram_image._image.empty() ||
dummy->_simple_image_date_generated > _simple_image_date_generated) {
do_set_simple_ram_image(dummy->get_simple_ram_image(),
dummy->get_simple_x_size(),
dummy->get_simple_y_size());
_simple_image_date_generated = dummy->_simple_image_date_generated;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: Texture::write_datagram
// Access: Public
// Access: Public, Virtual
// Description: Function to write the important information in
// the particular object to a Datagram
////////////////////////////////////////////////////////////////////
@ -7005,6 +6802,61 @@ void Texture::
write_datagram(BamWriter *manager, Datagram &me) {
MutexHolder holder(_lock);
bool has_rawdata = false;
do_write_datagram_header(manager, me, has_rawdata);
do_write_datagram_body(manager, me);
// If we are also including the texture's image data, then stuff it
// in here.
if (has_rawdata) {
do_write_datagram_rawdata(manager, me);
}
}
////////////////////////////////////////////////////////////////////
// Function: Texture::finalize
// Access: Public, Virtual
// Description: Called by the BamReader to perform any final actions
// needed for setting up the object after all objects
// have been read and all pointers have been completed.
////////////////////////////////////////////////////////////////////
void Texture::
finalize(BamReader *) {
// Unref the pointer that we explicitly reffed in make_from_bam().
unref();
// We should never get back to zero after unreffing our own count,
// because we expect to have been stored in a pointer somewhere. If
// we do get to zero, it's a memory leak; the way to avoid this is
// to call unref_delete() above instead of unref(), but this is
// dangerous to do from within a virtual function.
nassertv(get_ref_count() != 0);
}
////////////////////////////////////////////////////////////////////
// Function: Texture::do_write_datagram_header
// Access: Protected
// Description: Writes the header part of the texture to the
// Datagram. This is the common part that is shared by
// all Texture subclasses, and contains the filename and
// rawdata flags. This method is not virtual because
// all Texture subclasses must write the same data at
// this step.
//
// This part must be read first before calling
// do_fillin_body() to determine whether to load the
// Texture from the TexturePool or directly from the bam
// stream.
//
// After this call, has_rawdata will be filled with
// either true or false, according to whether we expect
// to write the texture rawdata to the bam stream
// following the texture body.
////////////////////////////////////////////////////////////////////
void Texture::
do_write_datagram_header(BamWriter *manager, Datagram &me, bool &has_rawdata) {
// Write out the texture's raw pixel data if (a) the current Bam
// Texture Mode requires that, or (b) there's no filename, so the
// file can't be loaded up from disk, but the raw pixel data is
@ -7014,11 +6866,11 @@ write_datagram(BamWriter *manager, Datagram &me) {
// loads the bam file later will have access to the image file on
// disk.
BamWriter::BamTextureMode file_texture_mode = manager->get_file_texture_mode();
bool has_rawdata =
(file_texture_mode == BamWriter::BTM_rawdata || (do_has_ram_image() && _filename.empty()));
if (has_rawdata && !do_has_ram_image()) {
do_get_ram_image();
if (!do_has_ram_image()) {
has_rawdata = (file_texture_mode == BamWriter::BTM_rawdata ||
(_filename.empty() && do_has_bam_rawdata()));
if (has_rawdata && !do_has_bam_rawdata()) {
do_get_bam_rawdata();
if (!do_has_bam_rawdata()) {
// No image data after all.
has_rawdata = false;
}
@ -7073,7 +6925,7 @@ write_datagram(BamWriter *manager, Datagram &me) {
<< "Unsupported bam-texture-mode: " << (int)file_texture_mode << "\n";
}
if (filename.empty() && do_has_ram_image()) {
if (filename.empty() && do_has_bam_rawdata()) {
// If we don't have a filename, we have to store rawdata anyway.
has_rawdata = true;
}
@ -7085,8 +6937,17 @@ write_datagram(BamWriter *manager, Datagram &me) {
me.add_uint8(_alpha_file_channel);
me.add_bool(has_rawdata);
me.add_uint8(_texture_type);
}
// The data beginning at this point is handled by fillin().
////////////////////////////////////////////////////////////////////
// Function: Texture::do_write_datagram_body
// Access: Protected, Virtual
// Description: Writes the body part of the texture to the
// Datagram. This is generally all of the texture
// parameters except for the header and the rawdata.
////////////////////////////////////////////////////////////////////
void Texture::
do_write_datagram_body(BamWriter *manager, Datagram &me) {
me.add_uint8(_wrap_u);
me.add_uint8(_wrap_v);
me.add_uint8(_wrap_w);
@ -7114,21 +6975,330 @@ write_datagram(BamWriter *manager, Datagram &me) {
me.add_uint32(_simple_ram_image._image.size());
me.append_data(_simple_ram_image._image, _simple_ram_image._image.size());
}
}
// If we are also including the texture's image data, then stuff it
// in here.
////////////////////////////////////////////////////////////////////
// Function: Texture::do_write_datagram_rawdata
// Access: Protected, Virtual
// Description: Writes the rawdata part of the texture to the
// Datagram.
////////////////////////////////////////////////////////////////////
void Texture::
do_write_datagram_rawdata(BamWriter *manager, Datagram &me) {
me.add_uint32(_x_size);
me.add_uint32(_y_size);
me.add_uint32(_z_size);
me.add_uint8(_component_type);
me.add_uint8(_component_width);
me.add_uint8(_ram_image_compression);
me.add_uint8(_ram_images.size());
for (size_t n = 0; n < _ram_images.size(); ++n) {
me.add_uint32(_ram_images[n]._page_size);
me.add_uint32(_ram_images[n]._image.size());
me.append_data(_ram_images[n]._image, _ram_images[n]._image.size());
}
}
////////////////////////////////////////////////////////////////////
// Function: Texture::make_from_bam
// Access: Protected, Static
// Description: Factory method to generate a Texture object
////////////////////////////////////////////////////////////////////
TypedWritable *Texture::
make_from_bam(const FactoryParams &params) {
PT(Texture) dummy = new Texture;
return dummy->make_this_from_bam(params);
}
////////////////////////////////////////////////////////////////////
// Function: Texture::make_this_from_bam
// Access: Protected, Virtual
// Description: Called by make_from_bam() once the particular
// subclass of Texture is known. This is called on a
// newly-constructed Texture object of the appropriate
// subclass. It will return either the same Texture
// object (e.g. this), or a different Texture object
// loaded via the TexturePool, as appropriate.
////////////////////////////////////////////////////////////////////
TypedWritable *Texture::
make_this_from_bam(const FactoryParams &params) {
// The process of making a texture is slightly different than making
// other TypedWritable objects. That is because all creation of
// Textures should be done through calls to TexturePool, which
// ensures that any loads of the same filename refer to the same
// memory.
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
// Get the header information--the filenames and texture type--so we
// can look up the file on disk first.
string name = scan.get_string();
Filename filename = scan.get_string();
Filename alpha_filename = scan.get_string();
int primary_file_num_channels = scan.get_uint8();
int alpha_file_channel = scan.get_uint8();
bool has_rawdata = scan.get_bool();
TextureType texture_type = (TextureType)scan.get_uint8();
Texture *me = NULL;
if (has_rawdata) {
me.add_uint32(_x_size);
me.add_uint32(_y_size);
me.add_uint32(_z_size);
me.add_uint8(_component_type);
me.add_uint8(_component_width);
me.add_uint8(_ram_image_compression);
me.add_uint8(_ram_images.size());
for (size_t n = 0; n < _ram_images.size(); ++n) {
me.add_uint32(_ram_images[n]._page_size);
me.add_uint32(_ram_images[n]._image.size());
me.append_data(_ram_images[n]._image, _ram_images[n]._image.size());
// If the raw image data is included, then just load the texture
// directly from the stream, and return it. In this case we
// return the "this" pointer, since it's a newly-created Texture
// object of the appropriate type.
me = this;
me->set_name(name);
me->_filename = filename;
me->_alpha_filename = alpha_filename;
me->_primary_file_num_channels = primary_file_num_channels;
me->_alpha_file_channel = alpha_file_channel;
me->_texture_type = texture_type;
// Read the texture attributes directly from the bam stream.
me->do_fillin_body(scan, manager);
me->do_fillin_rawdata(scan, manager);
// To manage the reference count, explicitly ref it now, then
// unref it in the finalize callback.
me->ref();
manager->register_finalize(me);
} else {
// The raw image data isn't included, so we'll be loading the
// Texture via the TexturePool. In this case we use the "this"
// pointer as a temporary object to read all of the attributes
// from the bam stream.
Texture *dummy = this;
dummy->do_fillin_body(scan, manager);
if (filename.empty()) {
// This texture has no filename; since we don't have an image to
// load, we can't actually create the texture.
gobj_cat.info()
<< "Cannot create texture '" << name << "' with no filename.\n";
} else {
// This texture does have a filename, so try to load it from disk.
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
if (!manager->get_filename().empty()) {
// If texture filename was given relative to the bam filename,
// expand it now.
Filename bam_dir = manager->get_filename().get_dirname();
vfs->resolve_filename(filename, bam_dir);
if (!alpha_filename.empty()) {
vfs->resolve_filename(alpha_filename, bam_dir);
}
}
LoaderOptions options = manager->get_loader_options();
if (dummy->uses_mipmaps()) {
options.set_texture_flags(options.get_texture_flags() | LoaderOptions::TF_generate_mipmaps);
}
switch (texture_type) {
case TT_1d_texture:
case TT_2d_texture:
if (alpha_filename.empty()) {
me = TexturePool::load_texture(filename, primary_file_num_channels,
false, options);
} else {
me = TexturePool::load_texture(filename, alpha_filename,
primary_file_num_channels,
alpha_file_channel,
false, options);
}
break;
case TT_3d_texture:
me = TexturePool::load_3d_texture(filename, false, options);
break;
case TT_2d_texture_array:
me = TexturePool::load_2d_texture_array(filename, false, options);
break;
case TT_cube_map:
me = TexturePool::load_cube_map(filename, false, options);
break;
}
}
if (me != (Texture *)NULL) {
{
MutexHolder holder(me->_lock);
me->do_fillin_from(dummy);
}
me->set_name(name);
// Since in this case me was loaded from the TexturePool,
// there's no need to explicitly manage the reference count.
// TexturePool will hold it safely.
}
}
return me;
}
////////////////////////////////////////////////////////////////////
// Function: Texture::do_fillin_body
// Access: Protected, Virtual
// Description: Reads in the part of the Texture that was written
// with do_write_datagram_body().
////////////////////////////////////////////////////////////////////
void Texture::
do_fillin_body(DatagramIterator &scan, BamReader *manager) {
_wrap_u = (WrapMode)scan.get_uint8();
_wrap_v = (WrapMode)scan.get_uint8();
_wrap_w = (WrapMode)scan.get_uint8();
_minfilter = (FilterType)scan.get_uint8();
_magfilter = (FilterType)scan.get_uint8();
_anisotropic_degree = scan.get_int16();
_border_color.read_datagram(scan);
if (manager->get_file_minor_ver() >= 1) {
_compression = (CompressionMode)scan.get_uint8();
}
if (manager->get_file_minor_ver() >= 16) {
_quality_level = (QualityLevel)scan.get_uint8();
}
_format = (Format)scan.get_uint8();
_num_components = scan.get_uint8();
++_properties_modified;
bool has_simple_ram_image = false;
if (manager->get_file_minor_ver() >= 18) {
_orig_file_x_size = scan.get_uint32();
_orig_file_y_size = scan.get_uint32();
has_simple_ram_image = scan.get_bool();
}
if (has_simple_ram_image) {
_simple_x_size = scan.get_uint32();
_simple_y_size = scan.get_uint32();
_simple_image_date_generated = scan.get_int32();
size_t u_size = scan.get_uint32();
PTA_uchar image = PTA_uchar::empty_array(u_size, get_class_type());
for (size_t u_idx = 0; u_idx < u_size; ++u_idx) {
image[(int)u_idx] = scan.get_uint8();
}
_simple_ram_image._image = image;
_simple_ram_image._page_size = u_size;
++_simple_image_modified;
}
}
////////////////////////////////////////////////////////////////////
// Function: Texture::do_fillin_rawdata
// Access: Protected, Virtual
// Description: Reads in the part of the Texture that was written
// with do_write_datagram_rawdata().
////////////////////////////////////////////////////////////////////
void Texture::
do_fillin_rawdata(DatagramIterator &scan, BamReader *manager) {
_x_size = scan.get_uint32();
_y_size = scan.get_uint32();
_z_size = scan.get_uint32();
_component_type = (ComponentType)scan.get_uint8();
_component_width = scan.get_uint8();
_ram_image_compression = CM_off;
if (manager->get_file_minor_ver() >= 1) {
_ram_image_compression = (CompressionMode)scan.get_uint8();
}
int num_ram_images = 1;
if (manager->get_file_minor_ver() >= 3) {
num_ram_images = scan.get_uint8();
}
_ram_images.clear();
_ram_images.reserve(num_ram_images);
for (int n = 0; n < num_ram_images; ++n) {
_ram_images.push_back(RamImage());
_ram_images[n]._page_size = get_expected_ram_page_size();
if (manager->get_file_minor_ver() >= 1) {
_ram_images[n]._page_size = scan.get_uint32();
}
size_t u_size = scan.get_uint32();
// fill the _image buffer with image data
PTA_uchar image = PTA_uchar::empty_array(u_size, get_class_type());
for (size_t u_idx = 0; u_idx < u_size; ++u_idx) {
image[(int)u_idx] = scan.get_uint8();
}
_ram_images[n]._image = image;
}
_loaded_from_image = true;
do_set_pad_size(0, 0, 0);
++_image_modified;
}
////////////////////////////////////////////////////////////////////
// Function: Texture::do_fillin_from
// Access: Protected, Virtual
// Description: Called in make_from_bam(), this method properly
// copies the attributes from the bam stream (as stored
// in dummy) into this texture, updating the modified
// flags appropriately.
////////////////////////////////////////////////////////////////////
void Texture::
do_fillin_from(Texture *dummy) {
// Use the setters instead of setting these directly, so we can
// correctly avoid incrementing _properties_modified if none of
// these actually change. (Otherwise, we'd have to reload the
// texture to the GSG every time we loaded a new bam file that
// reference the texture, since each bam file reference passes
// through this function.)
do_set_wrap_u(dummy->get_wrap_u());
do_set_wrap_v(dummy->get_wrap_v());
do_set_wrap_w(dummy->get_wrap_w());
do_set_border_color(dummy->get_border_color());
if (dummy->get_minfilter() != FT_default) {
do_set_minfilter(dummy->get_minfilter());
}
if (dummy->get_magfilter() != FT_default) {
do_set_magfilter(dummy->get_magfilter());
}
if (dummy->get_anisotropic_degree() != 0) {
do_set_anisotropic_degree(dummy->get_anisotropic_degree());
}
if (dummy->get_compression() != CM_default) {
do_set_compression(dummy->get_compression());
}
if (dummy->get_quality_level() != QL_default) {
do_set_quality_level(dummy->get_quality_level());
}
Format format = dummy->get_format();
int num_components = dummy->get_num_components();
if (num_components == _num_components) {
// Only reset the format if the number of components hasn't
// changed, since if the number of components has changed our
// texture no longer matches what it was when the bam was
// written.
do_set_format(format);
}
if (dummy->has_simple_ram_image()) {
// Only replace the simple ram image if it was generated more
// recently than the one we already have.
if (_simple_ram_image._image.empty() ||
dummy->_simple_image_date_generated > _simple_image_date_generated) {
do_set_simple_ram_image(dummy->get_simple_ram_image(),
dummy->get_simple_x_size(),
dummy->get_simple_y_size());
_simple_image_date_generated = dummy->_simple_image_date_generated;
}
}
}

View File

@ -63,6 +63,8 @@ struct DDSHeader;
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_GOBJ Texture : public TypedWritableReferenceCount, public Namable {
PUBLISHED:
typedef PT(Texture) MakeTextureFunc();
enum TextureType {
TT_1d_texture,
TT_2d_texture,
@ -244,9 +246,10 @@ PUBLISHED:
INLINE bool write(const Filename &fullpath, int z, int n,
bool write_pages, bool write_mipmaps);
bool read_txo(istream &in, const string &filename = "stream");
bool write_txo(ostream &out, const string &filename = "stream") const;
bool read_dds(istream &in, const string &filename = "stream", bool header_only = false);
bool read_txo(istream &in, const string &filename = "");
static PT(Texture) make_from_txo(istream &in, const string &filename = "");
bool write_txo(ostream &out, const string &filename = "") const;
bool read_dds(istream &in, const string &filename = "", bool header_only = false);
INLINE bool load(const PNMImage &pnmimage, const LoaderOptions &options = LoaderOptions());
INLINE bool load(const PNMImage &pnmimage, int z, int n, const LoaderOptions &options = LoaderOptions());
@ -328,6 +331,7 @@ PUBLISHED:
INLINE void clear_ram_image();
INLINE void set_keep_ram_image(bool keep_ram_image);
virtual bool get_keep_ram_image() const;
virtual bool is_cacheable() const;
INLINE bool compress_ram_image(CompressionMode compression = CM_on,
QualityLevel quality_level = QL_default,
@ -589,6 +593,9 @@ protected:
virtual bool do_can_reload();
bool do_reload();
virtual bool do_has_bam_rawdata() const;
virtual void do_get_bam_rawdata();
// This nested class declaration is used below.
class RamImage {
public:
@ -790,10 +797,17 @@ public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &me);
virtual void finalize(BamReader *manager);
protected:
void do_write_datagram_header(BamWriter *manager, Datagram &me, bool &has_rawdata);
virtual void do_write_datagram_body(BamWriter *manager, Datagram &me);
virtual void do_write_datagram_rawdata(BamWriter *manager, Datagram &me);
static TypedWritable *make_from_bam(const FactoryParams &params);
void fillin(DatagramIterator &scan, BamReader *manager, bool has_rawdata);
void fillin_from(Texture *dummy);
virtual TypedWritable *make_this_from_bam(const FactoryParams &params);
virtual void do_fillin_body(DatagramIterator &scan, BamReader *manager);
virtual void do_fillin_rawdata(DatagramIterator &scan, BamReader *manager);
virtual void do_fillin_from(Texture *dummy);
public:
static TypeHandle get_class_type() {

View File

@ -264,12 +264,48 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
// cache; it needs to be loaded from its source image(s).
gobj_cat.info()
<< "Loading texture " << filename << "\n";
tex = make_texture(filename.get_extension());
if (!tex->read(filename, Filename(), primary_file_num_channels, 0,
0, 0, false, read_mipmaps, record, options)) {
// This texture was not found or could not be read.
report_texture_unreadable(filename);
return NULL;
string ext = downcase(filename.get_extension());
if (ext == "txo" || ext == "bam") {
// Assume this is a txo file, which might conceivably contain a
// movie file or some other subclass of Texture. In that case,
// use make_from_txo() to load it instead of read().
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
filename.set_binary();
PT(VirtualFile) file = vfs->get_file(filename);
if (file == (VirtualFile *)NULL) {
// No such file.
gobj_cat.error()
<< "Could not find " << filename << "\n";
return false;
}
if (gobj_cat.is_debug()) {
gobj_cat.debug()
<< "Reading texture object " << filename << "\n";
}
istream *in = file->open_read_file(true);
tex = Texture::make_from_txo(*in, filename);
vfs->close_read_file(in);
if (tex == (Texture *)NULL) {
return false;
}
tex->set_fullpath(filename);
tex->clear_alpha_fullpath();
tex->set_keep_ram_image(false);
} else {
// Read it the conventional way.
tex = make_texture(ext);
if (!tex->read(filename, Filename(), primary_file_num_channels, 0,
0, 0, false, read_mipmaps, record, options)) {
// This texture was not found or could not be read.
report_texture_unreadable(filename);
return NULL;
}
}
if (options.get_texture_flags() & LoaderOptions::TF_preload_simple) {
@ -322,7 +358,7 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
_textures[filename] = tex;
}
if (store_record && tex->has_ram_image()) {
if (store_record && tex->is_cacheable()) {
// Store the on-disk cache record for next time.
record->set_data(tex, tex);
cache->store(record);
@ -454,7 +490,7 @@ ns_load_texture(const Filename &orig_filename,
_textures[filename] = tex;
}
if (store_record && tex->has_ram_image()) {
if (store_record && tex->is_cacheable()) {
// Store the on-disk cache record for next time.
record->set_data(tex, tex);
cache->store(record);
@ -566,7 +602,7 @@ ns_load_3d_texture(const Filename &filename_pattern,
_textures[filename] = tex;
}
if (store_record && tex->has_ram_image()) {
if (store_record && tex->is_cacheable()) {
// Store the on-disk cache record for next time.
record->set_data(tex, tex);
cache->store(record);
@ -672,7 +708,7 @@ ns_load_2d_texture_array(const Filename &filename_pattern,
_textures[unique_filename] = tex;
}
if (store_record && tex->has_ram_image()) {
if (store_record && tex->is_cacheable()) {
// Store the on-disk cache record for next time.
record->set_data(tex, tex);
cache->store(record);
@ -771,7 +807,7 @@ ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps,
_textures[filename] = tex;
}
if (store_record && tex->has_ram_image()) {
if (store_record && tex->is_cacheable()) {
// Store the on-disk cache record for next time.
record->set_data(tex, tex);
cache->store(record);

View File

@ -85,7 +85,7 @@ PUBLISHED:
static void write(ostream &out);
public:
typedef PT(Texture) MakeTextureFunc();
typedef Texture::MakeTextureFunc MakeTextureFunc;
void register_texture_type(MakeTextureFunc *func, const string &extensions);
void register_filter(TexturePoolFilter *filter);

View File

@ -51,7 +51,8 @@ VideoPage() {
////////////////////////////////////////////////////////////////////
INLINE FFMpegTexture::VideoPage::
VideoPage(const FFMpegTexture::VideoPage &copy) :
_color(copy._color)
_color(copy._color),
_alpha(copy._alpha)
{
}
@ -63,3 +64,14 @@ VideoPage(const FFMpegTexture::VideoPage &copy) :
INLINE FFMpegTexture::VideoPage::
~VideoPage() {
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::VideoPage::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void FFMpegTexture::VideoPage::
operator = (const FFMpegTexture::VideoPage &copy) {
_color = copy._color;
_alpha = copy._alpha;
}

View File

@ -21,6 +21,7 @@
#include "config_grutil.h"
#include "bamCacheRecord.h"
#include "bamReader.h"
#include "bamWriter.h"
TypeHandle FFMpegTexture::_type_handle;
@ -96,7 +97,7 @@ do_assign(const FFMpegTexture &copy) {
}
////////////////////////////////////////////////////////////////////
// Function: FFMPegTexture::modify_page
// Function: FFMpegTexture::modify_page
// Access: Private
// Description: Returns a reference to the zth VideoPage (level) of
// the texture. In the case of a 2-d texture, there is
@ -142,8 +143,8 @@ do_reconsider_video_properties(const FFMpegTexture::VideoStream &stream,
num_frames = (int)((stream._format_context->duration*frame_rate)/AV_TIME_BASE);
if (grutil_cat.is_debug()) {
grutil_cat.debug()
<< "Loaded " << stream._filename << ", " << num_frames << " frames at "
<< frame_rate << " fps\n";
<< "Loaded " << stream._filename << ", "
<< num_frames << " frames at " << frame_rate << " fps\n";
}
}
@ -202,7 +203,7 @@ make_texture() {
}
////////////////////////////////////////////////////////////////////
// Function: FFMPegTexture::update_frame
// Function: FFMpegTexture::update_frame
// Access: Protected, Virtual
// Description: Called once per frame, as needed, to load the new
// image contents.
@ -419,6 +420,30 @@ do_load_one(const PNMImage &pnmimage, const string &name, int z, int n,
return Texture::do_load_one(pnmimage, name, z, n, options);
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::do_has_bam_rawdata
// Access: Protected, Virtual
// Description: Returns true if there is a rawdata image that we have
// available to write to the bam stream. For a normal
// Texture, this is the same thing as
// do_has_ram_image(), but a movie texture might define
// it differently.
////////////////////////////////////////////////////////////////////
bool FFMpegTexture::
do_has_bam_rawdata() const {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::do_get_bam_rawdata
// Access: Protected, Virtual
// Description: If do_has_bam_rawdata() returned false, this attempts
// to reload the rawdata image if possible.
////////////////////////////////////////////////////////////////////
void FFMpegTexture::
do_get_bam_rawdata() {
}
@ -429,20 +454,77 @@ do_load_one(const PNMImage &pnmimage, const string &name, int z, int n,
////////////////////////////////////////////////////////////////////
void FFMpegTexture::
register_with_read_factory() {
// Since Texture is such a funny object that is reloaded from the
// TexturePool each time, instead of actually being read fully from
// the bam file, and since the VideoTexture and FFMpegTexture
// classes don't really add any useful data to the bam record, we
// don't need to define make_from_bam(), fillin(), or
// write_datagram() in this class--we just inherit the same
// functions from Texture.
// We do, however, have to register this class with the BamReader,
// to avoid warnings about creating the wrong kind of object from
// the bam file.
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::make_from_bam
// Access: Protected, Static
// Description: Factory method to generate an FFMpegTexture object
////////////////////////////////////////////////////////////////////
TypedWritable *FFMpegTexture::
make_from_bam(const FactoryParams &params) {
PT(FFMpegTexture) dummy = new FFMpegTexture;
return dummy->make_this_from_bam(params);
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::do_write_datagram_rawdata
// Access: Protected, Virtual
// Description: Writes the rawdata part of the texture to the
// Datagram.
////////////////////////////////////////////////////////////////////
void FFMpegTexture::
do_write_datagram_rawdata(BamWriter *manager, Datagram &me) {
me.add_uint32(_x_size);
me.add_uint32(_y_size);
me.add_uint32(_z_size);
me.add_uint8(_component_type);
me.add_uint8(_component_width);
me.add_uint8(_ram_image_compression);
me.add_uint16(_pages.size());
for (size_t n = 0; n < _pages.size(); ++n) {
VideoPage &page = _pages[n];
page.write_datagram_rawdata(manager, me);
}
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::do_fillin_rawdata
// Access: Protected, Virtual
// Description: Reads in the part of the Texture that was written
// with do_write_datagram_rawdata().
////////////////////////////////////////////////////////////////////
void FFMpegTexture::
do_fillin_rawdata(DatagramIterator &scan, BamReader *manager) {
_x_size = scan.get_uint32();
_y_size = scan.get_uint32();
_z_size = scan.get_uint32();
_component_type = (ComponentType)scan.get_uint8();
_component_width = scan.get_uint8();
_ram_image_compression = CM_off;
_ram_image_compression = (CompressionMode)scan.get_uint8();
int num_pages = scan.get_uint16();
_pages.clear();
for (int n = 0; n < num_pages; ++n) {
_pages.push_back(VideoPage());
VideoPage &page = _pages.back();
page.fillin_rawdata(scan, manager);
LoaderOptions options;
do_reconsider_video_properties(page._color, _num_components, n, options);
if (page._alpha.is_valid()) {
do_reconsider_video_properties(page._alpha, _num_components, n, options);
}
}
_loaded_from_image = true;
do_set_pad_size(0, 0, 0);
++_image_modified;
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::VideoStream::Constructor
// Access: Public
@ -474,15 +556,17 @@ VideoStream(const FFMpegTexture::VideoStream &copy) :
{
// Rather than copying the _capture pointer, we must open a new
// stream that references the same file.
if (copy.is_valid()) {
if (copy.is_from_file()) {
if (copy.is_valid() && copy.is_from_file()) {
if (copy._file_info.is_empty()) {
read(copy._filename);
} else {
read(copy._file_info);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::VideoStream::Copy Constructor
// Function: FFMpegTexture::VideoStream::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
@ -491,6 +575,26 @@ FFMpegTexture::VideoStream::
clear();
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::VideoStream::Copy Assignment Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void FFMpegTexture::VideoStream::
operator = (const FFMpegTexture::VideoStream &copy) {
clear();
// Rather than copying the _capture pointer, we must open a new
// stream that references the same file.
if (copy.is_valid() && copy.is_from_file()) {
if (copy._file_info.is_empty()) {
read(copy._filename);
} else {
read(copy._file_info);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::VideoStream::get_frame_data
// Access: Public
@ -546,7 +650,7 @@ get_frame_data(int frame_number) {
double time_stamp = ((double)AV_TIME_BASE * frame_number * vstream->r_frame_rate.den) / vstream->r_frame_rate.num;
double curr_time_stamp;
// find point in time
av_seek_frame(_format_context, -1, (long long)time_stamp,
AVSEEK_FLAG_BACKWARD);
@ -638,32 +742,147 @@ get_frame_data(int frame_number) {
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::VideoStream::read
// Access: Public
// Description: Sets up the stream to read the indicated file.
// Returns true on success, false on failure.
// Description: Sets up the stream to read the indicated file from
// the VFS. Returns true on success, false on failure.
////////////////////////////////////////////////////////////////////
bool FFMpegTexture::VideoStream::
read(const Filename &filename) {
// Clear out the last stream
clear();
string os_specific = filename.to_os_specific();
// Open video file
int result = av_open_input_file(&_format_context, os_specific.c_str(), NULL,
0, NULL);
if (result != 0) {
grutil_cat.error() << "ffmpeg AVERROR: " << result << endl;
if (!_ffvfile.open_vfs(filename)) {
grutil_cat.error()
<< "couldn't open " << filename << "\n";
// Don't call clear(), because nothing happened yet
return false;
}
_filename = filename;
return continue_read();
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::VideoStream::read
// Access: Public
// Description: Sets up the stream to read the indicated file,
// avoiding the VFS. Returns true on success, false on
// failure.
////////////////////////////////////////////////////////////////////
bool FFMpegTexture::VideoStream::
read(const SubfileInfo &info) {
// Clear out the last stream
clear();
// Open video file
if (!_ffvfile.open_subfile(info)) {
grutil_cat.error()
<< "couldn't open " << info << "\n";
// Don't call clear(), because nothing happened yet
return false;
}
_file_info = info;
_filename = _file_info.get_filename();
return continue_read();
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::VideoStream::clear
// Access: Public
// Description: Stops the video playback and frees the associated
// resources.
////////////////////////////////////////////////////////////////////
void FFMpegTexture::VideoStream::
clear() {
if (_codec_context) {
avcodec_close(_codec_context);
_codec_context = NULL;
}
if (_frame) {
av_free(_frame);
_frame = NULL;
}
if (_frame_out) {
av_free(_frame_out);
_frame_out = NULL;
}
// We cannot close the format_context, since we didn't open it--the
// FfmpegVirtualFile will do that.
_format_context = NULL;
_next_frame_number = 0;
_filename = Filename();
_file_info = SubfileInfo();
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::VideoStream::write_datagram_rawdata
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void FFMpegTexture::VideoStream::
write_datagram_rawdata(BamWriter *manager, Datagram &me) {
SubfileInfo result;
if (!_file_info.is_empty()) {
me.add_bool(true);
manager->write_file_data(result, _file_info);
} else if (!_filename.empty()) {
me.add_bool(true);
manager->write_file_data(result, _filename);
} else {
me.add_bool(false);
}
/* Not sure yet if this is a good idea.
if (!result.is_empty()) {
// If we've just copied the data to a local file, read it from
// there in the future.
_file_info = result;
}
*/
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::VideoStream::fillin_rawdata
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void FFMpegTexture::VideoStream::
fillin_rawdata(DatagramIterator &scan, BamReader *manager) {
bool got_info = scan.get_bool();
if (got_info) {
SubfileInfo info;
manager->read_file_data(info);
read(info);
} else {
clear();
}
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::VideoStream::continue_read
// Access: Private
// Description: Once the FfmpegVirtualFile has been opened, continues
// to make the appropriate ffmpeg calls to open the
// stream.
////////////////////////////////////////////////////////////////////
bool FFMpegTexture::VideoStream::
continue_read() {
_format_context = _ffvfile.get_format_context();
nassertr(_format_context != NULL, false);
// Retrieve stream information
result = av_find_stream_info(_format_context);
int result = av_find_stream_info(_format_context);
if (result < 0) {
grutil_cat.error() << "ffmpeg AVERROR: " << result << endl;
clear();
return false;
}
dump_format(_format_context, 0, os_specific.c_str(), false);
dump_format(_format_context, 0, _filename.c_str(), false);
_stream_number = -1;
for(size_t i = 0; i < _format_context->nb_streams; i++) {
@ -752,41 +971,11 @@ read(const Filename &filename) {
// We could put an option here for single channel frames.
_next_frame_number = 0;
_filename = filename;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::VideoStream::clear
// Access: Public
// Description: Stops the video playback and frees the associated
// resources.
////////////////////////////////////////////////////////////////////
void FFMpegTexture::VideoStream::
clear() {
if (_codec_context) {
avcodec_close(_codec_context);
_codec_context = NULL;
}
if (_format_context) {
av_close_input_file(_format_context);
_format_context = NULL;
}
if (_frame) {
av_free(_frame);
_frame = NULL;
}
if (_frame_out) {
av_free(_frame_out);
_frame_out = NULL;
}
_next_frame_number = 0;
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::VideoStream::read_video_frame
// Access: Private
@ -830,6 +1019,28 @@ read_video_frame(AVPacket *packet) {
return err;
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::VideoPage::write_datagram_rawdata
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void FFMpegTexture::VideoPage::
write_datagram_rawdata(BamWriter *manager, Datagram &me) {
_color.write_datagram_rawdata(manager, me);
_alpha.write_datagram_rawdata(manager, me);
}
////////////////////////////////////////////////////////////////////
// Function: FFMpegTexture::VideoPage::fillin_rawdata
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void FFMpegTexture::VideoPage::
fillin_rawdata(DatagramIterator &scan, BamReader *manager) {
_color.fillin_rawdata(scan, manager);
_alpha.fillin_rawdata(scan, manager);
}
#endif // HAVE_FFMpeg

View File

@ -19,6 +19,7 @@
#ifdef HAVE_FFMPEG
#include "videoTexture.h"
#include "ffmpegVirtualFile.h"
extern "C" {
#include "libavcodec/avcodec.h"
@ -55,6 +56,9 @@ protected:
virtual bool do_load_one(const PNMImage &pnmimage, const string &name,
int z, int n, const LoaderOptions &options);
virtual bool do_has_bam_rawdata() const;
virtual void do_get_bam_rawdata();
private:
class VideoPage;
class VideoStream;
@ -70,25 +74,34 @@ private:
VideoStream();
VideoStream(const VideoStream &copy);
~VideoStream();
void operator = (const VideoStream &copy);
bool read(const Filename &filename);
bool read(const SubfileInfo &info);
void clear();
INLINE bool is_valid() const;
INLINE bool is_from_file() const;
bool get_frame_data(int frame);
void write_datagram_rawdata(BamWriter *manager, Datagram &me);
void fillin_rawdata(DatagramIterator &scan, BamReader *manager);
private:
bool continue_read();
int read_video_frame(AVPacket *packet);
public:
AVCodecContext *_codec_context;
AVFormatContext *_format_context;
FfmpegVirtualFile _ffvfile;
int _stream_number;
AVFrame *_frame;
AVFrame *_frame_out;
Filename _filename;
SubfileInfo _file_info;
int _next_frame_number;
int _image_size_bytes;
@ -102,6 +115,10 @@ private:
INLINE VideoPage();
INLINE VideoPage(const VideoPage &copy);
INLINE ~VideoPage();
INLINE void operator = (const VideoPage &copy);
void write_datagram_rawdata(BamWriter *manager, Datagram &me);
void fillin_rawdata(DatagramIterator &scan, BamReader *manager);
VideoStream _color, _alpha;
};
@ -112,6 +129,10 @@ private:
public:
static void register_with_read_factory();
static TypedWritable *make_from_bam(const FactoryParams &params);
virtual void do_write_datagram_rawdata(BamWriter *manager, Datagram &me);
virtual void do_fillin_rawdata(DatagramIterator &scan, BamReader *manager);
public:
static TypeHandle get_class_type() {
return _type_handle;

View File

@ -47,7 +47,7 @@ MovieTexture(const string &name) :
// Description: Creates a texture playing the specified movie.
////////////////////////////////////////////////////////////////////
MovieTexture::
MovieTexture(PT(MovieVideo) video) :
MovieTexture(MovieVideo *video) :
Texture(video->get_name())
{
do_load_one(video->open(), NULL, 0, LoaderOptions());
@ -134,18 +134,6 @@ make_texture() {
return new MovieTexture("");
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::VideoPage::Constructor
// Access: Private
// Description: Creates a completely blank video page.
////////////////////////////////////////////////////////////////////
MovieTexture::VideoPage::
VideoPage() :
_color(0),
_alpha(0)
{
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::do_recalculate_image_properties
// Access: Protected
@ -161,8 +149,9 @@ do_recalculate_image_properties(CDWriter &cdata, const LoaderOptions &options) {
int y_max = 1;
bool alpha = false;
double len = 0.0;
for (int i=0; i<_z_size; i++) {
nassertv(cdata->_pages.size() == (size_t)_z_size);
for (int i = 0; i < _z_size; ++i) {
MovieVideoCursor *t = cdata->_pages[i]._color;
if (t) {
if (t->size_x() > x_max) x_max = t->size_x();
@ -299,27 +288,6 @@ do_load_one(const PNMImage &pnmimage, const string &name, int z, int n,
return false;
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::register_with_read_factory
// Access: Public, Static
// Description: Factory method to generate a Texture object
////////////////////////////////////////////////////////////////////
void MovieTexture::
register_with_read_factory() {
// Since Texture is such a funny object that is reloaded from the
// TexturePool each time, instead of actually being read fully from
// the bam file, and since the VideoTexture and MovieTexture
// classes don't really add any useful data to the bam record, we
// don't need to define make_from_bam(), fillin(), or
// write_datagram() in this class--we just inherit the same
// functions from Texture.
// We do, however, have to register this class with the BamReader,
// to avoid warnings about creating the wrong kind of object from
// the bam file.
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::has_cull_callback
// Access: Public, Virtual
@ -390,19 +358,6 @@ cull_callback(CullTraverser *, const CullTraverserData &) const {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::get_keep_ram_image
// Access: Published, Virtual
// Description: A MovieTexture must always keep its ram image,
// since there is no way to reload it from the
// source MovieVideo.
////////////////////////////////////////////////////////////////////
bool MovieTexture::
get_keep_ram_image() const {
// A MovieTexture should never dump its RAM image.
return true;
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::do_make_copy
// Access: Protected, Virtual
@ -476,6 +431,43 @@ do_reload_ram_image() {
// Therefore, this is not needed.
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::get_keep_ram_image
// Access: Published, Virtual
// Description: A MovieTexture must always keep its ram image,
// since there is no way to reload it from the
// source MovieVideo.
////////////////////////////////////////////////////////////////////
bool MovieTexture::
get_keep_ram_image() const {
// A MovieTexture should never dump its RAM image.
return true;
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::do_has_bam_rawdata
// Access: Protected, Virtual
// Description: Returns true if there is a rawdata image that we have
// available to write to the bam stream. For a normal
// Texture, this is the same thing as
// do_has_ram_image(), but a movie texture might define
// it differently.
////////////////////////////////////////////////////////////////////
bool MovieTexture::
do_has_bam_rawdata() const {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::do_get_bam_rawdata
// Access: Protected, Virtual
// Description: If do_has_bam_rawdata() returned false, this attempts
// to reload the rawdata image if possible.
////////////////////////////////////////////////////////////////////
void MovieTexture::
do_get_bam_rawdata() {
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::restart
// Access: Published
@ -677,4 +669,117 @@ unsynchronize() {
cdata->_synchronize = 0;
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::register_with_read_factory
// Access: Public, Static
// Description: Factory method to generate a Texture object
////////////////////////////////////////////////////////////////////
void MovieTexture::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::make_from_bam
// Access: Protected, Static
// Description: Factory method to generate a MovieTexture object
////////////////////////////////////////////////////////////////////
TypedWritable *MovieTexture::
make_from_bam(const FactoryParams &params) {
PT(MovieTexture) dummy = new MovieTexture("");
return dummy->make_this_from_bam(params);
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::complete_pointers
// Access: Public, Virtual
// Description: Receives an array of pointers, one for each time
// manager->read_pointer() was called in fillin().
// Returns the number of pointers processed.
////////////////////////////////////////////////////////////////////
int MovieTexture::
complete_pointers(TypedWritable **p_list, BamReader *manager) {
int pi = Texture::complete_pointers(p_list, manager);
CDWriter cdata(_cycler);
size_t num_pages = cdata->_pages.size();
for (size_t n = 0; n < num_pages; ++n) {
VideoPage &page = cdata->_pages[n];
page._color = DCAST(MovieVideoCursor, p_list[pi++]);
page._alpha = DCAST(MovieVideoCursor, p_list[pi++]);
}
return pi;
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::do_write_datagram_rawdata
// Access: Protected, Virtual
// Description: Writes the rawdata part of the texture to the
// Datagram.
////////////////////////////////////////////////////////////////////
void MovieTexture::
do_write_datagram_rawdata(BamWriter *manager, Datagram &dg) {
CDReader cdata(_cycler);
dg.add_uint16(cdata->_pages.size());
for (size_t n = 0; n < cdata->_pages.size(); ++n) {
const VideoPage &page = cdata->_pages[n];
manager->write_pointer(dg, page._color);
manager->write_pointer(dg, page._alpha);
}
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::do_fillin_rawdata
// Access: Protected, Virtual
// Description: Reads in the part of the Texture that was written
// with do_write_datagram_rawdata().
////////////////////////////////////////////////////////////////////
void MovieTexture::
do_fillin_rawdata(DatagramIterator &scan, BamReader *manager) {
CDWriter cdata(_cycler);
size_t num_pages = scan.get_uint16();
_z_size = (int)num_pages;
cdata->_pages.reserve(num_pages);
for (size_t n = 0; n < num_pages; ++n) {
cdata->_pages.push_back(VideoPage());
manager->read_pointer(scan); // page._color
manager->read_pointer(scan); // page._alpha
}
// We load one or more MovieVideoCursors during the above loop. We
// need a finalize callback so we can initialize ourselves once
// those cursors have been read completely.
manager->register_finalize(this);
}
////////////////////////////////////////////////////////////////////
// Function: MovieTexture::finalize
// Access: Public, Virtual
// Description: Called by the BamReader to perform any final actions
// needed for setting up the object after all objects
// have been read and all pointers have been completed.
////////////////////////////////////////////////////////////////////
void MovieTexture::
finalize(BamReader *manager) {
CDWriter cdata(_cycler);
// Insist that each of our video pages gets finalized before we do.
size_t num_pages = cdata->_pages.size();
for (size_t n = 0; n < num_pages; ++n) {
VideoPage &page = cdata->_pages[n];
manager->finalize_now(page._color);
manager->finalize_now(page._alpha);
}
do_recalculate_image_properties(cdata, LoaderOptions());
set_loaded_from_image();
set_loop(true);
play();
}
#endif // HAVE_AUDIO

View File

@ -34,7 +34,7 @@
class EXPCL_PANDA_GRUTIL MovieTexture : public Texture {
PUBLISHED:
MovieTexture(const string &name);
MovieTexture(PT(MovieVideo) video);
MovieTexture(MovieVideo *video);
private:
MovieTexture(const MovieTexture &copy);
PUBLISHED:
@ -71,6 +71,8 @@ protected:
virtual void do_reload_ram_image();
virtual bool get_keep_ram_image() const;
virtual bool do_has_bam_rawdata() const;
virtual void do_get_bam_rawdata();
virtual bool do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
int z, int n, int primary_file_num_channels, int alpha_file_channel,
const LoaderOptions &options,
@ -82,7 +84,6 @@ protected:
class VideoPage {
public:
VideoPage();
PT(MovieVideoCursor) _color;
PT(MovieVideoCursor) _alpha;
};
@ -120,6 +121,13 @@ protected:
public:
static void register_with_read_factory();
static TypedWritable *make_from_bam(const FactoryParams &params);
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
virtual void do_write_datagram_rawdata(BamWriter *manager, Datagram &dg);
virtual void do_fillin_rawdata(DatagramIterator &scan, BamReader *manager);
virtual void finalize(BamReader *manager);
public:
static TypeHandle get_class_type() {
return _type_handle;

View File

@ -15,6 +15,21 @@
#include "config_movies.h"
#include "dconfig.h"
#include "movieVideo.h"
#include "movieVideoCursor.h"
#include "movieAudio.h"
#include "movieAudioCursor.h"
#include "inkblotVideo.h"
#include "inkblotVideoCursor.h"
#include "ffmpegVideo.h"
#include "ffmpegVideoCursor.h"
#include "ffmpegAudio.h"
#include "ffmpegAudioCursor.h"
#ifdef HAVE_FFMPEG
extern "C" {
#include "libavcodec/avcodec.h"
@ -54,13 +69,17 @@ init_libmovies() {
UserDataAudio::init_type();
UserDataAudioCursor::init_type();
MicrophoneAudio::init_type();
#ifdef HAVE_FFMPEG
FfmpegVirtualFile::register_protocol();
FfmpegVideo::init_type();
FfmpegVideoCursor::init_type();
FfmpegAudio::init_type();
FfmpegAudioCursor::init_type();
av_register_all();
FfmpegVirtualFile::register_protocol();
FfmpegVideo::register_with_read_factory();
FfmpegVideoCursor::register_with_read_factory();
#endif
}

View File

@ -21,21 +21,6 @@
#include "configVariableDouble.h"
#include "dconfig.h"
#include "movieVideo.h"
#include "movieVideoCursor.h"
#include "movieAudio.h"
#include "movieAudioCursor.h"
#include "inkblotVideo.h"
#include "inkblotVideoCursor.h"
#include "ffmpegVideo.h"
#include "ffmpegVideoCursor.h"
#include "ffmpegAudio.h"
#include "ffmpegAudioCursor.h"
ConfigureDecl(config_movies, EXPCL_PANDA_MOVIES, EXPTP_PANDA_MOVIES);
NotifyCategoryDecl(movies, EXPCL_PANDA_MOVIES, EXPTP_PANDA_MOVIES);
NotifyCategoryDecl(ffmpeg, EXPCL_PANDA_MOVIES, EXPTP_PANDA_MOVIES);

View File

@ -14,6 +14,9 @@
#ifndef FFMPEGAUDIO_H
#define FFMPEGAUDIO_H
#include "pandabase.h"
#ifdef HAVE_FFMPEG
#include "movieAudio.h"

View File

@ -42,13 +42,14 @@ FfmpegAudioCursor(FfmpegAudio *src) :
_buffer(0),
_buffer_alloc(0)
{
string url = "pandavfs:";
url += _filename;
if (av_open_input_file(&_format_ctx, url.c_str(), NULL, 0, NULL)!=0) {
if (!_ffvfile.open_vfs(_filename)) {
cleanup();
return;
}
_format_ctx = _ffvfile.get_format_context();
nassertv(_format_ctx != NULL);
if (av_find_stream_info(_format_ctx)<0) {
cleanup();
return;
@ -130,22 +131,25 @@ cleanup() {
av_free_packet(_packet);
}
delete _packet;
_packet = 0;
_packet = NULL;
}
if (_buffer_alloc) {
delete[] _buffer_alloc;
_buffer_alloc = 0;
_buffer = 0;
_buffer = NULL;
}
if ((_audio_ctx)&&(_audio_ctx->codec)) {
avcodec_close(_audio_ctx);
}
_audio_ctx = 0;
_audio_ctx = NULL;
if (_format_ctx) {
av_close_input_file(_format_ctx);
_format_ctx = 0;
_ffvfile.close();
_format_ctx = NULL;
}
_audio_ctx = 0;
_audio_index = -1;
}

View File

@ -14,12 +14,16 @@
#ifndef FFMPEGAUDIOCURSOR_H
#define FFMPEGAUDIOCURSOR_H
#ifdef HAVE_FFMPEG
#include "pandabase.h"
#ifdef HAVE_FFMPEG
#include "movieAudioCursor.h"
#include "namable.h"
#include "texture.h"
#include "pointerTo.h"
#include "ffmpegVirtualFile.h"
struct AVFormatContext;
struct AVCodecContext;
@ -52,6 +56,7 @@ protected:
unsigned char *_packet_data;
AVFormatContext *_format_ctx;
AVCodecContext *_audio_ctx;
FfmpegVirtualFile _ffvfile;
int _audio_index;
double _audio_timebase;

View File

@ -15,6 +15,7 @@
#ifdef HAVE_FFMPEG
#include "ffmpegVideo.h"
#include "ffmpegVideoCursor.h"
#include "config_movies.h"
TypeHandle FfmpegVideo::_type_handle;
@ -22,7 +23,9 @@ TypeHandle FfmpegVideo::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideo::Constructor
// Access: Public
// Description: xxx
// Description: Constructs an ffmpeg video that reads its contents
// from the indicate filename, which may be a file in
// the VFS.
////////////////////////////////////////////////////////////////////
FfmpegVideo::
FfmpegVideo(const Filename &name) :
@ -31,6 +34,22 @@ FfmpegVideo(const Filename &name) :
_filename = name;
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideo::Constructor
// Access: Public
// Description: Constructs an ffmpeg video that reads its contents
// from the indicated subfile information. This is
// normally used for low-level purposes only; you would
// normally use the constructor that takes a filename.
////////////////////////////////////////////////////////////////////
FfmpegVideo::
FfmpegVideo(const SubfileInfo &info) :
MovieVideo(info.get_filename())
{
_filename = info.get_filename();
_subfile_info = info;
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideo::Destructor
// Access: Public
@ -52,10 +71,63 @@ open() {
movies_cat.error() << "Could not open " << _filename << "\n";
return NULL;
} else {
return (MovieVideoCursor*)(FfmpegVideoCursor*)result;
return result.p();
}
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideo::register_with_read_factory
// Access: Public, Static
// Description: Tells the BamReader how to create objects of type
// FfmpegVideo.
////////////////////////////////////////////////////////////////////
void FfmpegVideo::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideo::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void FfmpegVideo::
write_datagram(BamWriter *manager, Datagram &dg) {
MovieVideo::write_datagram(manager, dg);
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideo::make_from_bam
// Access: Protected, Static
// Description: This function is called by the BamReader's factory
// when a new object of type FfmpegVideo is encountered
// in the Bam file. It should create the FfmpegVideo
// and extract its information from the file.
////////////////////////////////////////////////////////////////////
TypedWritable *FfmpegVideo::
make_from_bam(const FactoryParams &params) {
FfmpegVideo *video = new FfmpegVideo("");
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
video->fillin(scan, manager);
return video;
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideo::fillin
// Access: Protected
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new FfmpegVideo.
////////////////////////////////////////////////////////////////////
void FfmpegVideo::
fillin(DatagramIterator &scan, BamReader *manager) {
MovieVideo::fillin(scan, manager);
}
////////////////////////////////////////////////////////////////////

View File

@ -14,11 +14,17 @@
#ifndef FFMPEGVIDEO_H
#define FFMPEGVIDEO_H
#include "pandabase.h"
#ifdef HAVE_FFMPEG
#include "movieVideo.h"
class FfmpegVideoCursor;
class FactoryParams;
class BamWriter;
class BamReader;
////////////////////////////////////////////////////////////////////
// Class : FfmpegVideo
@ -26,13 +32,20 @@ class FfmpegVideoCursor;
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_MOVIES FfmpegVideo : public MovieVideo {
PUBLISHED:
PUBLISHED:
FfmpegVideo(const Filename &name);
FfmpegVideo(const SubfileInfo &info);
virtual ~FfmpegVideo();
virtual PT(MovieVideoCursor) open();
private:
friend class FfmpegVideoCursor;
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
void fillin(DatagramIterator &scan, BamReader *manager);
public:
static TypeHandle get_class_type() {
@ -50,6 +63,8 @@ public:
private:
static TypeHandle _type_handle;
friend class FfmpegVideoCursor;
};
#include "ffmpegVideo.I"

View File

@ -32,39 +32,69 @@ TypeHandle FfmpegVideoCursor::_type_handle;
#define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO
#endif
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideoCursor::Constructor
// Access: Public
// Description: xxx
// Function: FfmpegVideoCursor::Default Constructor
// Access: Protected
// Description: This constructor is only used when reading from a bam
// file.
////////////////////////////////////////////////////////////////////
FfmpegVideoCursor::
FfmpegVideoCursor(FfmpegVideo *src) :
MovieVideoCursor(src),
_filename(src->_filename),
_format_ctx(0),
FfmpegVideoCursor() :
_packet(NULL),
_format_ctx(NULL),
_video_ctx(NULL),
_video_index(-1),
_video_ctx(0),
_frame(0),
_frame_out(0),
_packet(0),
_frame(NULL),
_frame_out(NULL),
_min_fseek(3.0)
{
string url = "pandavfs:";
url += _filename;
if (av_open_input_file(&_format_ctx, url.c_str(), NULL, 0, NULL)!=0) {
cleanup();
return;
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideoCursor::init_from
// Access: Protected
// Description: Specifies the source of the video cursor. This is
// normally called only by the constructor or when
// reading from a bam file.
////////////////////////////////////////////////////////////////////
void FfmpegVideoCursor::
init_from(FfmpegVideo *source) {
nassertv(source != NULL);
_source = source;
_filename = _source->get_filename();
if (!_source->get_subfile_info().is_empty()) {
// Read a subfile.
if (!_ffvfile.open_subfile(_source->get_subfile_info())) {
movies_cat.info()
<< "Couldn't open " << _source->get_subfile_info() << "\n";
cleanup();
return;
}
} else {
// Read a filename.
if (!_ffvfile.open_vfs(_filename)) {
movies_cat.info()
<< "Couldn't open " << _filename << "\n";
cleanup();
return;
}
}
if (av_find_stream_info(_format_ctx)<0) {
_format_ctx = _ffvfile.get_format_context();
nassertv(_format_ctx != NULL);
if (av_find_stream_info(_format_ctx) < 0) {
movies_cat.info()
<< "Couldn't find stream info\n";
cleanup();
return;
}
// Find the video stream
for(int i = 0; i < (int)_format_ctx->nb_streams; i++) {
if(_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
for (int i = 0; i < (int)_format_ctx->nb_streams; ++i) {
if (_format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
_video_index = i;
_video_ctx = _format_ctx->streams[i]->codec;
_video_timebase = av_q2d(_format_ctx->streams[i]->time_base);
@ -72,16 +102,22 @@ FfmpegVideoCursor(FfmpegVideo *src) :
}
if (_video_ctx == 0) {
movies_cat.info()
<< "Couldn't find video_ctx\n";
cleanup();
return;
}
AVCodec *pVideoCodec=avcodec_find_decoder(_video_ctx->codec_id);
if(pVideoCodec == 0) {
AVCodec *pVideoCodec = avcodec_find_decoder(_video_ctx->codec_id);
if (pVideoCodec == NULL) {
movies_cat.info()
<< "Couldn't find codec\n";
cleanup();
return;
}
if(avcodec_open(_video_ctx, pVideoCodec)<0) {
if (avcodec_open(_video_ctx, pVideoCodec) < 0) {
movies_cat.info()
<< "Couldn't open codec\n";
cleanup();
return;
}
@ -109,6 +145,24 @@ FfmpegVideoCursor(FfmpegVideo *src) :
_next_start = 0.0;
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideoCursor::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
FfmpegVideoCursor::
FfmpegVideoCursor(FfmpegVideo *src) :
_packet(NULL),
_format_ctx(NULL),
_video_ctx(NULL),
_video_index(-1),
_frame(NULL),
_frame_out(NULL),
_min_fseek(3.0)
{
init_from(src);
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideoCursor::Destructor
// Access: Public
@ -128,31 +182,34 @@ void FfmpegVideoCursor::
cleanup() {
if (_frame) {
av_free(_frame);
_frame = 0;
_frame = NULL;
}
if (_frame_out) {
_frame_out->data[0] = 0;
av_free(_frame_out);
_frame_out = 0;
_frame_out = NULL;
}
if (_packet) {
if (_packet->data) {
av_free_packet(_packet);
}
delete _packet;
_packet = 0;
_packet = NULL;
}
if ((_video_ctx)&&(_video_ctx->codec)) {
avcodec_close(_video_ctx);
}
_video_ctx = 0;
if (_format_ctx) {
av_close_input_file(_format_ctx);
_format_ctx = 0;
}
_video_ctx = 0;
_video_index = -1;
_video_ctx = NULL;
if (_format_ctx) {
_ffvfile.close();
_format_ctx = NULL;
}
_video_index = -1;
}
////////////////////////////////////////////////////////////////////
@ -171,7 +228,7 @@ export_frame(unsigned char *data, bool bgra, int bufx) {
#ifdef HAVE_SWSCALE
struct SwsContext *convert_ctx = sws_getContext(_size_x, _size_y,
_video_ctx->pix_fmt, _size_x, _size_y,
PIX_FMT_BGRA, 2, NULL, NULL, NULL);
PIX_FMT_BGRA, SWS_FAST_BILINEAR, NULL, NULL, NULL);
nassertv(convert_ctx != NULL);
sws_scale(convert_ctx, _frame->data, _frame->linesize,
0, _size_y, _frame_out->data, _frame_out->linesize);
@ -186,7 +243,7 @@ export_frame(unsigned char *data, bool bgra, int bufx) {
#ifdef HAVE_SWSCALE
struct SwsContext *convert_ctx = sws_getContext(_size_x, _size_y,
_video_ctx->pix_fmt, _size_x, _size_y,
PIX_FMT_BGR24, 2, NULL, NULL, NULL);
PIX_FMT_BGR24, SWS_FAST_BILINEAR, NULL, NULL, NULL);
nassertv(convert_ctx != NULL);
sws_scale(convert_ctx, _frame->data, _frame->linesize,
0, _size_y, _frame_out->data, _frame_out->linesize);
@ -385,5 +442,82 @@ fetch_into_buffer(double time, unsigned char *data, bool bgra) {
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideoCursor::register_with_read_factory
// Access: Public, Static
// Description: Tells the BamReader how to create objects of type
// FfmpegVideo.
////////////////////////////////////////////////////////////////////
void FfmpegVideoCursor::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideoCursor::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void FfmpegVideoCursor::
write_datagram(BamWriter *manager, Datagram &dg) {
MovieVideoCursor::write_datagram(manager, dg);
// No need to write any additional data here--all of it comes
// implicitly from the underlying MovieVideo, which we process in
// finalize().
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideoCursor::finalize
// Access: Public, Virtual
// Description: Called by the BamReader to perform any final actions
// needed for setting up the object after all objects
// have been read and all pointers have been completed.
////////////////////////////////////////////////////////////////////
void FfmpegVideoCursor::
finalize(BamReader *) {
if (_source != (MovieVideo *)NULL) {
FfmpegVideo *video;
DCAST_INTO_V(video, _source);
init_from(video);
}
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideoCursor::make_from_bam
// Access: Protected, Static
// Description: This function is called by the BamReader's factory
// when a new object of type FfmpegVideo is encountered
// in the Bam file. It should create the FfmpegVideo
// and extract its information from the file.
////////////////////////////////////////////////////////////////////
TypedWritable *FfmpegVideoCursor::
make_from_bam(const FactoryParams &params) {
FfmpegVideoCursor *video = new FfmpegVideoCursor;
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
video->fillin(scan, manager);
return video;
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideoCursor::fillin
// Access: Protected
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new FfmpegVideo.
////////////////////////////////////////////////////////////////////
void FfmpegVideoCursor::
fillin(DatagramIterator &scan, BamReader *manager) {
MovieVideoCursor::fillin(scan, manager);
// The MovieVideoCursor gets the underlying MovieVideo pointer. We
// need a finalize callback so we can initialize ourselves once that
// has been read completely.
manager->register_finalize(this);
}
#endif // HAVE_FFMPEG

View File

@ -14,11 +14,15 @@
#ifndef FFMPEGVIDEOCURSOR_H
#define FFMPEGVIDEOCURSOR_H
#ifdef HAVE_FFMPEG
#include "pandabase.h"
#ifdef HAVE_FFMPEG
#include "movieVideoCursor.h"
#include "texture.h"
#include "pointerTo.h"
#include "ffmpegVirtualFile.h"
struct AVFormatContext;
struct AVCodecContext;
@ -31,17 +35,19 @@ struct AVFrame;
// Description :
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_MOVIES FfmpegVideoCursor : public MovieVideoCursor {
friend class FfmpegVideo;
protected:
FfmpegVideoCursor();
void init_from(FfmpegVideo *src);
PUBLISHED:
PUBLISHED:
FfmpegVideoCursor(FfmpegVideo *src);
virtual ~FfmpegVideoCursor();
public:
public:
virtual void fetch_into_texture(double time, Texture *t, int page);
virtual void fetch_into_buffer(double time, unsigned char *block, bool rgba);
protected:
protected:
void fetch_packet(double default_time);
void fetch_frame();
void seek(double t);
@ -54,13 +60,24 @@ class EXPCL_PANDA_MOVIES FfmpegVideoCursor : public MovieVideoCursor {
double _packet_time;
AVFormatContext *_format_ctx;
AVCodecContext *_video_ctx;
int _video_index;
FfmpegVirtualFile _ffvfile;
int _video_index;
double _video_timebase;
AVFrame *_frame;
AVFrame *_frame_out;
int _initial_dts;
double _min_fseek;
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
virtual void finalize(BamReader *manager);
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);
void fillin(DatagramIterator &scan, BamReader *manager);
public:
static TypeHandle get_class_type() {
return _type_handle;
@ -77,6 +94,8 @@ public:
private:
static TypeHandle _type_handle;
friend class FfmpegVideo;
};
#include "ffmpegVideoCursor.I"

View File

@ -11,3 +11,15 @@
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: FfmpegVirtualFile::get_format_context
// Access: Public
// Description: Returns a pointer to the opened ffmpeg context, or
// NULL if the file was not successfully opened.
////////////////////////////////////////////////////////////////////
INLINE AVFormatContext *FfmpegVirtualFile::
get_format_context() const {
return _format_context;
}

View File

@ -18,154 +18,184 @@
#include "config_movies.h"
#include "ffmpegVirtualFile.h"
#include "virtualFileSystem.h"
extern "C" {
#include "libavformat/avio.h"
}
#ifndef AVSEEK_SIZE
#define AVSEEK_SIZE 0x10000
#endif
////////////////////////////////////////////////////////////////////
// These functions need to use C calling conventions.
// Function: FfmpegVirtualFile::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
extern "C" {
static int pandavfs_open(URLContext *h, const char *filename, int flags);
static int pandavfs_read(URLContext *h, unsigned char *buf, int size);
// This change happened a few days before 52.68.0
#if LIBAVFORMAT_VERSION_INT < 3425280
static int pandavfs_write(URLContext *h, unsigned char *buf, int size);
#else
static int pandavfs_write(URLContext *h, const unsigned char *buf, int size);
#endif
static int64_t pandavfs_seek(URLContext *h, int64_t pos, int whence);
static int pandavfs_close(URLContext *h);
FfmpegVirtualFile::
FfmpegVirtualFile() :
_format_context(NULL),
_in(NULL),
_owns_in(false)
{
}
////////////////////////////////////////////////////////////////////
// Function: pandavfs_open
// Access: Static Function
// Description: A hook to open a panda VFS file.
// Function: FfmpegVirtualFile::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
static int
pandavfs_open(URLContext *h, const char *filename, int flags) {
if (flags != 0) {
if (movies_cat.is_debug()) {
movies_cat.debug()
<< "ffmpeg is trying to write to the VFS.\n";
}
// We'll allow this, but just fail any actual writes.
}
FfmpegVirtualFile::
~FfmpegVirtualFile() {
close();
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVirtualFile::Copy Constructor
// Access: Private
// Description: These objects are not meant to be copied.
////////////////////////////////////////////////////////////////////
FfmpegVirtualFile::
FfmpegVirtualFile(const FfmpegVirtualFile &copy) {
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVirtualFile::Copy Assignment Operator
// Access: Private
// Description: These objects are not meant to be copied.
////////////////////////////////////////////////////////////////////
void FfmpegVirtualFile::
operator = (const FfmpegVirtualFile &copy) {
nassertv(false);
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVirtualFile::open_vfs
// Access: Public
// Description: Opens the movie file via Panda's VFS. Returns true
// on success, false on failure. If successful, use
// get_format_context() to get the open file handle.
////////////////////////////////////////////////////////////////////
bool FfmpegVirtualFile::
open_vfs(const Filename &filename) {
close();
filename += 9; // Skip over "pandavfs:"
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
istream *s = vfs->open_read_file(filename, true);
if (s == 0) {
return -1;
Filename fname = filename;
fname.set_binary();
PT(VirtualFile) vfile = vfs->get_file(fname);
if (vfile == NULL) {
return false;
}
// Test whether seek works.
s->seekg(1, ios::beg);
int tel1 = s->tellg();
s->seekg(0, ios::beg);
int tel2 = s->tellg();
if (s->fail() || (tel1!=1) || (tel2!=0)) {
movies_cat.error() << "cannot play movie (not seekable): " << h->filename << "\n";
delete s;
return -1;
_in = vfile->open_read_file(true);
if (_in == NULL) {
return false;
}
h->priv_data = s;
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: pandavfs_read
// Access: Static Function
// Description: A hook to read a panda VFS file.
////////////////////////////////////////////////////////////////////
static int
pandavfs_read(URLContext *h, unsigned char *buf, int size) {
istream *s = (istream*)(h->priv_data);
s->read((char*)buf, size);
int gc = s->gcount();
s->clear();
return gc;
}
_owns_in = true;
_start = 0;
_size = vfile->get_file_size(_in);
////////////////////////////////////////////////////////////////////
// Function: pandavfs_write
// Access: Static Function
// Description: A hook to write a panda VFS file.
////////////////////////////////////////////////////////////////////
static int
#if LIBAVFORMAT_VERSION_INT < 3425280
pandavfs_write(URLContext *h, unsigned char *buf, int size) {
#else
pandavfs_write(URLContext *h, const unsigned char *buf, int size) {
#endif
movies_cat.warning()
<< "ffmpeg is trying to write to the VFS.\n";
return -1;
}
// 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.
////////////////////////////////////////////////////////////////////
// Function: pandavfs_seek
// Access: Static Function
// Description: A hook to seek a panda VFS file.
////////////////////////////////////////////////////////////////////
static int64_t
pandavfs_seek(URLContext *h, int64_t pos, int whence) {
istream *s = (istream*)(h->priv_data);
switch(whence) {
case SEEK_SET: s->seekg(pos, ios::beg); break;
case SEEK_CUR: s->seekg(pos, ios::cur); break;
case SEEK_END: s->seekg(pos, ios::end); break;
case AVSEEK_SIZE: {
s->seekg(0, ios::cur);
int p = s->tellg();
s->seekg(-1, ios::end);
int size = s->tellg();
if (size < 0) {
movies_cat.error() << "Failed to determine filesize in ffmpegVirtualFile\n";
s->clear();
return -1;
}
size++;
s->seekg(p, ios::beg);
s->clear();
return size; }
default:
movies_cat.error() << "Illegal parameter to seek in ffmpegVirtualFile\n";
s->clear();
return -1;
// Nowadays we synthesize a "url" that references this pointer.
ostringstream strm;
strm << "pandavfs://" << (void *)this;
string url = strm.str();
// Now we can open the stream.
int result =
av_open_input_file(&_format_context, url.c_str(), NULL, 0, NULL);
if (result < 0) {
close();
return false;
}
s->clear();
int tl = s->tellg();
return tl;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: pandavfs_close
// Access: Static Function
// Description: A hook to close a panda VFS file.
// Function: FfmpegVirtualFile::open_subfile
// Access: Public
// Description: Opens the movie file directly from a file on disk
// (does not go through the VFS). Returns true on
// success, false on failure. If successful, use
// get_format_context() to get the open file handle.
////////////////////////////////////////////////////////////////////
static int
pandavfs_close(URLContext *h) {
istream *s = (istream*)(h->priv_data);
delete s;
h->priv_data = 0;
return 0;
bool FfmpegVirtualFile::
open_subfile(const SubfileInfo &info) {
close();
Filename fname = info.get_filename();
fname.set_binary();
if (!fname.open_read(_file_in)) {
return false;
}
_in = &_file_in;
_owns_in = false;
_start = info.get_start();
_size = info.get_size();
_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();
// Now we can open the stream.
int result =
av_open_input_file(&_format_context, url.c_str(), NULL, 0, NULL);
if (result < 0) {
close();
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVirtualFile::close
// Access: Public
// Description: Explicitly closes the opened file. This is also
// called implicitly by the destructor if necessary.
////////////////////////////////////////////////////////////////////
void FfmpegVirtualFile::
close() {
if (_format_context != NULL) {
av_close_input_file(_format_context);
_format_context = NULL;
}
if (_owns_in) {
nassertv(_in != NULL);
VirtualFileSystem::close_read_file(_in);
_owns_in = false;
}
_in = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVirtualFile::register_protocol
// Access: Public, Static
// Description: Enables ffmpeg to access panda's VFS.
//
// After calling this method, ffmpeg will be
// able to open "URLs" that look like this:
//
// pandavfs:/c/mygame/foo.avi
//
// Description: Should be called at startup to attach the appropriate
// hooks between Panda and FFMpeg.
////////////////////////////////////////////////////////////////////
void FfmpegVirtualFile::
register_protocol() {
@ -173,11 +203,22 @@ register_protocol() {
if (initialized) {
return;
}
// Here's a good place to call this global ffmpeg initialization
// function.
av_register_all();
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
@ -192,6 +233,119 @@ register_protocol() {
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
// Access: Private, Static
// Description: A callback to read a virtual file.
////////////////////////////////////////////////////////////////////
int FfmpegVirtualFile::
pandavfs_read(URLContext *h, unsigned char *buf, int size) {
FfmpegVirtualFile *self = (FfmpegVirtualFile *)(h->priv_data);
istream *in = self->_in;
// Since we may be simulating a subset of the opened stream, don't
// allow it to read past the "end".
streampos remaining = self->_start + (streampos)self->_size - in->tellg();
if (remaining < size) {
if (remaining <= 0) {
return 0;
}
size = (int)remaining;
}
in->read((char *)buf, size);
int gc = in->gcount();
in->clear();
return gc;
}
////////////////////////////////////////////////////////////////////
// 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) {
movies_cat.warning()
<< "ffmpeg is trying to write to the VFS.\n";
return -1;
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVirtualFile::pandavfs_seek
// Access: Private, Static
// Description: A callback to change the read position on an istream.
////////////////////////////////////////////////////////////////////
int64_t FfmpegVirtualFile::
pandavfs_seek(URLContext *h, int64_t pos, int whence) {
FfmpegVirtualFile *self = (FfmpegVirtualFile *)(h->priv_data);
istream *in = self->_in;
switch(whence) {
case SEEK_SET:
in->seekg(self->_start + pos, ios::beg);
break;
case SEEK_CUR:
in->seekg(pos, ios::cur);
break;
case SEEK_END:
// For seeks relative to the end, we actually compute the end
// based on _start + _size, and then use ios::beg.
in->seekg(self->_start + (streampos)self->_size + pos, ios::beg);
break;
case AVSEEK_SIZE:
return self->_size;
default:
movies_cat.error()
<< "Illegal parameter to seek in ffmpegVirtualFile\n";
in->clear();
return -1;
}
in->clear();
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
// Access: Private, Static

View File

@ -14,27 +14,62 @@
#ifndef FFMPEGVIRTUALFILE_H
#define FFMPEGVIRTUALFILE_H
#include "pandabase.h"
#ifdef HAVE_FFMPEG
#include "config_movies.h"
#include "filename.h"
#include "subfileInfo.h"
extern "C" {
#include "libavformat/avio.h"
}
#include <stdarg.h>
struct URLContext;
struct AVFormatContext;
////////////////////////////////////////////////////////////////////
// Class : FfmpegVirtualFile
// Description : Enables ffmpeg to access panda's VFS.
//
// Once register_protocol() is called, ffmpeg will be
// able to open "URLs" that look like this:
//
// pandavfs:/c/mygame/foo.avi
//
// Description : Enables ffmpeg to access panda's VFS. Create an
// instance of the FfmpegVirtualFile for each ffmpeg
// stream you wish to open.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_MOVIES FfmpegVirtualFile {
public:
public:
FfmpegVirtualFile();
~FfmpegVirtualFile();
private:
FfmpegVirtualFile(const FfmpegVirtualFile &copy);
void operator = (const FfmpegVirtualFile &copy);
public:
bool open_vfs(const Filename &filename);
bool open_subfile(const SubfileInfo &info);
void close();
INLINE AVFormatContext *get_format_context() const;
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);
static void log_callback(void *ptr, int level, const char *fmt, va_list v1);
private:
AVFormatContext *_format_context;
streampos _start;
streamsize _size;
istream *_in;
pifstream _file_in;
bool _owns_in;
};
#include "ffmpegVirtualFile.I"

View File

@ -14,6 +14,7 @@
#include "movieAudio.h"
#include "movieAudioCursor.h"
#include "ffmpegAudio.h"
TypeHandle MovieAudio::_type_handle;

View File

@ -12,14 +12,27 @@
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: MovieVideo::get_filename
// Access: Published
// Description: Returns the movie's filename. A movie is not
// guaranteed to have a filename, if not, then this
// function returns a null filename.
// function returns an empty filename.
////////////////////////////////////////////////////////////////////
INLINE const Filename &MovieVideo::
get_filename() const {
return _filename;
}
////////////////////////////////////////////////////////////////////
// Function: MovieVideo::get_subfile_info
// Access: Published
// Description: If the movie is to be loaded from a subfile on disk,
// this returns the subfile info. Check info.is_empty()
// to see if this is valid data.
////////////////////////////////////////////////////////////////////
INLINE const SubfileInfo &MovieVideo::
get_subfile_info() const {
return _subfile_info;
}

View File

@ -14,6 +14,9 @@
#include "movieVideo.h"
#include "config_movies.h"
#include "ffmpegVideo.h"
#include "bamReader.h"
#include "bamWriter.h"
TypeHandle MovieVideo::_type_handle;
@ -43,11 +46,12 @@ MovieVideo::
////////////////////////////////////////////////////////////////////
// Function: MovieVideo::open
// Access: Published, Virtual
// Description: Open this video, returning a MovieVideoCursor.
// Description: Open this video, returning a MovieVideoCursor of the
// appropriate type. Returns NULL on error.
////////////////////////////////////////////////////////////////////
PT(MovieVideoCursor) MovieVideo::
open() {
return new MovieVideoCursor(this);
return NULL;
}
////////////////////////////////////////////////////////////////////
@ -66,3 +70,57 @@ get(const Filename &name) {
#endif
}
////////////////////////////////////////////////////////////////////
// Function: MovieVideo::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void MovieVideo::
write_datagram(BamWriter *manager, Datagram &dg) {
TypedWritableReferenceCount::write_datagram(manager, dg);
dg.add_string(_filename);
// Now we record the raw movie data directly into the bam stream.
// We always do this, regardless of bam-texture-mode; we generally
// won't get to this codepath if bam-texture-mode isn't rawdata
// anyway.
SubfileInfo result;
if (!_subfile_info.is_empty()) {
dg.add_bool(true);
manager->write_file_data(result, _subfile_info);
} else if (!_filename.empty()) {
dg.add_bool(true);
manager->write_file_data(result, _filename);
} else {
dg.add_bool(false);
}
/* Not sure yet if this is a good idea.
if (!result.is_empty()) {
// If we've just copied the data to a local file, read it from
// there in the future.
_subfile_info = result;
}
*/
}
////////////////////////////////////////////////////////////////////
// Function: MovieVideo::fillin
// Access: Protected
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new MovieVideo.
////////////////////////////////////////////////////////////////////
void MovieVideo::
fillin(DatagramIterator &scan, BamReader *manager) {
TypedWritableReferenceCount::fillin(scan, manager);
_filename = scan.get_string();
bool got_info = scan.get_bool();
if (got_info) {
manager->read_file_data(_subfile_info);
}
}

View File

@ -19,7 +19,13 @@
#include "namable.h"
#include "pointerTo.h"
#include "typedWritableReferenceCount.h"
#include "subfileInfo.h"
#include "filename.h"
class MovieVideoCursor;
class FactoryParams;
class BamWriter;
class BamReader;
////////////////////////////////////////////////////////////////////
// Class : MovieVideo
@ -35,17 +41,26 @@ class MovieVideoCursor;
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_MOVIES MovieVideo : public TypedWritableReferenceCount, public Namable {
PUBLISHED:
PUBLISHED:
MovieVideo(const string &name = "Blank Video");
virtual ~MovieVideo();
virtual PT(MovieVideoCursor) open();
static PT(MovieVideo) get(const Filename &name);
INLINE const Filename &get_filename() const;
INLINE const SubfileInfo &get_subfile_info() const;
protected:
protected:
Filename _filename;
SubfileInfo _subfile_info;
public:
virtual void write_datagram(BamWriter *manager, Datagram &dg);
protected:
void fillin(DatagramIterator &scan, BamReader *manager);
public:
public:
static TypeHandle get_class_type() {
return _type_handle;
}
@ -59,7 +74,7 @@ class EXPCL_PANDA_MOVIES MovieVideo : public TypedWritableReferenceCount, public
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
private:
static TypeHandle _type_handle;
};

View File

@ -16,16 +16,17 @@
#include "config_movies.h"
#include "pStatCollector.h"
#include "pStatTimer.h"
#include "bamReader.h"
#include "bamWriter.h"
TypeHandle MovieVideoCursor::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: MovieVideoCursor::Constructor
// Access: Public
// Description: This constructor returns a null video stream --- a
// stream of plain blue and white frames that last one
// second each. To get more interesting video, you need
// to construct a subclass of this class.
// Function: MovieVideoCursor::Default Constructor
// Access: Protected
// Description: This is a virtual base class and should not be
// created directly. Instead, create a more specialized
// class.
////////////////////////////////////////////////////////////////////
MovieVideoCursor::
MovieVideoCursor(MovieVideo *src) :
@ -302,3 +303,46 @@ fetch_into_buffer(double time, unsigned char *data, bool bgra) {
}
}
////////////////////////////////////////////////////////////////////
// Function: MovieVideoCursor::write_datagram
// Access: Public, Virtual
// Description: Writes the contents of this object to the datagram
// for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void MovieVideoCursor::
write_datagram(BamWriter *manager, Datagram &dg) {
TypedWritableReferenceCount::write_datagram(manager, dg);
manager->write_pointer(dg, _source);
}
////////////////////////////////////////////////////////////////////
// Function: MovieVideoCursor::complete_pointers
// Access: Public, Virtual
// Description: Receives an array of pointers, one for each time
// manager->read_pointer() was called in fillin().
// Returns the number of pointers processed.
////////////////////////////////////////////////////////////////////
int MovieVideoCursor::
complete_pointers(TypedWritable **p_list, BamReader *manager) {
int pi = TypedWritableReferenceCount::complete_pointers(p_list, manager);
_source = DCAST(MovieVideo, p_list[pi++]);
return pi;
}
////////////////////////////////////////////////////////////////////
// Function: MovieVideoCursor::fillin
// Access: Protected
// Description: This internal function is called by make_from_bam to
// read in all of the relevant data from the BamFile for
// the new MovieVideoCursor.
////////////////////////////////////////////////////////////////////
void MovieVideoCursor::
fillin(DatagramIterator &scan, BamReader *manager) {
TypedWritableReferenceCount::fillin(scan, manager);
manager->read_pointer(scan); // _source
}

View File

@ -18,7 +18,11 @@
#include "pandabase.h"
#include "texture.h"
#include "pointerTo.h"
class MovieVideo;
class FactoryParams;
class BamWriter;
class BamReader;
////////////////////////////////////////////////////////////////////
// Class : MovieVideoCursor
@ -35,9 +39,10 @@ class MovieVideo;
// use separate MovieVideoCursor objects.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_MOVIES MovieVideoCursor : public TypedWritableReferenceCount {
protected:
MovieVideoCursor(MovieVideo *src = NULL);
PUBLISHED:
MovieVideoCursor(MovieVideo *src);
PUBLISHED:
virtual ~MovieVideoCursor();
PT(MovieVideo) get_source() const;
INLINE int size_x() const;
@ -57,14 +62,14 @@ class EXPCL_PANDA_MOVIES MovieVideoCursor : public TypedWritableReferenceCount {
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);
public:
public:
virtual void fetch_into_buffer(double time, unsigned char *block, bool bgra);
private:
private:
void allocate_conversion_buffer();
unsigned char *_conversion_buffer;
protected:
protected:
PT(MovieVideo) _source;
int _size_x;
int _size_y;
@ -77,6 +82,13 @@ class EXPCL_PANDA_MOVIES MovieVideoCursor : public TypedWritableReferenceCount {
double _next_start;
bool _streaming;
bool _ready;
public:
virtual void write_datagram(BamWriter *manager, Datagram &dg);
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
protected:
void fillin(DatagramIterator &scan, BamReader *manager);
public:
static TypeHandle get_class_type() {

View File

@ -417,7 +417,7 @@ continue_open_read(const string &bam_filename, bool report_errors) {
return false;
}
_reader = new BamReader(&_din, _bam_filename);
_reader = new BamReader(&_din);
if (!_reader->init()) {
close();
return false;
@ -444,7 +444,7 @@ continue_open_write(const string &bam_filename, bool report_errors) {
return false;
}
_writer = new BamWriter(&_dout, _bam_filename);
_writer = new BamWriter(&_dout);
if (!_writer->init()) {
close();

View File

@ -33,7 +33,7 @@ static const unsigned short _bam_major_ver = 6;
// Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData.
static const unsigned short _bam_first_minor_ver = 14;
static const unsigned short _bam_minor_ver = 24;
static const unsigned short _bam_minor_ver = 25;
// Bumped to minor version 14 on 12/19/07 to change default ColorAttrib.
// Bumped to minor version 15 on 4/9/08 to add TextureAttrib::_implicit_sort.
// Bumped to minor version 16 on 5/13/08 to add Texture::_quality_level.
@ -45,6 +45,7 @@ static const unsigned short _bam_minor_ver = 24;
// Bumped to minor version 22 on 7/31/09 to add UvScrollNode R speed.
// Bumped to minor version 23 on 5/4/10 to add internal TextureAttrib overrides.
// Bumped to minor version 24 on 5/4/10 to add internal TexMatrixAttrib overrides.
// Bumped to minor version 25 on 6/22/11 to add support for caching movie files.
#endif

View File

@ -223,16 +223,8 @@ store(BamCacheRecord *record) {
temp_pathname.set_extension(extension);
temp_pathname.set_binary();
pofstream temp_file;
if (!temp_pathname.open_write(temp_file)) {
util_cat.error()
<< "Could not open cache file: " << temp_pathname << "\n";
emergency_read_only();
return false;
}
DatagramOutputFile dout;
if (!dout.open(temp_file)) {
if (!dout.open(temp_pathname)) {
util_cat.error()
<< "Could not write cache file: " << temp_pathname << "\n";
temp_pathname.unlink();
@ -248,7 +240,7 @@ store(BamCacheRecord *record) {
}
{
BamWriter writer(&dout, temp_pathname);
BamWriter writer(&dout);
if (!writer.init()) {
temp_pathname.unlink();
return false;
@ -279,8 +271,8 @@ store(BamCacheRecord *record) {
// delete any TypedWritables below that haven't been written yet.
}
record->_record_size = temp_file.tellp();
temp_file.close();
record->_record_size = dout.get_file_pos();
dout.close();
// Now move the file into place.
if (!temp_pathname.rename_to(cache_pathname) && temp_pathname.exists()) {
@ -669,22 +661,13 @@ check_cache_size() {
// success, or NULL on failure.
////////////////////////////////////////////////////////////////////
BamCacheIndex *BamCache::
do_read_index(Filename &index_pathname) {
do_read_index(const Filename &index_pathname) {
if (index_pathname.empty()) {
return NULL;
}
index_pathname.set_binary();
pifstream index_file;
if (!index_pathname.open_read(index_file)) {
util_cat.error()
<< "Could not open index file: " << index_pathname << "\n";
return NULL;
}
DatagramInputFile din;
if (!din.open(index_file)) {
if (!din.open(index_pathname)) {
util_cat.debug()
<< "Could not read index file: " << index_pathname << "\n";
return NULL;
@ -703,7 +686,7 @@ do_read_index(Filename &index_pathname) {
return NULL;
}
BamReader reader(&din, index_pathname);
BamReader reader(&din);
if (!reader.init()) {
return NULL;
}
@ -738,18 +721,9 @@ do_read_index(Filename &index_pathname) {
// Description: Writes the given index data to the specified filename.
////////////////////////////////////////////////////////////////////
bool BamCache::
do_write_index(Filename &index_pathname, const BamCacheIndex *index) {
index_pathname.set_binary();
pofstream index_file;
if (!index_pathname.open_write(index_file)) {
util_cat.error()
<< "Could not open index file: " << index_pathname << "\n";
return false;
}
do_write_index(const Filename &index_pathname, const BamCacheIndex *index) {
DatagramOutputFile dout;
if (!dout.open(index_file)) {
if (!dout.open(index_pathname)) {
util_cat.error()
<< "Could not write index file: " << index_pathname << "\n";
index_pathname.unlink();
@ -764,7 +738,7 @@ do_write_index(Filename &index_pathname, const BamCacheIndex *index) {
}
{
BamWriter writer(&dout, index_pathname);
BamWriter writer(&dout);
if (!writer.init()) {
index_pathname.unlink();
return false;
@ -776,7 +750,6 @@ do_write_index(Filename &index_pathname, const BamCacheIndex *index) {
}
}
index_file.close();
return true;
}
@ -866,18 +839,9 @@ read_record(const Filename &source_pathname,
// Description: Actually reads a record from the file.
////////////////////////////////////////////////////////////////////
PT(BamCacheRecord) BamCache::
do_read_record(Filename &cache_pathname, bool read_data) {
cache_pathname.set_binary();
pifstream cache_file;
if (!cache_pathname.open_read(cache_file)) {
util_cat.debug()
<< "Could not open cache file: " << cache_pathname << "\n";
return NULL;
}
do_read_record(const Filename &cache_pathname, bool read_data) {
DatagramInputFile din;
if (!din.open(cache_file)) {
if (!din.open(cache_pathname)) {
util_cat.debug()
<< "Could not read cache file: " << cache_pathname << "\n";
return NULL;
@ -896,7 +860,7 @@ do_read_record(Filename &cache_pathname, bool read_data) {
return NULL;
}
BamReader reader(&din, cache_pathname);
BamReader reader(&din);
if (!reader.init()) {
return NULL;
}
@ -944,10 +908,11 @@ do_read_record(Filename &cache_pathname, bool read_data) {
}
}
// Also get the file size.
cache_file.clear();
cache_file.seekg(0, ios::end);
record->_record_size = cache_file.tellg();
// Also get the total file size.
istream &in = din.get_stream();
in.clear();
in.seekg(0, ios::end);
record->_record_size = in.tellg();
// And the last access time is now, duh.
record->_record_access_time = time(NULL);

View File

@ -97,15 +97,15 @@ private:
void emergency_read_only();
static BamCacheIndex *do_read_index(Filename &index_pathname);
static bool do_write_index(Filename &index_pathname, const BamCacheIndex *index);
static BamCacheIndex *do_read_index(const Filename &index_pathname);
static bool do_write_index(const Filename &index_pathname, const BamCacheIndex *index);
PT(BamCacheRecord) find_and_read_record(const Filename &source_pathname,
const Filename &cache_filename);
PT(BamCacheRecord) read_record(const Filename &source_pathname,
const Filename &cache_filename,
int pass);
static PT(BamCacheRecord) do_read_record(Filename &cache_pathname,
static PT(BamCacheRecord) do_read_record(const Filename &cache_pathname,
bool read_data);
static string hash_filename(const string &filename);

View File

@ -66,6 +66,9 @@ operator << (ostream &out, BamEnums::BamObjectCode boc) {
case BamEnums::BOC_remove:
return out << "remove";
case BamEnums::BOC_file_data:
return out << "file_data";
}
return out << "**invalid BamEnums::BamObjectCode value: (" << (int)boc << ")**";

View File

@ -46,12 +46,15 @@ PUBLISHED:
// (which does not). A BOC_adjunct includes an object definition
// but does not push the level; it is associated with the current
// level. BOC_remove lists object ID's that have been deallocated
// on the sender end.
// on the sender end. BOC_file_data may appear at any level and
// indicates the following datagram contains auxiliary file data
// that may be referenced by a later object.
enum BamObjectCode {
BOC_push,
BOC_pop,
BOC_adjunct,
BOC_remove,
BOC_file_data,
};
// This enum is used to control how textures are written to a bam

View File

@ -22,6 +22,17 @@ INLINE BamReaderAuxData::
BamReaderAuxData() {
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::get_source
// Access: Published
// Description: Returns the current source of the BamReader as set by
// set_source() or the constructor.
////////////////////////////////////////////////////////////////////
INLINE DatagramGenerator *BamReader::
get_source() {
return _source;
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::get_filename
// Access: Published
@ -32,7 +43,11 @@ BamReaderAuxData() {
////////////////////////////////////////////////////////////////////
INLINE const Filename &BamReader::
get_filename() const {
return _filename;
if (_source != (DatagramGenerator *)NULL) {
return _source->get_filename();
}
static const Filename empty_filename;
return empty_filename;
}
////////////////////////////////////////////////////////////////////
@ -134,14 +149,27 @@ get_current_minor_ver() const {
////////////////////////////////////////////////////////////////////
// Function: BamReader::get_file
// Access: Public
// Description: Returns the FileReference that provides the source for
// these datagrams, if any, or NULL if the datagrams do
// not originate from a file on disk.
////////////////////////////////////////////////////////////////////
INLINE const FileReference *BamReader::
get_file() {
nassertr(_source != NULL, NULL);
return _source->get_file();
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::get_vfile
// Access: Public
// Description: Returns the VirtualFile that provides the source for
// these datagrams, if any, or NULL if the datagrams do
// not originate from a VirtualFile.
////////////////////////////////////////////////////////////////////
INLINE VirtualFile *BamReader::
get_file() {
get_vfile() {
nassertr(_source != NULL, NULL);
return _source->get_file();
return _source->get_vfile();
}
////////////////////////////////////////////////////////////////////

View File

@ -39,8 +39,8 @@ const int BamReader::_cur_minor = _bam_minor_ver;
// Description:
////////////////////////////////////////////////////////////////////
BamReader::
BamReader(DatagramGenerator *source, const Filename &name)
: _source(source), _filename(name)
BamReader(DatagramGenerator *source)
: _source(source)
{
_needs_init = true;
_num_extra_objects = 0;
@ -599,7 +599,7 @@ read_handle(DatagramIterator &scan) {
type = TypeRegistry::ptr()->register_dynamic_type(name);
bam_cat.warning()
<< "Bam file '" << _filename << "' contains objects of unknown type: "
<< "Bam file '" << get_filename() << "' contains objects of unknown type: "
<< type << "\n";
new_type = true;
_new_types.insert(type);
@ -653,7 +653,7 @@ read_handle(DatagramIterator &scan) {
// complete_pointers() callback function will be called
// with an array of actual pointers, one for each time
// read_pointer() was called. It is then the calling
// object's responsibilty to store these pointers in the
// object's responsibility to store these pointers in the
// object properly.
////////////////////////////////////////////////////////////////////
void BamReader::
@ -718,6 +718,30 @@ skip_pointer(DatagramIterator &scan) {
read_object_id(scan);
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::read_file_data
// Access: Public
// Description: Reads a block of auxiliary file data from the Bam
// file. This can be a block of arbitrary size, and it
// is assumed it may be quite large. Rather than
// reading the entire block into memory, a file
// reference is returned to locate the block on disk.
// The data must have been written by a matching call to
// write_file_data().
////////////////////////////////////////////////////////////////////
void BamReader::
read_file_data(SubfileInfo &info) {
// write_file_data() actually writes the blocks in datagrams prior
// to this particular datagram. Assume we get the calls to
// read_file_data() in the same order as the corresponding calls to
// write_file_data(), and just pop the first one off the
// queue. There's no actual data written to the stream at this
// point.
nassertv(!_file_data_records.empty());
info = _file_data_records.front();
_file_data_records.pop_front();
}
////////////////////////////////////////////////////////////////////
// Function: BamReader::read_cdata
// Access: Public
@ -962,7 +986,9 @@ register_change_this(ChangeThisRefFunc func, TypedWritableReferenceCount *object
////////////////////////////////////////////////////////////////////
void BamReader::
finalize_now(TypedWritable *whom) {
nassertv(whom != (TypedWritable *)NULL);
if (whom == (TypedWritable *)NULL) {
return;
}
Finalize::iterator fi = _finalize_list.find(whom);
if (fi != _finalize_list.end()) {
@ -1136,10 +1162,10 @@ read_pta_id(DatagramIterator &scan) {
////////////////////////////////////////////////////////////////////
int BamReader::
p_read_object() {
Datagram packet;
Datagram dg;
// First, read a datagram for the object.
if (!get_datagram(packet)) {
if (!get_datagram(dg)) {
// When we run out of datagrams, we're at the end of the file.
if (bam_cat.is_debug()) {
bam_cat.debug()
@ -1149,7 +1175,7 @@ p_read_object() {
}
// Now extract the object definition from the datagram.
DatagramIterator scan(packet);
DatagramIterator scan(dg);
// First, read the BamObjectCode. In bam versions prior to 6.21,
// there was no BamObjectCode in the stream.
@ -1179,6 +1205,23 @@ p_read_object() {
// next object id in the stream. It's easiest to do this by
// calling recursively.
return p_read_object();
case BOC_file_data:
// Another special case. This marks an auxiliary file data record
// that we skip over for now, but we note its position within the
// stream, so that we can hand it to a future object who may
// request it.
{
SubfileInfo info;
if (!_source->save_datagram(info)) {
bam_cat.error()
<< "Failed to read file data.\n";
return 0;
}
_file_data_records.push_back(info);
}
return p_read_object();
}
// An object definition in a Bam file consists of a TypeHandle

View File

@ -25,11 +25,13 @@
#include "datagramIterator.h"
#include "bamReaderParam.h"
#include "bamEnums.h"
#include "subfileInfo.h"
#include "loaderOptions.h"
#include "factory.h"
#include "vector_int.h"
#include "pset.h"
#include "pmap.h"
#include "pdeque.h"
#include "dcast.h"
#include "pipelineCyclerBase.h"
#include "referenceCount.h"
@ -125,10 +127,11 @@ public:
PUBLISHED:
// The primary interface for a caller.
BamReader(DatagramGenerator *source = NULL, const Filename &name = "");
BamReader(DatagramGenerator *source = NULL);
~BamReader();
void set_source(DatagramGenerator *source);
INLINE DatagramGenerator *get_source();
bool init();
@ -163,6 +166,8 @@ public:
void read_pointers(DatagramIterator &scan, int count);
void skip_pointer(DatagramIterator &scan);
void read_file_data(SubfileInfo &info);
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler);
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler,
void *extra_data);
@ -187,7 +192,8 @@ public:
TypeHandle read_handle(DatagramIterator &scan);
INLINE VirtualFile *get_file();
INLINE const FileReference *get_file();
INLINE VirtualFile *get_vfile();
INLINE streampos get_file_pos();
public:
@ -233,9 +239,6 @@ private:
typedef phash_map<int, TypeHandle, int_hash> IndexMap;
IndexMap _index_map;
// This is the filename of the BAM, or empty string if not in a file.
Filename _filename;
LoaderOptions _loader_options;
// This maps the object ID numbers encountered within the Bam file
@ -307,6 +310,12 @@ private:
PTAMap _pta_map;
int _pta_id;
// This is a queue of the currently-pending file data blocks that we
// have recently encountered in the stream and still expect a
// subsequent object to request.
typedef pdeque<SubfileInfo> FileDataRecords;
FileDataRecords _file_data_records;
// This is used internally to record all of the new types created
// on-the-fly to satisfy bam requirements. We keep track of this
// just so we can suppress warning messages from attempts to create

View File

@ -13,6 +13,17 @@
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: BamWriter::get_target
// Access: Published
// Description: Returns the current target of the BamWriter as set by
// set_target() or the constructor.
////////////////////////////////////////////////////////////////////
INLINE DatagramSink *BamWriter::
get_target() {
return _target;
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::get_filename
// Access: Published
@ -23,7 +34,11 @@
////////////////////////////////////////////////////////////////////
INLINE const Filename &BamWriter::
get_filename() const {
return _filename;
if (_target != (DatagramSink *)NULL) {
return _target->get_filename();
}
static const Filename empty_filename;
return empty_filename;
}
////////////////////////////////////////////////////////////////////

View File

@ -30,8 +30,7 @@
// Description:
////////////////////////////////////////////////////////////////////
BamWriter::
BamWriter(DatagramSink *target, const Filename &name) :
_filename(name),
BamWriter(DatagramSink *target) :
_target(target)
{
++_writing_seq;
@ -320,6 +319,74 @@ write_pointer(Datagram &packet, const TypedWritable *object) {
}
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::write_file_data
// Access: Public
// Description: Writes a block of auxiliary file data from the
// indicated file (within the vfs). This can be a block
// of arbitrary size, and it is assumed it may be quite
// large. This must be balanced by a matching call to
// read_file_data() on restore.
////////////////////////////////////////////////////////////////////
void BamWriter::
write_file_data(SubfileInfo &result, const Filename &filename) {
// We write file data by preceding with a singleton datagram that
// contains only the BOC_file_data token.
Datagram dg;
dg.add_uint8(BOC_file_data);
if (!_target->put_datagram(dg)) {
util_cat.error()
<< "Unable to write data to output.\n";
return;
}
// Then we can write the file data itself, as its own (possibly
// quite large) followup datagram.
if (!_target->copy_datagram(result, filename)) {
util_cat.error()
<< "Unable to write file data to output.\n";
return;
}
// Both of those get written to the bam stream prior to the datagram
// that represents this particular object, but they'll get pulled
// out in the same order and queued up in the BamReader.
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::write_file_data
// Access: Public
// Description: Writes a block of auxiliary file data from the
// indicated file (outside of the vfs). This can be a
// block of arbitrary size, and it is assumed it may be
// quite large. This must be balanced by a matching
// call to read_file_data() on restore.
////////////////////////////////////////////////////////////////////
void BamWriter::
write_file_data(SubfileInfo &result, const SubfileInfo &source) {
// We write file data by preceding with a singleton datagram that
// contains only the BOC_file_data token.
Datagram dg;
dg.add_uint8(BOC_file_data);
if (!_target->put_datagram(dg)) {
util_cat.error()
<< "Unable to write data to output.\n";
return;
}
// Then we can write the file data itself, as its own (possibly
// quite large) followup datagram.
if (!_target->copy_datagram(result, source)) {
util_cat.error()
<< "Unable to write file data to output.\n";
return;
}
// Both of those get written to the bam stream prior to the datagram
// that represents this particular object, but they'll get pulled
// out in the same order and queued up in the BamReader.
}
////////////////////////////////////////////////////////////////////
// Function: BamWriter::write_cdata
// Access: Public

View File

@ -72,10 +72,11 @@
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PUTIL BamWriter : public BamEnums {
PUBLISHED:
BamWriter(DatagramSink *target = NULL, const Filename &name = "");
BamWriter(DatagramSink *target = NULL);
~BamWriter();
void set_target(DatagramSink *target);
INLINE DatagramSink *get_target();
bool init();
INLINE const Filename &get_filename() const;
@ -94,6 +95,10 @@ public:
void consider_update(const TypedWritable *obj);
void write_pointer(Datagram &packet, const TypedWritable *dest);
void write_file_data(SubfileInfo &result, const Filename &filename);
void write_file_data(SubfileInfo &result, const SubfileInfo &source);
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler);
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler,
void *extra_data);
@ -108,9 +113,6 @@ private:
int enqueue_object(const TypedWritable *object);
bool flush_queue();
// This is the filename of the BAM, or null string if not in a file.
Filename _filename;
BamEndian _file_endian;
BamTextureMode _file_texture_mode;

View File

@ -15,7 +15,7 @@
////////////////////////////////////////////////////////////////////
// Function: DatagramInputFile::Constructor
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE DatagramInputFile::
@ -25,3 +25,26 @@ DatagramInputFile() {
_in = (istream *)NULL;
_owns_in = false;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramInputFile::open
// Access: Published
// Description: Opens the indicated filename for reading. Returns
// true on success, false on failure.
////////////////////////////////////////////////////////////////////
INLINE bool DatagramInputFile::
open(const Filename &filename) {
return open(new FileReference(filename));
}
////////////////////////////////////////////////////////////////////
// Function: DatagramInputFile::get_stream
// Access: Published
// Description: Returns the istream represented by the input file.
////////////////////////////////////////////////////////////////////
INLINE istream &DatagramInputFile::
get_stream() {
static ifstream null_stream;
nassertr(_in != NULL, null_stream);
return *_in;
}

View File

@ -13,6 +13,7 @@
////////////////////////////////////////////////////////////////////
#include "datagramInputFile.h"
#include "temporaryFile.h"
#include "numeric_types.h"
#include "datagramIterator.h"
#include "profileTimer.h"
@ -24,19 +25,22 @@
////////////////////////////////////////////////////////////////////
// Function: DatagramInputFile::open
// Access: Public
// Access: Published
// Description: Opens the indicated filename for reading. Returns
// true on success, false on failure.
////////////////////////////////////////////////////////////////////
bool DatagramInputFile::
open(Filename filename) {
open(const FileReference *file) {
close();
_file = file;
_filename = _file->get_filename();
// DatagramInputFiles are always binary.
filename.set_binary();
_filename.set_binary();
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
_vfile = vfs->get_file(filename);
_vfile = vfs->get_file(_filename);
if (_vfile == (VirtualFile *)NULL) {
// No such file.
return false;
@ -48,7 +52,7 @@ open(Filename filename) {
////////////////////////////////////////////////////////////////////
// Function: DatagramInputFile::open
// Access: Public
// Access: Published
// Description: Starts reading from the indicated stream. Returns
// true on success, false on failure. The
// DatagramInputFile does not take ownership of the
@ -56,18 +60,23 @@ open(Filename filename) {
// it when you are done.
////////////////////////////////////////////////////////////////////
bool DatagramInputFile::
open(istream &in) {
open(istream &in, const Filename &filename) {
close();
_in = &in;
_owns_in = false;
_filename = filename;
if (!filename.empty()) {
_file = new FileReference(filename);
}
return !_in->fail();
}
////////////////////////////////////////////////////////////////////
// Function: DatagramInputFile::close
// Access: Public
// Access: Published
// Description: Closes the file. This is also implicitly done when
// the DatagramInputFile destructs.
////////////////////////////////////////////////////////////////////
@ -82,13 +91,16 @@ close() {
_in = (istream *)NULL;
_owns_in = false;
_file.clear();
_filename = Filename();
_read_first_datagram = false;
_error = false;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramInputFile::read_header
// Access: Public
// Access: Published
// Description: Reads a sequence of bytes from the beginning of the
// datagram file. This may be called any number of
// times after the file has been opened and before the
@ -115,7 +127,7 @@ read_header(string &header, size_t num_bytes) {
////////////////////////////////////////////////////////////////////
// Function: DatagramInputFile::get_datagram
// Access: Public, Virtual
// Access: Published, Virtual
// Description: Reads the next datagram from the file. Returns true
// on success, false if there is an error or end of
// file.
@ -127,7 +139,7 @@ get_datagram(Datagram &data) {
// First, get the size of the upcoming datagram.
StreamReader reader(_in, false);
PN_uint32 num_bytes = reader.get_uint32();
size_t num_bytes = reader.get_uint32();
if (_in->fail() || _in->eof()) {
return false;
}
@ -175,9 +187,90 @@ get_datagram(Datagram &data) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramInputFile::save_datagram
// Access: Published, Virtual
// Description: Skips over the next datagram without extracting it,
// but saves the relevant file information in the
// SubfileInfo object so that its data may be read
// later. For non-file-based datagram generators, this
// may mean creating a temporary file and copying the
// contents of the datagram to disk.
//
// Returns true on success, false on failure or if this
// method is unimplemented.
////////////////////////////////////////////////////////////////////
bool DatagramInputFile::
save_datagram(SubfileInfo &info) {
nassertr(_in != (istream *)NULL, false);
_read_first_datagram = true;
// First, get the size of the upcoming datagram.
StreamReader reader(_in, false);
size_t num_bytes = reader.get_uint32();
if (_in->fail() || _in->eof()) {
return false;
}
// If this stream is file-based, we can just point the SubfileInfo
// directly into this file.
if (_file != (FileReference *)NULL) {
info = SubfileInfo(_file, _in->tellg(), num_bytes);
_in->seekg(num_bytes, ios::cur);
return true;
}
// Otherwise, we have to dump the data into a temporary file.
PT(TemporaryFile) tfile = new TemporaryFile(Filename::temporary("", ""));
pofstream out;
Filename filename = tfile->get_filename();
filename.set_binary();
if (!filename.open_write(out)) {
util_cat.error()
<< "Couldn't write to " << tfile->get_filename() << "\n";
return false;
}
if (util_cat.is_debug()) {
util_cat.debug()
<< "Copying " << num_bytes << " bytes to " << tfile->get_filename() << "\n";
}
size_t num_remaining = num_bytes;
static const size_t buffer_size = 4096;
char buffer[buffer_size];
_in->read(buffer, min(buffer_size, num_remaining));
size_t count = _in->gcount();
while (count != 0) {
out.write(buffer, count);
if (out.fail()) {
util_cat.error()
<< "Couldn't write " << num_bytes << " bytes to "
<< tfile->get_filename() << "\n";
return false;
}
num_remaining -= count;
if (num_remaining == 0) {
break;
}
_in->read(buffer, min(buffer_size, num_remaining));
count = _in->gcount();
}
if (num_remaining != 0) {
util_cat.error()
<< "Truncated data stream.\n";
return false;
}
info = SubfileInfo(tfile, 0, num_bytes);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramInputFile::is_eof
// Access: Public, Virtual
// Access: Published, Virtual
// Description: Returns true if the file has reached the end-of-file.
// This test may only be made after a call to
// read_header() or get_datagram() has failed.
@ -189,7 +282,7 @@ is_eof() {
////////////////////////////////////////////////////////////////////
// Function: DatagramInputFile::is_error
// Access: Public, Virtual
// Access: Published, Virtual
// Description: Returns true if the file has reached an error
// condition.
////////////////////////////////////////////////////////////////////
@ -205,21 +298,45 @@ is_error() {
return _error;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramInputFile::get_filename
// Access: Published, Virtual
// Description: Returns the filename that provides the source for
// these datagrams, if any, or empty string if the
// datagrams do not originate from a file on disk.
////////////////////////////////////////////////////////////////////
const Filename &DatagramInputFile::
get_filename() {
return _filename;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramInputFile::get_file
// Access: Public, Virtual
// Access: Published, Virtual
// Description: Returns the FileReference that provides the source for
// these datagrams, if any, or NULL if the datagrams do
// not originate from a file on disk.
////////////////////////////////////////////////////////////////////
const FileReference *DatagramInputFile::
get_file() {
return _file;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramInputFile::get_vfile
// Access: Published, Virtual
// Description: Returns the VirtualFile that provides the source for
// these datagrams, if any, or NULL if the datagrams do
// not originate from a VirtualFile.
////////////////////////////////////////////////////////////////////
VirtualFile *DatagramInputFile::
get_file() {
get_vfile() {
return _vfile;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramInputFile::get_file_pos
// Access: Public, Virtual
// Access: Published, Virtual
// Description: Returns the current file position within the data
// stream, if any, or 0 if the file position is not
// meaningful or cannot be determined.

View File

@ -19,6 +19,7 @@
#include "datagramGenerator.h"
#include "filename.h"
#include "fileReference.h"
#include "virtualFile.h"
////////////////////////////////////////////////////////////////////
@ -28,29 +29,36 @@
// of datagrams.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PUTIL DatagramInputFile : public DatagramGenerator {
public:
PUBLISHED:
INLINE DatagramInputFile();
bool open(Filename filename);
bool open(istream &in);
bool open(const FileReference *file);
INLINE bool open(const Filename &filename);
bool open(istream &in, const Filename &filename = Filename());
INLINE istream &get_stream();
void close();
bool read_header(string &header, size_t num_bytes);
virtual bool get_datagram(Datagram &data);
virtual bool save_datagram(SubfileInfo &info);
virtual bool is_eof();
virtual bool is_error();
virtual VirtualFile *get_file();
virtual const Filename &get_filename();
virtual const FileReference *get_file();
virtual VirtualFile *get_vfile();
virtual streampos get_file_pos();
private:
bool _read_first_datagram;
bool _error;
CPT(FileReference) _file;
PT(VirtualFile) _vfile;
pifstream _in_file;
istream *_in;
bool _owns_in;
Filename _filename;
};
#include "datagramInputFile.I"

View File

@ -25,3 +25,26 @@ DatagramOutputFile() {
_out = (ostream *)NULL;
_owns_out = false;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramOutputFile::open
// Access: Published
// Description: Opens the indicated filename for writing. Returns
// true on success, false on failure.
////////////////////////////////////////////////////////////////////
INLINE bool DatagramOutputFile::
open(const Filename &filename) {
return open(new FileReference(filename));
}
////////////////////////////////////////////////////////////////////
// Function: DatagramOutputFile::get_stream
// Access: Published
// Description: Returns the ostream represented by the output file.
////////////////////////////////////////////////////////////////////
INLINE ostream &DatagramOutputFile::
get_stream() {
static ofstream null_stream;
nassertr(_out != NULL, null_stream);
return *_out;
}

View File

@ -19,21 +19,24 @@
////////////////////////////////////////////////////////////////////
// Function: DatagramOutputFile::open
// Access: Public
// Description: Opens the indicated filename for reading. Returns
// Description: Opens the indicated filename for writing. Returns
// true if successful, false on failure.
////////////////////////////////////////////////////////////////////
bool DatagramOutputFile::
open(Filename filename) {
open(const FileReference *file) {
close();
_file = file;
_filename = _file->get_filename();
// DatagramOutputFiles are always binary.
filename.set_binary();
_filename.set_binary();
_out = &_out_file;
_owns_out = false;
#ifdef HAVE_ZLIB
if (filename.get_extension() == "pz") {
if (_filename.get_extension() == "pz") {
// The filename ends in .pz, which means to automatically
// compress the bam file that we write.
_out = new OCompressStream(_out, _owns_out);
@ -41,7 +44,7 @@ open(Filename filename) {
}
#endif // HAVE_ZLIB
return filename.open_write(_out_file);
return _filename.open_write(_out_file);
}
////////////////////////////////////////////////////////////////////
@ -54,11 +57,16 @@ open(Filename filename) {
// it when you are done.
////////////////////////////////////////////////////////////////////
bool DatagramOutputFile::
open(ostream &out) {
open(ostream &out, const Filename &filename) {
close();
_out = &out;
_owns_out = false;
_filename = filename;
if (!filename.empty()) {
_file = new FileReference(filename);
}
return !_out->fail();
}
@ -78,6 +86,9 @@ close() {
_out = (ostream *)NULL;
_owns_out = false;
_file.clear();
_filename = Filename();
_wrote_first_datagram = false;
_error = false;
}
@ -123,6 +134,130 @@ put_datagram(const Datagram &data) {
return !_out->fail();
}
////////////////////////////////////////////////////////////////////
// Function: DatagramOutputFile::copy_datagram
// Access: Published, Virtual
// Description: Copies the file data from the entire indicated
// file (via the vfs) as the next datagram. This is
// intended to support potentially very large datagrams.
//
// Returns true on success, false on failure or if this
// method is unimplemented. On true, fills "result"
// with the information that references the copied file,
// if possible.
////////////////////////////////////////////////////////////////////
bool DatagramOutputFile::
copy_datagram(SubfileInfo &result, const Filename &filename) {
nassertr(_out != (ostream *)NULL, false);
_wrote_first_datagram = true;
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
PT(VirtualFile) vfile = vfs->get_file(filename);
if (vfile == NULL) {
return false;
}
istream *in = vfile->open_read_file(true);
if (in == NULL) {
return false;
}
off_t size = vfile->get_file_size(in);
size_t num_remaining = (size_t)size;
nassertr(num_remaining == size, false);
StreamWriter writer(_out, false);
writer.add_uint32(num_remaining);
static const size_t buffer_size = 4096;
char buffer[buffer_size];
streampos start = _out->tellp();
in->read(buffer, min(buffer_size, num_remaining));
size_t count = in->gcount();
while (count != 0) {
_out->write(buffer, count);
if (_out->fail()) {
vfile->close_read_file(in);
return false;
}
num_remaining -= count;
if (num_remaining == 0) {
break;
}
in->read(buffer, min(buffer_size, num_remaining));
count = in->gcount();
}
vfile->close_read_file(in);
if (num_remaining != 0) {
util_cat.error()
<< "Truncated input stream.\n";
return false;
}
result = SubfileInfo(_file, start, size);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramOutputFile::copy_datagram
// Access: Published, Virtual
// Description: Copies the file data from the range of the indicated
// file (outside of the vfs) as the next datagram. This
// is intended to support potentially very large
// datagrams.
//
// Returns true on success, false on failure or if this
// method is unimplemented. On true, fills "result"
// with the information that references the copied file,
// if possible.
////////////////////////////////////////////////////////////////////
bool DatagramOutputFile::
copy_datagram(SubfileInfo &result, const SubfileInfo &source) {
nassertr(_out != (ostream *)NULL, false);
_wrote_first_datagram = true;
pifstream in;
if (!source.get_filename().open_read(in)) {
return false;
}
size_t num_remaining = source.get_size();
StreamWriter writer(_out, false);
writer.add_uint32(num_remaining);
static const size_t buffer_size = 4096;
char buffer[buffer_size];
streampos start = _out->tellp();
in.seekg(source.get_start());
in.read(buffer, min(buffer_size, num_remaining));
size_t count = in.gcount();
while (count != 0) {
_out->write(buffer, count);
if (_out->fail()) {
return false;
}
num_remaining -= count;
if (num_remaining == 0) {
break;
}
in.read(buffer, min(buffer_size, num_remaining));
count = in.gcount();
}
if (num_remaining != 0) {
util_cat.error()
<< "Truncated input stream.\n";
return false;
}
result = SubfileInfo(_file, start, source.get_size());
return true;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramOutputFile::is_error
// Access: Public, Virtual
@ -153,3 +288,48 @@ flush() {
_out->flush();
}
}
////////////////////////////////////////////////////////////////////
// Function: DatagramOutputFile::get_filename
// Access: Published, Virtual
// Description: Returns the filename that provides the target for
// these datagrams, if any, or empty string if the
// datagrams do not get written to a file on disk.
////////////////////////////////////////////////////////////////////
const Filename &DatagramOutputFile::
get_filename() {
return _filename;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramOutputFile::get_file
// Access: Published, Virtual
// Description: Returns the FileReference that provides the target for
// these datagrams, if any, or NULL if the datagrams do
// not written to a file on disk.
////////////////////////////////////////////////////////////////////
const FileReference *DatagramOutputFile::
get_file() {
return _file;
}
////////////////////////////////////////////////////////////////////
// Function: DatagramOutputFile::get_file_pos
// Access: Published, Virtual
// Description: Returns the current file position within the data
// stream, if any, or 0 if the file position is not
// meaningful or cannot be determined.
//
// For DatagramOutputFiles that return a meaningful file
// position, this will be pointing to the first byte
// following the datagram returned after a call to
// put_datagram().
////////////////////////////////////////////////////////////////////
streampos DatagramOutputFile::
get_file_pos() {
if (_out == (ostream *)NULL) {
return 0;
}
return _out->tellp();
}

View File

@ -19,6 +19,7 @@
#include "datagramSink.h"
#include "filename.h"
#include "fileReference.h"
////////////////////////////////////////////////////////////////////
// Class : DatagramOutputFile
@ -30,22 +31,32 @@ class EXPCL_PANDA_PUTIL DatagramOutputFile : public DatagramSink {
public:
INLINE DatagramOutputFile();
bool open(Filename filename);
bool open(ostream &out);
bool open(const FileReference *file);
INLINE bool open(const Filename &filename);
bool open(ostream &out, const Filename &filename = Filename());
INLINE ostream &get_stream();
void close();
bool write_header(const string &header);
virtual bool put_datagram(const Datagram &data);
virtual bool copy_datagram(SubfileInfo &result, const Filename &filename);
virtual bool copy_datagram(SubfileInfo &result, const SubfileInfo &source);
virtual bool is_error();
virtual void flush();
virtual const Filename &get_filename();
virtual const FileReference *get_file();
virtual streampos get_file_pos();
private:
bool _wrote_first_datagram;
bool _error;
CPT(FileReference) _file;
pofstream _out_file;
ostream *_out;
bool _owns_out;
Filename _filename;
};
#include "datagramOutputFile.I"

View File

@ -299,7 +299,7 @@ encode_to_bam_stream(string &data, BamWriter *writer) const {
return false;
}
BamWriter writer(&dout, "bam_stream");
BamWriter writer(&dout);
if (!writer.init()) {
return false;
}
@ -371,7 +371,7 @@ decode_raw_from_bam_stream(TypedWritable *&ptr, ReferenceCount *&ref_ptr,
return false;
}
BamReader reader(&din, "bam_stream");
BamReader reader(&din);
if (!reader.init()) {
return false;
}