Friday 20 June 2014

Frame extraction from Video in Windows Phone 8.1 C# App Part ||

C++ project of Part I. Frankly speaking this is my first c++ project, I may have made terrible mistakes in it, but best part is, its working. So anyone have any suggestion to improve it please comment.

I modified this Media Playback sample, It plays video using a timer, so I removed swapchaining and created a ID3D11Texture2D and transferred video frame using TransferVideoFrame in Ontimer function.

 ComPtr<ID3D11Texture2D> spTextureDst;  
                MEDIA::ThrowIfFailed(  
                     m_d3dDevice->CreateTexture2D(  
                     &CD3D11_TEXTURE2D_DESC(  
                     DXGI_FORMAT_B8G8R8A8_UNORM,  
                     m_rcTarget.right,    // Width  
                     m_rcTarget.bottom,    // Height  
                     1,     // MipLevels  
                     1,     // ArraySize  
                     D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET  
                     ),  
                     nullptr,  
                     &spTextureDst  
                     )  
                     );  
                if (FAILED(  
                     m_spMediaEngine->TransferVideoFrame(spTextureDst.Get(), nullptr, &m_rcTarget, &m_bkgColor)  
                     ))  
                {  
                     return;  
                }  

then I moved the video to next position and finally generated a bitmap from dxgiSurface

 ComPtr<IDXGISurface2> surface;  
                MEDIA::ThrowIfFailed(  
                     spTextureDst.Get()->QueryInterface(  
                     __uuidof(IDXGISurface2), &surface)  
                     );  
                D2D1_BITMAP_PROPERTIES1 bitmapProperties =  
                     D2D1::BitmapProperties1(  
                     D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,  
                     D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),  
                     96,  
                     96  
                     );  
                m_d2dContext->CreateBitmapFromDxgiSurface(surface.Get(), &bitmapProperties, &bitmap);  

In this I have following issues which I think someone could suggest something:

1) Is this the right and only way of extracting frames ?
2) How can i pass bitmap to c# project directly instead of storing them on file?
3) When the events are raised, they are raised from different thread, so c# project need to use dispatcher.invoke to execute anything, what is the solution for this ?

Frame extraction from Video in Windows Phone 8.1 C# App


This Project is available on GitHub feel free to download and use it, If you have any suggestion or issue, Please post your comments in comment section.


Solution Layout:

It has following two projects :

1) VideoToolPhone (C++) : This is the main project which implements the Media Foundation interface and extracts frames.

2) TestApp (C#) : This app is to demonstrate how to use this in c# app.


I know most of the people will be interested in only c# part, so I will first explain c# app.

First you need to create an Object of FrameGenerator

frameGenerator = new VideoToolPhone.FrameGenerator(150, 90);

150 and 90 is width and height of frame size you want.

FrameGenerator has 2 events FrameGenerationCompleted and FrameGenerated. FrameGenerated fires after every frame generation and gives you file name of frame being generated. FrameGenerationCompleted fires when all frames are generated.

frameGenerator.FrameGenerationCompleted += fb_FrameGenerationCompleted; frameGenerator.FrameGenerated += frameGenerator_FrameGenerated;

Create only one instance of framegenerator in your app and don't forget to dispose it when you no longer needs it.

Next is GenerateFrames method which actually starts generating frames, you need to pass following arguments:

VideoFile : Video file from which frame needs to be extracted
Destination Folder: This is folder where all the extracted frames will be stored.
Count : Count is how many frames you want to extract. Suppose you set count as 10 for 10sec video so each frame will be extracted after 1sec.

frameGenerator.GenerateFrames(VideoFile, DestinationFolder,100 );

Snapshot

Those who are interested in c++ code please vist my next post.