2025-11-28 00:35:46 +09:00

262 lines
8.2 KiB
C++

//////////////////////////////////////////////////////////////////////////
//
// MPEG1Source.h
// Implements the MPEG-1 media source object.
//
// 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 <windows.h>
#include <assert.h>
#ifndef _ASSERTE
#define _ASSERTE assert
#endif
#include <mftransform.h>
#include <mfapi.h>
#include <mfobjects.h>
#include <mfidl.h>
#include <mferror.h>
#include <uuids.h> // MPEG-1 subtypes
#include <amvideo.h> // VIDEOINFOHEADER definition
#include <dvdmedia.h> // VIDEOINFOHEADER2
#include <mmreg.h> // MPEG1WAVEFORMAT
#include <shlwapi.h>
#pragma comment(lib, "mfplat")
#pragma comment(lib, "mfuuid") // Media Foundation GUIDs
#pragma comment(lib, "strmiids") // DirectShow GUIDs
#pragma comment(lib, "Ws2_32") // htonl, etc
#pragma comment(lib, "shlwapi")
// Common sample files.
#define USE_LOGGING
#include "common.h"
using namespace MediaFoundationSamples;
#define CHECK_HR(hr) IF_FAILED_GOTO(hr, done)
#include "OpQueue.h"
// Forward declares
class MPEG1ByteStreamHandler;
class MPEG1Source;
class MPEG1Stream;
class SourceOp;
// Typedefs
typedef GrowableArray<MPEG1Stream*> StreamList;
typedef TinyMap<BYTE, DWORD> StreamMap; // Maps stream ID to index
typedef ComPtrList<IMFSample> SampleList;
typedef ComPtrList<IUnknown, true> TokenList; // List of tokens for IMFMediaStream::RequestSample
enum SourceState
{
STATE_INVALID, // Initial state. Have not started opening the stream.
STATE_OPENING, // BeginOpen is in progress.
STATE_STOPPED,
STATE_PAUSED,
STATE_STARTED,
STATE_SHUTDOWN
};
// Internal headers
#include "Parse.h" // MPEG-1 parser
#include "MPEG1Stream.h" // MPEG-1 stream
// Constants
const DWORD INITIAL_BUFFER_SIZE = 4 * 1024; // Initial size of the read buffer. (The buffer expands dynamically.)
const DWORD READ_SIZE = 4 * 1024; // Size of each read request.
const DWORD SAMPLE_QUEUE = 2; // How many samples does each stream try to hold in its queue?
// SourceOp: Represents a request for an asynchronous operation.
class SourceOp : RefCountedObject, public IUnknown
{
public:
enum Operation
{
OP_START,
OP_PAUSE,
OP_STOP,
OP_REQUEST_DATA,
OP_END_OF_STREAM
};
static HRESULT CreateOp(Operation op, SourceOp **ppOp);
static HRESULT CreateStartOp(IMFPresentationDescriptor *pPD, SourceOp **ppOp);
// IUnknown
STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
STDMETHODIMP_(ULONG) AddRef() { return RefCountedObject::AddRef(); }
STDMETHODIMP_(ULONG) Release() { return RefCountedObject::Release(); }
SourceOp(Operation op);
virtual ~SourceOp();
HRESULT SetData(const PROPVARIANT& var);
Operation Op() const { return m_op; }
const PROPVARIANT& Data() { return m_data;}
protected:
Operation m_op;
PROPVARIANT m_data; // Data for the operation.
};
class StartOp : public SourceOp
{
public:
StartOp(IMFPresentationDescriptor *pPD);
~StartOp();
HRESULT GetPresentationDescriptor(IMFPresentationDescriptor **ppPD);
protected:
IMFPresentationDescriptor *m_pPD; // Presentation descriptor for Start operations.
};
// MPEG1Source: The media source object.
class MPEG1Source : BaseObject, RefCountedObject, public OpQueue<SourceOp>, public IMFMediaSource
{
public:
static HRESULT CreateInstance(MPEG1Source **ppSource);
// IUnknown
STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
STDMETHODIMP_(ULONG) AddRef() { return RefCountedObject::AddRef(); }
STDMETHODIMP_(ULONG) Release() { return RefCountedObject::Release(); }
// IMFMediaEventGenerator
STDMETHODIMP BeginGetEvent(IMFAsyncCallback* pCallback,IUnknown* punkState);
STDMETHODIMP EndGetEvent(IMFAsyncResult* pResult, IMFMediaEvent** ppEvent);
STDMETHODIMP GetEvent(DWORD dwFlags, IMFMediaEvent** ppEvent);
STDMETHODIMP QueueEvent(MediaEventType met, REFGUID guidExtendedType, HRESULT hrStatus, const PROPVARIANT* pvValue);
// IMFMediaSource
STDMETHODIMP CreatePresentationDescriptor(IMFPresentationDescriptor** ppPresentationDescriptor);
STDMETHODIMP GetCharacteristics(DWORD* pdwCharacteristics);
STDMETHODIMP Pause();
STDMETHODIMP Shutdown();
STDMETHODIMP Start(
IMFPresentationDescriptor* pPresentationDescriptor,
const GUID* pguidTimeFormat,
const PROPVARIANT* pvarStartPosition
);
STDMETHODIMP Stop();
// Called by the byte stream handler.
HRESULT BeginOpen(IMFByteStream *pStream, IMFAsyncCallback *pCB, IUnknown *pUnkState);
HRESULT EndOpen(IMFAsyncResult *pResult);
// Queues an asynchronous operation, specify by op-type.
// (This method is public because the streams call it.)
HRESULT QueueAsyncOperation(SourceOp::Operation OpType);
// Lock/Unlock:
// Holds and releases the source's critical section. Called by the streams.
void Lock() { m_critSec.Lock(); }
void Unlock() { m_critSec.Unlock(); }
// Callbacks
HRESULT OnByteStreamRead(IMFAsyncResult *pResult); // Async callback for RequestData
private:
MPEG1Source(HRESULT& hr);
~MPEG1Source();
// CheckShutdown: Returns MF_E_SHUTDOWN if the source was shut down.
HRESULT CheckShutdown() const
{
return ( m_state == STATE_SHUTDOWN ? MF_E_SHUTDOWN : S_OK );
}
HRESULT CompleteOpen(HRESULT hrStatus);
HRESULT IsInitialized() const;
BOOL IsStreamTypeSupported(StreamType type) const;
BOOL IsStreamActive(const MPEG1PacketHeader& packetHdr);
BOOL StreamsNeedData() const;
HRESULT DoStart(StartOp *pOp);
HRESULT DoStop(SourceOp *pOp);
HRESULT DoPause(SourceOp *pOp);
HRESULT OnStreamRequestSample(SourceOp *pOp);
HRESULT OnEndOfStream(SourceOp *pOp);
HRESULT InitPresentationDescriptor();
HRESULT SelectStreams(IMFPresentationDescriptor *pPD, const PROPVARIANT varStart);
HRESULT RequestData(DWORD cbRequest);
HRESULT ParseData();
HRESULT ReadPayload(DWORD *pcbAte, DWORD *pcbNextRequest);
HRESULT DeliverPayload();
HRESULT EndOfMPEGStream();
HRESULT CreateStream(const MPEG1PacketHeader& packetHdr);
HRESULT ValidatePresentationDescriptor(IMFPresentationDescriptor *pPD);
// Handler for async errors.
void StreamingError(HRESULT hr);
// GetStream: Looks up a stream by ID.
MPEG1Stream* GetStream(BYTE stream_id); // Can return NULL
HRESULT BeginAsyncOp(SourceOp *pOp);
HRESULT CompleteAsyncOp(SourceOp *pOp);
HRESULT DispatchOperation(SourceOp *pOp);
HRESULT ValidateOperation(SourceOp *pOp);
private:
CritSec m_critSec; // critical section for thread safety
SourceState m_state; // Current state (running, stopped, paused)
Buffer m_ReadBuffer;
Parser *m_pParser;
IMFMediaEventQueue *m_pEventQueue; // Event generator helper
IMFPresentationDescriptor *m_pPresentationDescriptor; // Presentation descriptor.
IMFAsyncResult *m_pBeginOpenResult; // Result object for async BeginOpen operation.
IMFByteStream *m_pByteStream;
MPEG1SystemHeader *m_pHeader; // Release with CoTaskMemFree
StreamList m_streams; // Array of streams.
StreamMap m_streamMap; // Maps stream IDs to indexes into m_streams array.
DWORD m_cPendingEOS; // Pending EOS notifications.
ULONG m_cRestartCounter; // Counter for sample requests.
SourceOp *m_pCurrentOp;
SourceOp *m_pSampleRequest;
// Async callback helper.
AsyncCallback<MPEG1Source> m_OnByteStreamRead;
};