Media Foundation-based VideoWriter added
This commit is contained in:
parent
033e3092a3
commit
ccb8292e8e
@ -408,8 +408,20 @@ CV_IMPL CvVideoWriter* cvCreateVideoWriter( const char* filename, int fourcc,
|
|||||||
if(!fourcc || !fps)
|
if(!fourcc || !fps)
|
||||||
result = cvCreateVideoWriter_Images(filename);
|
result = cvCreateVideoWriter_Images(filename);
|
||||||
|
|
||||||
|
#ifdef HAVE_FFMPEG
|
||||||
if(!result)
|
if(!result)
|
||||||
result = cvCreateVideoWriter_FFMPEG_proxy (filename, fourcc, fps, frameSize, is_color);
|
result = cvCreateVideoWriter_FFMPEG_proxy (filename, fourcc, fps, frameSize, is_color);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_VFW
|
||||||
|
if(!result)
|
||||||
|
return cvCreateVideoWriter_VFW(filename, fourcc, fps, frameSize, isColor);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_MSMF
|
||||||
|
if (!result)
|
||||||
|
result = cvCreateVideoWriter_MSMF(filename, fourcc, fps, frameSize, is_color);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* #ifdef HAVE_XINE
|
/* #ifdef HAVE_XINE
|
||||||
if(!result)
|
if(!result)
|
||||||
|
@ -263,9 +263,5 @@ CvVideoWriter* cvCreateVideoWriter_FFMPEG_proxy( const char* filename, int fourc
|
|||||||
if( result->open( filename, fourcc, fps, frameSize, isColor != 0 ))
|
if( result->open( filename, fourcc, fps, frameSize, isColor != 0 ))
|
||||||
return result;
|
return result;
|
||||||
delete result;
|
delete result;
|
||||||
#ifdef HAVE_VFW
|
|
||||||
return cvCreateVideoWriter_VFW(filename, fourcc, fps, frameSize, isColor);
|
|
||||||
#else
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,8 @@
|
|||||||
#include <mfplay.h>
|
#include <mfplay.h>
|
||||||
#include <mfobjects.h>
|
#include <mfobjects.h>
|
||||||
#include "Strsafe.h"
|
#include "Strsafe.h"
|
||||||
|
#include <wrl/client.h>
|
||||||
|
#include <Mfreadwrite.h>
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -67,6 +69,7 @@
|
|||||||
#pragma comment(lib, "mf")
|
#pragma comment(lib, "mf")
|
||||||
#pragma comment(lib, "mfuuid")
|
#pragma comment(lib, "mfuuid")
|
||||||
#pragma comment(lib, "Strmiids")
|
#pragma comment(lib, "Strmiids")
|
||||||
|
#pragma comment(lib, "Mfreadwrite")
|
||||||
#pragma comment(lib, "MinCore_Downlevel")
|
#pragma comment(lib, "MinCore_Downlevel")
|
||||||
|
|
||||||
struct IMFMediaType;
|
struct IMFMediaType;
|
||||||
@ -146,7 +149,6 @@ private:
|
|||||||
|
|
||||||
DWORD WINAPI MainThreadFunction( LPVOID lpParam );
|
DWORD WINAPI MainThreadFunction( LPVOID lpParam );
|
||||||
typedef void(*emergensyStopEventCallback)(int, void *);
|
typedef void(*emergensyStopEventCallback)(int, void *);
|
||||||
typedef unsigned char BYTE;
|
|
||||||
|
|
||||||
class RawImage
|
class RawImage
|
||||||
{
|
{
|
||||||
@ -2939,4 +2941,352 @@ CvCapture* cvCreateCameraCapture_MSMF( int index )
|
|||||||
delete capture;
|
delete capture;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Media Foundation-based Video Writer
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
using namespace Microsoft::WRL;
|
||||||
|
|
||||||
|
class CvVideoWriter_MSMF : public CvVideoWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CvVideoWriter_MSMF();
|
||||||
|
virtual ~CvVideoWriter_MSMF();
|
||||||
|
virtual bool open( const char* filename, int fourcc,
|
||||||
|
double fps, CvSize frameSize, bool isColor );
|
||||||
|
virtual void close();
|
||||||
|
virtual bool writeFrame( const IplImage* img);
|
||||||
|
|
||||||
|
private:
|
||||||
|
UINT32 videoWidth;
|
||||||
|
UINT32 videoHeight;
|
||||||
|
double fps;
|
||||||
|
UINT32 bitRate;
|
||||||
|
UINT32 frameSize;
|
||||||
|
GUID encodingFormat;
|
||||||
|
GUID inputFormat;
|
||||||
|
|
||||||
|
DWORD streamIndex;
|
||||||
|
ComPtr<IMFSinkWriter> sinkWriter;
|
||||||
|
|
||||||
|
bool initiated;
|
||||||
|
|
||||||
|
LONGLONG rtStart;
|
||||||
|
UINT64 rtDuration;
|
||||||
|
|
||||||
|
HRESULT InitializeSinkWriter(const char* filename);
|
||||||
|
HRESULT WriteFrame(DWORD *videoFrameBuffer, const LONGLONG& rtStart, const LONGLONG& rtDuration);
|
||||||
|
};
|
||||||
|
|
||||||
|
CvVideoWriter_MSMF::CvVideoWriter_MSMF()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CvVideoWriter_MSMF::~CvVideoWriter_MSMF()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CvVideoWriter_MSMF::open( const char* filename, int fourcc,
|
||||||
|
double _fps, CvSize frameSize, bool isColor )
|
||||||
|
{
|
||||||
|
videoWidth = frameSize.width;
|
||||||
|
videoHeight = frameSize.height;
|
||||||
|
fps = _fps;
|
||||||
|
bitRate = 4*800000;
|
||||||
|
encodingFormat = MFVideoFormat_WMV3;
|
||||||
|
inputFormat = MFVideoFormat_RGB32;
|
||||||
|
|
||||||
|
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
printf("CoInitializeEx is successfull\n");
|
||||||
|
hr = MFStartup(MF_VERSION);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
printf("MFStartup is successfull\n");
|
||||||
|
hr = InitializeSinkWriter(filename);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
printf("InitializeSinkWriter is successfull\n");
|
||||||
|
initiated = true;
|
||||||
|
rtStart = 0;
|
||||||
|
MFFrameRateToAverageTimePerFrame(fps, 1, &rtDuration);
|
||||||
|
printf("duration: %d\n", rtDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCEEDED(hr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CvVideoWriter_MSMF::close()
|
||||||
|
{
|
||||||
|
printf("VideoWriter::close()\n");
|
||||||
|
if (!initiated)
|
||||||
|
{
|
||||||
|
printf("VideoWriter was not Initialized\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
initiated = false;
|
||||||
|
HRESULT hr = sinkWriter->Finalize();
|
||||||
|
printf("sinkWriter Finalize status %u\n", hr);
|
||||||
|
MFShutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CvVideoWriter_MSMF::writeFrame(const IplImage* img)
|
||||||
|
{
|
||||||
|
if (!img)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
printf("Writing not empty IplImage\n");
|
||||||
|
|
||||||
|
auto length = img->width * img->height * 4;
|
||||||
|
printf("Image: %dx%d, %d\n", img->width, img->height, length);
|
||||||
|
DWORD* target = new DWORD[length];
|
||||||
|
|
||||||
|
printf("Before for loop\n");
|
||||||
|
for (int rowIdx = 0; rowIdx < img->height; rowIdx++)
|
||||||
|
{
|
||||||
|
char* rowStart = img->imageData + rowIdx*img->widthStep;
|
||||||
|
for (int colIdx = 0; colIdx < img->width; colIdx++)
|
||||||
|
{
|
||||||
|
BYTE b = rowStart[colIdx * img->nChannels + 0];
|
||||||
|
BYTE g = rowStart[colIdx * img->nChannels + 1];
|
||||||
|
BYTE r = rowStart[colIdx * img->nChannels + 2];
|
||||||
|
|
||||||
|
// On ARM devices data is stored starting from the last line
|
||||||
|
// (and not the first line) so you have to revert them on the Y axis
|
||||||
|
#if _M_ARM
|
||||||
|
auto row = index / videoWidth;
|
||||||
|
auto targetRow = videoHeight - row - 1;
|
||||||
|
auto column = index - (row * videoWidth);
|
||||||
|
target[(targetRow * videoWidth) + column] = (r << 16) + (g << 8) + b;
|
||||||
|
#else
|
||||||
|
target[rowIdx*img->width+colIdx] = (r << 16) + (g << 8) + b;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send frame to the sink writer.
|
||||||
|
printf("Before private WriteFrame call\n");
|
||||||
|
HRESULT hr = WriteFrame(target, rtStart, rtDuration);
|
||||||
|
printf("After private WriteFrame call\n");
|
||||||
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
printf("Private WriteFrame failed\n");
|
||||||
|
delete[] target;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
rtStart += rtDuration;
|
||||||
|
|
||||||
|
printf("End of writing IplImage\n");
|
||||||
|
|
||||||
|
delete[] target;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT CvVideoWriter_MSMF::InitializeSinkWriter(const char* filename)
|
||||||
|
{
|
||||||
|
ComPtr<IMFAttributes> spAttr;
|
||||||
|
ComPtr<IMFMediaType> mediaTypeOut;
|
||||||
|
ComPtr<IMFMediaType> mediaTypeIn;
|
||||||
|
ComPtr<IMFByteStream> spByteStream;
|
||||||
|
|
||||||
|
MFCreateAttributes(&spAttr, 10);
|
||||||
|
spAttr->SetUINT32(MF_READWRITE_ENABLE_HARDWARE_TRANSFORMS, true);
|
||||||
|
|
||||||
|
wchar_t* unicodeFileName = new wchar_t[strlen(filename)+1];
|
||||||
|
MultiByteToWideChar(CP_ACP, 0, filename, -1, unicodeFileName, strlen(filename)+1);
|
||||||
|
|
||||||
|
HRESULT hr = MFCreateSinkWriterFromURL(unicodeFileName, NULL, spAttr.Get(), &sinkWriter);
|
||||||
|
|
||||||
|
delete[] unicodeFileName;
|
||||||
|
|
||||||
|
// Set the output media type.
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
printf("MFCreateSinkWriterFromURL is successfull\n");
|
||||||
|
hr = MFCreateMediaType(&mediaTypeOut);
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = mediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = mediaTypeOut->SetGUID(MF_MT_SUBTYPE, encodingFormat);
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = mediaTypeOut->SetUINT32(MF_MT_AVG_BITRATE, bitRate);
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = mediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = MFSetAttributeSize(mediaTypeOut.Get(), MF_MT_FRAME_SIZE, videoWidth, videoHeight);
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_FRAME_RATE, fps, 1);
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = MFSetAttributeRatio(mediaTypeOut.Get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = sinkWriter->AddStream(mediaTypeOut.Get(), &streamIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the input media type.
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = MFCreateMediaType(&mediaTypeIn);
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = mediaTypeIn->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = mediaTypeIn->SetGUID(MF_MT_SUBTYPE, inputFormat);
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = mediaTypeIn->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = MFSetAttributeSize(mediaTypeIn.Get(), MF_MT_FRAME_SIZE, videoWidth, videoHeight);
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = MFSetAttributeRatio(mediaTypeIn.Get(), MF_MT_FRAME_RATE, fps, 1);
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = MFSetAttributeRatio(mediaTypeIn.Get(), MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = sinkWriter->SetInputMediaType(streamIndex, mediaTypeIn.Get(), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tell the sink writer to start accepting data.
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = sinkWriter->BeginWriting();
|
||||||
|
}
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT CvVideoWriter_MSMF::WriteFrame(DWORD *videoFrameBuffer, const LONGLONG& Start, const LONGLONG& Duration)
|
||||||
|
{
|
||||||
|
printf("Private WriteFrame(%p, %llu, %llu)\n", videoFrameBuffer, Start, Duration);
|
||||||
|
IMFSample* sample;
|
||||||
|
IMFMediaBuffer* buffer;
|
||||||
|
|
||||||
|
const LONG cbWidth = 4 * videoWidth;
|
||||||
|
const DWORD cbBuffer = cbWidth * videoHeight;
|
||||||
|
|
||||||
|
BYTE *pData = NULL;
|
||||||
|
|
||||||
|
// Create a new memory buffer.
|
||||||
|
HRESULT hr = MFCreateMemoryBuffer(cbBuffer, &buffer);
|
||||||
|
|
||||||
|
// Lock the buffer and copy the video frame to the buffer.
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
printf("MFCreateMemoryBuffer successfull\n");
|
||||||
|
hr = buffer->Lock(&pData, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
printf("Before MFCopyImage(%p, %d, %p, %d, %d %d)\n", pData, cbWidth, videoFrameBuffer, cbWidth, cbWidth, videoHeight);
|
||||||
|
hr = MFCopyImage(
|
||||||
|
pData, // Destination buffer.
|
||||||
|
cbWidth, // Destination stride.
|
||||||
|
(BYTE*)videoFrameBuffer, // First row in source image.
|
||||||
|
cbWidth, // Source stride.
|
||||||
|
cbWidth, // Image width in bytes.
|
||||||
|
videoHeight // Image height in pixels.
|
||||||
|
);
|
||||||
|
printf("After MFCopyImage()\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Before buffer.Get()\n");
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
printf("Before buffer->Unlock\n");
|
||||||
|
buffer->Unlock();
|
||||||
|
printf("After buffer->Unlock\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the data length of the buffer.
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
printf("MFCopyImage successfull\n");
|
||||||
|
hr = buffer->SetCurrentLength(cbBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a media sample and add the buffer to the sample.
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = MFCreateSample(&sample);
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = sample->AddBuffer(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the time stamp and the duration.
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
printf("Sample time: %d\n", Start);
|
||||||
|
hr = sample->SetSampleTime(Start);
|
||||||
|
}
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
printf("Duration: %d\n", Duration);
|
||||||
|
hr = sample->SetSampleDuration(Duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the sample to the Sink Writer.
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
printf("Setting writer params successfull\n");
|
||||||
|
hr = sinkWriter->WriteSample(streamIndex, sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Private WriteFrame(%d, %p) end with status %u\n", streamIndex, sample, hr);
|
||||||
|
|
||||||
|
SafeRelease(&sample);
|
||||||
|
SafeRelease(&buffer);
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
CvVideoWriter* cvCreateVideoWriter_MSMF( const char* filename, int fourcc,
|
||||||
|
double fps, CvSize frameSize, int isColor )
|
||||||
|
{
|
||||||
|
printf("Creating Media Foundation VideoWriter\n");
|
||||||
|
CvVideoWriter_MSMF* writer = new CvVideoWriter_MSMF;
|
||||||
|
if( writer->open( filename, fourcc, fps, frameSize, isColor != 0 ))
|
||||||
|
return writer;
|
||||||
|
delete writer;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -119,6 +119,8 @@ CvVideoWriter* cvCreateVideoWriter_VFW( const char* filename, int fourcc,
|
|||||||
double fps, CvSize frameSize, int is_color );
|
double fps, CvSize frameSize, int is_color );
|
||||||
CvCapture* cvCreateCameraCapture_DShow( int index );
|
CvCapture* cvCreateCameraCapture_DShow( int index );
|
||||||
CvCapture* cvCreateCameraCapture_MSMF( int index );
|
CvCapture* cvCreateCameraCapture_MSMF( int index );
|
||||||
|
CvVideoWriter* cvCreateVideoWriter_MSMF( const char* filename, int fourcc,
|
||||||
|
double fps, CvSize frameSize, int is_color );
|
||||||
CvCapture* cvCreateCameraCapture_OpenNI( int index );
|
CvCapture* cvCreateCameraCapture_OpenNI( int index );
|
||||||
CvCapture* cvCreateFileCapture_OpenNI( const char* filename );
|
CvCapture* cvCreateFileCapture_OpenNI( const char* filename );
|
||||||
CvCapture* cvCreateCameraCapture_Android( int index );
|
CvCapture* cvCreateCameraCapture_Android( int index );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user