From 4ced7dffc413a43e4f1963935d483dd282678b7e Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 3 Nov 2010 10:37:32 +0000 Subject: [PATCH] From Wang Rui, "additional FFmpegParameters class in the ffmpeg plugin for setting parameters before opening the video file, which benefits from getPluginStringData() as shown in the ReaderWriter implementation. Now we can use ffmpeg to render webcam video (using the vfwcap device) under Windows: osgmovie 0 -e ffmpeg -O "format=vfwcap frame_rate=25" The number 0 just indicates a default device number in ffmpeg. I think this can work under Linux, too, and should be a bit better than comparing the filename with a '/dev/' string. Just type: ./osgmovie /dev/yourcam -e ffmpeg -O "format=video4linux2 frame_rate=30 size=320x240"" --- src/osgPlugins/ffmpeg/CMakeLists.txt | 2 + src/osgPlugins/ffmpeg/FFmpegDecoder.cpp | 7 +- src/osgPlugins/ffmpeg/FFmpegDecoder.hpp | 4 +- src/osgPlugins/ffmpeg/FFmpegImageStream.cpp | 5 +- src/osgPlugins/ffmpeg/FFmpegImageStream.hpp | 4 +- src/osgPlugins/ffmpeg/FFmpegParameters.cpp | 79 ++++++++++++++++++++ src/osgPlugins/ffmpeg/FFmpegParameters.hpp | 40 ++++++++++ src/osgPlugins/ffmpeg/ReaderWriterFFmpeg.cpp | 38 ++++++++-- 8 files changed, 168 insertions(+), 11 deletions(-) create mode 100644 src/osgPlugins/ffmpeg/FFmpegParameters.cpp create mode 100644 src/osgPlugins/ffmpeg/FFmpegParameters.hpp diff --git a/src/osgPlugins/ffmpeg/CMakeLists.txt b/src/osgPlugins/ffmpeg/CMakeLists.txt index a0dc7d7b1..b9c0340ed 100644 --- a/src/osgPlugins/ffmpeg/CMakeLists.txt +++ b/src/osgPlugins/ffmpeg/CMakeLists.txt @@ -26,6 +26,7 @@ SET(TARGET_SRC FFmpegDecoderVideo.cpp FFmpegImageStream.cpp FFmpegAudioStream.cpp + FFmpegParameters.cpp ReaderWriterFFmpeg.cpp ) @@ -39,6 +40,7 @@ SET(TARGET_H FFmpegPacket.hpp FFmpegImageStream.hpp FFmpegAudioStream.hpp + FFmpegParameters.hpp MessageQueue.hpp ) diff --git a/src/osgPlugins/ffmpeg/FFmpegDecoder.cpp b/src/osgPlugins/ffmpeg/FFmpegDecoder.cpp index 85cabbac3..bd1308519 100644 --- a/src/osgPlugins/ffmpeg/FFmpegDecoder.cpp +++ b/src/osgPlugins/ffmpeg/FFmpegDecoder.cpp @@ -1,5 +1,6 @@ #include "FFmpegDecoder.hpp" +#include "FFmpegParameters.hpp" #include #include @@ -36,7 +37,7 @@ FFmpegDecoder::~FFmpegDecoder() } -bool FFmpegDecoder::open(const std::string & filename) +bool FFmpegDecoder::open(const std::string & filename, FFmpegParameters* parameters) { try { @@ -100,7 +101,9 @@ bool FFmpegDecoder::open(const std::string & filename) } else { - if (av_open_input_file(&p_format_context, filename.c_str(), 0, 0, 0) !=0 ) + AVInputFormat* av_format = (parameters ? parameters->getFormat() : 0); + AVFormatParameters* av_params = (parameters ? parameters->getFormatParameter() : 0); + if (av_open_input_file(&p_format_context, filename.c_str(), av_format, 0, av_params) !=0 ) throw std::runtime_error("av_open_input_file() failed"); } diff --git a/src/osgPlugins/ffmpeg/FFmpegDecoder.hpp b/src/osgPlugins/ffmpeg/FFmpegDecoder.hpp index a783f0161..f0212214b 100644 --- a/src/osgPlugins/ffmpeg/FFmpegDecoder.hpp +++ b/src/osgPlugins/ffmpeg/FFmpegDecoder.hpp @@ -10,6 +10,8 @@ namespace osgFFmpeg { +class FFmpegParameters; + class FormatContextPtr { public: @@ -65,7 +67,7 @@ public: FFmpegDecoder(); ~FFmpegDecoder(); - bool open(const std::string & filename); + bool open(const std::string & filename, FFmpegParameters* parameters); void close(bool waitForThreadToExit); bool readNextPacket(); diff --git a/src/osgPlugins/ffmpeg/FFmpegImageStream.cpp b/src/osgPlugins/ffmpeg/FFmpegImageStream.cpp index bd25ef8bd..89984628c 100644 --- a/src/osgPlugins/ffmpeg/FFmpegImageStream.cpp +++ b/src/osgPlugins/ffmpeg/FFmpegImageStream.cpp @@ -1,6 +1,7 @@ #include "FFmpegImageStream.hpp" #include "FFmpegAudioStream.hpp" +#include "FFmpegParameters.hpp" #include #include @@ -60,11 +61,11 @@ FFmpegImageStream::~FFmpegImageStream() -bool FFmpegImageStream::open(const std::string & filename) +bool FFmpegImageStream::open(const std::string & filename, FFmpegParameters* parameters) { setFileName(filename); - if (! m_decoder->open(filename)) + if (! m_decoder->open(filename, parameters)) return false; setImage( diff --git a/src/osgPlugins/ffmpeg/FFmpegImageStream.hpp b/src/osgPlugins/ffmpeg/FFmpegImageStream.hpp index 4395a58df..11cb332b7 100644 --- a/src/osgPlugins/ffmpeg/FFmpegImageStream.hpp +++ b/src/osgPlugins/ffmpeg/FFmpegImageStream.hpp @@ -15,6 +15,8 @@ namespace osgFFmpeg template class MessageQueue; + + class FFmpegParameters; class FFmpegImageStream : public osg::ImageStream, public OpenThreads::Thread { @@ -25,7 +27,7 @@ namespace osgFFmpeg META_Object(osgFFmpeg, FFmpegImageStream); - bool open(const std::string & filename); + bool open(const std::string & filename, FFmpegParameters* parameters); virtual void play(); virtual void pause(); diff --git a/src/osgPlugins/ffmpeg/FFmpegParameters.cpp b/src/osgPlugins/ffmpeg/FFmpegParameters.cpp new file mode 100644 index 000000000..b64e0315c --- /dev/null +++ b/src/osgPlugins/ffmpeg/FFmpegParameters.cpp @@ -0,0 +1,79 @@ + +#include "FFmpegParameters.hpp" + +#include +#include +#include + + + +namespace osgFFmpeg { + + + +FFmpegParameters::FFmpegParameters() : + m_format(0) +{ + memset(&m_parameters, 0, sizeof(m_parameters)); +} + + +FFmpegParameters::~FFmpegParameters() +{} + + +void FFmpegParameters::parse(const std::string& name, const std::string& value) +{ + if (value.empty()) + { + return; + } + else if (name == "format") + { + avdevice_register_all(); + m_format = av_find_input_format(value.c_str()); + if (!m_format) + OSG_NOTICE<<"Failed to apply input video format: "<> audio_sample_rate; + m_parameters.sample_rate = audio_sample_rate; + } +} + + + +} // namespace osgFFmpeg diff --git a/src/osgPlugins/ffmpeg/FFmpegParameters.hpp b/src/osgPlugins/ffmpeg/FFmpegParameters.hpp new file mode 100644 index 000000000..1c2d4b922 --- /dev/null +++ b/src/osgPlugins/ffmpeg/FFmpegParameters.hpp @@ -0,0 +1,40 @@ + +#ifndef HEADER_GUARD_OSGFFMPEG_FFMPEG_PARAMETERS_H +#define HEADER_GUARD_OSGFFMPEG_FFMPEG_PARAMETERS_H + +#include "FFmpegHeaders.hpp" + +#include + + +namespace osgFFmpeg { + + + +class FFmpegParameters : public osg::Referenced +{ +public: + + FFmpegParameters(); + ~FFmpegParameters(); + + bool isFormatAvailable() const { return m_format!=NULL; } + + AVInputFormat* getFormat() { return m_format; } + AVFormatParameters* getFormatParameter() { return &m_parameters; } + + void parse(const std::string& name, const std::string& value); + +protected: + + AVInputFormat* m_format; + AVFormatParameters m_parameters; +}; + + + +} // namespace osgFFmpeg + + + +#endif // HEADER_GUARD_OSGFFMPEG_FFMPEG_PARAMETERS_H diff --git a/src/osgPlugins/ffmpeg/ReaderWriterFFmpeg.cpp b/src/osgPlugins/ffmpeg/ReaderWriterFFmpeg.cpp index c58b59d6b..c108235cb 100644 --- a/src/osgPlugins/ffmpeg/ReaderWriterFFmpeg.cpp +++ b/src/osgPlugins/ffmpeg/ReaderWriterFFmpeg.cpp @@ -13,6 +13,7 @@ #include "FFmpegHeaders.hpp" #include "FFmpegImageStream.hpp" +#include "FFmpegParameters.hpp" #include #include @@ -49,6 +50,12 @@ public: supportsExtension("sav", "MPEG-4"); supportsExtension("3gp", "MPEG-4"); supportsExtension("sdp", "MPEG-4"); + + supportsOption("format", "Force setting input format (e.g. vfwcap for Windows webcam)"); + supportsOption("pixel_format", "Set pixel format"); + supportsOption("frame_size", "Set frame size (e.g. 320x240)"); + supportsOption("frame_rate", "Set frame rate (e.g. 25)"); + supportsOption("audio_sample_rate", "Set audio sampling rate (e.g. 44100)"); #ifdef USE_AV_LOCK_MANAGER // enable thread locking @@ -75,9 +82,16 @@ public: if (filename.compare(0, 5, "/dev/")==0) { - return readImageStream(filename, options); + return readImageStream(filename, NULL); } - + + osg::ref_ptr parameters(new osgFFmpeg::FFmpegParameters); + parseOptions(parameters.get(), options); + if (parameters->isFormatAvailable()) + { + return readImageStream(filename, parameters.get()); + } + if (! acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; @@ -88,22 +102,36 @@ public: if (path.empty()) return ReadResult::FILE_NOT_FOUND; - return readImageStream(path, options); + return readImageStream(path, parameters.get()); } - ReadResult readImageStream(const std::string& filename, const osgDB::ReaderWriter::Options * options) const + ReadResult readImageStream(const std::string& filename, osgFFmpeg::FFmpegParameters* parameters) const { OSG_INFO << "ReaderWriterFFmpeg::readImage " << filename << std::endl; osg::ref_ptr image_stream(new osgFFmpeg::FFmpegImageStream); - if (! image_stream->open(filename)) + if (! image_stream->open(filename, parameters)) return ReadResult::FILE_NOT_HANDLED; return image_stream.release(); } private: + + void parseOptions(osgFFmpeg::FFmpegParameters* parameters, const osgDB::ReaderWriter::Options * options) const + { + if (options && options->getNumPluginStringData()>0) + { + const FormatDescriptionMap& supportedOptList = supportedOptions(); + for (FormatDescriptionMap::const_iterator itr = supportedOptList.begin(); + itr != supportedOptList.end(); ++itr) + { + const std::string& name = itr->first; + parameters->parse(name, options->getPluginStringData(name)); + } + } + } #ifdef USE_AV_LOCK_MANAGER static int lockMgr(void **mutex, enum AVLockOp op)