support caching movie files in the model-cache-dir and in a txo file
This commit is contained in:
parent
b00edc02d4
commit
285d70c29e
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
@ -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 ©) :
|
||||
_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 ©) {
|
||||
_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;
|
||||
}
|
||||
|
|
@ -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 ©);
|
||||
INLINE void operator = (const FileSystemInfo ©);
|
||||
|
||||
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
|
||||
|
|
@ -26,7 +26,6 @@
|
|||
#include "referenceCount.h"
|
||||
#include "pvector.h"
|
||||
#include "openSSLWrapper.h"
|
||||
#include "fileSystemInfo.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : Multifile
|
||||
|
|
|
|||
|
|
@ -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 ©) :
|
||||
_file(copy._file),
|
||||
_start(copy._start),
|
||||
_size(copy._size)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SubfileInfo::Copy Assignment Operator
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void SubfileInfo::
|
||||
operator = (const SubfileInfo ©) {
|
||||
_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;
|
||||
}
|
||||
|
|
@ -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 << ")";
|
||||
}
|
||||
|
|
@ -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 ©);
|
||||
INLINE void operator = (const SubfileInfo ©);
|
||||
|
||||
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
|
||||
|
|
@ -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) {
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 ¶ms) {
|
||||
// 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 ¶ms) {
|
||||
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 ¶ms) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ¶ms);
|
||||
void fillin(DatagramIterator &scan, BamReader *manager, bool has_rawdata);
|
||||
void fillin_from(Texture *dummy);
|
||||
virtual TypedWritable *make_this_from_bam(const FactoryParams ¶ms);
|
||||
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() {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,8 @@ VideoPage() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE FFMpegTexture::VideoPage::
|
||||
VideoPage(const FFMpegTexture::VideoPage ©) :
|
||||
_color(copy._color)
|
||||
_color(copy._color),
|
||||
_alpha(copy._alpha)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -63,3 +64,14 @@ VideoPage(const FFMpegTexture::VideoPage ©) :
|
|||
INLINE FFMpegTexture::VideoPage::
|
||||
~VideoPage() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FFMpegTexture::VideoPage::Copy Assignment Operator
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void FFMpegTexture::VideoPage::
|
||||
operator = (const FFMpegTexture::VideoPage ©) {
|
||||
_color = copy._color;
|
||||
_alpha = copy._alpha;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ©) {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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 ¶ms) {
|
||||
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 ©) :
|
|||
{
|
||||
// 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 ©) {
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ©);
|
||||
~VideoStream();
|
||||
void operator = (const VideoStream ©);
|
||||
|
||||
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 ©);
|
||||
INLINE ~VideoPage();
|
||||
INLINE void operator = (const VideoPage ©);
|
||||
|
||||
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 ¶ms);
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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 ¶ms) {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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 ©);
|
||||
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 ¶ms);
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#ifndef FFMPEGAUDIO_H
|
||||
#define FFMPEGAUDIO_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#ifdef HAVE_FFMPEG
|
||||
|
||||
#include "movieAudio.h"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ¶ms) {
|
||||
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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ¶ms);
|
||||
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"
|
||||
|
|
|
|||
|
|
@ -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 ¶ms) {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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 ¶ms);
|
||||
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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: FfmpegVirtualFile::Copy Assignment Operator
|
||||
// Access: Private
|
||||
// Description: These objects are not meant to be copied.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void FfmpegVirtualFile::
|
||||
operator = (const FfmpegVirtualFile ©) {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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 ©);
|
||||
void operator = (const FfmpegVirtualFile ©);
|
||||
|
||||
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"
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "movieAudio.h"
|
||||
#include "movieAudioCursor.h"
|
||||
#include "ffmpegAudio.h"
|
||||
|
||||
TypeHandle MovieAudio::_type_handle;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 << ")**";
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 = ∈
|
||||
_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.
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue