我正在使用Win32s Sink Writer制作屏幕录像机(无音频),将一系列位图编码为MP4文件。
由于某种原因,视频播放速度与视频宽度成比例地(似乎)增加。
从this post,我已经收集到最可能的原因是因为我错误地计算了缓冲区大小。区别在于,一旦音频缓冲区大小的计算正确后,他们的视频播放问题就得到解决,但是由于我根本不编码任何音频,因此我不确定从中获得什么。
我也曾尝试阅读有关how the buffer works的信息,但对于<>缓冲区大小导致不同的播放速度,我确实感到茫然。Here is a pastebin表示代码的完整性,除了缓冲区大小和/或帧索引/持续时间之外,我真的无法找到问题所在。
即:
根据成员变量m_width
的宽度(以像素为单位),播放速度会发生变化。那是;宽度越大,视频播放越快,反之亦然。以下是两个视频示例:
3840x1080和640x1080,请注意系统时钟。Imugr不会保留文件的原始分辨率,但是我在上传之前仔细检查了一下,该程序确实确实创建了所声明分辨率的文件。rtStart和rtDuration如此定义,并且都是MP4File类的私有成员。LONGLONG rtStart = 0;
UINT64 rtDuration;
MFFrameRateToAverageTimePerFrame(m_FPS, 1, &rtDuration);
这是rtStart的更新位置,位图的各个位传递到帧编写器。将
LPVOID
对象移动到私有成员,以希望提高性能。现在,无需在每次添加框架时分配堆。
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::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; }
有关编码的几个详细信息: