#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 #include #include 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 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 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; #if 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