Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ///////////////// MP4File.h /////////////////
- #pragma once
- #include <Windows.h>
- #include <mfapi.h>
- #include <mfidl.h>
- #include <Mfreadwrite.h>
- #include <mferror.h>
- #include <string>
- #pragma comment(lib, "mfreadwrite")
- #pragma comment(lib, "mfplat")
- #pragma comment(lib, "mfuuid")
- class MP4File
- {
- private:
- HDC m_hDC;
- IMFSinkWriter* m_pSinkWriter;
- HRESULT m_writeFrameResult;
- LONGLONG rtStart; // m_currentFrameTimestamp
- LPVOID m_lpBitsBuffer;
- HANDLE m_hHeap;
- DWORD m_streamIndex;
- // File details
- std::wstring m_name;
- UINT32 m_width;
- UINT32 m_height;
- UINT32 m_FPS;
- UINT64 rtDuration; // m_frameDuration
- UINT32 m_bitrate;
- GUID m_encoding;
- GUID m_inputEncoding;
- bool m_isInitialFrame;
- void ReleaseMemory();
- HRESULT InitializeMovieCreation();
- HRESULT InitializeSinkWriter();
- HRESULT WriteFrame();
- template <class T> void SafeRelease(T** ppT)
- {
- if (*ppT)
- {
- (*ppT)->Release();
- *ppT = NULL;
- }
- }
- public:
- MP4File(std::wstring, UINT32, UINT32);
- ~MP4File();
- HRESULT AppendFrame(HBITMAP);
- HRESULT Finalize();
- };
- ///////////////// MP4File.cpp /////////////////
- #include "stdafx.h"
- #include "MP4File.h"
- MP4File::MP4File(std::wstring fileName, UINT32 videoWidth, UINT32 videoHeight) :
- m_hDC(NULL),
- m_pSinkWriter(NULL),
- m_writeFrameResult(NULL),
- rtStart(0),
- m_lpBitsBuffer(NULL),
- m_hHeap(NULL),
- m_name(fileName),
- m_width(videoWidth),
- m_height(videoHeight),
- m_FPS(30),
- rtDuration(0),//10 * 1000 * 1000 / 30),
- m_bitrate(15000000),
- m_encoding(MFVideoFormat_H264),
- m_inputEncoding(MFVideoFormat_RGB32),
- m_isInitialFrame(true)
- {
- HRESULT hr = MFFrameRateToAverageTimePerFrame(30, 1, &rtDuration);
- }
- MP4File::~MP4File()
- {
- ReleaseMemory();
- }
- void MP4File::ReleaseMemory()
- {
- if (m_hDC)
- {
- DeleteDC(m_hDC);
- m_hDC = NULL;
- }
- if (m_lpBitsBuffer)
- {
- HeapFree(m_hHeap, HEAP_NO_SERIALIZE, m_lpBitsBuffer);
- m_lpBitsBuffer = NULL;
- }
- if (m_hHeap)
- {
- HeapDestroy(m_hHeap);
- m_hHeap = NULL;
- }
- SafeRelease(&m_pSinkWriter);
- MFShutdown();
- CoUninitialize();
- }
- HRESULT MP4File::InitializeMovieCreation()
- {
- HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
- if (SUCCEEDED(hr))
- {
- hr = MFStartup(MF_VERSION);
- if (SUCCEEDED(hr))
- {
- hr = InitializeSinkWriter();
- if (SUCCEEDED(hr))
- {
- m_hDC = CreateCompatibleDC(NULL);
- if (m_hDC == NULL)
- {
- return E_FAIL;
- }
- m_hHeap = HeapCreate(HEAP_NO_SERIALIZE, m_width * m_height * 4, 0);
- if (m_hHeap == NULL)
- {
- return E_FAIL;
- }
- m_lpBitsBuffer = HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE, m_width * m_height * 4);
- if (m_lpBitsBuffer == NULL)
- {
- return E_FAIL;
- }
- return S_OK;
- }
- }
- }
- return E_FAIL;
- }
- HRESULT MP4File::InitializeSinkWriter()
- {
- IMFSinkWriter *pSinkWriter = NULL;
- IMFMediaType *pMediaTypeOut = NULL;
- IMFMediaType *pMediaTypeIn = NULL;
- DWORD streamIndex;
- HRESULT hr = MFCreateSinkWriterFromURL((m_name + L".mp4").c_str(), NULL, NULL, &pSinkWriter);
- // Set the output media type.
- if (SUCCEEDED(hr))
- {
- hr = MFCreateMediaType(&pMediaTypeOut);
- }
- if (SUCCEEDED(hr))
- {
- hr = pMediaTypeOut->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
- }
- if (SUCCEEDED(hr))
- {
- hr = pMediaTypeOut->SetGUID(MF_MT_SUBTYPE, m_encoding);
- }
- if (SUCCEEDED(hr))
- {
- hr = pMediaTypeOut->SetUINT32(MF_MT_AVG_BITRATE, m_bitrate);
- }
- if (SUCCEEDED(hr))
- {
- hr = pMediaTypeOut->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
- }
- if (SUCCEEDED(hr))
- {
- hr = MFSetAttributeSize(pMediaTypeOut, MF_MT_FRAME_SIZE, m_width, m_height);
- }
- if (SUCCEEDED(hr))
- {
- hr = MFSetAttributeRatio(pMediaTypeOut, MF_MT_FRAME_RATE, m_FPS, 1);
- }
- if (SUCCEEDED(hr))
- {
- hr = MFSetAttributeRatio(pMediaTypeOut, MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
- }
- if (SUCCEEDED(hr))
- {
- hr = pSinkWriter->AddStream(pMediaTypeOut, &streamIndex);
- }
- // Set the input media type.
- if (SUCCEEDED(hr))
- {
- hr = MFCreateMediaType(&pMediaTypeIn);
- }
- if (SUCCEEDED(hr))
- {
- hr = pMediaTypeIn->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video);
- }
- if (SUCCEEDED(hr))
- {
- hr = pMediaTypeIn->SetGUID(MF_MT_SUBTYPE, m_inputEncoding);
- }
- if (SUCCEEDED(hr))
- {
- hr = pMediaTypeIn->SetUINT32(MF_MT_INTERLACE_MODE, MFVideoInterlace_Progressive);
- }
- if (SUCCEEDED(hr))
- {
- hr = MFSetAttributeSize(pMediaTypeIn, MF_MT_FRAME_SIZE, m_width, m_height);
- }
- if (SUCCEEDED(hr))
- {
- hr = MFSetAttributeRatio(pMediaTypeIn, MF_MT_FRAME_RATE, m_FPS, 1);
- }
- if (SUCCEEDED(hr))
- {
- hr = MFSetAttributeRatio(pMediaTypeIn, MF_MT_PIXEL_ASPECT_RATIO, 1, 1);
- }
- if (SUCCEEDED(hr))
- {
- hr = pSinkWriter->SetInputMediaType(streamIndex, pMediaTypeIn, NULL);
- }
- // Tell the sink writer to start accepting data.
- if (SUCCEEDED(hr))
- {
- hr = pSinkWriter->BeginWriting();
- }
- // Assign pointers to members upon complete success
- if (SUCCEEDED(hr))
- {
- m_pSinkWriter = pSinkWriter;
- m_pSinkWriter->AddRef();
- m_streamIndex = streamIndex;
- }
- SafeRelease(&pSinkWriter);
- SafeRelease(&pMediaTypeOut);
- SafeRelease(&pMediaTypeIn);
- return hr;
- }
- HRESULT MP4File::WriteFrame()
- {
- IMFSample *pSample = NULL;
- IMFMediaBuffer *pBuffer = NULL;
- const LONG cbWidth = 4 * m_width;
- const DWORD cbBufferSize = cbWidth * m_height;
- BYTE *pData = NULL;
- // Create a new memory buffer.
- HRESULT hr = MFCreateMemoryBuffer(cbBufferSize, &pBuffer);
- // Lock the buffer and copy the video frame to the buffer.
- if (SUCCEEDED(hr))
- {
- hr = pBuffer->Lock(&pData, NULL, NULL);
- }
- if (SUCCEEDED(hr))
- {
- hr = MFCopyImage(
- pData, // Destination buffer.
- cbWidth, // Destination stride.
- (BYTE*)m_lpBitsBuffer, // First row in source image.
- cbWidth, // Source stride.
- cbWidth, // Image width in bytes.
- m_height // Image height in pixels.
- );
- }
- if (pBuffer)
- {
- pBuffer->Unlock();
- }
- // Set the data length of the buffer.
- if (SUCCEEDED(hr))
- {
- hr = pBuffer->SetCurrentLength(cbBufferSize);
- }
- // Create a media sample and add the buffer to the sample.
- if (SUCCEEDED(hr))
- {
- hr = MFCreateSample(&pSample);
- }
- if (SUCCEEDED(hr))
- {
- hr = pSample->AddBuffer(pBuffer);
- }
- // Set the time stamp and the duration.
- if (SUCCEEDED(hr))
- {
- hr = pSample->SetSampleTime(rtStart);
- }
- if (SUCCEEDED(hr))
- {
- hr = pSample->SetSampleDuration(rtDuration);
- }
- // Send the sample to the Sink Writer and update the timestamp
- if (SUCCEEDED(hr))
- {
- hr = m_pSinkWriter->WriteSample(m_streamIndex, pSample);
- }
- SafeRelease(&pSample);
- SafeRelease(&pBuffer);
- return hr;
- }
- HRESULT MP4File::AppendFrame(HBITMAP frame)
- {
- HRESULT hr = NULL;
- if (m_isInitialFrame)
- {
- hr = InitializeMovieCreation();
- if (FAILED(hr))
- return hr;
- m_isInitialFrame = false;
- }
- if (m_hHeap && m_lpBitsBuffer) // Makes sure buffer is initialized
- {
- BITMAPINFO bmpInfo;
- bmpInfo.bmiHeader.biBitCount = 0;
- bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- // Get individual bits from bitmap and loads it into the buffer used by `WriteFrame`
- GetDIBits(m_hDC, frame, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS);
- bmpInfo.bmiHeader.biCompression = BI_RGB;
- GetDIBits(m_hDC, frame, 0, bmpInfo.bmiHeader.biHeight, m_lpBitsBuffer, &bmpInfo, DIB_RGB_COLORS);
- hr = WriteFrame();
- if (SUCCEEDED(hr))
- {
- rtStart += rtDuration;
- }
- }
- return m_writeFrameResult = hr;
- }
- HRESULT MP4File::Finalize()
- {
- if (SUCCEEDED(m_writeFrameResult))
- {
- m_pSinkWriter->Finalize();
- m_isInitialFrame = true;
- return S_OK;
- }
- return E_FAIL;
- }
- ///////////////// main.cpp /////////////////
- #include "stdafx.h"
- #include "MP4File.h"
- #include <iostream>
- const UINT32 VIDEO_WIDTH = 3840;
- const UINT32 VIDEO_HEIGHT = 1080;
- HBITMAP GetBitmap()
- {
- HDC hScreen = GetDC(NULL);
- HDC hDC = CreateCompatibleDC(hScreen);
- HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, VIDEO_WIDTH, VIDEO_HEIGHT);
- HGDIOBJ old_obj = SelectObject(hDC, hBitmap);
- BOOL bRet = BitBlt(hDC, 0, 0, VIDEO_WIDTH, VIDEO_HEIGHT, hScreen, -1920, 0, SRCCOPY);
- SelectObject(hDC, old_obj);
- DeleteDC(hDC);
- ReleaseDC(NULL, hScreen);
- return hBitmap;
- }
- int main()
- {
- HRESULT hr;
- MP4File file(L"test", VIDEO_WIDTH, VIDEO_HEIGHT);
- while (true)
- {
- HBITMAP hBitmap = GetBitmap();
- hr = file.AppendFrame(hBitmap);
- if (FAILED(hr))
- break;
- if (GetAsyncKeyState(0x51))
- {
- std::cout << "Stopped recording";
- break;
- }
- }
- file.Finalize();
- return 0;
- }
Add Comment
Please, Sign In to add comment