tagparser/ogg/oggpage.h

258 lines
7.3 KiB
C++

#ifndef TAG_PARSER_OGGPAGE_H
#define TAG_PARSER_OGGPAGE_H
#include "../global.h"
#include <cstdint>
#include <iosfwd>
#include <numeric>
#include <vector>
namespace TagParser {
class TAG_PARSER_EXPORT OggPage {
public:
OggPage();
OggPage(std::istream &stream, std::uint64_t startOffset, std::int32_t maxSize);
void parseHeader(std::istream &stream, std::uint64_t startOffset, std::int32_t maxSize);
static std::uint32_t computeChecksum(std::istream &stream, std::uint64_t startOffset);
static void updateChecksum(std::iostream &stream, std::uint64_t startOffset);
std::uint64_t startOffset() const;
std::uint8_t streamStructureVersion() const;
std::uint8_t headerTypeFlag() const;
bool isContinued() const;
bool isFirstpage() const;
bool isLastPage() const;
std::uint64_t absoluteGranulePosition() const;
std::uint32_t streamSerialNumber() const;
bool matchesStreamSerialNumber(std::uint32_t streamSerialNumber) const;
std::uint32_t sequenceNumber() const;
std::uint32_t checksum() const;
std::uint8_t segmentTableSize() const;
const std::vector<std::uint32_t> &segmentSizes() const;
std::uint32_t headerSize() const;
std::uint32_t dataSize() const;
std::uint32_t totalSize() const;
std::uint64_t dataOffset(std::vector<std::uint32_t>::size_type segmentIndex = 0) const;
static std::uint32_t makeSegmentSizeDenotation(std::ostream &stream, std::uint32_t size);
private:
std::uint64_t m_startOffset;
std::uint8_t m_streamStructureVersion;
std::uint8_t m_headerTypeFlag;
std::uint64_t m_absoluteGranulePosition;
std::uint32_t m_streamSerialNumber;
std::uint32_t m_sequenceNumber;
std::uint32_t m_checksum;
std::uint8_t m_segmentCount;
std::vector<std::uint32_t> m_segmentSizes;
};
/*!
* \brief Constructs a new OGG page.
*/
inline OggPage::OggPage()
: m_startOffset(0)
, m_streamStructureVersion(0)
, m_headerTypeFlag(0)
, m_absoluteGranulePosition(0)
, m_streamSerialNumber(0)
, m_sequenceNumber(0)
, m_checksum(0)
, m_segmentCount(0)
{
}
/*!
* \brief Constructs a new OggPage and instantly parses the header read from the specified \a stream
* at the specified \a startOffset.
*/
inline OggPage::OggPage(std::istream &stream, std::uint64_t startOffset, std::int32_t maxSize)
: OggPage()
{
parseHeader(stream, startOffset, maxSize);
}
/*!
* \brief Returns the start offset of the page.
*
* The start offset has been specified when calling the parseHeader() method.
*/
inline std::uint64_t OggPage::startOffset() const
{
return m_startOffset;
}
/*!
* \brief Returns the stream structure version.
*/
inline std::uint8_t OggPage::streamStructureVersion() const
{
return m_streamStructureVersion;
}
/*!
* \brief Returns the header type flag.
* \sa isContinued()
* \sa isFirstpage()
* \sa isLastPage()
*/
inline std::uint8_t OggPage::headerTypeFlag() const
{
return m_headerTypeFlag;
}
/*!
* \brief Returns whether this page is a continued packed (true) or a fresh packed (false).
*/
inline bool OggPage::isContinued() const
{
return m_headerTypeFlag & 0x01;
}
/*!
* \brief Returns whether this page is the first page of the logical bitstream.
*/
inline bool OggPage::isFirstpage() const
{
return m_headerTypeFlag & 0x02;
}
/*!
* \brief Returns whether this page is the last page of the logical bitstream.
*/
inline bool OggPage::isLastPage() const
{
return m_headerTypeFlag & 0x04;
}
/*!
* \brief Returns the absolute granule position.
*
* The position specified is the total samples encoded after including all packets finished on this
* page (packets begun on this page but continuing on to the next page do not count). The rationale
* here is that the position specified in the frame header of the last page tells how long the data
* coded by the bitstream is. A truncated stream will still return the proper number of samples that
* can be decoded fully.
*
* A special value of '-1' (in two's complement) indicates that no packets finish on this page.
*/
inline std::uint64_t OggPage::absoluteGranulePosition() const
{
return m_absoluteGranulePosition;
}
/*!
* \brief Returns the stream serial number.
*
* Ogg allows for separate logical bitstreams to be mixed at page granularity in a physical bitstream.
* The most common case would be sequential arrangement, but it is possible to interleave pages for
* two separate bitstreams to be decoded concurrently. The serial number is the means by which pages
* physical pages are associated with a particular logical stream.
*/
inline std::uint32_t OggPage::streamSerialNumber() const
{
return m_streamSerialNumber;
}
/*!
* \brief Returns whether the stream serial number of the current instance matches the specified one.
* \sa streamSerialNumber()
*/
inline bool OggPage::matchesStreamSerialNumber(std::uint32_t streamSerialNumber) const
{
return m_streamSerialNumber == streamSerialNumber;
}
/*!
* \brief Returns the page sequence number.
*
* Page counter; lets us know if a page is lost (useful where packets span page boundaries).
*/
inline std::uint32_t OggPage::sequenceNumber() const
{
return m_sequenceNumber;
}
/*!
* \brief Returns the page checksum.
*
* 32 bit CRC value (direct algorithm, initial val and final XOR = 0, generator polynomial=0x04c11db7).
* The value is computed over the entire header (with the CRC field in the header set to zero) and then
* continued over the page. The CRC field is then filled with the computed value.
*
* \sa This method returns the checksum denoted by the header. To compute the actual checksum use
* the computeChecksum() method.
*/
inline std::uint32_t OggPage::checksum() const
{
return m_checksum;
}
/*!
* \brief Returns the size of the segment table.
*
* The number of segment entries to appear in the segment table.
*/
inline std::uint8_t OggPage::segmentTableSize() const
{
return m_segmentCount;
}
/*!
* \brief Returns the sizes of the segments of the page in byte.
*
* The lacing values for each packet segment physically appearing in this page are listed in contiguous order.
*/
inline const std::vector<std::uint32_t> &OggPage::segmentSizes() const
{
return m_segmentSizes;
}
/*!
* \brief Returns the header size in byte.
*
* This is 27 plus the number of segment entries in the segment table.
*/
inline std::uint32_t OggPage::headerSize() const
{
return 27 + m_segmentCount;
}
/*!
* \brief Returns the data size in byte.
*/
inline std::uint32_t OggPage::dataSize() const
{
return std::accumulate(m_segmentSizes.cbegin(), m_segmentSizes.cend(), 0u);
}
/*!
* \brief Returns the total size of the page in byte.
*/
inline std::uint32_t OggPage::totalSize() const
{
return headerSize() + dataSize();
}
/*!
* \brief Returns the data offset of the segment with the specified \a segmentIndex.
*
* This is the start offset plus the header size.
*
* \sa startOffset()
* \sa headerSize()
*/
inline std::uint64_t OggPage::dataOffset(std::vector<std::uint32_t>::size_type segmentIndex) const
{
return startOffset() + headerSize()
+ std::accumulate<decltype(m_segmentSizes)::const_iterator, std::uint64_t>(
m_segmentSizes.cbegin(), m_segmentSizes.cbegin() + static_cast<decltype(m_segmentSizes)::difference_type>(segmentIndex), 0u);
}
} // namespace TagParser
#endif // TAG_PARSER_OGGPAGE_H