Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Thema wird beschrieben, wie DirectX Video Acceleration (DXVA) 2.0 in einem DirectShow-Decoderfilter unterstützt wird. Insbesondere wird die Kommunikation zwischen dem Decoder und dem Videorenderer beschrieben. In diesem Thema wird nicht erklärt, wie die DXVA-Decodierung implementiert wird.
- Voraussetzungen
- Migrationsnotizen
- Suchen einer Decoderkonfiguration
- Benachrichtigen des Videorenderers
- Zuordnen von nicht komprimierten Puffern
- Decodieren
- Verwandte Themen
Voraussetzungen
In diesem Thema wird davon ausgegangen, dass Sie mit dem Schreiben von DirectShow-Filtern vertraut sind. Weitere Informationen finden Sie im Thema Schreiben von DirectShow-Filtern in der DirectShow SDK-Dokumentation. In den Codebeispielen in diesem Thema wird davon ausgegangen, dass der Decoderfilter von der CTransformFilter-Klasse mit der folgenden Klassendefinition abgeleitet wird:
class CDecoder : public CTransformFilter
{
public:
static CUnknown* WINAPI CreateInstance(IUnknown *pUnk, HRESULT *pHr);
HRESULT CompleteConnect(PIN_DIRECTION direction, IPin *pPin);
HRESULT InitAllocator(IMemAllocator **ppAlloc);
HRESULT DecideBufferSize(IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *pProp);
// TODO: The implementations of these methods depend on the specific decoder.
HRESULT CheckInputType(const CMediaType *mtIn);
HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut);
HRESULT CTransformFilter::GetMediaType(int,CMediaType *);
private:
CDecoder(HRESULT *pHr);
~CDecoder();
CBasePin * GetPin(int n);
HRESULT ConfigureDXVA2(IPin *pPin);
HRESULT SetEVRForDXVA2(IPin *pPin);
HRESULT FindDecoderConfiguration(
/* [in] */ IDirectXVideoDecoderService *pDecoderService,
/* [in] */ const GUID& guidDecoder,
/* [out] */ DXVA2_ConfigPictureDecode *pSelectedConfig,
/* [out] */ BOOL *pbFoundDXVA2Configuration
);
private:
IDirectXVideoDecoderService *m_pDecoderService;
DXVA2_ConfigPictureDecode m_DecoderConfig;
GUID m_DecoderGuid;
HANDLE m_hDevice;
FOURCC m_fccOutputFormat;
};
Im Folgenden bezieht sich der Decoder auf den Decoderfilter, der komprimiertes Video empfängt und unkomprimiertes Video ausgibt. Das Decoder-Gerät ist ein hardwarebasierter Videobeschleuniger, der vom Grafiktreiber implementiert wird.
Hier sind die grundlegenden Schritte, die ein Decoderfilter ausführen muss, um DXVA 2.0 zu unterstützen:
- Einen Medientyp aushandeln.
- Suchen Sie eine DXVA-Decoderkonfiguration.
- Benachrichtigen Sie den Videorenderer, dass der Decoder DXVA-Decodierung verwendet.
- Stellen Sie einen benutzerdefinierten Zuweisungsverteiler bereit, der Direct3D-Oberflächen zuordnet.
Diese Schritte werden im weiteren Verlauf dieses Themas ausführlicher beschrieben.
Migrationsnotizen
Wenn Sie von DXVA 1.0 migrieren, sollten Sie einige wesentliche Unterschiede zwischen den beiden Versionen beachten:
- DXVA 2.0 verwendet nicht die IAMVideoAccelerator - und IAMVideoAcceleratorNotify-Schnittstellen , da der Decoder direkt über die IDirectXVideoDecoder-Schnittstelle auf die DXVA 2.0-APIs zugreifen kann.
- Während der Medientypverhandlung verwendet der Decoder keine Videobeschleunigungs-GUID als Untertyp. Stattdessen ist der Untertyp nur das nicht komprimierte Videoformat (z. B. NV12), wie bei der Softwaredecodierung.
- Das Verfahren zum Konfigurieren des Beschleunigers wurde geändert. In DXVA 1.0 ruft der Decoder Execute mit einer DXVA_ConfigPictureDecode-Struktur auf, um den Beschleuniger zu konfigurieren. In DXVA 2.0 verwendet der Decoder die IDirectXVideoDecoderService-Schnittstelle , wie im nächsten Abschnitt beschrieben.
- Der Decoder weist die nicht komprimierten Puffer zu. Der Videorenderer weist sie nicht mehr zu.
- Anstatt IAMVideoAccelerator::DisplayFrame zum Anzeigen des decodierten Frames aufzurufen, liefert der Decoder den Frame an den Renderer, indem er IMemInputPin::Receive wie bei der Softwaredecodierung aufruft.
- Der Decoder ist nicht mehr für die Überprüfung verantwortlich, wenn Datenpuffer für Updates sicher sind. Daher verfügt DXVA 2.0 nicht über eine Methode, die dem IAMVideoAccelerator::QueryRenderStatus entspricht.
- Die Subpicture-Mischung erfolgt über den Videorenderer mithilfe der DXVA2.0-Videoprozessor-APIs. Decoder, die Unterbilder (z. B. DVD-Decoder) bereitstellen, sollten Unterbild-Daten über einen separaten Ausgangsstift senden.
Bei Decodierungsvorgängen verwendet DXVA 2.0 dieselben Datenstrukturen wie DXVA 1.0.
Der erweiterte Videorenderer -Filter (EVR) unterstützt DXVA 2.0. Filter der Videomisch-Renderer (VMR-7 und VMR-9) unterstützen nur DXVA 1.0.
Suchen einer Decoderkonfiguration
Nachdem der Decoder den Ausgabemedientyp aushandelt, muss er eine kompatible Konfiguration für das DXVA-Decodergerät finden. Sie können diesen Schritt innerhalb der CBaseOutputPin::CompleteConnect-Methode des Ausgabepins ausführen. In diesem Schritt wird sichergestellt, dass der Grafiktreiber die vom Decoder benötigten Funktionen unterstützt, bevor der Decoder mit DXVA arbeitet.
Gehen Sie wie folgt vor, um eine Konfiguration für das Decodergerät zu finden:
Fragen Sie nach dem Eingangspin des Renderers für die IMFGetService-Schnittstelle.
Rufen Sie IMFGetService::GetService auf, um einen Zeiger auf die IDirect3DDeviceManager9-Schnittstelle abzurufen. Die Dienst-GUID ist MR_VIDEO_ACCELERATION_SERVICE.
Rufen Sie IDirect3DDeviceManager9::OpenDeviceHandle auf, um ein Handle für das Direct3D-Gerät des Renderers abzurufen.
Rufen Sie IDirect3DDeviceManager9::GetVideoService auf, und übergeben Sie das Gerätehandle. Diese Methode gibt einen Zeiger auf die IDirectXVideoDecoderService-Schnittstelle zurück.
Rufen Sie IDirectXVideoDecoderService::GetDecoderDeviceGuids auf. Diese Methode gibt ein Array von Decodergeräte-GUIDs zurück.
Durchlaufen Sie das Array von Decoder-GUIDs, um diejenigen zu finden, die der Decoderfilter unterstützt. Zum Beispiel würden Sie bei einem MPEG-2-Decoder nach DXVA2_ModeMPEG2_MOCOMP, DXVA2_ModeMPEG2_IDCT oder DXVA2_ModeMPEG2_VLD suchen.
Wenn Sie eine Kandidatendecodergeräte-GUID finden, übergeben Sie die GUID an die IDirectXVideoDecoderService::GetDecoderRenderTargets-Methode . Diese Methode gibt ein Array von Renderzielformaten zurück, das als D3DFORMAT Werte angegeben ist.
Durchlaufen Sie die Renderzielformate, und suchen Sie nach einem Format, das Ihrem Ausgabeformat entspricht. In der Regel unterstützt ein Decodergerät ein einzelnes Renderzielformat. Der Decoderfilter sollte mit diesem Untertyp eine Verbindung mit dem Renderer herstellen. Im ersten Aufruf von CompleteConnect kann der Decoder das Renderzielformat bestimmen und dieses Format dann als bevorzugten Ausgabetyp zurückgeben.
Rufen Sie IDirectXVideoDecoderService::GetDecoderConfigurations auf. Übergeben Sie dieselbe Decodergeräte-GUID zusammen mit einer DXVA2_VideoDesc Struktur, die das vorgeschlagene Format beschreibt. Die Methode gibt ein Array von DXVA2_ConfigPictureDecode Strukturen zurück. Jede Struktur beschreibt eine mögliche Konfiguration für das Decodergerät.
Wenn die vorherigen Schritte erfolgreich sind, speichern Sie das Direct3D-Gerätehandle, die Decodergeräte-GUID und die Konfigurationsstruktur. Der Filter verwendet diese Informationen, um das Decodergerät zu erstellen.
Der folgende Code zeigt, wie Sie eine Decoderkonfiguration finden.
HRESULT CDecoder::ConfigureDXVA2(IPin *pPin)
{
UINT cDecoderGuids = 0;
BOOL bFoundDXVA2Configuration = FALSE;
GUID guidDecoder = GUID_NULL;
DXVA2_ConfigPictureDecode config;
ZeroMemory(&config, sizeof(config));
// Variables that follow must be cleaned up at the end.
IMFGetService *pGetService = NULL;
IDirect3DDeviceManager9 *pDeviceManager = NULL;
IDirectXVideoDecoderService *pDecoderService = NULL;
GUID *pDecoderGuids = NULL; // size = cDecoderGuids
HANDLE hDevice = INVALID_HANDLE_VALUE;
// Query the pin for IMFGetService.
HRESULT hr = pPin->QueryInterface(IID_PPV_ARGS(&pGetService));
// Get the Direct3D device manager.
if (SUCCEEDED(hr))
{
hr = pGetService->GetService(
MR_VIDEO_ACCELERATION_SERVICE,
IID_PPV_ARGS(&pDeviceManager)
);
}
// Open a new device handle.
if (SUCCEEDED(hr))
{
hr = pDeviceManager->OpenDeviceHandle(&hDevice);
}
// Get the video decoder service.
if (SUCCEEDED(hr))
{
hr = pDeviceManager->GetVideoService(
hDevice, IID_PPV_ARGS(&pDecoderService));
}
// Get the decoder GUIDs.
if (SUCCEEDED(hr))
{
hr = pDecoderService->GetDecoderDeviceGuids(
&cDecoderGuids, &pDecoderGuids);
}
if (SUCCEEDED(hr))
{
// Look for the decoder GUIDs we want.
for (UINT iGuid = 0; iGuid < cDecoderGuids; iGuid++)
{
// Do we support this mode?
if (!IsSupportedDecoderMode(pDecoderGuids[iGuid]))
{
continue;
}
// Find a configuration that we support.
hr = FindDecoderConfiguration(pDecoderService, pDecoderGuids[iGuid],
&config, &bFoundDXVA2Configuration);
if (FAILED(hr))
{
break;
}
if (bFoundDXVA2Configuration)
{
// Found a good configuration. Save the GUID and exit the loop.
guidDecoder = pDecoderGuids[iGuid];
break;
}
}
}
if (!bFoundDXVA2Configuration)
{
hr = E_FAIL; // Unable to find a configuration.
}
if (SUCCEEDED(hr))
{
// Store the things we will need later.
SafeRelease(&m_pDecoderService);
m_pDecoderService = pDecoderService;
m_pDecoderService->AddRef();
m_DecoderConfig = config;
m_DecoderGuid = guidDecoder;
m_hDevice = hDevice;
}
if (FAILED(hr))
{
if (hDevice != INVALID_HANDLE_VALUE)
{
pDeviceManager->CloseDeviceHandle(hDevice);
}
}
SafeRelease(&pGetService);
SafeRelease(&pDeviceManager);
SafeRelease(&pDecoderService);
return hr;
}
HRESULT CDecoder::FindDecoderConfiguration(
/* [in] */ IDirectXVideoDecoderService *pDecoderService,
/* [in] */ const GUID& guidDecoder,
/* [out] */ DXVA2_ConfigPictureDecode *pSelectedConfig,
/* [out] */ BOOL *pbFoundDXVA2Configuration
)
{
HRESULT hr = S_OK;
UINT cFormats = 0;
UINT cConfigurations = 0;
D3DFORMAT *pFormats = NULL; // size = cFormats
DXVA2_ConfigPictureDecode *pConfig = NULL; // size = cConfigurations
// Find the valid render target formats for this decoder GUID.
hr = pDecoderService->GetDecoderRenderTargets(
guidDecoder,
&cFormats,
&pFormats
);
if (SUCCEEDED(hr))
{
// Look for a format that matches our output format.
for (UINT iFormat = 0; iFormat < cFormats; iFormat++)
{
if (pFormats[iFormat] != (D3DFORMAT)m_fccOutputFormat)
{
continue;
}
// Fill in the video description. Set the width, height, format,
// and frame rate.
DXVA2_VideoDesc videoDesc = {0};
FillInVideoDescription(&videoDesc); // Private helper function.
videoDesc.Format = pFormats[iFormat];
// Get the available configurations.
hr = pDecoderService->GetDecoderConfigurations(
guidDecoder,
&videoDesc,
NULL, // Reserved.
&cConfigurations,
&pConfig
);
if (FAILED(hr))
{
break;
}
// Find a supported configuration.
for (UINT iConfig = 0; iConfig < cConfigurations; iConfig++)
{
if (IsSupportedDecoderConfig(pConfig[iConfig]))
{
// This configuration is good.
*pbFoundDXVA2Configuration = TRUE;
*pSelectedConfig = pConfig[iConfig];
break;
}
}
CoTaskMemFree(pConfig);
break;
} // End of formats loop.
}
CoTaskMemFree(pFormats);
// Note: It is possible to return S_OK without finding a configuration.
return hr;
}
Da dieses Beispiel generisch ist, wurden einige der Logik in Hilfsfunktionen platziert, die vom Decoder implementiert werden müssen. Der folgende Code zeigt die Deklarationen für diese Funktionen:
// Returns TRUE if the decoder supports a given decoding mode.
BOOL IsSupportedDecoderMode(const GUID& mode);
// Returns TRUE if the decoder supports a given decoding configuration.
BOOL IsSupportedDecoderConfig(const DXVA2_ConfigPictureDecode& config);
// Fills in a DXVA2_VideoDesc structure based on the input format.
void FillInVideoDescription(DXVA2_VideoDesc *pDesc);
Benachrichtigen des Videorenderers
Wenn der Decoder eine Decoderkonfiguration findet, besteht der nächste Schritt darin, den Videorenderer darüber zu informieren, dass der Decoder die Hardwarebeschleunigung verwendet. Sie können diesen Schritt innerhalb der CompleteConnect-Methode ausführen. Dieser Schritt muss erfolgen, bevor der Allocator ausgewählt wird, da er sich darauf auswirkt, wie der Allokator ausgewählt wird.
- Fragen Sie nach dem Eingangspin des Renderers für die IMFGetService-Schnittstelle.
- Rufen Sie IMFGetService::GetService auf, um einen Zeiger auf die IDirectXVideoMemoryConfiguration-Schnittstelle abzurufen. Die Dienst-GUID ist MR_VIDEO_ACCELERATION_SERVICE.
- Rufen Sie IDirectXVideoMemoryConfiguration::GetAvailableSurfaceTypeByIndex in einer Schleife auf, wobei die dwTypeIndex-Variable ab null inkrementiert wird. Beenden Sie, wenn die Methode den Wert DXVA2_SurfaceType_DecoderRenderTarget im pdwType-Parameter zurückgibt. Dieser Schritt stellt sicher, dass der Videorenderer hardwarebeschleunigte Decodierung unterstützt. Dieser Schritt wird für den EVR-Filter immer erfolgreich ausgeführt.
- Wenn der vorherige Schritt erfolgreich war, rufen Sie IDirectXVideoMemoryConfiguration::SetSurfaceType mit dem Wert DXVA2_SurfaceType_DecoderRenderTarget auf. Durch Aufrufen von SetSurfaceType mit diesem Wert wird der Videorenderer in den DXVA-Modus versetzt. Wenn sich der Videorenderer in diesem Modus befindet, muss der Decoder einen eigenen Zuweisungscode bereitstellen.
Der folgende Code zeigt, wie der Videorenderer benachrichtigt wird.
HRESULT CDecoder::SetEVRForDXVA2(IPin *pPin)
{
HRESULT hr = S_OK;
IMFGetService *pGetService = NULL;
IDirectXVideoMemoryConfiguration *pVideoConfig = NULL;
// Query the pin for IMFGetService.
hr = pPin->QueryInterface(__uuidof(IMFGetService), (void**)&pGetService);
// Get the IDirectXVideoMemoryConfiguration interface.
if (SUCCEEDED(hr))
{
hr = pGetService->GetService(
MR_VIDEO_ACCELERATION_SERVICE, IID_PPV_ARGS(&pVideoConfig));
}
// Notify the EVR.
if (SUCCEEDED(hr))
{
DXVA2_SurfaceType surfaceType;
for (DWORD iTypeIndex = 0; ; iTypeIndex++)
{
hr = pVideoConfig->GetAvailableSurfaceTypeByIndex(iTypeIndex, &surfaceType);
if (FAILED(hr))
{
break;
}
if (surfaceType == DXVA2_SurfaceType_DecoderRenderTarget)
{
hr = pVideoConfig->SetSurfaceType(DXVA2_SurfaceType_DecoderRenderTarget);
break;
}
}
}
SafeRelease(&pGetService);
SafeRelease(&pVideoConfig);
return hr;
}
Wenn der Decoder eine gültige Konfiguration findet und den Videorenderer erfolgreich benachrichtigt, kann der Decoder DXVA zum Decodieren verwenden. Der Decoder muss einen individuellen Allocator für seinen Ausgabepin implementieren, wie im nächsten Abschnitt beschrieben.
Zuordnen von nicht komprimierten Puffern
In DXVA 2.0 ist der Decoder für die Zuordnung von Direct3D-Oberflächen verantwortlich, die als nicht komprimierte Videopuffer verwendet werden. Daher muss der Decoder einen benutzerdefinierten Allocator implementieren, der die Oberflächen erstellt. Die von diesem Allocator bereitgestellten Medienbeispiele enthalten Zeiger auf die Direct3D-Oberflächen. Der EVR ruft einen Zeiger auf die Oberfläche ab, indem IMFGetService::GetService im Medienbeispiel aufgerufen wird. Der Dienstbezeichner ist MR_BUFFER_SERVICE.
Führen Sie die folgenden Schritte aus, um den benutzerdefinierten Zuweisungsgeber bereitzustellen:
- Definieren Sie eine Klasse für die Medienbeispiele. Diese Klasse kann von der CMediaSample-Klasse abgeleitet werden. Führen Sie in dieser Klasse die folgenden Schritte aus:
- Speichern Sie einen Zeiger auf die Direct3D-Oberfläche.
- Implementieren Sie die IMFGetService-Schnittstelle . Wenn die Dienst-GUID MR_BUFFER_SERVICE ist, fragen Sie in der GetService-Methode die Direct3D-Oberfläche für die angeforderte Schnittstelle ab. Andernfalls kann GetServiceMF_E_UNSUPPORTED_SERVICE zurückgeben.
- Überschreiben Sie die CMediaSample::GetPointer-Methode , um E_NOTIMPL zurückzugeben.
- Definieren Sie eine Klasse für den Allocator. Der Allocator kann von der CBaseAllocator-Klasse abgeleitet werden. Führen Sie in dieser Klasse die folgenden Schritte aus.
- Überschreiben Sie die CBaseAllocator::Alloc-Methode . Rufen Sie in dieser Methode IDirectXVideoAccelerationService::CreateSurface auf, um die Oberflächen zu erstellen. (Die IDirectXVideoDecoderService-Schnittstelle erbt diese Methode von IDirectXVideoAccelerationService.)
- Überschreiben Sie die CBaseAllocator::Free-Methode, um die Oberflächen freizugeben.
- Überschreiben Sie im Ausgabepin des Filters die CBaseOutputPin::InitAllocator-Methode. Erstellen Sie in dieser Methode eine Instanz Ihres benutzerdefinierten Zuweisungsgebers.
- Implementieren Sie in Ihrem Filter die CTransformFilter::D ecideBufferSize-Methode . Der Parameter pProperties gibt die Anzahl der Oberflächen an, die der EVR benötigt. Fügen Sie diesem Wert die Anzahl der Oberflächen hinzu, die Ihr Decoder benötigt, und rufen Sie die Methode IMemAllocator::SetProperties auf dem Allocator auf.
Der folgende Code zeigt, wie die Medienbeispielklasse implementiert wird:
class CDecoderSample : public CMediaSample, public IMFGetService
{
friend class CDecoderAllocator;
public:
CDecoderSample(CDecoderAllocator *pAlloc, HRESULT *phr)
: CMediaSample(NAME("DecoderSample"), (CBaseAllocator*)pAlloc, phr, NULL, 0),
m_pSurface(NULL),
m_dwSurfaceId(0)
{
}
// Note: CMediaSample does not derive from CUnknown, so we cannot use the
// DECLARE_IUNKNOWN macro that is used by most of the filter classes.
STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
{
CheckPointer(ppv, E_POINTER);
if (riid == IID_IMFGetService)
{
*ppv = static_cast<IMFGetService*>(this);
AddRef();
return S_OK;
}
else
{
return CMediaSample::QueryInterface(riid, ppv);
}
}
STDMETHODIMP_(ULONG) AddRef()
{
return CMediaSample::AddRef();
}
STDMETHODIMP_(ULONG) Release()
{
// Return a temporary variable for thread safety.
ULONG cRef = CMediaSample::Release();
return cRef;
}
// IMFGetService::GetService
STDMETHODIMP GetService(REFGUID guidService, REFIID riid, LPVOID *ppv)
{
if (guidService != MR_BUFFER_SERVICE)
{
return MF_E_UNSUPPORTED_SERVICE;
}
else if (m_pSurface == NULL)
{
return E_NOINTERFACE;
}
else
{
return m_pSurface->QueryInterface(riid, ppv);
}
}
// Override GetPointer because this class does not manage a system memory buffer.
// The EVR uses the MR_BUFFER_SERVICE service to get the Direct3D surface.
STDMETHODIMP GetPointer(BYTE ** ppBuffer)
{
return E_NOTIMPL;
}
private:
// Sets the pointer to the Direct3D surface.
void SetSurface(DWORD surfaceId, IDirect3DSurface9 *pSurf)
{
SafeRelease(&m_pSurface);
m_pSurface = pSurf;
if (m_pSurface)
{
m_pSurface->AddRef();
}
m_dwSurfaceId = surfaceId;
}
IDirect3DSurface9 *m_pSurface;
DWORD m_dwSurfaceId;
};
Der folgende Code zeigt, wie die Alloc-Methode für den Allocator implementiert wird.
HRESULT CDecoderAllocator::Alloc()
{
CAutoLock lock(this);
HRESULT hr = S_OK;
if (m_pDXVA2Service == NULL)
{
return E_UNEXPECTED;
}
hr = CBaseAllocator::Alloc();
// If the requirements have not changed, do not reallocate.
if (hr == S_FALSE)
{
return S_OK;
}
if (SUCCEEDED(hr))
{
// Free the old resources.
Free();
// Allocate a new array of pointers.
m_ppRTSurfaceArray = new (std::nothrow) IDirect3DSurface9*[m_lCount];
if (m_ppRTSurfaceArray == NULL)
{
hr = E_OUTOFMEMORY;
}
else
{
ZeroMemory(m_ppRTSurfaceArray, sizeof(IDirect3DSurface9*) * m_lCount);
}
}
// Allocate the surfaces.
if (SUCCEEDED(hr))
{
hr = m_pDXVA2Service->CreateSurface(
m_dwWidth,
m_dwHeight,
m_lCount - 1,
(D3DFORMAT)m_dwFormat,
D3DPOOL_DEFAULT,
0,
DXVA2_VideoDecoderRenderTarget,
m_ppRTSurfaceArray,
NULL
);
}
if (SUCCEEDED(hr))
{
for (m_lAllocated = 0; m_lAllocated < m_lCount; m_lAllocated++)
{
CDecoderSample *pSample = new (std::nothrow) CDecoderSample(this, &hr);
if (pSample == NULL)
{
hr = E_OUTOFMEMORY;
break;
}
if (FAILED(hr))
{
break;
}
// Assign the Direct3D surface pointer and the index.
pSample->SetSurface(m_lAllocated, m_ppRTSurfaceArray[m_lAllocated]);
// Add to the sample list.
m_lFree.Add(pSample);
}
}
if (SUCCEEDED(hr))
{
m_bChanged = FALSE;
}
return hr;
}
Hier ist der Code für die Free-Methode :
void CDecoderAllocator::Free()
{
CMediaSample *pSample = NULL;
do
{
pSample = m_lFree.RemoveHead();
if (pSample)
{
delete pSample;
}
} while (pSample);
if (m_ppRTSurfaceArray)
{
for (long i = 0; i < m_lAllocated; i++)
{
SafeRelease(&m_ppRTSurfaceArray[i]);
}
delete [] m_ppRTSurfaceArray;
}
m_lAllocated = 0;
}
Weitere Informationen zum Implementieren von benutzerdefinierten Zuweisungen finden Sie im Thema Bereitstellen eines benutzerdefinierten Allocators in der DirectShow SDK-Dokumentation.
Dekodierung
Rufen Sie zum Erstellen des Decodergeräts IDirectXVideoDecoderService::CreateVideoDecoder auf. Die Methode gibt einen Zeiger auf die IDirectXVideoDecoder-Schnittstelle des Decodergeräts zurück.
Rufen Sie auf jedem Frame IDirect3DDeviceManager9::TestDevice auf, um das Gerätehandle zu testen. Wenn sich das Gerät geändert hat, gibt die Methode DXVA2_E_NEW_VIDEO_DEVICE zurück. Gehen Sie in diesem Fall wie folgt vor:
- Schließen Sie das Gerätehandle, indem Sie IDirect3DDeviceManager9::CloseDeviceHandle aufrufen.
- Geben Sie die IDirectXVideoDecoderService- und die IDirectXVideoDecoder-Zeiger frei.
- Öffnen Sie ein neues Gerätehandle.
- Verhandeln Sie eine neue Decoderkonfiguration, wie im Abschnitt Suchen einer Decoderkonfiguration beschrieben.
- Erstellen Sie ein neues Decodergerät.
Wenn der Gerätehandle gültig ist, funktioniert der Decodierungsprozess wie folgt:
- Rufen Sie IDirectXVideoDecoder::BeginFrame auf.
- Führen Sie eine oder mehrere Male die folgenden Aktionen aus:
- Rufen Sie IDirectXVideoDecoder::GetBuffer auf, um einen DXVA-Decoderpuffer abzurufen.
- Füllen Sie den Puffer aus.
- Rufen Sie IDirectXVideoDecoder::ReleaseBuffer auf.
- Rufen Sie IDirectXVideoDecoder::Execute auf, um die Decodierungsvorgänge für den Frame auszuführen.
DXVA 2.0 verwendet dieselben Datenstrukturen wie DXVA 1.0 für Decodierungsvorgänge. Für den ursprünglichen Satz von DXVA-Profilen (für H.261, H.263 und MPEG-2) werden diese Datenstrukturen in der DXVA 1.0-Spezifikation beschrieben.
Innerhalb jedes BeginFrame/ Execute-Aufrufpaars können Sie GetBuffer mehrmals aufrufen, jedoch nur einmal für jeden DXVA-Puffertyp. Wenn Sie sie zweimal mit demselben Puffertyp aufrufen, überschreiben Sie die Daten.
Rufen Sie nach dem Aufrufen von ExecuteIMemInputPin::Receive auf, um den Frame wie bei der Softwaredecodierung an den Videorenderer zu übermitteln. Die Receive-Methode ist asynchron; nach dem Zurückgeben kann der Decoder die Decodierung des nächsten Frames fortsetzen. Der Anzeigetreiber verhindert, dass decodierungsbefehle den Puffer überschreiben, während der Puffer verwendet wird. Der Decoder sollte eine Oberfläche nicht wiederverwenden, um einen anderen Frame zu decodieren, bis der Renderer das Beispiel freigegeben hat. Wenn der Renderer das Beispiel loslässt, fügt der Allocator das Beispiel wieder in seinen Pool der verfügbaren Beispiele ein. Um die nächste verfügbare Probe zu erhalten, rufen Sie CBaseOutputPin::GetDeliveryBuffer auf, das wiederum IMemAllocator::GetBuffer aufruft. Weitere Informationen finden Sie im Thema "Übersicht über den Datenfluss in DirectShow " in der DirectShow-Dokumentation.
Zugehörige Themen