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""
This commit is contained in:
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
#include "FFmpegDecoder.hpp"
|
||||
#include "FFmpegParameters.hpp"
|
||||
|
||||
#include <osg/Notify>
|
||||
#include <osgDB/FileNameUtils>
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
#include "FFmpegImageStream.hpp"
|
||||
#include "FFmpegAudioStream.hpp"
|
||||
#include "FFmpegParameters.hpp"
|
||||
|
||||
#include <OpenThreads/ScopedLock>
|
||||
#include <osg/Notify>
|
||||
@@ -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(
|
||||
|
||||
@@ -15,6 +15,8 @@ namespace osgFFmpeg
|
||||
|
||||
template <class T>
|
||||
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();
|
||||
|
||||
79
src/osgPlugins/ffmpeg/FFmpegParameters.cpp
Normal file
79
src/osgPlugins/ffmpeg/FFmpegParameters.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
|
||||
#include "FFmpegParameters.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
|
||||
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: "<<value.c_str()<<std::endl;
|
||||
}
|
||||
else if (name == "pixel_format")
|
||||
{
|
||||
m_parameters.pix_fmt = avcodec_get_pix_fmt(value.c_str());
|
||||
}
|
||||
else if (name == "frame_size")
|
||||
{
|
||||
int frame_width = 0, frame_height = 0;
|
||||
if (av_parse_video_frame_size(&frame_width, &frame_height, value.c_str()) < 0)
|
||||
{
|
||||
OSG_NOTICE<<"Failed to apply frame size: "<<value.c_str()<<std::endl;
|
||||
return;
|
||||
}
|
||||
if ((frame_width % 2) != 0 || (frame_height % 2) != 0)
|
||||
{
|
||||
OSG_NOTICE<<"Frame size must be a multiple of 2: "<<frame_width<<"x"<<frame_height<<std::endl;
|
||||
return;
|
||||
}
|
||||
m_parameters.width = frame_width;
|
||||
m_parameters.height = frame_height;
|
||||
}
|
||||
else if (name == "frame_rate")
|
||||
{
|
||||
AVRational frame_rate;
|
||||
if (av_parse_video_frame_rate(&frame_rate, value.c_str()) < 0)
|
||||
{
|
||||
OSG_NOTICE<<"Failed to apply frame rate: "<<value.c_str()<<std::endl;
|
||||
return;
|
||||
}
|
||||
m_parameters.time_base.den = frame_rate.num;
|
||||
m_parameters.time_base.num = frame_rate.den;
|
||||
}
|
||||
else if (name == "audio_sample_rate")
|
||||
{
|
||||
int audio_sample_rate = 44100;
|
||||
std::stringstream ss(value); ss >> audio_sample_rate;
|
||||
m_parameters.sample_rate = audio_sample_rate;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace osgFFmpeg
|
||||
40
src/osgPlugins/ffmpeg/FFmpegParameters.hpp
Normal file
40
src/osgPlugins/ffmpeg/FFmpegParameters.hpp
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
#ifndef HEADER_GUARD_OSGFFMPEG_FFMPEG_PARAMETERS_H
|
||||
#define HEADER_GUARD_OSGFFMPEG_FFMPEG_PARAMETERS_H
|
||||
|
||||
#include "FFmpegHeaders.hpp"
|
||||
|
||||
#include <osg/Notify>
|
||||
|
||||
|
||||
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
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "FFmpegHeaders.hpp"
|
||||
#include "FFmpegImageStream.hpp"
|
||||
#include "FFmpegParameters.hpp"
|
||||
|
||||
#include <osgDB/Registry>
|
||||
#include <osgDB/FileNameUtils>
|
||||
@@ -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<osgFFmpeg::FFmpegParameters> 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<osgFFmpeg::FFmpegImageStream> 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)
|
||||
|
||||
Reference in New Issue
Block a user