Hi Robert,
Sorry in advance for the long message...
I wanted to test the ffmpeg module on Windows, so I had to modify the
FindFFMPEG.cmake file to find the headers and libs on my machine.
I added steps that will be executed only if ffmpeg is not found using
pkgconfig (if applicable). In my case, I have pkgconfig, but it doesn't
know about the ffmpeg libraries I have, so I get the pkgconfig messages
saying that libavformat and others are not found, but that doesn't
matter much. Most other Windows machines won't have pkgconfig at all, so
they'll just run the other find code.
I made a macro to find the include and lib directories of a given
library (libavformat, libavdevice, ...) in one shot. It's a simple
macro, but looks a lot better than copy-pasting that code 5 times. :-)
For the swscale case, I'm not sure about which header(s) to look for to
find its include path. I put swscale.h, but for all I know that could
not even exist (the windows binaries Tanguy sent do not use swscale).
Could you please check and correct that?
For the paths, I used the FindCOLLADA.cmake file as an example, keeping
most of the paths that are there in case they're used on other
architectures. Feel free to tweak the list of paths as you want. In my
case, the first one is used (FFMPEG_ROOT) since I set FFMPEG_DIR in my
environment variables.
Note that using this code path (not using pkgconfig), even if ffmpeg is
not found the paths can be entered manually (or with -D command line
options I think) by the user. I prefer setting an env var so that it
will always be found, but others might prefer doing it manually.
I also added a message that will be displayed when FFMPEG is not found,
you can keep that or remove it at your discretion, but I think we should
be clearer about which optional libraries are found and which are not so
that we know what we're getting in our build... And if it's clear at
CMake configure time, we can check it right then instead of waiting till
the project is generated or building to find out.
Using this CMake module, I can build the ffmpeg plugin. For some unknown
reason, FFmpegDecoderVideo.hpp included <boost/shared_ptr.h> but didn't
use it, so I removed the include (attached the modified file too).
I'm getting warnings building the ffmpeg plugin, I thought you'd like to
know right now so they can be fixed or suppressed.
____________________________________________________________________
2>FFmpegDecoderVideo.cpp
2>c:\dev\libs\ffmpeg-r15261\include\libavutil\common.h(213) : warning
C4244: 'return' : conversion from 'int' to 'uint8_t', possible loss of data
2>c:\dev\libs\ffmpeg-r15261\include\libavutil\common.h(214) : warning
C4244: 'return' : conversion from 'int' to 'uint8_t', possible loss of data
2>c:\dev\libs\ffmpeg-r15261\include\libavutil\common.h(224) : warning
C4244: 'return' : conversion from 'int' to 'int16_t', possible loss of data
2>c:\dev\libs\ffmpeg-r15261\include\libavutil\common.h(225) : warning
C4244: 'return' : conversion from 'int' to 'int16_t', possible loss of data
2>c:\dev\libs\ffmpeg-r15261\include\libavutil\rational.h(51) : warning
C4244: 'return' : conversion from 'const int64_t' to 'int', possible
loss of data
2>FFmpegDecoder.cpp
2>..\..\..\..\src\osgPlugins\ffmpeg\FFmpegDecoder.cpp(225) : warning
C4389: '==' : signed/unsigned mismatch
2>..\..\..\..\src\osgPlugins\ffmpeg\FFmpegDecoder.cpp(232) : warning
C4389: '==' : signed/unsigned mismatch
2>FFmpegDecoderAudio.cpp
2>..\..\..\..\src\osgPlugins\ffmpeg\FFmpegDecoderAudio.cpp(120) :
warning C4189: 'filled' : local variable is initialized but not referenced
____________________________________________________________________
But once the plugin is built, I can do:
osgmovie -e ffmpeg <path>\aliensong.mpg --screen 1
and see the video. It seems to work with pretty much any video I throw
at it (.mov, .wmv, .avi, .flv, ...).
I'm getting a crash on exit if I quit after letting it play for a while
though (but if I quit after just a few seconds it doesn't crash). I'll
investigate that and get back to you.
Great work! Thanks,
J-S
--
______________________________________________________
Jean-Sebastien Guay [email protected]
http://www.cm-labs.com/
http://whitestar02.webhop.org/
# Locate ffmpeg
# This module defines
# FFMPEG_LIBRARIES
# FFMPEG_FOUND, if false, do not try to link to ffmpeg
# FFMPEG_INCLUDE_DIR, where to find the headers
#
# $FFMPEG_DIR is an environment variable that would
# correspond to the ./configure --prefix=$FFMPEG_DIR
#
# Created by Robert Osfield.
#use pkg-config to find various modes
INCLUDE(FindPkgConfig OPTIONAL)
IF(PKG_CONFIG_FOUND)
INCLUDE(FindPkgConfig)
pkg_check_modules(FFMPEG_LIBAVFORMAT libavformat)
pkg_check_modules(FFMPEG_LIBAVDEVICE libavdevice)
pkg_check_modules(FFMPEG_LIBAVCODEC libavcodec)
pkg_check_modules(FFMPEG_LIBAVUTIL libavutil)
pkg_check_modules(FFMPEG_LIBSWSCALE libswscale)
ENDIF(PKG_CONFIG_FOUND)
# If FFMPEG was not found with pkgconfig, try to find it through other means.
IF(NOT FFMPEG_LIBAVFORMAT_FOUND)
# Macro to find header and lib directories
# example: FFMPEG_FIND(AVFORMAT avformat avformat.h)
MACRO(FFMPEG_FIND varname shortname headername)
# First try to find header directly in include directory
FIND_PATH(FFMPEG_${varname}_INCLUDE_DIRS ${headername}
${FFMPEG_ROOT}/include
$ENV{FFMPEG_DIR}/include
$ENV{OSGDIR}/include
$ENV{OSG_ROOT}/include
~/Library/Frameworks
/Library/Frameworks
/usr/local/include
/usr/include/
/sw/include # Fink
/opt/local/include # DarwinPorts
/opt/csw/include # Blastwave
/opt/include
/usr/freeware/include
)
# If not found, try to find it in a subdirectory. Tanguy's build has
# avformat.h in include/libavformat, so this catches that case. If
that's
# standard, perhaps we can keep just this case.
IF(NOT FFMPEG_${varname}_INCLUDE_DIRS)
FIND_PATH(FFMPEG_${varname}_INCLUDE_DIRS
lib${shortname}/${headername}
${FFMPEG_ROOT}/include
$ENV{FFMPEG_DIR}/include
$ENV{OSGDIR}/include
$ENV{OSG_ROOT}/include
~/Library/Frameworks
/Library/Frameworks
/usr/local/include
/usr/include/
/sw/include # Fink
/opt/local/include # DarwinPorts
/opt/csw/include # Blastwave
/opt/include
/usr/freeware/include
)
ENDIF(NOT FFMPEG_${varname}_INCLUDE_DIRS)
FIND_LIBRARY(FFMPEG_${varname}_LIBRARIES
NAMES ${shortname}
PATHS
${FFMPEG_ROOT}/lib
$ENV{FFMPEG_DIR}/lib
$ENV{OSGDIR}/lib
$ENV{OSG_ROOT}/lib
~/Library/Frameworks
/Library/Frameworks
/usr/local/lib
/usr/local/lib64
/usr/lib
/usr/lib64
/sw/lib
/opt/local/lib
/opt/csw/lib
/opt/lib
/usr/freeware/lib64
)
IF (FFMPEG_${varname}_LIBRARIES)
SET(FFMPEG_${varname}_FOUND 1)
ENDIF(FFMPEG_${varname}_LIBRARIES)
ENDMACRO(FFMPEG_FIND)
SET(FFMPEG_ROOT "$ENV{FFMPEG_DIR}" CACHE PATH "Location of FFMPEG")
FFMPEG_FIND(LIBAVFORMAT avformat avformat.h)
FFMPEG_FIND(LIBAVDEVICE avdevice avdevice.h)
FFMPEG_FIND(LIBAVCODEC avcodec avcodec.h)
FFMPEG_FIND(LIBAVUTIL avutil avutil.h)
FFMPEG_FIND(LIBSWSCALE swscale swscale.h) # not sure about the header to
look for here.
ENDIF(NOT FFMPEG_LIBAVFORMAT_FOUND)
SET(FFMPEG_FOUND "NO")
# Note we don't check FFMPEG_LIBSWSCALE_FOUND here, it's optional.
IF (FFMPEG_LIBAVFORMAT_FOUND AND FFMPEG_LIBAVDEVICE_FOUND AND
FFMPEG_LIBAVCODEC_FOUND AND FFMPEG_LIBAVUTIL_FOUND)
SET(FFMPEG_FOUND "YES")
SET(FFMPEG_INCLUDE_DIRS ${FFMPEG_LIBAVFORMAT_INCLUDE_DIRS})
SET(FFMPEG_LIBRARY_DIRS ${FFMPEG_LIBAVFORMAT_LIBRARY_DIRS})
# Note we don't add FFMPEG_LIBSWSCALE_LIBRARIES here, it will be added if
found later.
SET(FFMPEG_LIBRARIES
${FFMPEG_LIBAVFORMAT_LIBRARIES}
${FFMPEG_LIBAVDEVICE_LIBRARIES}
${FFMPEG_LIBAVCODEC_LIBRARIES}
${FFMPEG_LIBAVUTIL_LIBRARIES})
ELSE (FFMPEG_LIBAVFORMAT_FOUND AND FFMPEG_LIBAVDEVICE_FOUND AND
FFMPEG_LIBAVCODEC_FOUND AND FFMPEG_LIBAVUTIL_FOUND)
MESSAGE(STATUS "Could not find FFMPEG")
ENDIF(FFMPEG_LIBAVFORMAT_FOUND AND FFMPEG_LIBAVDEVICE_FOUND AND
FFMPEG_LIBAVCODEC_FOUND AND FFMPEG_LIBAVUTIL_FOUND)
#ifndef HEADER_GUARD_OSGFFMPEG_FFMPEG_DECODER_VIDEO_H
#define HEADER_GUARD_OSGFFMPEG_FFMPEG_DECODER_VIDEO_H
#include "FFmpegHeaders.hpp"
#include "BoundedMessageQueue.hpp"
#include "FFmpegClocks.hpp"
#include "FFmpegPacket.hpp"
#include <OpenThreads/Thread>
#include <vector>
namespace osgFFmpeg {
class FramePtr
{
public:
typedef AVFrame T;
explicit FramePtr() : _ptr(0) {}
explicit FramePtr(T* ptr) : _ptr(ptr) {}
~FramePtr()
{
cleanup();
}
T* get() { return _ptr; }
T * operator-> () const // never throws
{
return _ptr;
}
void reset(T* ptr)
{
if (ptr==_ptr) return;
cleanup();
_ptr = ptr;
}
void cleanup()
{
if (_ptr) av_free(_ptr);
_ptr = 0;
}
protected:
T* _ptr;
};
class FFmpegDecoderVideo : public OpenThreads::Thread
{
public:
typedef BoundedMessageQueue<FFmpegPacket> PacketQueue;
typedef void (* PublishFunc) (const FFmpegDecoderVideo & decoder, void *
user_data);
FFmpegDecoderVideo(PacketQueue & packets, FFmpegClocks & clocks);
~FFmpegDecoderVideo();
void open(AVStream * stream);
virtual void run();
void setUserData(void * user_data);
void setPublishCallback(PublishFunc function);
int width() const;
int height() const;
double aspectRatio() const;
bool alphaChannel() const;
double frameRate() const;
const uint8_t * image() const;
private:
typedef std::vector<uint8_t> Buffer;
void decodeLoop();
void findAspectRatio();
void publishFrame(double delay);
void swapBuffers();
double synchronizeVideo(double pts);
void yuva420pToRgba(AVPicture *dst, const AVPicture *src, int width, int
height);
int convert(AVPicture *dst, int dst_pix_fmt, const AVPicture *src,
int src_pix_fmt, int src_width, int src_height);
static int getBuffer(AVCodecContext * context, AVFrame * picture);
static void releaseBuffer(AVCodecContext * context, AVFrame * picture);
PacketQueue & m_packets;
FFmpegClocks & m_clocks;
AVStream * m_stream;
AVCodecContext * m_context;
AVCodec * m_codec;
const uint8_t * m_packet_data;
int m_bytes_remaining;
int64_t m_packet_pts;
FramePtr m_frame;
FramePtr m_frame_rgba;
Buffer m_buffer_rgba;
Buffer m_buffer_rgba_public;
void * m_user_data;
PublishFunc m_publish_func;
double m_frame_rate;
double m_aspect_ratio;
int m_width;
int m_height;
size_t m_next_frame_index;
bool m_alpha_channel;
volatile bool m_exit;
#ifdef USE_SWSCALE
struct SwsContext * m_swscale_ctx;
#endif
};
inline void FFmpegDecoderVideo::setUserData(void * const user_data)
{
m_user_data = user_data;
}
inline void FFmpegDecoderVideo::setPublishCallback(const PublishFunc function)
{
m_publish_func = function;
}
inline int FFmpegDecoderVideo::width() const
{
return m_width;
}
inline int FFmpegDecoderVideo::height() const
{
return m_height;
}
inline double FFmpegDecoderVideo::aspectRatio() const
{
return m_aspect_ratio;
}
inline bool FFmpegDecoderVideo::alphaChannel() const
{
return m_alpha_channel;
}
inline double FFmpegDecoderVideo::frameRate() const
{
return m_frame_rate;
}
inline const uint8_t * FFmpegDecoderVideo::image() const
{
return &m_buffer_rgba_public[0];
}
} // namespace osgFFmpeg
#endif // HEADER_GUARD_OSGFFMPEG_FFMPEG_DECODER_VIDEO_H
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org