root/libmedia/FLVParser.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


// FLVParser.h:  Flash Video file format parser, for Gnash.
//
//   Copyright (C) 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//


// Information about the FLV format can be found at http://osflash.org/flv

#ifndef GNASH_FLVPARSER_H
#define GNASH_FLVPARSER_H

#include "dsodefs.h"
#include "MediaParser.h" // for inheritance
#include "SimpleBuffer.h" 

#include <set>
#include <memory>
#include <map>

#include <boost/thread/mutex.hpp>

namespace gnash {
namespace media {

/// Extra video info found in some FLV embedded streams
//
/// This is basically composed by an header for the audio stream
///
class ExtraVideoInfoFlv : public VideoInfo::ExtraInfo
{
public:

    /// Construct an ExtraVideoInfoFlv
    //
    /// @param extradata
    ///     Video header data. Ownership transferred.
    ///
    /// @param datasize
    ///     Video header data size
    ///
    /// @todo take a SimpleBuffer by auto_ptr
    ///
    ExtraVideoInfoFlv(boost::uint8_t* extradata, size_t datasize)
        :
        data(extradata),
        size(datasize)
    {
    }

    /// Video stream header
    boost::scoped_array<boost::uint8_t> data;

    /// Video stream header size
    size_t size;
};

/// Extra audoi info found in some FLV embedded streams
//
/// This is basically composed by an header for the audio stream
///
class ExtraAudioInfoFlv : public AudioInfo::ExtraInfo
{
public:

    /// Construct an ExtraAudioInfoFlv
    //
    /// @param extradata
    ///     Audio header data. Ownership transferred.
    ///
    /// @param datasize
    ///     Audio header data size
    ///
    /// @todo take a SimpleBuffer by auto_ptr
    ///
    ExtraAudioInfoFlv(boost::uint8_t* extradata, size_t datasize)
        :
        data(extradata),
        size(datasize)
    {
    }

    /// Audio stream header
    boost::scoped_array<boost::uint8_t> data;

    /// Audio stream header size
    size_t size;
};

/// The FLVParser class parses FLV streams
class DSOEXPORT FLVParser : public MediaParser
{

public:

    /// The size of padding for all buffers that might be read by FFMPEG.
    //
    /// This possibly also applies to other media handlers (gst).
    /// Ideally this would be taken from the current Handler, but we don't
    /// know about it here.
    static const size_t paddingBytes = 8;

        /// \brief
        /// Create an FLV parser reading input from
        /// the given IOChannel
        //
        /// @param lt
        ///     IOChannel to use for input.
        ///     Ownership transferred.
        ///
        FLVParser(std::auto_ptr<IOChannel> lt);

        /// Kills the parser...
        ~FLVParser();

        // see dox in MediaParser.h
        virtual bool seek(boost::uint32_t&);

        // see dox in MediaParser.h
        virtual bool parseNextChunk();

        // see dox in MediaParser.h
        boost::uint64_t getBytesLoaded() const;

        // see dox in MediaParser.h
        bool indexingCompleted() const
        {
                return _indexingCompleted;
        }

    /// Retrieve any parsed metadata tags up to a specified timestamp.
    //
    /// This copies pointers to a SimpleBuffer of AMF data from _metaTags,
    /// then removes those pointers from the MetaTags map. Any metadata later
    /// than the timestamp is kept until fetchMetaTags is called again (or 
    /// the dtor is called).
    //
    /// @param ts   The latest timestamp to retrieve metadata for.
    /// @param tags This is filled with shared pointers to metatags in
    ///             timestamp order. Ownership of the data is shared. It
    ///             is destroyed automatically along with the last owner.
    //
    virtual void fetchMetaTags(OrderedMetaTags& tags, boost::uint64_t ts);

private:

        enum tagType
        {
                FLV_AUDIO_TAG = 0x08,
                FLV_VIDEO_TAG = 0x09,
                FLV_META_TAG = 0x12
        };

        struct FLVTag : public boost::noncopyable
        {
                FLVTag(boost::uint8_t* stream)
                    :
            type(stream[0]),
            body_size(getUInt24(stream+1)),
            timestamp(getUInt24(stream+4) | (stream[7] << 24) )
                {}

                /// Equals tagType
                boost::uint8_t type;
                boost::uint32_t body_size;
                boost::uint32_t timestamp;
        };

        struct FLVAudioTag : public boost::noncopyable
        {
                FLVAudioTag(const boost::uint8_t& byte)
                    :
            codec( (byte & 0xf0) >> 4 ),
                    samplerate( flv_audio_rates[(byte & 0x0C) >> 2] ),
                    samplesize( 1 + ((byte & 0x02) >> 1)),
                    stereo( (byte & 0x01) )
                {
                }

                /// Equals audioCodecType
                boost::uint8_t codec;

                boost::uint16_t samplerate;

                /// Size of each sample, in bytes
                boost::uint8_t samplesize;

                bool stereo;

    private:
        
        static const boost::uint16_t flv_audio_rates[];
        
    };

        enum frameType
        {
                FLV_VIDEO_KEYFRAME = 1,
                FLV_VIDEO_INTERLACED = 2,
                FLV_VIDEO_DISPOSABLE = 3
        };

        struct FLVVideoTag : public boost::noncopyable
        {
                FLVVideoTag(const boost::uint8_t& byte)
            :
            frametype( (byte & 0xf0) >> 4 ),
                    codec( byte & 0x0f )
                {}

                /// Equals frameType
                boost::uint8_t frametype;
                /// Equals videoCodecType
                boost::uint8_t codec;
        };

        /// Parses next tag from the file
        //
        /// Returns true if something was parsed, false otherwise.
        /// Sets _parsingComplete=true on end of file.
        ///
        bool parseNextTag(bool index_only);

        std::auto_ptr<EncodedAudioFrame> parseAudioTag(const FLVTag& flvtag,
            const FLVAudioTag& audiotag, boost::uint32_t thisTagPos);
        
    std::auto_ptr<EncodedVideoFrame> parseVideoTag(const FLVTag& flvtag,
            const FLVVideoTag& videotag, boost::uint32_t thisTagPos);

        void indexAudioTag(const FLVTag& tag, boost::uint32_t thisTagPos);
        
    void indexVideoTag(const FLVTag& tag, const FLVVideoTag& videotag,
            boost::uint32_t thisTagPos);

        /// Parses the header of the file
        bool parseHeader();

        /// Reads three bytes in FLV (big endian) byte order.
        /// @param in Pointer to read 3 bytes from.
        /// @return 24-bit integer.
        static boost::uint32_t getUInt24(boost::uint8_t* in);

        /// The position where the parsing should continue from.
        /// Will be reset on seek, and will be protected by the _streamMutex
        boost::uint64_t _lastParsedPosition;

        /// Position of next tag to index
        boost::uint64_t _nextPosToIndex;

        /// Audio frame cursor position 
        //
        /// This is the video frame number that will
        /// be referenced by nextVideoFrame and nextVideoFrameTimestamp
        ///
        size_t _nextAudioFrame;

        /// Video frame cursor position 
        //
        /// This is the video frame number that will
        /// be referenced by nextVideoFrame and nextVideoFrameTimestamp
        ///
        size_t _nextVideoFrame;

        /// Audio stream is present
        bool _audio;

        /// Audio stream is present
        bool _video;

        std::auto_ptr<EncodedAudioFrame>
        readAudioFrame(boost::uint32_t dataSize, boost::uint32_t timestamp);

        std::auto_ptr<EncodedVideoFrame>
        readVideoFrame(boost::uint32_t dataSize, boost::uint32_t timestamp);

        /// Position in input stream for each cue point
        /// first: timestamp
        /// second: position in input stream
        typedef std::map<boost::uint64_t, long> CuePointsMap;
        CuePointsMap _cuePoints;

        bool _indexingCompleted;

    MetaTags _metaTags;

    boost::mutex _metaTagsMutex;
};

} // end of gnash::media namespace
} // end of gnash namespace

#endif 

/* [<][>][^][v][top][bottom][index][help] */