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:
Robert Osfield
2010-11-03 10:37:32 +00:00
parent afa563df57
commit 4ced7dffc4
8 changed files with 168 additions and 11 deletions

View File

@@ -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
)

View File

@@ -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");
}

View File

@@ -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();

View File

@@ -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(

View File

@@ -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();

View 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

View 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

View File

@@ -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)