diff --git a/panda/metalibs/panda/Sources.pp b/panda/metalibs/panda/Sources.pp index b3127375c6..6e853a768a 100644 --- a/panda/metalibs/panda/Sources.pp +++ b/panda/metalibs/panda/Sources.pp @@ -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 \ diff --git a/panda/src/configfiles/panda.prc.pp b/panda/src/configfiles/panda.prc.pp index 79631837b4..6cf74d0407 100644 --- a/panda/src/configfiles/panda.prc.pp +++ b/panda/src/configfiles/panda.prc.pp @@ -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 { name } into whatever egg diff --git a/panda/src/ffmpeg/Sources.pp b/panda/src/ffmpeg/Sources.pp new file mode 100644 index 0000000000..47c7f4a048 --- /dev/null +++ b/panda/src/ffmpeg/Sources.pp @@ -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 diff --git a/panda/src/ffmpeg/config_ffmpeg.cxx b/panda/src/ffmpeg/config_ffmpeg.cxx new file mode 100644 index 0000000000..26ce7c07ed --- /dev/null +++ b/panda/src/ffmpeg/config_ffmpeg.cxx @@ -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 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, "*"); +} diff --git a/panda/src/ffmpeg/config_ffmpeg.h b/panda/src/ffmpeg/config_ffmpeg.h new file mode 100644 index 0000000000..76527c7f38 --- /dev/null +++ b/panda/src/ffmpeg/config_ffmpeg.h @@ -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 */ diff --git a/panda/src/movies/ffmpegAudio.I b/panda/src/ffmpeg/ffmpegAudio.I similarity index 100% rename from panda/src/movies/ffmpegAudio.I rename to panda/src/ffmpeg/ffmpegAudio.I diff --git a/panda/src/movies/ffmpegAudio.cxx b/panda/src/ffmpeg/ffmpegAudio.cxx similarity index 81% rename from panda/src/movies/ffmpegAudio.cxx rename to panda/src/ffmpeg/ffmpegAudio.cxx index 16256f76a3..3f2c751673 100644 --- a/panda/src/movies/ffmpegAudio.cxx +++ b/panda/src/ffmpeg/ffmpegAudio.cxx @@ -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)); +} diff --git a/panda/src/movies/ffmpegAudio.h b/panda/src/ffmpeg/ffmpegAudio.h similarity index 92% rename from panda/src/movies/ffmpegAudio.h rename to panda/src/ffmpeg/ffmpegAudio.h index 3a28f1c292..0650b85986 100644 --- a/panda/src/movies/ffmpegAudio.h +++ b/panda/src/ffmpeg/ffmpegAudio.h @@ -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 diff --git a/panda/src/movies/ffmpegAudioCursor.I b/panda/src/ffmpeg/ffmpegAudioCursor.I similarity index 100% rename from panda/src/movies/ffmpegAudioCursor.I rename to panda/src/ffmpeg/ffmpegAudioCursor.I diff --git a/panda/src/movies/ffmpegAudioCursor.cxx b/panda/src/ffmpeg/ffmpegAudioCursor.cxx similarity index 97% rename from panda/src/movies/ffmpegAudioCursor.cxx rename to panda/src/ffmpeg/ffmpegAudioCursor.cxx index 0d2c02d223..fd297ad2ba 100644 --- a/panda/src/movies/ffmpegAudioCursor.cxx +++ b/panda/src/ffmpeg/ffmpegAudioCursor.cxx @@ -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 diff --git a/panda/src/movies/ffmpegAudioCursor.h b/panda/src/ffmpeg/ffmpegAudioCursor.h similarity index 92% rename from panda/src/movies/ffmpegAudioCursor.h rename to panda/src/ffmpeg/ffmpegAudioCursor.h index 06f3ef674c..bed23b2724 100644 --- a/panda/src/movies/ffmpegAudioCursor.h +++ b/panda/src/ffmpeg/ffmpegAudioCursor.h @@ -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 diff --git a/panda/src/movies/ffmpegVideo.I b/panda/src/ffmpeg/ffmpegVideo.I similarity index 100% rename from panda/src/movies/ffmpegVideo.I rename to panda/src/ffmpeg/ffmpegVideo.I diff --git a/panda/src/movies/ffmpegVideo.cxx b/panda/src/ffmpeg/ffmpegVideo.cxx similarity index 92% rename from panda/src/movies/ffmpegVideo.cxx rename to panda/src/ffmpeg/ffmpegVideo.cxx index ca5d82585d..2c35ce5658 100644 --- a/panda/src/movies/ffmpegVideo.cxx +++ b/panda/src/ffmpeg/ffmpegVideo.cxx @@ -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 diff --git a/panda/src/movies/ffmpegVideo.h b/panda/src/ffmpeg/ffmpegVideo.h similarity index 94% rename from panda/src/movies/ffmpegVideo.h rename to panda/src/ffmpeg/ffmpegVideo.h index 96209e32f3..b042674dcf 100644 --- a/panda/src/movies/ffmpegVideo.h +++ b/panda/src/ffmpeg/ffmpegVideo.h @@ -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 diff --git a/panda/src/movies/ffmpegVideoCursor.I b/panda/src/ffmpeg/ffmpegVideoCursor.I similarity index 100% rename from panda/src/movies/ffmpegVideoCursor.I rename to panda/src/ffmpeg/ffmpegVideoCursor.I diff --git a/panda/src/movies/ffmpegVideoCursor.cxx b/panda/src/ffmpeg/ffmpegVideoCursor.cxx similarity index 99% rename from panda/src/movies/ffmpegVideoCursor.cxx rename to panda/src/ffmpeg/ffmpegVideoCursor.cxx index 104a6cd350..221987ae8e 100644 --- a/panda/src/movies/ffmpegVideoCursor.cxx +++ b/panda/src/ffmpeg/ffmpegVideoCursor.cxx @@ -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 diff --git a/panda/src/movies/ffmpegVideoCursor.h b/panda/src/ffmpeg/ffmpegVideoCursor.h similarity index 97% rename from panda/src/movies/ffmpegVideoCursor.h rename to panda/src/ffmpeg/ffmpegVideoCursor.h index ccbb9fe970..4b5e881e3e 100644 --- a/panda/src/movies/ffmpegVideoCursor.h +++ b/panda/src/ffmpeg/ffmpegVideoCursor.h @@ -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 diff --git a/panda/src/movies/ffmpegVirtualFile.I b/panda/src/ffmpeg/ffmpegVirtualFile.I similarity index 100% rename from panda/src/movies/ffmpegVirtualFile.I rename to panda/src/ffmpeg/ffmpegVirtualFile.I diff --git a/panda/src/movies/ffmpegVirtualFile.cxx b/panda/src/ffmpeg/ffmpegVirtualFile.cxx similarity index 99% rename from panda/src/movies/ffmpegVirtualFile.cxx rename to panda/src/ffmpeg/ffmpegVirtualFile.cxx index 63b26c4b28..8cdb6edd60 100644 --- a/panda/src/movies/ffmpegVirtualFile.cxx +++ b/panda/src/ffmpeg/ffmpegVirtualFile.cxx @@ -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 diff --git a/panda/src/movies/ffmpegVirtualFile.h b/panda/src/ffmpeg/ffmpegVirtualFile.h similarity index 95% rename from panda/src/movies/ffmpegVirtualFile.h rename to panda/src/ffmpeg/ffmpegVirtualFile.h index 4c60e93367..a692a31625 100644 --- a/panda/src/movies/ffmpegVirtualFile.h +++ b/panda/src/ffmpeg/ffmpegVirtualFile.h @@ -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 diff --git a/panda/src/movies/p3movies_composite2.cxx b/panda/src/ffmpeg/p3ffmpeg_composite1.cxx similarity index 84% rename from panda/src/movies/p3movies_composite2.cxx rename to panda/src/ffmpeg/p3ffmpeg_composite1.cxx index 962abbdb0e..a4315b76d0 100644 --- a/panda/src/movies/p3movies_composite2.cxx +++ b/panda/src/ffmpeg/p3ffmpeg_composite1.cxx @@ -1,3 +1,4 @@ +#include "config_ffmpeg.cxx" #include "ffmpegAudio.cxx" #include "ffmpegVideo.cxx" #include "ffmpegVirtualFile.cxx" diff --git a/panda/src/grutil/Sources.pp b/panda/src/grutil/Sources.pp index f22237457e..509409b9e1 100644 --- a/panda/src/grutil/Sources.pp +++ b/panda/src/grutil/Sources.pp @@ -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 \ diff --git a/panda/src/grutil/config_grutil.cxx b/panda/src/grutil/config_grutil.cxx index 99a9eff81b..291535704b 100644 --- a/panda/src/grutil/config_grutil.cxx +++ b/panda/src/grutil/config_grutil.cxx @@ -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 } - diff --git a/panda/src/grutil/movieTexture.h b/panda/src/grutil/movieTexture.h index 50392f3ba6..99b469bf1f 100644 --- a/panda/src/grutil/movieTexture.h +++ b/panda/src/grutil/movieTexture.h @@ -20,6 +20,7 @@ #ifdef HAVE_AUDIO #include "movieVideo.h" +#include "movieVideoCursor.h" #include "audioSound.h" #include "pipelineCycler.h" #include "cycleData.h" diff --git a/panda/src/movies/Sources.pp b/panda/src/movies/Sources.pp index 4af73ed3e9..adec18e915 100644 --- a/panda/src/movies/Sources.pp +++ b/panda/src/movies/Sources.pp @@ -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 - diff --git a/panda/src/movies/config_movies.cxx b/panda/src/movies/config_movies.cxx index 637263f934..a38f5976d7 100644 --- a/panda/src/movies/config_movies.cxx +++ b/panda/src/movies/config_movies.cxx @@ -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 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 } - diff --git a/panda/src/movies/config_movies.h b/panda/src/movies/config_movies.h index 61236624fa..d0c02724d8 100644 --- a/panda/src/movies/config_movies.h +++ b/panda/src/movies/config_movies.h @@ -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 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 */ diff --git a/panda/src/movies/inkblotVideoCursor.h b/panda/src/movies/inkblotVideoCursor.h index 9680ab532f..84ce025bf5 100644 --- a/panda/src/movies/inkblotVideoCursor.h +++ b/panda/src/movies/inkblotVideoCursor.h @@ -19,6 +19,7 @@ #include "texture.h" #include "pointerTo.h" #include "inkblotVideo.h" +#include "movieVideoCursor.h" //////////////////////////////////////////////////////////////////// // Class : InkblotVideoCursor diff --git a/panda/src/movies/microphoneAudio.h b/panda/src/movies/microphoneAudio.h index 6fbcb38699..91f525f8f8 100644 --- a/panda/src/movies/microphoneAudio.h +++ b/panda/src/movies/microphoneAudio.h @@ -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()); } diff --git a/panda/src/movies/movieAudio.cxx b/panda/src/movies/movieAudio.cxx index 5e59a1aa41..6c84abb3eb 100644 --- a/panda/src/movies/movieAudio.cxx +++ b/panda/src/movies/movieAudio.cxx @@ -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); } diff --git a/panda/src/movies/movieAudio.h b/panda/src/movies/movieAudio.h index 43bad08305..810c0acdbf 100644 --- a/panda/src/movies/movieAudio.h +++ b/panda/src/movies/movieAudio.h @@ -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 diff --git a/panda/src/movies/movieTypeRegistry.I b/panda/src/movies/movieTypeRegistry.I new file mode 100644 index 0000000000..5fdf04368c --- /dev/null +++ b/panda/src/movies/movieTypeRegistry.I @@ -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; +} diff --git a/panda/src/movies/movieTypeRegistry.cxx b/panda/src/movies/movieTypeRegistry.cxx new file mode 100644 index 0000000000..751b6c5e6e --- /dev/null +++ b/panda/src/movies/movieTypeRegistry.cxx @@ -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; + } +} diff --git a/panda/src/movies/movieTypeRegistry.h b/panda/src/movies/movieTypeRegistry.h new file mode 100644 index 0000000000..cb2e03a495 --- /dev/null +++ b/panda/src/movies/movieTypeRegistry.h @@ -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 _audio_type_registry; + pmap _deferred_audio_types; + + pmap _video_type_registry; + pmap _deferred_video_types; +}; + +#include "movieTypeRegistry.I" + +#endif diff --git a/panda/src/movies/movieVideo.cxx b/panda/src/movies/movieVideo.cxx index 1620151a5a..2ab59bf4bd 100644 --- a/panda/src/movies/movieVideo.cxx +++ b/panda/src/movies/movieVideo.cxx @@ -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 diff --git a/panda/src/movies/movieVideo.h b/panda/src/movies/movieVideo.h index d63383bdc2..354b011f43 100644 --- a/panda/src/movies/movieVideo.h +++ b/panda/src/movies/movieVideo.h @@ -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 diff --git a/panda/src/movies/p3movies_composite1.cxx b/panda/src/movies/p3movies_composite1.cxx index d60e632190..ecb10339a6 100644 --- a/panda/src/movies/p3movies_composite1.cxx +++ b/panda/src/movies/p3movies_composite1.cxx @@ -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" diff --git a/panda/src/movies/vorbisAudio.I b/panda/src/movies/vorbisAudio.I new file mode 100644 index 0000000000..f03256aa47 --- /dev/null +++ b/panda/src/movies/vorbisAudio.I @@ -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." +// +//////////////////////////////////////////////////////////////////// + diff --git a/panda/src/movies/vorbisAudio.cxx b/panda/src/movies/vorbisAudio.cxx new file mode 100644 index 0000000000..9dd3f90ee0 --- /dev/null +++ b/panda/src/movies/vorbisAudio.cxx @@ -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 diff --git a/panda/src/movies/vorbisAudio.h b/panda/src/movies/vorbisAudio.h new file mode 100644 index 0000000000..6dd7d23666 --- /dev/null +++ b/panda/src/movies/vorbisAudio.h @@ -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 diff --git a/panda/src/movies/vorbisAudioCursor.I b/panda/src/movies/vorbisAudioCursor.I new file mode 100644 index 0000000000..88afa719ff --- /dev/null +++ b/panda/src/movies/vorbisAudioCursor.I @@ -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." +// +//////////////////////////////////////////////////////////////////// + diff --git a/panda/src/movies/vorbisAudioCursor.cxx b/panda/src/movies/vorbisAudioCursor.cxx new file mode 100644 index 0000000000..a0265f10ed --- /dev/null +++ b/panda/src/movies/vorbisAudioCursor.cxx @@ -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 diff --git a/panda/src/movies/vorbisAudioCursor.h b/panda/src/movies/vorbisAudioCursor.h new file mode 100644 index 0000000000..2828b3d961 --- /dev/null +++ b/panda/src/movies/vorbisAudioCursor.h @@ -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 +#include + +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 diff --git a/panda/src/movies/wavAudio.I b/panda/src/movies/wavAudio.I new file mode 100644 index 0000000000..f03256aa47 --- /dev/null +++ b/panda/src/movies/wavAudio.I @@ -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." +// +//////////////////////////////////////////////////////////////////// + diff --git a/panda/src/movies/wavAudio.cxx b/panda/src/movies/wavAudio.cxx new file mode 100644 index 0000000000..7dd6f10e9b --- /dev/null +++ b/panda/src/movies/wavAudio.cxx @@ -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)); +} diff --git a/panda/src/movies/wavAudio.h b/panda/src/movies/wavAudio.h new file mode 100644 index 0000000000..a5ea4fc513 --- /dev/null +++ b/panda/src/movies/wavAudio.h @@ -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 diff --git a/panda/src/movies/wavAudioCursor.I b/panda/src/movies/wavAudioCursor.I new file mode 100644 index 0000000000..88afa719ff --- /dev/null +++ b/panda/src/movies/wavAudioCursor.I @@ -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." +// +//////////////////////////////////////////////////////////////////// + diff --git a/panda/src/movies/wavAudioCursor.cxx b/panda/src/movies/wavAudioCursor.cxx new file mode 100644 index 0000000000..0493de8f60 --- /dev/null +++ b/panda/src/movies/wavAudioCursor.cxx @@ -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; +} diff --git a/panda/src/movies/wavAudioCursor.h b/panda/src/movies/wavAudioCursor.h new file mode 100644 index 0000000000..f8d220160e --- /dev/null +++ b/panda/src/movies/wavAudioCursor.h @@ -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 diff --git a/panda/src/pandabase/pandasymbols.h b/panda/src/pandabase/pandasymbols.h index eb37afa93b..1f75ec5a86 100644 --- a/panda/src/pandabase/pandasymbols.h +++ b/panda/src/pandabase/pandasymbols.h @@ -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 diff --git a/panda/src/vrpn/Sources.pp b/panda/src/vrpn/Sources.pp index 7fc6d544fc..8f878cfa93 100644 --- a/panda/src/vrpn/Sources.pp +++ b/panda/src/vrpn/Sources.pp @@ -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 \ diff --git a/panda/src/vrpn/config_vrpn.h b/panda/src/vrpn/config_vrpn.h index 7377872c6d..05c7dc0810 100644 --- a/panda/src/vrpn/config_vrpn.h +++ b/panda/src/vrpn/config_vrpn.h @@ -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 diff --git a/panda/src/vrpn/vrpnClient.h b/panda/src/vrpn/vrpnClient.h index d1ce03ee3d..1f23ddc51b 100644 --- a/panda/src/vrpn/vrpnClient.h +++ b/panda/src/vrpn/vrpnClient.h @@ -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();