アップデート成功!! 下部の編集を参照してください
部分的な成功ですが、質問に答えるには十分かもしれません。読み進めてください。
私のシステムでは、例外をデバッグするOnTimer()
と、 を呼び出そうとしたときに関数が失敗したことが示されましたTransferVideoFrame()
。それが与えたエラーはInvalidArgumentException
.
それで、ちょっとしたグーグル検索が私の最初の発見につながりました - どうやらNVIDIA ドライバにバグがあるようです - これはビデオの再生が 11 と 10 の機能レベルで失敗するように見えることを意味します。
したがって、私の最初の変更はCreateDX11Device()
次のように機能していました。
static const D3D_FEATURE_LEVEL levels[] = {
/*
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
*/
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1
};
今TransferVideoFrame()
でも失敗しますがE_FAIL
、無効な引数の代わりに (HRESULT として) を返します。
さらにグーグルが私の2番目の発見につながりました-
これは、テクスチャを事前に作成するために を使用TransferVideoFrame()
せずに を使用した例です。CreateTexture2D()
これに似たコードが既にあるOnTimer()
ようですが、使用されていないので、同じリンクを見つけたと思います。
とにかく、次のコードを使用してビデオ フレームを取得しました。
ComPtr <ID3D11Texture2D> spTextureDst;
m_spDX11SwapChain->GetBuffer (0, IID_PPV_ARGS (&spTextureDst));
m_spMediaEngine->TransferVideoFrame (spTextureDst.Get (), nullptr, &m_rcTarget, &m_bkgColor);
TransferVideoFrame()
これを行った後、成功したことがわかります(良い!) がMap()
、コピーしたテクスチャの呼び出しはm_spCopyTexture
失敗します。そのテクスチャは CPU 読み取りアクセスで作成されていないためです。
そのため、代わりにコピーのターゲットとして読み取り/書き込みm_spRenderTexture
を使用しました。これには正しいフラグがあり、以前の変更により、使用しなくなったためです。
//copy the render target texture to the readable texture.
m_spDX11DeviceContext->CopySubresourceRegion(m_spRenderTexture.Get(),0,0,0,0,spTextureDst.Get(),0,NULL);
m_spDX11DeviceContext->Flush();
//Map the readable texture;
D3D11_MAPPED_SUBRESOURCE mapped = {0};
HRESULT hr = m_spDX11DeviceContext->Map(m_spRenderTexture.Get(),0,D3D11_MAP_READ,0,&mapped);
void* buffer = ::CoTaskMemAlloc(176 * 144 * 3);
memcpy(buffer, mapped.pData,176 * 144 * 3);
//unmap so we can copy during next update.
m_spDX11DeviceContext->Unmap(m_spRenderTexture.Get(),0);
今、私のシステムでは、OnTimer()
関数は失敗しません。ビデオ フレームがテクスチャにレンダリングされ、ピクセル データが正常にメモリ バッファにコピーされます。
さらに問題があるかどうかを確認する前に、これまでと同じように進歩できるかどうかを確認する良い機会かもしれません. この回答に詳細情報をコメントしていただければ、回答を編集して、可能であればヘルプを追加します。
編集
のテクスチャ記述に加えられた変更FramePlayer::CreateBackBuffers()
//make first texture cpu readable
D3D11_TEXTURE2D_DESC texDesc = {0};
texDesc.Width = 176;
texDesc.Height = 144;
texDesc.MipLevels = 1;
texDesc.ArraySize = 1;
texDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
texDesc.Usage = D3D11_USAGE_STAGING;
texDesc.BindFlags = 0;
texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
texDesc.MiscFlags = 0;
MEDIA::ThrowIfFailed(m_spDX11Device->CreateTexture2D(&texDesc,NULL,&m_spRenderTexture));
また、いつかクリアする必要があるメモリ リークがあることにも注意してください (ご存じだと思います)。次の行で割り当てられたメモリは決して解放されません。
void* buffer = ::CoTaskMemAlloc(176 * 144 * 3); // sizes changed for my test
成功
個々のフレームを保存することに成功しましたが、コピー テクスチャを使用しなくなりました。
まず、DX11 テクスチャ ヘルパー機能を提供するDirectXTex ライブラリの最新バージョンをダウンロードしました。たとえば、テクスチャから画像を抽出してファイルに保存します。DirectXTex ライブラリを既存のプロジェクトとしてソリューションに追加する手順には、Windows 8 ストア アプリに必要な変更に注意して慎重に従う必要があります。
上記のライブラリが含まれ、参照され、ビルドされたら、次#include
の を追加しますFramePlayer.cpp
#include "..\DirectXTex\DirectXTex.h" // nb - use the relative path you copied to
#include <wincodec.h>
最後に、コードの中央セクションはFramePlayer::OnTimer()
次のようにする必要があります。毎回同じファイル名に保存するだけなので、名前にフレーム番号などを追加するために修正する必要があります。
// new frame available at the media engine so get it
ComPtr<ID3D11Texture2D> spTextureDst;
MEDIA::ThrowIfFailed(m_spDX11SwapChain->GetBuffer(0, IID_PPV_ARGS(&spTextureDst)));
auto rcNormalized = MFVideoNormalizedRect();
rcNormalized.left = 0;
rcNormalized.right = 1;
rcNormalized.top = 0;
rcNormalized.bottom = 1;
MEDIA::ThrowIfFailed(m_spMediaEngine->TransferVideoFrame(spTextureDst.Get(), &rcNormalized, &m_rcTarget, &m_bkgColor));
// capture an image from the DX11 texture
DirectX::ScratchImage pImage;
HRESULT hr = DirectX::CaptureTexture(m_spDX11Device.Get(), m_spDX11DeviceContext.Get(), spTextureDst.Get(), pImage);
if (SUCCEEDED(hr))
{
// get the image object from the wrapper
const DirectX::Image *pRealImage = pImage.GetImage(0, 0, 0);
// set some place to save the image frame
StorageFolder ^dataFolder = ApplicationData::Current->LocalFolder;
Platform::String ^szPath = dataFolder->Path + "\\frame.png";
// save the image to file
hr = DirectX::SaveToWICFile(*pRealImage, DirectX::WIC_FLAGS_NONE, GUID_ContainerFormatPng, szPath->Data());
}
// and the present it to the screen
MEDIA::ThrowIfFailed(m_spDX11SwapChain->Present(1, 0));
今はこれ以上進める時間はありませんが、これまでに達成したことには非常に満足しています :-))
もう一度見直して、コメントで結果を更新していただけますか?