Split vrpn out of panda into a libp3vrpn. Split ffmpeg out of movies into libp3ffmpeg. Add registry for MovieVideo and MovieAudio. Add a libvorbisfile-based Ogg Vorbis loader. Add a native .wav loader.

This commit is contained in:
rdb 2013-08-26 12:16:27 +00:00
parent 0821026944
commit bca09667a6
53 changed files with 1944 additions and 240 deletions

View File

@ -10,7 +10,7 @@
#define COMPONENT_LIBS \
p3recorder p3pgraph p3pgraphnodes p3pipeline \
p3vrpn p3grutil p3chan p3pstatclient \
p3grutil p3chan p3pstatclient \
p3char p3collide p3cull p3device \
p3dgraph p3display p3event p3gobj p3gsgbase \
p3linmath p3mathutil p3movies p3net p3nativenet \

View File

@ -59,6 +59,17 @@ audio-library-name p3openal_audio
load-file-type egg pandaegg
# These entries work very similar to load-file-type, except they are
# used by the MovieVideo and MovieAudio code to determine which module
# should be loaded in order to decode files of the given extension.
# ffmpeg is added by default because it used to be compiled in.
# The * is a special catch-all extension that is consulted unless a
# loader has been defined with an explicit extension.
load-audio-type * p3ffmpeg
load-video-type * p3ffmpeg
# The following lines define some handy object types to use within the
# egg syntax. This remaps <ObjectType> { name } into whatever egg

View File

@ -0,0 +1,44 @@
#define BUILD_DIRECTORY $[HAVE_FFMPEG]
#define OTHER_LIBS p3interrogatedb:c p3dconfig:c p3dtoolconfig:m \
p3dtoolutil:c p3dtoolbase:c p3dtool:m p3prc:c
#define BUILDING_DLL BUILDING_FFMPEG
#define USE_PACKAGES ffmpeg
#begin lib_target
#define TARGET p3ffmpeg
#define LOCAL_LIBS p3movies
#define COMBINED_SOURCES \
$[TARGET]_composite1.cxx
#define SOURCES \
config_ffmpeg.h \
ffmpegVideo.h ffmpegVideo.I \
ffmpegVideoCursor.h ffmpegVideoCursor.I \
ffmpegAudio.h ffmpegAudio.I \
ffmpegAudioCursor.h ffmpegAudioCursor.I \
ffmpegVirtualFile.h ffmpegVirtualFile.I
#define INCLUDED_SOURCES \
config_ffmpeg.cxx \
ffmpegVideo.cxx \
ffmpegVideoCursor.cxx \
ffmpegAudio.cxx \
ffmpegAudioCursor.cxx \
ffmpegVirtualFile.cxx
#define INSTALL_HEADERS \
config_ffmpeg.h \
ffmpegVideo.h ffmpegVideo.I \
ffmpegVideoCursor.h ffmpegVideoCursor.I \
ffmpegAudio.h ffmpegAudio.I \
ffmpegAudioCursor.h ffmpegAudioCursor.I \
ffmpegVirtualFile.h ffmpegVirtualFile.I
#define IGATESCAN all
#end lib_target

View File

@ -0,0 +1,110 @@
// Filename: config_ffmpeg.cxx
// Created by: rdb (23Aug13)
//
////////////////////////////////////////////////////////////////////
//
// 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 "config_ffmpeg.h"
#include "dconfig.h"
#include "ffmpegVideo.h"
#include "ffmpegVideoCursor.h"
#include "ffmpegAudio.h"
#include "ffmpegAudioCursor.h"
#include "movieTypeRegistry.h"
extern "C" {
#include "libavcodec/avcodec.h"
}
ConfigureDef(config_ffmpeg);
NotifyCategoryDef(ffmpeg, "");
ConfigureFn(config_ffmpeg) {
init_libffmpeg();
}
ConfigVariableInt ffmpeg_max_readahead_frames
("ffmpeg-max-readahead-frames", 2,
PRC_DESC("The maximum number of frames ahead which an ffmpeg decoder thread "
"should read in advance of actual playback. Set this to 0 to "
"decode ffmpeg videos in the main thread."));
ConfigVariableBool ffmpeg_show_seek_frames
("ffmpeg-show-seek-frames", true,
PRC_DESC("Set this true to allow showing the intermediate results of seeking "
"through the ffmpeg stream to a target frame, or false to hold the "
"current frame until the target frame is achieved. This has the "
"biggest effect on videos that are too expensive to decode in real "
"time: when this is true, the video can be seen to animate at least "
"a little bit; when it is false, you may get long periods of one "
"held frame."));
ConfigVariableBool ffmpeg_support_seek
("ffmpeg-support-seek", true,
PRC_DESC("True to use the av_seek_frame() function to seek within ffmpeg "
"video files. If this is false, Panda will only seek within a "
"file by reading it from the beginning until the desired point, "
"which can be much slower. Set this false only if you suspect "
"a problem with av_seek_frame()."));
ConfigVariableBool ffmpeg_global_lock
("ffmpeg-global-lock", false,
PRC_DESC("Set this true to enable a single global mutex across *all* ffmpeg "
"operations. Leave this false to use the mutex only for "
"the ffmpeg operations that are generally known to be "
"not thread-safe. This will negatively affect ffmpeg performance, "
"especially when decoding multiple videos at once (including the "
"left and right channels of a stereo video). Set this true only "
"if you suspect a problem with ffmpeg's own thread-safe nature."));
ConfigVariableEnum<ThreadPriority> ffmpeg_thread_priority
("ffmpeg-thread-priority", TP_normal,
PRC_DESC("The default thread priority at which to start ffmpeg decoder "
"threads."));
ConfigVariableInt ffmpeg_read_buffer_size
("ffmpeg-read-buffer-size", 4096,
PRC_DESC("The size in bytes of the buffer used when reading input files. "
"This is important for performance. A typical size is that of a "
"cache page, e.g. 4kb."));
////////////////////////////////////////////////////////////////////
// Function: init_libffmpeg
// Description: Initializes the library. This must be called at
// least once before any of the functions or classes in
// this library can be used. Normally it will be
// called by the static initializers and need not be
// called explicitly, but special cases exist.
////////////////////////////////////////////////////////////////////
void
init_libffmpeg() {
static bool initialized = false;
if (initialized) {
return;
}
initialized = true;
FfmpegVirtualFile::register_protocol();
FfmpegVideo::init_type();
FfmpegVideoCursor::init_type();
FfmpegAudio::init_type();
FfmpegAudioCursor::init_type();
FfmpegVideo::register_with_read_factory();
FfmpegVideoCursor::register_with_read_factory();
// Register ffmpeg as catch-all audio/video type.
MovieTypeRegistry *reg = MovieTypeRegistry::get_global_ptr();
reg->register_audio_type(&FfmpegAudio::make, "*");
reg->register_video_type(&FfmpegVideo::make, "*");
}

View File

@ -0,0 +1,31 @@
// Filename: config_ffmpeg.h
// Created by: rdb (23Aug13)
//
////////////////////////////////////////////////////////////////////
//
// 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 CONFIG_FFMPEG_H
#define CONFIG_FFMPEG_H
#include "pandabase.h"
#include "notifyCategoryProxy.h"
#include "configVariableEnum.h"
#include "configVariableInt.h"
#include "configVariableBool.h"
#include "threadPriority.h"
#include "dconfig.h"
ConfigureDecl(config_ffmpeg, EXPCL_FFMPEG, EXPTP_FFMPEG);
NotifyCategoryDecl(ffmpeg, EXPCL_FFMPEG, EXPTP_FFMPEG);
extern EXPCL_FFMPEG void init_libffmpeg();
#endif /* CONFIG_FFMPEG_H */

View File

@ -13,10 +13,8 @@
////////////////////////////////////////////////////////////////////
#include "ffmpegAudio.h"
#ifdef HAVE_FFMPEG
#include "ffmpegAudioCursor.h"
#include "dcast.h"
TypeHandle FfmpegAudio::_type_handle;
@ -50,7 +48,7 @@ PT(MovieAudioCursor) FfmpegAudio::
open() {
PT(FfmpegAudioCursor) result = new FfmpegAudioCursor(this);
if (result->_format_ctx == 0) {
movies_cat.error() << "Could not open " << _filename << "\n";
ffmpeg_cat.error() << "Could not open " << _filename << "\n";
return NULL;
} else {
return (MovieAudioCursor*)(FfmpegAudioCursor*)result;
@ -58,5 +56,11 @@ open() {
}
////////////////////////////////////////////////////////////////////
#endif // HAVE_FFMPEG
// Function: FfmpegAudio::make
// Access: Published, Static
// Description: Obtains a MovieAudio that references a file.
////////////////////////////////////////////////////////////////////
PT(MovieAudio) FfmpegAudio::
make(const Filename &name) {
return DCAST(MovieAudio, new FfmpegAudio(name));
}

View File

@ -16,9 +16,6 @@
#define FFMPEGAUDIO_H
#include "pandabase.h"
#ifdef HAVE_FFMPEG
#include "movieAudio.h"
class FfmpegAudioCursor;
@ -27,13 +24,14 @@ class FfmpegAudioCursor;
// Class : FfmpegAudio
// Description : A stream that generates a sequence of audio samples.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_MOVIES FfmpegAudio : public MovieAudio {
class EXPCL_FFMPEG FfmpegAudio : public MovieAudio {
PUBLISHED:
FfmpegAudio(const Filename &name);
virtual ~FfmpegAudio();
virtual PT(MovieAudioCursor) open();
static PT(MovieAudio) make(const Filename &name);
private:
friend class FfmpegAudioCursor;
@ -57,5 +55,4 @@ private:
#include "ffmpegAudio.I"
#endif // HAVE_FFMPEG
#endif // FFMPEG_AUDIO.H
#endif // FFMPEGAUDIO_H

View File

@ -14,8 +14,6 @@
#include "ffmpegAudioCursor.h"
#ifdef HAVE_FFMPEG
#include "ffmpegAudio.h"
extern "C" {
#include "libavutil/dict.h"
@ -116,10 +114,10 @@ FfmpegAudioCursor(FfmpegAudio *src) :
if (_audio_ctx->sample_fmt != AV_SAMPLE_FMT_S16) {
#ifdef HAVE_SWRESAMPLE
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(53, 25, 0)
movies_cat.error()
ffmpeg_cat.error()
<< "Codec does not use signed 16-bit sample format. Upgrade libavcodec to 53.25.0 or higher.\n";
#else
movies_cat.debug()
ffmpeg_cat.debug()
<< "Codec does not use signed 16-bit sample format. Setting up swresample context.\n";
#endif
@ -132,12 +130,12 @@ FfmpegAudioCursor(FfmpegAudio *src) :
av_opt_set_sample_fmt(_resample_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
if (swr_init(_resample_ctx) != 0) {
movies_cat.error()
ffmpeg_cat.error()
<< "Failed to set up resample context.\n";
_resample_ctx = NULL;
}
#else
movies_cat.error()
ffmpeg_cat.error()
<< "Codec does not use signed 16-bit sample format, but support for libswresample has not been enabled.\n";
#endif
}
@ -354,7 +352,7 @@ seek(double t) {
target_ts = _initial_dts;
}
if (av_seek_frame(_format_ctx, _audio_index, target_ts, AVSEEK_FLAG_BACKWARD) < 0) {
movies_cat.error() << "Seek failure. Shutting down movie.\n";
ffmpeg_cat.error() << "Seek failure. Shutting down movie.\n";
cleanup();
return;
}
@ -417,7 +415,3 @@ read_samples(int n, PN_int16 *data) {
}
_samples_read += n;
}
////////////////////////////////////////////////////////////////////
#endif // HAVE_FFMPEG

View File

@ -17,8 +17,6 @@
#include "pandabase.h"
#ifdef HAVE_FFMPEG
#include "movieAudioCursor.h"
#include "namable.h"
#include "texture.h"
@ -43,7 +41,7 @@ struct SwrContext;
// Class : FfmpegAudioCursor
// Description : A stream that generates a sequence of audio samples.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_MOVIES FfmpegAudioCursor : public MovieAudioCursor {
class EXPCL_FFMPEG FfmpegAudioCursor : public MovieAudioCursor {
friend class FfmpegAudio;
PUBLISHED:
@ -85,7 +83,7 @@ public:
return _type_handle;
}
static void init_type() {
TypedWritableReferenceCount::init_type();
MovieAudioCursor::init_type();
register_type(_type_handle, "FfmpegAudioCursor",
MovieAudioCursor::get_class_type());
}
@ -100,5 +98,4 @@ private:
#include "ffmpegAudioCursor.I"
#endif // HAVE_FFMPEG
#endif // FFMPEG_AUDIO.H
#endif // FFMPEGAUDIOCURSOR_H

View File

@ -13,12 +13,10 @@
////////////////////////////////////////////////////////////////////
#include "ffmpegVideo.h"
#ifdef HAVE_FFMPEG
#include "ffmpegVideoCursor.h"
#include "config_movies.h"
#include "bamReader.h"
#include "dcast.h"
TypeHandle FfmpegVideo::_type_handle;
@ -70,13 +68,23 @@ PT(MovieVideoCursor) FfmpegVideo::
open() {
PT(FfmpegVideoCursor) result = new FfmpegVideoCursor(this);
if (result->_format_ctx == 0) {
movies_cat.error() << "Could not open " << _filename << "\n";
ffmpeg_cat.error() << "Could not open " << _filename << "\n";
return NULL;
} else {
return result.p();
}
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideo::make
// Access: Published, Static
// Description: Obtains a MovieVideo that references a file.
////////////////////////////////////////////////////////////////////
PT(MovieVideo) FfmpegVideo::
make(const Filename &name) {
return DCAST(MovieVideo, new FfmpegVideo(name));
}
////////////////////////////////////////////////////////////////////
// Function: FfmpegVideo::register_with_read_factory
// Access: Public, Static
@ -130,7 +138,3 @@ void FfmpegVideo::
fillin(DatagramIterator &scan, BamReader *manager) {
MovieVideo::fillin(scan, manager);
}
////////////////////////////////////////////////////////////////////
#endif // HAVE_FFMPEG

View File

@ -17,8 +17,6 @@
#include "pandabase.h"
#ifdef HAVE_FFMPEG
#include "movieVideo.h"
class FfmpegVideoCursor;
@ -30,15 +28,16 @@ class BamReader;
// Class : FfmpegVideo
// Description :
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_MOVIES FfmpegVideo : public MovieVideo {
class EXPCL_FFMPEG FfmpegVideo : public MovieVideo {
PUBLISHED:
FfmpegVideo(const Filename &name);
FfmpegVideo(const SubfileInfo &info);
virtual ~FfmpegVideo();
virtual PT(MovieVideoCursor) open();
static PT(MovieVideo) make(const Filename &name);
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
@ -69,5 +68,4 @@ private:
#include "ffmpegVideo.I"
#endif // HAVE_FFMPEG
#endif // FFMPEGVIDEO_H

View File

@ -13,9 +13,6 @@
////////////////////////////////////////////////////////////////////
#include "ffmpegVideoCursor.h"
#ifdef HAVE_FFMPEG
#include "config_movies.h"
#include "pStatCollector.h"
#include "pStatTimer.h"
@ -1299,5 +1296,3 @@ get_timestamp() const {
int mid_frame = (_begin_frame + _end_frame - 1) / 2;
return mid_frame * _video_timebase;
}
#endif // HAVE_FFMPEG

View File

@ -16,9 +16,6 @@
#define FFMPEGVIDEOCURSOR_H
#include "pandabase.h"
#ifdef HAVE_FFMPEG
#include "movieVideoCursor.h"
#include "texture.h"
#include "pointerTo.h"
@ -42,7 +39,7 @@ struct SwsContext;
// Class : FfmpegVideoCursor
// Description :
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_MOVIES FfmpegVideoCursor : public MovieVideoCursor {
class EXPCL_FFMPEG FfmpegVideoCursor : public MovieVideoCursor {
private:
FfmpegVideoCursor();
void init_from(FfmpegVideo *src);
@ -67,7 +64,7 @@ public:
public:
// Nested class must be public for PT(FfmpegBuffer) to work correctly.
class EXPCL_PANDA_MOVIES FfmpegBuffer : public Buffer {
class EXPCL_FFMPEG FfmpegBuffer : public Buffer {
public:
ALLOC_DELETED_CHAIN(FfmpegBuffer);
INLINE FfmpegBuffer(size_t block_size, double video_timebase);
@ -215,5 +212,4 @@ private:
#include "ffmpegVideoCursor.I"
#endif // HAVE_FFMPEG
#endif // FFMPEGVIDEO_H

View File

@ -14,8 +14,6 @@
#include "pandabase.h"
#ifdef HAVE_FFMPEG
#include "config_movies.h"
#include "ffmpegVirtualFile.h"
#include "virtualFileSystem.h"
@ -349,5 +347,3 @@ log_callback(void *ptr, int level, const char *fmt, va_list v1) {
<< buffer;
}
}
#endif // HAVE_FFMPEG

View File

@ -16,9 +16,6 @@
#define FFMPEGVIRTUALFILE_H
#include "pandabase.h"
#ifdef HAVE_FFMPEG
#include "config_movies.h"
#include "filename.h"
#include "subfileInfo.h"
@ -37,7 +34,7 @@ struct AVFormatContext;
// instance of the FfmpegVirtualFile for each ffmpeg
// stream you wish to open.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_MOVIES FfmpegVirtualFile {
class EXPCL_FFMPEG FfmpegVirtualFile {
public:
FfmpegVirtualFile();
~FfmpegVirtualFile();
@ -76,5 +73,4 @@ private:
#include "ffmpegVirtualFile.I"
#endif // HAVE_FFMPEG
#endif // FFMPEGVIRTUALFILE_H

View File

@ -1,3 +1,4 @@
#include "config_ffmpeg.cxx"
#include "ffmpegAudio.cxx"
#include "ffmpegVideo.cxx"
#include "ffmpegVirtualFile.cxx"

View File

@ -1,8 +1,6 @@
#define OTHER_LIBS p3interrogatedb:c p3dconfig:c p3dtoolconfig:m \
p3dtoolutil:c p3dtoolbase:c p3dtool:m p3prc:c
#define USE_PACKAGES ffmpeg
#begin lib_target
#define TARGET p3grutil
#define LOCAL_LIBS \

View File

@ -118,14 +118,8 @@ init_libgrutil() {
#ifdef HAVE_AUDIO
MovieTexture::init_type();
MovieTexture::register_with_read_factory();
#endif // HAVE_AUDIO
#ifdef HAVE_FFMPEG
MovieTexture::init_type();
MovieTexture::register_with_read_factory();
TexturePool *ts = TexturePool::get_global_ptr();
ts->register_texture_type(MovieTexture::make_texture, "avi mov mpg mpeg mp4 wmv asf flv nut ogm mkv ogv");
#endif // HAVE_FFMPEG
#endif
}

View File

@ -20,6 +20,7 @@
#ifdef HAVE_AUDIO
#include "movieVideo.h"
#include "movieVideoCursor.h"
#include "audioSound.h"
#include "pipelineCycler.h"
#include "cycleData.h"

View File

@ -1,68 +1,67 @@
#define OTHER_LIBS p3interrogatedb:c p3dconfig:c p3dtoolconfig:m \
p3dtoolutil:c p3dtoolbase:c p3dtool:m p3prc:c
#define USE_PACKAGES ffmpeg dx9
#define WIN_SYS_LIBS strmiids.lib
#begin lib_target
#define TARGET p3movies
#define LOCAL_LIBS \
p3gobj
#define LOCAL_LIBS p3gobj
#define USE_PACKAGES dx9 vorbis
#define WIN_SYS_LIBS $[WIN_SYS_LIBS] strmiids.lib
#define COMBINED_SOURCES \
$[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
$[TARGET]_composite1.cxx
#define SOURCES \
movieAudio.h movieAudio.I \
movieAudioCursor.h movieAudioCursor.I \
movieVideo.h movieVideo.I \
movieVideoCursor.h movieVideoCursor.I \
config_movies.h \
inkblotVideo.h inkblotVideo.I \
inkblotVideoCursor.h inkblotVideoCursor.I \
ffmpegVideo.h ffmpegVideo.I \
ffmpegVideoCursor.h ffmpegVideoCursor.I \
ffmpegAudio.h ffmpegAudio.I \
ffmpegAudioCursor.h ffmpegAudioCursor.I \
ffmpegVirtualFile.h ffmpegVirtualFile.I \
microphoneAudio.h microphoneAudio.I \
movieAudio.h movieAudio.I \
movieAudioCursor.h movieAudioCursor.I \
movieTypeRegistry.h movieTypeRegistry.I \
movieVideo.h movieVideo.I \
movieVideoCursor.h movieVideoCursor.I \
userDataAudio.h userDataAudio.I \
userDataAudioCursor.h userDataAudioCursor.I \
microphoneAudio.h microphoneAudio.I \
config_movies.h
vorbisAudio.h vorbisAudio.I \
vorbisAudioCursor.h vorbisAudioCursor.I \
wavAudio.h wavAudio.I \
wavAudioCursor.h wavAudioCursor.I
#define INCLUDED_SOURCES \
movieVideo.cxx \
movieVideoCursor.cxx \
movieAudio.cxx \
movieAudioCursor.cxx \
config_movies.cxx \
inkblotVideo.cxx \
inkblotVideoCursor.cxx \
ffmpegVideo.cxx \
ffmpegVideoCursor.cxx \
ffmpegAudio.cxx \
ffmpegAudioCursor.cxx \
ffmpegVirtualFile.cxx \
userDataAudio.cxx \
userDataAudioCursor.cxx \
microphoneAudio.cxx \
microphoneAudioDS.cxx \
config_movies.cxx
movieAudio.cxx \
movieAudioCursor.cxx \
movieTypeRegistry.cxx \
movieVideo.cxx \
movieVideoCursor.cxx \
userDataAudio.cxx \
userDataAudioCursor.cxx \
vorbisAudio.cxx \
vorbisAudioCursor.cxx \
wavAudio.cxx \
wavAudioCursor.cxx
#define INSTALL_HEADERS \
movieAudio.h movieAudio.I \
movieAudioCursor.h movieAudioCursor.I \
movieVideo.h movieVideo.I \
movieVideoCursor.h movieVideoCursor.I \
config_movies.h \
inkblotVideo.h inkblotVideo.I \
inkblotVideoCursor.h inkblotVideoCursor.I \
ffmpegVideo.h ffmpegVideo.I \
ffmpegVideoCursor.h ffmpegVideoCursor.I \
ffmpegAudio.h ffmpegAudio.I \
ffmpegAudioCursor.h ffmpegAudioCursor.I \
ffmpegVirtualFile.h ffmpegVirtualFile.I \
microphoneAudio.h microphoneAudio.I \
config_movies.h
movieAudio.h movieAudio.I \
movieAudioCursor.h movieAudioCursor.I \
movieTypeRegistry.h movieTypeRegistry.I \
movieVideo.h movieVideo.I \
movieVideoCursor.h movieVideoCursor.I \
vorbisAudio.h vorbisAudio.I \
vorbisAudioCursor.h vorbisAudioCursor.I \
wavAudio.h wavAudio.I \
wavAudioCursor.h wavAudioCursor.I
#define IGATESCAN all
#end lib_target

View File

@ -14,78 +14,48 @@
#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"
#include "microphoneAudio.h"
#include "movieAudio.h"
#include "movieAudioCursor.h"
#include "movieTypeRegistry.h"
#include "movieVideo.h"
#include "movieVideoCursor.h"
#include "userDataAudio.h"
#include "userDataAudioCursor.h"
#include "microphoneAudio.h"
#ifdef HAVE_FFMPEG
extern "C" {
#include "libavcodec/avcodec.h"
}
#endif
#include "vorbisAudio.h"
#include "vorbisAudioCursor.h"
#include "wavAudio.h"
#include "wavAudioCursor.h"
ConfigureDef(config_movies);
NotifyCategoryDef(movies, "");
NotifyCategoryDef(ffmpeg, "movies");
ConfigureFn(config_movies) {
init_libmovies();
}
ConfigVariableInt ffmpeg_max_readahead_frames
("ffmpeg-max-readahead-frames", 2,
PRC_DESC("The maximum number of frames ahead which an ffmpeg decoder thread "
"should read in advance of actual playback. Set this to 0 to "
"decode ffmpeg videos in the main thread."));
ConfigVariableList load_audio_type
("load-audio-type",
PRC_DESC("List the audio loader modules that Panda will automatically "
"import when a new, unknown audio type is loaded. This may be "
"either the name of a module, or a space-separate list of filename "
"extensions, followed by the name of the module."));
ConfigVariableBool ffmpeg_show_seek_frames
("ffmpeg-show-seek-frames", true,
PRC_DESC("Set this true to allow showing the intermediate results of seeking "
"through the ffmpeg stream to a target frame, or false to hold the "
"current frame until the target frame is achieved. This has the "
"biggest effect on videos that are too expensive to decode in real "
"time: when this is true, the video can be seen to animate at least "
"a little bit; when it is false, you may get long periods of one "
"held frame."));
ConfigVariableList load_video_type
("load-video-type",
PRC_DESC("List the video loader modules that Panda will automatically "
"import when a new, unknown video type is loaded. This may be "
"either the name of a module, or a space-separate list of filename "
"extensions, followed by the name of the module."));
ConfigVariableBool ffmpeg_support_seek
("ffmpeg-support-seek", true,
PRC_DESC("True to use the av_seek_frame() function to seek within ffmpeg "
"video files. If this is false, Panda will only seek within a "
"file by reading it from the beginning until the desired point, "
"which can be much slower. Set this false only if you suspect "
"a problem with av_seek_frame()."));
ConfigVariableBool ffmpeg_global_lock
("ffmpeg-global-lock", false,
PRC_DESC("Set this true to enable a single global mutex across *all* ffmpeg "
"operations. Leave this false to use the mutex only for "
"the ffmpeg operations that are generally known to be "
"not thread-safe. This will negatively affect ffmpeg performance, "
"especially when decoding multiple videos at once (including the "
"left and right channels of a stereo video). Set this true only "
"if you suspect a problem with ffmpeg's own thread-safe nature."));
ConfigVariableEnum<ThreadPriority> ffmpeg_thread_priority
("ffmpeg-thread-priority", TP_normal,
PRC_DESC("The default thread priority at which to start ffmpeg decoder "
"threads."));
ConfigVariableInt ffmpeg_read_buffer_size
("ffmpeg-read-buffer-size", 4096,
PRC_DESC("The size in bytes of the buffer used when reading input files. "
"This is important for performance. A typical size is that of a "
"cache page, e.g. 4kb."));
ConfigVariableBool vorbis_seek_lap
("vorbis-seek-lap", true,
PRC_DESC("If this is set to true, the Ogg Vorbis decoder will automatically "
"crosslap the transition from the previous playback position into "
"the new playback position when seeking in order to eliminate "
"clicking and boundary discontinuities."));
////////////////////////////////////////////////////////////////////
// Function: init_libmovies
@ -103,26 +73,27 @@ init_libmovies() {
}
initialized = true;
MovieVideo::init_type();
MovieVideoCursor::init_type();
MovieAudio::init_type();
MovieAudioCursor::init_type();
InkblotVideo::init_type();
InkblotVideoCursor::init_type();
MicrophoneAudio::init_type();
MovieAudio::init_type();
MovieAudioCursor::init_type();
MovieVideo::init_type();
MovieVideoCursor::init_type();
UserDataAudio::init_type();
UserDataAudioCursor::init_type();
MicrophoneAudio::init_type();
WavAudio::init_type();
WavAudioCursor::init_type();
#ifdef HAVE_FFMPEG
FfmpegVirtualFile::register_protocol();
#ifdef HAVE_VORBIS
VorbisAudio::init_type();
VorbisAudioCursor::init_type();
#endif
FfmpegVideo::init_type();
FfmpegVideoCursor::init_type();
FfmpegAudio::init_type();
FfmpegAudioCursor::init_type();
MovieTypeRegistry *reg = MovieTypeRegistry::get_global_ptr();
reg->register_audio_type(&WavAudio::make, "wav wave");
FfmpegVideo::register_with_read_factory();
FfmpegVideoCursor::register_with_read_factory();
#ifdef HAVE_VORBIS
reg->register_audio_type(&VorbisAudio::make, "ogg oga");
#endif
}

View File

@ -12,28 +12,24 @@
//
////////////////////////////////////////////////////////////////////
#ifndef __CONFIG_MOVIES_H__
#define __CONFIG_MOVIES_H__
#ifndef CONFIG_MOVIES_H
#define CONFIG_MOVIES_H
#include "pandabase.h"
#include "notifyCategoryProxy.h"
#include "configVariableEnum.h"
#include "configVariableInt.h"
#include "configVariableBool.h"
#include "configVariableList.h"
#include "threadPriority.h"
#include "dconfig.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);
extern ConfigVariableInt ffmpeg_max_readahead_frames;
extern ConfigVariableBool ffmpeg_show_seek_frames;
extern ConfigVariableBool ffmpeg_support_seek;
extern ConfigVariableBool ffmpeg_global_lock;
extern ConfigVariableEnum<ThreadPriority> ffmpeg_thread_priority;
extern ConfigVariableInt ffmpeg_read_buffer_size;
extern ConfigVariableList load_audio_type;
extern ConfigVariableList load_video_type;
extern ConfigVariableBool vorbis_seek_lap;
extern EXPCL_PANDA_MOVIES void init_libmovies();
#endif /* __CONFIG_MOVIES_H__ */
#endif /* CONFIG_MOVIES_H */

View File

@ -19,6 +19,7 @@
#include "texture.h"
#include "pointerTo.h"
#include "inkblotVideo.h"
#include "movieVideoCursor.h"
////////////////////////////////////////////////////////////////////
// Class : InkblotVideoCursor

View File

@ -52,7 +52,7 @@ protected:
return _type_handle;
}
static void init_type() {
TypedWritableReferenceCount::init_type();
MovieAudio::init_type();
register_type(_type_handle, "MicrophoneAudio",
MovieAudio::get_class_type());
}

View File

@ -14,7 +14,8 @@
#include "movieAudio.h"
#include "movieAudioCursor.h"
#include "ffmpegAudio.h"
#include "config_movies.h"
#include "movieTypeRegistry.h"
TypeHandle MovieAudio::_type_handle;
@ -55,14 +56,10 @@ open() {
// Function: MovieAudio::get
// Access: Published, Static
// Description: Obtains a MovieAudio that references a file.
// Just calls MovieTypeRegistry::make_audio().
////////////////////////////////////////////////////////////////////
PT(MovieAudio) MovieAudio::
get(const Filename &name) {
#ifdef HAVE_FFMPEG
// Someday, I'll probably put a dispatcher here.
// But for now, just hardwire it to go to FFMPEG.
return new FfmpegAudio(name);
#else
return new MovieAudio("Load-Failure Stub");
#endif
MovieTypeRegistry *reg = MovieTypeRegistry::get_global_ptr();
return reg->make_audio(name);
}

View File

@ -19,8 +19,8 @@
#include "namable.h"
#include "pointerTo.h"
#include "typedWritableReferenceCount.h"
class MovieAudioCursor;
class MovieAudioCursor;
#ifdef NOTIFY_DEBUG //[
// Non-release build:
@ -33,7 +33,6 @@ class MovieAudioCursor;
#define movies_debug(msg) ((void)0);
#endif //]
////////////////////////////////////////////////////////////////////
// Class : MovieAudio
// Description : A MovieAudio is actually any source that provides
@ -47,12 +46,12 @@ class MovieAudioCursor;
// is what allows access.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_MOVIES MovieAudio : public TypedWritableReferenceCount, public Namable {
PUBLISHED:
MovieAudio(const string &name = "Blank Audio");
virtual ~MovieAudio();
virtual PT(MovieAudioCursor) open();
static PT(MovieAudio) get(const Filename &name);
INLINE const Filename &get_filename() const;
protected:
@ -76,9 +75,6 @@ class EXPCL_PANDA_MOVIES MovieAudio : public TypedWritableReferenceCount, public
static TypeHandle _type_handle;
};
/* okcircular */
#include "movieAudioCursor.h"
#include "movieAudio.I"
#endif

View File

@ -0,0 +1,29 @@
// Filename: movieTypeRegistry.I
// Created by: rdb (24Aug13)
//
////////////////////////////////////////////////////////////////////
//
// 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: MovieTypeRegistry::get_global_ptr
// Access: Published, Static
// Description: Returns a pointer to the global MovieTypeRegistry
// instance.
////////////////////////////////////////////////////////////////////
INLINE MovieTypeRegistry *MovieTypeRegistry::
get_global_ptr() {
if (_global_ptr == NULL) {
_global_ptr = new MovieTypeRegistry;
}
return _global_ptr;
}

View File

@ -0,0 +1,290 @@
// Filename: movieTypeRegistry.cxx
// Created by: rdb (24Aug13)
//
////////////////////////////////////////////////////////////////////
//
// 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 "movieTypeRegistry.h"
#include "config_movies.h"
#include "config_util.h"
#include "load_dso.h"
MovieTypeRegistry *MovieTypeRegistry::_global_ptr = NULL;
////////////////////////////////////////////////////////////////////
// Function: MovieTypeRegistry::make_audio
// Access: Published, Static
// Description: Obtains a MovieVideo that references a file.
////////////////////////////////////////////////////////////////////
PT(MovieAudio) MovieTypeRegistry::
make_audio(const Filename &name) {
string ext = downcase(name.get_extension());
// Make sure that the list of audio types has been read in.
load_audio_types();
// Maybe we need to load a module?
if (_deferred_audio_types.count(ext)) {
load_movie_library(_deferred_audio_types[ext]);
_deferred_audio_types.erase(ext);
}
// Explicit extension is preferred over catch-all.
if (_audio_type_registry.count(ext)) {
MakeAudioFunc func = _audio_type_registry[ext];
return (*func)(name);
}
// If we didn't find it, see if there was a type registered
// with '*' as extension. This is a catch-all loader.
if (_deferred_audio_types.count("*")) {
load_movie_library(_deferred_audio_types["*"]);
_deferred_audio_types.erase("*");
}
if (_audio_type_registry.count("*")) {
MakeAudioFunc func = _audio_type_registry["*"];
return (*func)(name);
}
movies_cat.error()
<< "Support for audio files with extension ." << ext << " was not enabled.\n";
return new MovieAudio("Load-Failure Stub");
}
////////////////////////////////////////////////////////////////////
// Function: MovieTypeRegistry::register_audio_type
// Access: Published, Static
// Description: Registers a MovieAudio type, so that files with
// any of the given extensions will be loaded as this
// type. You may use * as a catch-all extension.
////////////////////////////////////////////////////////////////////
void MovieTypeRegistry::
register_audio_type(MakeAudioFunc func, const string &extensions) {
vector_string words;
extract_words(downcase(extensions), words);
vector_string::const_iterator wi;
for (wi = words.begin(); wi != words.end(); ++wi) {
if (_audio_type_registry.count(*wi)) {
movies_cat->warning()
<< "Attempt to register multiple audio types with extension " << (*wi) << "\n";
} else {
movies_cat->debug()
<< "Registered audio type with extension " << (*wi) << "\n";
}
_audio_type_registry[*wi] = func;
}
}
////////////////////////////////////////////////////////////////////
// Function: MovieTypeRegistry::load_audio_types
// Access: Published, Static
// Description: Loads the list with audio types, if we haven't
// already.
////////////////////////////////////////////////////////////////////
void MovieTypeRegistry::
load_audio_types() {
static bool audio_types_loaded = false;
if (!audio_types_loaded) {
int num_unique_values = load_audio_type.get_num_unique_values();
for (int i = 0; i < num_unique_values; i++) {
string param = load_audio_type.get_unique_value(i);
vector_string words;
extract_words(param, words);
if (words.size() == 1) {
// Exactly one word: load the named library immediately.
string name = words[0];
Filename dlname = Filename::dso_filename("lib" + name + ".so");
movies_cat.info()
<< "loading audio type module: " << name << endl;
void *tmp = load_dso(get_plugin_path().get_value(), dlname);
if (tmp == (void *)NULL) {
movies_cat.warning()
<< "Unable to load " << dlname.to_os_specific()
<< ": " << load_dso_error() << endl;
} else if (movies_cat.is_debug()) {
movies_cat.debug()
<< "done loading audio type module: " << name << endl;
}
} else if (words.size() > 1) {
// Multiple words: the first n words are filename extensions,
// and the last word is the name of the library to load should
// any of those filename extensions be encountered.
size_t num_extensions = words.size() - 1;
string library_name = words[num_extensions];
for (size_t i = 0; i < num_extensions; i++) {
string extension = downcase(words[i]);
if (extension[0] == '.') {
extension = extension.substr(1);
}
_deferred_audio_types[extension] = library_name;
}
}
}
audio_types_loaded = true;
}
}
////////////////////////////////////////////////////////////////////
// Function: MovieTypeRegistry::make_video
// Access: Published, Static
// Description: Obtains a MovieVideo that references a file.
////////////////////////////////////////////////////////////////////
PT(MovieVideo) MovieTypeRegistry::
make_video(const Filename &name) {
string ext = downcase(name.get_extension());
// Make sure that the list of video types has been read in.
load_video_types();
// Maybe we need to load a module?
if (_deferred_video_types.count(ext)) {
load_movie_library(_deferred_video_types[ext]);
_deferred_video_types.erase(ext);
}
// Explicit extension is preferred over catch-all.
if (_video_type_registry.count(ext)) {
MakeVideoFunc func = _video_type_registry[ext];
return (*func)(name);
}
// If we didn't find it, see if there was a type registered
// with '*' as extension. This is a catch-all loader.
if (_deferred_video_types.count("*")) {
load_movie_library(_deferred_video_types["*"]);
_deferred_video_types.erase("*");
}
if (_video_type_registry.count("*")) {
MakeVideoFunc func = _video_type_registry["*"];
return (*func)(name);
}
movies_cat.error()
<< "Support for video files with extension ." << ext << " was not enabled.\n";
return new MovieVideo("Load-Failure Stub");
}
////////////////////////////////////////////////////////////////////
// Function: MovieTypeRegistry::register_video_type
// Access: Published, Static
// Description: Registers a MovieVideo type, so that files with
// any of the given extensions will be loaded as this
// type. You may use * as a catch-all extension.
////////////////////////////////////////////////////////////////////
void MovieTypeRegistry::
register_video_type(MakeVideoFunc func, const string &extensions) {
vector_string words;
extract_words(downcase(extensions), words);
vector_string::const_iterator wi;
for (wi = words.begin(); wi != words.end(); ++wi) {
if (_video_type_registry.count(*wi)) {
movies_cat->warning()
<< "Attempt to register multiple video types with extension " << (*wi) << "\n";
} else {
movies_cat->debug()
<< "Registered video type with extension " << (*wi) << "\n";
}
_video_type_registry[*wi] = func;
}
}
////////////////////////////////////////////////////////////////////
// Function: MovieTypeRegistry::load_video_types
// Access: Published, Static
// Description: Loads the list with video types, if we haven't
// already.
////////////////////////////////////////////////////////////////////
void MovieTypeRegistry::
load_video_types() {
static bool video_types_loaded = false;
if (!video_types_loaded) {
int num_unique_values = load_video_type.get_num_unique_values();
for (int i = 0; i < num_unique_values; i++) {
string param = load_video_type.get_unique_value(i);
vector_string words;
extract_words(param, words);
if (words.size() == 1) {
// Exactly one word: load the named library immediately.
string name = words[0];
Filename dlname = Filename::dso_filename("lib" + name + ".so");
movies_cat.info()
<< "loading video type module: " << name << endl;
void *tmp = load_dso(get_plugin_path().get_value(), dlname);
if (tmp == (void *)NULL) {
movies_cat.warning()
<< "Unable to load " << dlname.to_os_specific()
<< ": " << load_dso_error() << endl;
} else if (movies_cat.is_debug()) {
movies_cat.debug()
<< "done loading video type module: " << name << endl;
}
} else if (words.size() > 1) {
// Multiple words: the first n words are filename extensions,
// and the last word is the name of the library to load should
// any of those filename extensions be encountered.
size_t num_extensions = words.size() - 1;
string library_name = words[num_extensions];
for (size_t i = 0; i < num_extensions; i++) {
string extension = downcase(words[i]);
if (extension[0] == '.') {
extension = extension.substr(1);
}
_deferred_video_types[extension] = library_name;
}
}
}
video_types_loaded = true;
}
}
////////////////////////////////////////////////////////////////////
// Function: MovieTypeRegistry::load_library
// Access: Published, Static
// Description: Loads the module.
////////////////////////////////////////////////////////////////////
void MovieTypeRegistry::
load_movie_library(const string &name) {
Filename dlname = Filename::dso_filename("lib" + name + ".so");
movies_cat.info()
<< "loading video type module: " << name << endl;
void *tmp = load_dso(get_plugin_path().get_value(), dlname);
if (tmp == (void *)NULL) {
movies_cat.warning()
<< "Unable to load " << dlname.to_os_specific()
<< ": " << load_dso_error() << endl;
} else if (movies_cat.is_debug()) {
movies_cat.debug()
<< "done loading video type module: " << name << endl;
}
}

View File

@ -0,0 +1,57 @@
// Filename: movieTypeRegistry.h
// Created by: rdb (24Aug13)
//
////////////////////////////////////////////////////////////////////
//
// 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 MOVIETYPEREGISTRY_H
#define MOVIETYPEREGISTRY_H
#include "pandabase.h"
#include "movieAudio.h"
#include "movieVideo.h"
#include "filename.h"
#include "pmap.h"
////////////////////////////////////////////////////////////////////
// Class : MovieTypeRegistry
// Description : This class records the different types of MovieAudio
// and MovieVideo that are available for loading.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_MOVIES MovieTypeRegistry {
public:
typedef PT(MovieAudio) (*MakeAudioFunc)(const Filename&);
PT(MovieAudio) make_audio(const Filename &name);
void register_audio_type(MakeAudioFunc func, const string &extensions);
void load_audio_types();
typedef PT(MovieVideo) (*MakeVideoFunc)(const Filename&);
PT(MovieVideo) make_video(const Filename &name);
void register_video_type(MakeVideoFunc func, const string &extensions);
void load_video_types();
void load_movie_library(const string &name);
INLINE static MovieTypeRegistry *get_global_ptr();
private:
static MovieTypeRegistry *_global_ptr;
pmap<string, MakeAudioFunc> _audio_type_registry;
pmap<string, string> _deferred_audio_types;
pmap<string, MakeVideoFunc> _video_type_registry;
pmap<string, string> _deferred_video_types;
};
#include "movieTypeRegistry.I"
#endif

View File

@ -13,8 +13,9 @@
////////////////////////////////////////////////////////////////////
#include "movieVideo.h"
#include "movieVideoCursor.h"
#include "config_movies.h"
#include "ffmpegVideo.h"
#include "movieTypeRegistry.h"
#include "bamReader.h"
#include "bamWriter.h"
@ -58,19 +59,14 @@ open() {
// Function: MovieVideo::get
// Access: Published, Static
// Description: Obtains a MovieVideo that references a file.
// Just calls MovieTypeRegistry::make_video().
////////////////////////////////////////////////////////////////////
PT(MovieVideo) MovieVideo::
get(const Filename &name) {
#ifdef HAVE_FFMPEG
// Someday, I'll probably put a dispatcher here.
// But for now, just hardwire it to go to FFMPEG.
return new FfmpegVideo(name);
#else
return new MovieVideo("Load-Failure Stub");
#endif
MovieTypeRegistry *reg = MovieTypeRegistry::get_global_ptr();
return reg->make_video(name);
}
////////////////////////////////////////////////////////////////////
// Function: MovieVideo::write_datagram
// Access: Public, Virtual

View File

@ -40,7 +40,6 @@ class BamReader;
// is what allows access.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_MOVIES MovieVideo : public TypedWritableReferenceCount, public Namable {
PUBLISHED:
MovieVideo(const string &name = "Blank Video");
virtual ~MovieVideo();
@ -78,9 +77,6 @@ private:
static TypeHandle _type_handle;
};
/* okcircular */
#include "movieVideoCursor.h"
#include "movieVideo.I"
#endif

View File

@ -1,11 +1,16 @@
#include "movieVideo.cxx"
#include "movieVideoCursor.cxx"
#include "movieAudio.cxx"
#include "movieAudioCursor.cxx"
#include "config_movies.cxx"
#include "inkblotVideo.cxx"
#include "inkblotVideoCursor.cxx"
#include "userDataAudio.cxx"
#include "userDataAudioCursor.cxx"
#include "microphoneAudio.cxx"
#include "microphoneAudioDS.cxx"
#include "config_movies.cxx"
#include "movieAudio.cxx"
#include "movieAudioCursor.cxx"
#include "movieTypeRegistry.cxx"
#include "movieVideo.cxx"
#include "movieVideoCursor.cxx"
#include "userDataAudio.cxx"
#include "userDataAudioCursor.cxx"
#include "vorbisAudio.cxx"
#include "vorbisAudioCursor.cxx"
#include "wavAudio.cxx"
#include "wavAudioCursor.cxx"

View File

@ -0,0 +1,14 @@
// Filename: wavAudio.I
// Created by: rdb (23Aug13)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,77 @@
// Filename: vorbisAudio.cxx
// Created by: rdb (23Aug13)
//
////////////////////////////////////////////////////////////////////
//
// 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 "vorbisAudio.h"
#include "vorbisAudioCursor.h"
#include "virtualFileSystem.h"
#include "dcast.h"
#ifdef HAVE_VORBIS
TypeHandle VorbisAudio::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: VorbisAudio::Constructor
// Access: Protected
// Description: xxx
////////////////////////////////////////////////////////////////////
VorbisAudio::
VorbisAudio(const Filename &name) :
MovieAudio(name)
{
_filename = name;
}
////////////////////////////////////////////////////////////////////
// Function: VorbisAudio::Destructor
// Access: Protected, Virtual
// Description: xxx
////////////////////////////////////////////////////////////////////
VorbisAudio::
~VorbisAudio() {
}
////////////////////////////////////////////////////////////////////
// Function: VorbisAudio::open
// Access: Published, Virtual
// Description: Open this audio, returning a MovieAudioCursor
////////////////////////////////////////////////////////////////////
PT(MovieAudioCursor) VorbisAudio::
open() {
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
istream *stream = vfs->open_read_file(_filename, true);
if (stream == NULL) {
return NULL;
} else {
PT(VorbisAudioCursor) cursor = new VorbisAudioCursor(this, stream);
if (cursor == NULL || !cursor->_is_valid) {
return NULL;
} else {
return DCAST(MovieAudioCursor, cursor);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: VorbisAudio::make
// Access: Published, Static
// Description: Obtains a MovieAudio that references a file.
////////////////////////////////////////////////////////////////////
PT(MovieAudio) VorbisAudio::
make(const Filename &name) {
return DCAST(MovieAudio, new VorbisAudio(name));
}
#endif // HAVE_VORBIS

View File

@ -0,0 +1,63 @@
// Filename: vorbisAudio.h
// Created by: rdb (23Aug13)
//
////////////////////////////////////////////////////////////////////
//
// 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 VORBISAUDIO_H
#define VORBISAUDIO_H
#include "pandabase.h"
#include "movieAudio.h"
#ifdef HAVE_VORBIS
class VorbisAudioCursor;
////////////////////////////////////////////////////////////////////
// Class : VorbisAudio
// Description : Interfaces with the libvorbisfile library to
// implement decoding of Ogg Vorbis audio files.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_MOVIES VorbisAudio : public MovieAudio {
PUBLISHED:
VorbisAudio(const Filename &name);
virtual ~VorbisAudio();
virtual PT(MovieAudioCursor) open();
static PT(MovieAudio) make(const Filename &name);
private:
friend class VorbisAudioCursor;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
TypedWritableReferenceCount::init_type();
register_type(_type_handle, "VorbisAudio",
MovieAudio::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 "vorbisAudio.I"
#endif // HAVE_VORBIS
#endif // VORBISAUDIO_H

View File

@ -0,0 +1,14 @@
// Filename: wavAudioCursor.I
// Created by: rdb (23Aug13)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,235 @@
// Filename: vorbisAudioCursor.cxx
// Created by: rdb (23Aug13)
//
////////////////////////////////////////////////////////////////////
//
// 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 "vorbisAudioCursor.h"
#include "virtualFileSystem.h"
#ifdef HAVE_VORBIS
TypeHandle VorbisAudioCursor::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: VorbisAudioCursor::Constructor
// Access: Protected
// Description: Reads the .wav header from the indicated stream.
// This leaves the read pointer positioned at the
// start of the data.
////////////////////////////////////////////////////////////////////
VorbisAudioCursor::
VorbisAudioCursor(VorbisAudio *src, istream *stream) :
MovieAudioCursor(src),
_is_valid(false),
_bitstream(0)
{
nassertv(stream != NULL);
// Set up the callbacks to read via the VFS.
ov_callbacks callbacks;
callbacks.read_func = &cb_read_func;
callbacks.seek_func = &cb_seek_func;
callbacks.close_func = &cb_close_func;
callbacks.tell_func = &cb_tell_func;
if (ov_open_callbacks((void*) stream, &_ov, NULL, 0, callbacks) != 0) {
movies_cat.error()
<< "Failed to read Ogg Vorbis file.\n";
return;
}
_length = ov_time_total(&_ov, -1);
vorbis_info *vi = ov_info(&_ov, -1);
_audio_channels = vi->channels;
_audio_rate = vi->rate;
_can_seek = (ov_seekable(&_ov) != 0);
_can_seek_fast = _can_seek;
_is_valid = true;
}
////////////////////////////////////////////////////////////////////
// Function: VorbisAudioCursor::Destructor
// Access: Protected, Virtual
// Description: xxx
////////////////////////////////////////////////////////////////////
VorbisAudioCursor::
~VorbisAudioCursor() {
ov_clear(&_ov);
}
////////////////////////////////////////////////////////////////////
// Function: VorbisAudioCursor::seek
// Access: Protected
// Description: Seeks to a target location. Afterward, the
// packet_time is guaranteed to be less than or
// equal to the specified time.
////////////////////////////////////////////////////////////////////
void VorbisAudioCursor::
seek(double t) {
t = max(t, 0.0);
// Use ov_time_seek_lap if cross-lapping is enabled.
if (vorbis_seek_lap) {
if (ov_time_seek_lap(&_ov, t) != 0) {
movies_cat.error()
<< "Seek failed. Ogg Vorbis stream may not be seekable.\n";
return;
}
} else {
if (ov_time_seek(&_ov, t) != 0) {
movies_cat.error()
<< "Seek failed. Ogg Vorbis stream may not be seekable.\n";
return;
}
}
_last_seek = ov_time_tell(&_ov);
_samples_read = 0;
}
////////////////////////////////////////////////////////////////////
// Function: VorbisAudioCursor::read_samples
// Access: Public, Virtual
// Description: Read audio samples from the stream. N is the
// number of samples you wish to read. Your buffer
// must be equal in size to N * channels.
// Multiple-channel audio will be interleaved.
////////////////////////////////////////////////////////////////////
void VorbisAudioCursor::
read_samples(int n, PN_int16 *data) {
int desired = n * _audio_channels;
char *buffer = (char*) data;
int length = desired * 2;
// Call ov_read repeatedly until the buffer is full.
while (length > 0) {
int bitstream;
// ov_read can give it to us in the exact format we need. Nifty!
long read_bytes = ov_read(&_ov, buffer, length, 0, 2, 1, &bitstream);
if (read_bytes > 0) {
buffer += read_bytes;
length -= read_bytes;
} else {
break;
}
if (_bitstream != bitstream) {
// It is technically possible for it to change parameters from one
// bitstream to the next. However, we don't offer this flexibility.
vorbis_info *vi = ov_info(&_ov, -1);
if (vi->channels != _audio_channels || vi->rate != _audio_rate) {
movies_cat.error()
<< "Ogg Vorbis file has non-matching bitstreams!\n";
// We'll change it anyway. Not sure what happens next.
_audio_channels = vi->channels;
_audio_rate = vi->rate;
break;
}
_bitstream = bitstream;
}
}
// Fill the rest of the buffer with silence.
if (length > 0) {
memset(buffer, 0, length);
n -= length / 2 / _audio_channels;
}
_samples_read += n;
}
////////////////////////////////////////////////////////////////////
// Function: VorbisAudioCursor::cb_read_func
// Access: Private, Static
// Description: Callback passed to libvorbisfile to implement
// file I/O via the VirtualFileSystem.
////////////////////////////////////////////////////////////////////
size_t VorbisAudioCursor::
cb_read_func(void *ptr, size_t size, size_t nmemb, void *datasource) {
istream *stream = (istream*) datasource;
stream->read((char *)ptr, size * nmemb);
return stream->gcount();
}
////////////////////////////////////////////////////////////////////
// Function: VorbisAudioCursor::cb_seek_func
// Access: Private, Static
// Description: Callback passed to libvorbisfile to implement
// file I/O via the VirtualFileSystem.
////////////////////////////////////////////////////////////////////
int VorbisAudioCursor::
cb_seek_func(void *datasource, ogg_int64_t offset, int whence) {
istream *stream = (istream*) datasource;
switch (whence) {
case SEEK_SET:
stream->seekg(offset, ios::beg);
break;
case SEEK_CUR:
stream->seekg(offset, ios::cur);
break;
case SEEK_END:
stream->seekg(offset, ios::end);
break;
default:
movies_cat.error()
<< "Illegal parameter to seek in VorbisAudioCursor::cb_seek_func\n";
return -1;
}
if (stream->fail()) {
return -1;
}
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: VorbisAudioCursor::cb_close_func
// Access: Private, Static
// Description: Callback passed to libvorbisfile to implement
// file I/O via the VirtualFileSystem.
////////////////////////////////////////////////////////////////////
int VorbisAudioCursor::
cb_close_func(void *datasource) {
istream *stream = (istream*) datasource;
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
vfs->close_read_file(stream);
// Return value isn't checked, but let's be predictable
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: VorbisAudioCursor::cb_tell_func
// Access: Private, Static
// Description: Callback passed to libvorbisfile to implement
// file I/O via the VirtualFileSystem.
////////////////////////////////////////////////////////////////////
long VorbisAudioCursor::
cb_tell_func(void *datasource) {
istream *stream = (istream*) datasource;
return stream->tellg();
}
#endif // HAVE_VORBIS

View File

@ -0,0 +1,88 @@
// Filename: vorbisAudioCursor.h
// Created by: rdb (23Aug13)
//
////////////////////////////////////////////////////////////////////
//
// 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 VORBISAUDIOCURSOR_H
#define VORBISAUDIOCURSOR_H
#include "pandabase.h"
#include "movieAudioCursor.h"
#ifdef HAVE_VORBIS
#include <vorbis/codec.h>
#include <vorbis/vorbisfile.h>
class VorbisAudio;
////////////////////////////////////////////////////////////////////
// Class : VorbisAudioCursor
// Description : Interfaces with the libvorbisfile library to
// implement decoding of Ogg Vorbis audio files.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_MOVIES VorbisAudioCursor : public MovieAudioCursor {
PUBLISHED:
VorbisAudioCursor(VorbisAudio *src, istream *stream);
virtual ~VorbisAudioCursor();
virtual void seek(double offset);
public:
virtual void read_samples(int n, PN_int16 *data);
bool _is_valid;
private:
// Callbacks passed to libvorbisfile that read via VFS.
static size_t cb_read_func(void *ptr, size_t size, size_t nmemb, void *datasource);
static int cb_seek_func(void *datasource, ogg_int64_t offset, int whence);
static int cb_close_func(void *datasource);
static long cb_tell_func(void *datasource);
protected:
#ifndef CPPPARSER
OggVorbis_File _ov;
#endif
int _bitstream;
double _byte_rate;
int _block_align;
int _bytes_per_sample;
bool _is_float;
streampos _data_start;
streampos _data_pos;
size_t _data_size;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
MovieAudioCursor::init_type();
register_type(_type_handle, "VorbisAudioCursor",
MovieAudioCursor::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 "vorbisAudioCursor.I"
#endif // HAVE_VORBIS
#endif // VORBISAUDIOCURSOR_H

View File

@ -0,0 +1,14 @@
// Filename: wavAudio.I
// Created by: rdb (23Aug13)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,73 @@
// Filename: wavAudio.cxx
// Created by: rdb (23Aug13)
//
////////////////////////////////////////////////////////////////////
//
// 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 "wavAudio.h"
#include "wavAudioCursor.h"
#include "virtualFileSystem.h"
#include "dcast.h"
TypeHandle WavAudio::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: WavAudio::Constructor
// Access: Protected
// Description: xxx
////////////////////////////////////////////////////////////////////
WavAudio::
WavAudio(const Filename &name) :
MovieAudio(name)
{
_filename = name;
}
////////////////////////////////////////////////////////////////////
// Function: WavAudio::Destructor
// Access: Protected, Virtual
// Description: xxx
////////////////////////////////////////////////////////////////////
WavAudio::
~WavAudio() {
}
////////////////////////////////////////////////////////////////////
// Function: WavAudio::open
// Access: Published, Virtual
// Description: Open this audio, returning a MovieAudioCursor
////////////////////////////////////////////////////////////////////
PT(MovieAudioCursor) WavAudio::
open() {
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
istream *stream = vfs->open_read_file(_filename, true);
if (stream == NULL) {
return NULL;
} else {
PT(WavAudioCursor) cursor = new WavAudioCursor(this, stream);
if (cursor == NULL || !cursor->_is_valid) {
return NULL;
} else {
return DCAST(MovieAudioCursor, cursor);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: WavAudio::make
// Access: Published, Static
// Description: Obtains a MovieAudio that references a file.
////////////////////////////////////////////////////////////////////
PT(MovieAudio) WavAudio::
make(const Filename &name) {
return DCAST(MovieAudio, new WavAudio(name));
}

View File

@ -0,0 +1,59 @@
// Filename: wavAudio.h
// Created by: rdb (23Aug13)
//
////////////////////////////////////////////////////////////////////
//
// 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 WAVAUDIO_H
#define WAVAUDIO_H
#include "pandabase.h"
#include "movieAudio.h"
class WavAudioCursor;
////////////////////////////////////////////////////////////////////
// Class : WavAudio
// Description : A native PCM .wav loader. Supported formats
// are linear PCM, IEEE float, A-law and mu-law.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_MOVIES WavAudio : public MovieAudio {
PUBLISHED:
WavAudio(const Filename &name);
virtual ~WavAudio();
virtual PT(MovieAudioCursor) open();
static PT(MovieAudio) make(const Filename &name);
private:
friend class WavAudioCursor;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
TypedWritableReferenceCount::init_type();
register_type(_type_handle, "WavAudio",
MovieAudio::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 "wavAudio.I"
#endif

View File

@ -0,0 +1,14 @@
// Filename: wavAudioCursor.I
// Created by: rdb (23Aug13)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,438 @@
// Filename: wavAudioCursor.cxx
// Created by: rdb (23Aug13)
//
////////////////////////////////////////////////////////////////////
//
// 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 "wavAudioCursor.h"
#include "virtualFileSystem.h"
// Tables for decompressing mu-law and A-law wav files.
static PN_int16 mulaw_table[256] = {
-32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
-23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
-15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
-11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
-7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
-5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
-3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
-2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
-1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
-1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
-876, -844, -812, -780, -748, -716, -684, -652,
-620, -588, -556, -524, -492, -460, -428, -396,
-372, -356, -340, -324, -308, -292, -276, -260,
-244, -228, -212, -196, -180, -164, -148, -132,
-120, -112, -104, -96, -88, -80, -72, -64,
-56, -48, -40, -32, -24, -16, -8, -1,
32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
876, 844, 812, 780, 748, 716, 684, 652,
620, 588, 556, 524, 492, 460, 428, 396,
372, 356, 340, 324, 308, 292, 276, 260,
244, 228, 212, 196, 180, 164, 148, 132,
120, 112, 104, 96, 88, 80, 72, 64,
56, 48, 40, 32, 24, 16, 8, 0
};
static PN_int16 alaw_table[256] = {
-5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
-7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
-2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
-3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
-22016,-20992,-24064,-23040,-17920,-16896,-19968,-18944,
-30208,-29184,-32256,-31232,-26112,-25088,-28160,-27136,
-11008,-10496,-12032,-11520,-8960, -8448, -9984, -9472,
-15104,-14592,-16128,-15616,-13056,-12544,-14080,-13568,
-344, -328, -376, -360, -280, -264, -312, -296,
-472, -456, -504, -488, -408, -392, -440, -424,
-88, -72, -120, -104, -24, -8, -56, -40,
-216, -200, -248, -232, -152, -136, -184, -168,
-1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
-1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
-688, -656, -752, -720, -560, -528, -624, -592,
-944, -912, -1008, -976, -816, -784, -880, -848,
5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
344, 328, 376, 360, 280, 264, 312, 296,
472, 456, 504, 488, 408, 392, 440, 424,
88, 72, 120, 104, 24, 8, 56, 40,
216, 200, 248, 232, 152, 136, 184, 168,
1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
688, 656, 752, 720, 560, 528, 624, 592,
944, 912, 1008, 976, 816, 784, 880, 848
};
TypeHandle WavAudioCursor::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: WavAudioCursor::Constructor
// Access: Protected
// Description: Reads the .wav header from the indicated stream.
// This leaves the read pointer positioned at the
// start of the data.
////////////////////////////////////////////////////////////////////
WavAudioCursor::
WavAudioCursor(WavAudio *src, istream *stream) :
MovieAudioCursor(src),
_is_valid(false),
_stream(stream),
_reader(stream, false),
_format(F_pcm),
_data_pos(0),
_data_size(0)
{
nassertv(stream != NULL);
// Beginning of "RIFF" chunk.
if (_reader.extract_bytes(4) != "RIFF") {
movies_cat.error()
<< ".wav file is not a valid RIFF file.\n";
return;
}
unsigned int chunk_size = _reader.get_uint32();
if (_reader.extract_bytes(4) != "WAVE") {
movies_cat.error()
<< ".wav file is a RIFF file but does not start with a WAVE chunk.\n";
return;
}
// Find a "fmt " subchunk followed by a "data" subchunk.
bool have_fmt = false, have_data = false;
unsigned int bytes_read = 4;
while ((!have_fmt || !have_data) && _stream->good() && (bytes_read + 8) < chunk_size) {
string subchunk_id = _reader.extract_bytes(4);
unsigned int subchunk_size = _reader.get_uint32();
if (subchunk_id == "fmt ") {
// The format chunk specifies information about the storage.
nassertv(subchunk_size >= 16);
have_fmt = true;
_format = (Format) _reader.get_uint16();
_audio_channels = _reader.get_uint16();
_audio_rate = _reader.get_uint32();
_byte_rate = (double) _reader.get_uint32();
_block_align = _reader.get_uint16();
// We can round up to next multiple of 8.
PN_uint16 bps = _reader.get_uint16();
bps = (bps + 7) & 0xfff8;
// How many bytes in this chunk we've read so far.
unsigned int read_bytes = 16;
// See if there is an extra header to read.
if (_format == F_extensible) {
unsigned short ext_size = _reader.get_uint16();
read_bytes += 2;
if (ext_size >= 8) {
/*n_valid_bits =*/ _reader.get_uint16();
/*speaker_mask =*/ _reader.get_uint32();
_format = (Format) _reader.get_uint16();
read_bytes += 8;
}
}
switch (_format) {
case F_pcm:
if (bps != 8 && bps != 16 && bps != 24 && bps != 32 && bps != 64) {
movies_cat.error()
<< "Unsupported number of bits per sample for PCM storage: " << bps << "\n";
return;
}
break;
case F_float:
if (bps != 32 && bps != 64) {
movies_cat.error()
<< "Unsupported number of bits per sample for float storage: " << bps << "\n";
return;
}
break;
case F_alaw:
case F_mulaw:
if (bps != 8) {
movies_cat.error()
<< ".wav file with A-law or mu-law compression must specify 8 bits per sample, not " << bps << ".\n";
return;
}
break;
default:
movies_cat.error()
<< "Unsupported .wav format " << _format << ". Only PCM, float, A-law and mu-law encodings are supported.\n";
return;
}
_bytes_per_sample = bps / 8;
// Skip to the end of the chunk.
if (subchunk_size > read_bytes) {
_reader.skip_bytes(subchunk_size - read_bytes);
}
} else if (subchunk_id == "data") {
// The data chunk contains the actual sammples.
if (!have_fmt) {
movies_cat.error()
<< ".wav file specifies 'data' chunk before 'fmt ' chunk.\n";
break;
}
// Excellent! We've reached the beginning of the data. Write down
// where we are and don't move until we want to start reading the data.
_data_start = stream->tellg();
_data_size = subchunk_size;
have_data = true;
break;
} else {
// A chunk we do not recognize. Just skip it.
_reader.skip_bytes(subchunk_size);
}
bytes_read += subchunk_size + 8;
}
// If we bailed out prematurely, there must have been an error.
if (_stream->eof()) {
movies_cat.error()
<< "Reached end of file while reading .wav file header.\n";
} else if (!_stream->good()) {
movies_cat.error()
<< "Stream error while reading .wav file header.\n";
return;
}
if (!have_fmt) {
movies_cat.error()
<< ".wav file did not specify a 'fmt ' chunk.\n";
return;
}
if (!have_data) {
movies_cat.error()
<< ".wav file did not specify a 'data' chunk.\n";
return;
}
// We can always seek by skipping bytes, rereading if necessary.
_can_seek = true;
// How to tell if a stream is seekable? We'll set it to true, and
// then change it to false as soon as we find out that we can't.
_can_seek_fast = true;
if (_block_align != _audio_channels * _bytes_per_sample) {
movies_cat.warning()
<< ".wav file specified an unexpected block alignment of " << _block_align
<< ", expected " << (_audio_channels * _bytes_per_sample) << ".\n";
_block_align = _audio_channels * _bytes_per_sample;
}
if (_byte_rate != _audio_rate * _block_align) {
movies_cat.warning()
<< ".wav file specified an unexpected byte rate of " << _byte_rate
<< ", expected " << (_audio_rate * _block_align) << ".\n";
_byte_rate = _audio_rate * _block_align;
}
_length = _data_size / _byte_rate;
_is_valid = true;
}
////////////////////////////////////////////////////////////////////
// Function: WavAudioCursor::Destructor
// Access: Protected, Virtual
// Description: xxx
////////////////////////////////////////////////////////////////////
WavAudioCursor::
~WavAudioCursor() {
if (_stream != NULL) {
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
vfs->close_read_file(_stream);
}
}
////////////////////////////////////////////////////////////////////
// Function: WavAudioCursor::seek
// Access: Protected
// Description: Seeks to a target location. Afterward, the
// packet_time is guaranteed to be less than or
// equal to the specified time.
////////////////////////////////////////////////////////////////////
void WavAudioCursor::
seek(double t) {
t = max(t, 0.0);
streampos pos = _data_start + (streampos) min(t * _byte_rate, _data_size);
if (_can_seek_fast) {
_stream->seekg(pos);
if (_stream->tellg() != pos) {
// Clearly, we can't seek fast.
// Fall back to the case below.
_can_seek_fast = false;
}
}
if (!_can_seek_fast) {
streampos current = _stream->tellg();
if (pos > current) {
// It is ahead of our current position. Skip ahead.
_reader.skip_bytes(pos - current);
} else if (pos < current) {
// We'll have to reopen the file.
//TODO
}
}
_last_seek = _stream->tellg() / _byte_rate;
_samples_read = 0;
}
////////////////////////////////////////////////////////////////////
// Function: WavAudioCursor::read_samples
// Access: Public, Virtual
// Description: Read audio samples from the stream. N is the
// number of samples you wish to read. Your buffer
// must be equal in size to N * channels.
// Multiple-channel audio will be interleaved.
////////////////////////////////////////////////////////////////////
void WavAudioCursor::
read_samples(int n, PN_int16 *data) {
int desired = n * _audio_channels;
int read_samples = min(desired, (_data_size - _data_pos) / _bytes_per_sample);
if (read_samples <= 0) {
return;
}
switch (_format) {
case F_pcm:
// Linear PCM storage.
switch (_bytes_per_sample) {
case 1:
// Upsample. Also, 8-bits samples are stored unsigned.
for (int i = 0; i < read_samples; ++i) {
data[i] = (_reader.get_uint8() - 128) * 258/*ish*/;
}
break;
case 2:
// Our native format. Read directly from file.
read_samples = _reader.extract_bytes((unsigned char*) data, read_samples * 2) / 2;
break;
case 3: {
// The scale factor happens to be 256 for 24-bit samples.
// That means we can just read the most significant bytes.
for (int i = 0; i < read_samples; ++i) {
_reader.skip_bytes(1);
data[i] = _reader.get_int16();
}
break;
} case 4: {
// Downsample.
const PN_int32 scale_factor = 0x7fffffff / 0x7fff;
for (int i = 0; i < read_samples; ++i) {
data[i] = _reader.get_int32() / scale_factor;
}
break;
} case 8: {
// Downsample.
const PN_int64 scale_factor = 0x7fffffffffffffff / 0x7fff;
for (int i = 0; i < read_samples; ++i) {
data[i] = _reader.get_int64() / scale_factor;
}
break;
} default:
// Huh?
read_samples = 0;
}
break;
case F_float:
// IEEE float storage.
switch (_bytes_per_sample) {
case 4:
for (int i = 0; i < read_samples; ++i) {
data[i] = (PN_int16) (_reader.get_float32() * 0x7fff);
}
break;
case 8:
for (int i = 0; i < read_samples; ++i) {
data[i] = (PN_int16) (_reader.get_float64() * 0x7fff);
}
break;
default:
read_samples = 0;
}
break;
case F_alaw:
for (int i = 0; i < read_samples; ++i) {
data[i] = alaw_table[_reader.get_uint8()];
}
break;
case F_mulaw:
for (int i = 0; i < read_samples; ++i) {
data[i] = mulaw_table[_reader.get_uint8()];
}
break;
default:
read_samples = 0;
}
// Fill the rest of the buffer with silence.
if (read_samples < desired) {
memset(data + read_samples, 0, (desired - read_samples) * 2);
}
_data_pos = _stream->tellg() - _data_start;
_samples_read += read_samples / _audio_channels;
}

View File

@ -0,0 +1,83 @@
// Filename: wavAudioCursor.h
// Created by: rdb (23Aug13)
//
////////////////////////////////////////////////////////////////////
//
// 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 WAVAUDIOCURSOR_H
#define WAVAUDIOCURSOR_H
#include "pandabase.h"
#include "movieAudioCursor.h"
#include "streamReader.h"
class WavAudio;
////////////////////////////////////////////////////////////////////
// Class : WavAudioCursor
// Description : Used for reading PCM .wav files. Supported formats
// are linear PCM, IEEE float, A-law and mu-law.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_MOVIES WavAudioCursor : public MovieAudioCursor {
PUBLISHED:
WavAudioCursor(WavAudio *src, istream *stream);
virtual ~WavAudioCursor();
virtual void seek(double offset);
public:
virtual void read_samples(int n, PN_int16 *data);
bool _is_valid;
protected:
// Format codes as used by wave files.
enum Format {
F_pcm = 0x0001,
F_float = 0x0003,
F_alaw = 0x0006,
F_mulaw = 0x0007,
F_extensible = 0xfffe,
};
istream *_stream;
StreamReader _reader;
Format _format;
double _byte_rate;
int _block_align;
int _bytes_per_sample;
streampos _data_start;
streampos _data_pos;
size_t _data_size;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
MovieAudioCursor::init_type();
register_type(_type_handle, "WavAudioCursor",
MovieAudioCursor::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 "wavAudioCursor.I"
#endif // WAVAUDIOCURSOR_H

View File

@ -40,6 +40,14 @@
#define EXPTP_COLLADA extern
#endif
#ifdef BUILDING_FFMPEG
#define EXPCL_FFMPEG __declspec(dllexport)
#define EXPTP_FFMPEG
#else
#define EXPCL_FFMPEG __declspec(dllimport)
#define EXPTP_FFMPEG extern
#endif
#ifdef BUILDING_FRAMEWORK
#define EXPCL_FRAMEWORK __declspec(dllexport)
#define EXPTP_FRAMEWORK
@ -72,6 +80,14 @@
#define EXPTP_FMOD_AUDIO extern
#endif
#ifdef BUILDING_OCULUSVR
#define EXPCL_OCULUSVR __declspec(dllexport)
#define EXPTP_OCULUSVR
#else
#define EXPCL_OCULUSVR __declspec(dllimport)
#define EXPTP_OCULUSVR extern
#endif
#ifdef BUILDING_OPENAL_AUDIO
#define EXPCL_OPENAL_AUDIO __declspec(dllexport)
#define EXPTP_OPENAL_AUDIO
@ -264,6 +280,14 @@
#define EXPTP_VISION extern
#endif
#ifdef BUILDING_VRPN
#define EXPCL_VRPN __declspec(dllexport)
#define EXPTP_VRPN
#else
#define EXPCL_VRPN __declspec(dllimport)
#define EXPTP_VRPN extern
#endif
#else /* !WIN32_VC */
#define EXPCL_CFTALK
@ -272,6 +296,9 @@
#define EXPCL_COLLADA
#define EXPTP_COLLADA
#define EXPCL_FFMPEG
#define EXPTP_FFMPEG
#define EXPCL_FRAMEWORK
#define EXPTP_FRAMEWORK
@ -284,6 +311,9 @@
#define EXPCL_FMOD_AUDIO
#define EXPTP_FMOD_AUDIO
#define EXPCL_OCULUSVR
#define EXPTP_OCULUSVR
#define EXPCL_OPENAL_AUDIO
#define EXPTP_OPENAL_AUDIO
@ -359,6 +389,9 @@
#define EXPCL_VISION
#define EXPTP_VISION
#define EXPCL_VRPN
#define EXPTP_VRPN
#endif /* WIN32_VC */
#if (defined(WIN32_VC) || defined(WIN64_VC)) && !defined(CPPPARSER)
@ -429,9 +462,6 @@
#define EXPCL_PANDA_PIPELINE EXPCL_PANDA
#define EXPTP_PANDA_PIPELINE EXPTP_PANDA
#define EXPCL_PANDA_VRPN EXPCL_PANDA
#define EXPTP_PANDA_VRPN EXPTP_PANDA
#define EXPCL_PANDA_GRUTIL EXPCL_PANDA
#define EXPTP_PANDA_GRUTIL EXPTP_PANDA

View File

@ -3,6 +3,8 @@
#define OTHER_LIBS p3interrogatedb:c p3dconfig:c p3dtoolconfig:m \
p3dtoolutil:c p3dtoolbase:c p3dtool:m
#define BUILDING_DLL BUILDING_VRPN
#begin lib_target
#define TARGET p3vrpn
#define LOCAL_LIBS \

View File

@ -18,6 +18,6 @@
#include "pandabase.h"
#include "notifyCategoryProxy.h"
NotifyCategoryDecl(vrpn, EXPCL_PANDA_VRPN, EXPTP_PANDA_VRPN);
NotifyCategoryDecl(vrpn, EXPCL_VRPN, EXPTP_VRPN);
#endif

View File

@ -35,7 +35,7 @@ class VrpnDialDevice;
// and records information on the connected VRPN
// devices.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_VRPN VrpnClient : public ClientBase {
class EXPCL_VRPN VrpnClient : public ClientBase {
PUBLISHED:
VrpnClient(const string &server_name);
~VrpnClient();