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

Reply via email to