UPDATE successo !! vedi di modifica nella parte inferiore
Alcuni parziale successo, ma forse abbastanza per rispondere alla tua domanda. Per favore continua a leggere.
Sul mio sistema, il debug dell'eccezione indica che la funzione OnTimer()
non è riuscita quando si è tentato di chiamare TransferVideoFrame()
. L'errore che ha dato è stato InvalidArgumentException
.
Quindi, un po 'di Google ha portato alla mia prima scoperta - apparentemente c'è a bug in NVIDIA drivers - il che significa che la riproduzione del video sembra fallire con 11 e 10 livelli di funzionalità.
Così il mio primo cambiamento era in funzione CreateDX11Device()
come segue:
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
};
Ora TransferVideoFrame()
non riesce ancora, ma dà E_FAIL
(come un HRESULT) invece di un argomento non valido.
Più Googling ha portato al mio second discovery -
Che era un esempio che mostra l'utilizzo di TransferVideoFrame()
senza utilizzare CreateTexture2D()
di pre-creare la trama. Vedo che hai già un codice in OnTimer()
simile a questo ma che non è stato utilizzato, quindi suppongo che tu abbia trovato lo stesso link.
Ad ogni modo, ora usato questo codice per ottenere il fotogramma video:
ComPtr <ID3D11Texture2D> spTextureDst;
m_spDX11SwapChain->GetBuffer (0, IID_PPV_ARGS (&spTextureDst));
m_spMediaEngine->TransferVideoFrame (spTextureDst.Get(), nullptr, &m_rcTarget, &m_bkgColor);
Dopo aver fatto questo, vedo che TransferVideoFrame()
riesce (bene!), Ma chiamando Map()
sulla consistenza copiato - m_spCopyTexture
- non riesce perché la trama non è stata creata con l'accesso in lettura della CPU.
Quindi, ho appena usato la lettura/scrittura m_spRenderTexture
come destinazione della copia, perché ha le bandiere corrette e, a causa della modifica precedente, non lo usavo più.
//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);
Ora, sul mio sistema, la funzione OnTimer()
non fallisce. I fotogrammi video vengono renderizzati alla trama e i dati dei pixel vengono copiati correttamente nel buffer di memoria.
Prima di vedere se ci sono ulteriori problemi, forse questo è un buon momento per vedere se è possibile fare gli stessi progressi che ho finora. Se commentate questa risposta con maggiori informazioni, modificheremo la risposta per aggiungere ulteriore aiuto se possibile.
EDIT
Le modifiche apportate alla descrizione texture in 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));
Si noti anche che ci sia una perdita di memoria che deve essere chiarito qualche volta (sono sicuro che siete a conoscenza) - la memoria allocata nella riga successiva viene mai liberato:
void* buffer = ::CoTaskMemAlloc(176 * 144 * 3); // sizes changed for my test
SUCCESSO
Ora sono riuscito a salvare un singolo fotogramma, ma ora senza l'uso della trama di copia.
Innanzitutto, ho scaricato l'ultima versione di the DirectXTex Library, che fornisce le funzioni di supporto di texture DX11, ad esempio per estrarre un'immagine da una trama e salvarla in un file. The instructions per aggiungere la libreria DirectXTex alla soluzione in quanto un progetto esistente deve essere seguito attentamente, prendendo nota delle modifiche necessarie per le App Store di Windows 8.
volta, la libreria di cui sopra è incluso, riferimento e costruito, aggiungere le seguenti #include
's per FramePlayer.cpp
#include "..\DirectXTex\DirectXTex.h" // nb - use the relative path you copied to
#include <wincodec.h>
Infine, la sezione centrale del codice FramePlayer::OnTimer()
deve essere simile alla seguente. Vedrai che mi limiterò a salvare lo stesso nome ogni volta, quindi è necessario modificare per aggiungere ad es.un numero di frame al nome
// 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));
non ho tempo ora di prendere questo ulteriormente, ma io sono molto soddisfatto di quello che ho ottenuto finora :-))
Potete prendere un nuovo aspetto e aggiornare i risultati nei commenti?
Puoi condividere il tuo codice con me visto che sto sviluppando un'applicazione per WP 8.1 e sono sconosciuto alla programmazione C++? Sarebbe un grande aiuto da parte tua. – Xyroid
Ciao, sto lavorando ad un'applicazione winrt e devo anche estrarre i frame dal video. Ho usato il tuo codice ma estrae solo il primo 2 fotogramma. C'è qualcosa di specifico da cambiare. Ho aggiornato il codice come indicato nell'edit apr di questa domanda. –
Puoi condividere codice funzionante? –