252 lines
8.0 KiB
C++
252 lines
8.0 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Parse.h
|
|
// MPEG-1 parsing code.
|
|
//
|
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma once
|
|
#include "GrowArray.h"
|
|
|
|
|
|
// Note: The structs, enums, and constants defined in this header are not taken from
|
|
// Media Foundation or DirectShow headers. The parser code is written to be API-agnostic.
|
|
// The only exceptions are:
|
|
// - Use of the MFRatio structure to describe ratios.
|
|
// - The MPEG1AudioFlags enum defined here maps directly to the equivalent DirectShow flags.
|
|
|
|
// Sizes
|
|
const DWORD MPEG1_MAX_PACKET_SIZE = 65535 + 6; // Maximum packet size.
|
|
const DWORD MPEG1_PACK_HEADER_SIZE = 12; // Pack header.
|
|
|
|
const DWORD MPEG1_SYSTEM_HEADER_MIN_SIZE = 12; // System header, excluding the stream info.
|
|
const DWORD MPEG1_SYSTEM_HEADER_PREFIX = 6; // This value + header length = total size of the system header.
|
|
const DWORD MPEG1_SYSTEM_HEADER_STREAM = 3; // Size of each stream info in the system header.
|
|
|
|
const DWORD MPEG1_PACKET_HEADER_MIN_SIZE = 6; // Minimum amount to read in the packet header. (Up to the variable-sized padding bytes)
|
|
const DWORD MPEG1_PACKET_HEADER_MAX_STUFFING_BYTE = 16; // Maximum number of stuffing bytes in a packet header.
|
|
const DWORD MPEG1_PACKET_HEADER_MAX_SIZE = 34; // Maximum size of a packet header.
|
|
|
|
const DWORD MPEG1_VIDEO_SEQ_HEADER_MIN_SIZE = 12; // Minimum length of the video sequence header.
|
|
const DWORD MPEG1_VIDEO_SEQ_HEADER_MAX_SIZE = 140; // Maximum length of the video sequence header.
|
|
|
|
const DWORD MPEG1_AUDIO_FRAME_HEADER_SIZE = 4;
|
|
|
|
|
|
// Codes
|
|
const DWORD MPEG1_START_CODE_PREFIX = 0x00000100;
|
|
const DWORD MPEG1_PACK_START_CODE = 0x000001BA;
|
|
const DWORD MPEG1_SYSTEM_HEADER_CODE = 0x000001BB;
|
|
const DWORD MPEG1_SEQUENCE_HEADER_CODE = 0x000001B3;
|
|
const DWORD MPEG1_STOP_CODE = 0x000001B9;
|
|
|
|
// Stream ID codes
|
|
const BYTE MPEG1_STREAMTYPE_ALL_AUDIO = 0xB8;
|
|
const BYTE MPEG1_STREAMTYPE_ALL_VIDEO = 0xB9;
|
|
const BYTE MPEG1_STREAMTYPE_RESERVED = 0xBC;
|
|
const BYTE MPEG1_STREAMTYPE_PRIVATE1 = 0xBD;
|
|
const BYTE MPEG1_STREAMTYPE_PADDING = 0xBE;
|
|
const BYTE MPEG1_STREAMTYPE_PRIVATE2 = 0xBF;
|
|
const BYTE MPEG1_STREAMTYPE_AUDIO_MASK = 0xC0;
|
|
const BYTE MPEG1_STREAMTYPE_VIDEO_MASK = 0xE0;
|
|
const BYTE MPEG1_STREAMTYPE_DATA_MASK = 0xF0;
|
|
|
|
|
|
|
|
// Systems layer
|
|
|
|
enum StreamType
|
|
{
|
|
StreamType_Unknown,
|
|
StreamType_AllAudio,
|
|
StreamType_AllVideo,
|
|
StreamType_Reserved,
|
|
StreamType_Private1,
|
|
StreamType_Padding,
|
|
StreamType_Private2,
|
|
StreamType_Audio, // ISO/IEC 11172-3
|
|
StreamType_Video, // ISO/IEC 11172-2
|
|
StreamType_Data
|
|
};
|
|
|
|
struct MPEG1StreamHeader
|
|
{
|
|
BYTE stream_id; // Raw stream_id field.
|
|
StreamType type; // Stream type (audio, video, etc)
|
|
BYTE number; // Index within the stream type (audio 0, audio 1, etc)
|
|
DWORD sizeBound;
|
|
};
|
|
|
|
// MPEG1SystemHeader
|
|
// Holds information from the system header. This structure is variable
|
|
// length, because the last field is an array of stream headers.
|
|
struct MPEG1SystemHeader
|
|
{
|
|
DWORD cbSize; // Size of this structure, including the streams array.
|
|
DWORD rateBound;
|
|
BYTE cAudioBound;
|
|
BOOL bFixed;
|
|
BOOL bCSPS;
|
|
BOOL bAudioLock;
|
|
BOOL bVideoLock;
|
|
BYTE cVideoBound;
|
|
DWORD cStreams;
|
|
MPEG1StreamHeader streams[1]; // Array of 1 or more stream headers.
|
|
};
|
|
|
|
struct MPEG1PacketHeader
|
|
{
|
|
BYTE stream_id; // Raw stream_id field.
|
|
StreamType type; // Stream type (audio, video, etc)
|
|
BYTE number; // Index within the stream type (audio 0, audio 1, etc)
|
|
DWORD cbPacketSize; // Size of the entire packet (header + payload).
|
|
DWORD cbPayload; // Size of the packet payload (packet size - header size).
|
|
BOOL bHasPTS; // Did the packet header contain a Presentation Time Stamp (PTS)?
|
|
LONGLONG PTS; // Presentation Time Stamp (in 90 kHz clock)
|
|
};
|
|
|
|
// Video
|
|
|
|
struct MPEG1VideoSeqHeader
|
|
{
|
|
WORD width;
|
|
WORD height;
|
|
MFRatio pixelAspectRatio;
|
|
MFRatio frameRate;
|
|
DWORD bitRate;
|
|
WORD cbVBV_Buffer;
|
|
BOOL bConstrained;
|
|
DWORD cbHeader;
|
|
BYTE header[MPEG1_VIDEO_SEQ_HEADER_MAX_SIZE]; // Raw header.
|
|
};
|
|
|
|
// Audio
|
|
|
|
enum MPEG1AudioLayer
|
|
{
|
|
MPEG1_Audio_Layer1 = 0,
|
|
MPEG1_Audio_Layer2,
|
|
MPEG1_Audio_Layer3
|
|
};
|
|
|
|
enum MPEG1AudioMode
|
|
{
|
|
MPEG1_Audio_Stereo = 0,
|
|
MPEG1_Audio_JointStereo,
|
|
MPEG1_Audio_DualChannel,
|
|
MPEG1_Audio_SingleChannel
|
|
};
|
|
|
|
|
|
// Various bit flags used in the audio frame header.
|
|
// (Note: These enum values are not the actual values in the audio frame header.)
|
|
enum MPEG1AudioFlags
|
|
{
|
|
MPEG1_AUDIO_PRIVATE_BIT = 0x01, // = ACM_MPEG_PRIVATEBIT
|
|
MPEG1_AUDIO_COPYRIGHT_BIT = 0x02, // = ACM_MPEG_COPYRIGHT
|
|
MPEG1_AUDIO_ORIGINAL_BIT = 0x04, // = ACM_MPEG_ORIGINALHOME
|
|
MPEG1_AUDIO_PROTECTION_BIT = 0x08, // = ACM_MPEG_PROTECTIONBIT
|
|
};
|
|
|
|
|
|
struct MPEG1AudioFrameHeader
|
|
{
|
|
MPEG1AudioLayer layer;
|
|
DWORD dwBitRate; // Bit rate in Kbits / sec
|
|
DWORD dwSamplesPerSec;
|
|
WORD nBlockAlign;
|
|
WORD nChannels;
|
|
MPEG1AudioMode mode;
|
|
BYTE modeExtension;
|
|
BYTE emphasis;
|
|
WORD wFlags; // bitwise OR of MPEG1AudioFlags
|
|
};
|
|
|
|
// Buffer class:
|
|
// Resizable buffer used to hold the MPEG-1 data.
|
|
|
|
class Buffer : GrowableArray<BYTE>
|
|
{
|
|
public:
|
|
Buffer();
|
|
HRESULT Initalize(DWORD cbSize);
|
|
|
|
BYTE* DataPtr();
|
|
DWORD DataSize() const;
|
|
|
|
// Reserve: Reserves cb bytes of free data in the buffer.
|
|
// The reserved bytes start at DataPtr() + DataSize().
|
|
HRESULT Reserve(DWORD cb);
|
|
|
|
// MoveStart: Moves the front of the buffer.
|
|
// Call this method after consuming data from the buffer.
|
|
HRESULT MoveStart(DWORD cb);
|
|
|
|
// MoveEnd: Moves the end of the buffer.
|
|
// Call this method after reading data into the buffer.
|
|
HRESULT MoveEnd(DWORD cb);
|
|
|
|
private:
|
|
DWORD CurrentFreeSize() const;
|
|
|
|
private:
|
|
DWORD m_begin;
|
|
DWORD m_end; // 1 past the last element
|
|
};
|
|
|
|
|
|
// Parser class:
|
|
// Parses an MPEG-1 systems-layer stream.
|
|
class Parser
|
|
{
|
|
public:
|
|
|
|
Parser();
|
|
~Parser();
|
|
|
|
HRESULT ParseBytes(const BYTE *pData, DWORD cbLen, DWORD *pAte);
|
|
|
|
BOOL HasSystemHeader() const { return m_pHeader != NULL; }
|
|
HRESULT GetSystemHeader(MPEG1SystemHeader **ppHeader);
|
|
|
|
BOOL HasPacket() const { return m_bHasPacketHeader; }
|
|
const MPEG1PacketHeader& PacketHeader() { assert(m_bHasPacketHeader); return m_curPacketHeader; }
|
|
|
|
DWORD PayloadSize() const { assert(m_bHasPacketHeader); return m_curPacketHeader.cbPayload; }
|
|
void ClearPacket() { m_bHasPacketHeader = FALSE; }
|
|
|
|
BOOL IsEndOfStream() const { return m_bEOS; }
|
|
|
|
private:
|
|
|
|
HRESULT FindNextStartCode(const BYTE *pData, DWORD cbLen, DWORD *pAte);
|
|
HRESULT ParsePackHeader(const BYTE *pData, DWORD cbLen, DWORD *pAte);
|
|
HRESULT ParseSystemHeader(const BYTE *pData, DWORD cbLen, DWORD *pAte);
|
|
HRESULT ParsePacketHeader(const BYTE *pData, DWORD cbLen, DWORD *pAte);
|
|
HRESULT OnEndOfStream();
|
|
|
|
private:
|
|
|
|
LONGLONG m_SCR;
|
|
DWORD m_muxRate;
|
|
|
|
MPEG1SystemHeader *m_pHeader;
|
|
// Note: Size of header = sizeof(MPEG1SystemHeader) + (sizeof(MPEG1StreamHeader) * (cStreams - 1))
|
|
|
|
BOOL m_bHasPacketHeader;
|
|
MPEG1PacketHeader m_curPacketHeader; // Most recent packet header.
|
|
|
|
BOOL m_bEOS;
|
|
};
|
|
|
|
|
|
HRESULT ReadVideoSequenceHeader(const BYTE *pData, DWORD cbData, MPEG1VideoSeqHeader& seqHeader, DWORD *pAte);
|
|
|
|
HRESULT ReadAudioFrameHeader(const BYTE *pData, DWORD cbData, MPEG1AudioFrameHeader& audioHeader, DWORD *pAte); |