使用IMFSinkWriter编码的视频的播放速度根据宽度而变化

问题描述 投票:0回答:1

我正在使用Win32s Sink Writer制作屏幕录像机(无音频),将一系列位图编码为MP4文件。

由于某种原因,视频播放速度与视频宽度成比例地(似乎)增加。

this post,我已经收集到最可能的原因是因为我错误地计算了缓冲区大小。区别在于,一旦音频缓冲区大小的计算正确后,他们的视频播放问题就得到解决,但是由于我根本不编码任何音频,因此我不确定从中获得什么。

我也曾尝试阅读有关how the buffer works的信息,但对于<>缓冲区大小导致不同的播放速度,我确实感到茫然。Here is a pastebin表示代码的完整性,除了缓冲区大小和/或帧索引/持续时间之外,我真的无法找到问题所在。

即:

根据成员变量m_width的宽度(以像素为单位),播放速度会发生变化。那是;宽度越大,视频播放越快,反之亦然。

以下是两个视频示例:

3840x1080640x1080,请注意系统时钟。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; }

有关编码的几个详细信息:

    帧率:30FPS
  • 比特率:15000000
  • 输出编码格式:H264(MP4)
  • 我正在使用Win32s Sink Writer制作屏幕录像机(不带音频),以将一系列位图编码为MP4文件。由于某些原因,视频播放速度成比例地提高(似乎)...
c++ winapi video-capture video-encoding ms-media-foundation
1个回答
0
投票
对我来说,这种行为是有道理的。

请参见https://github.com/mofo7777/Stackoverflow/tree/master/ScreenCaptureEncode

© www.soinside.com 2019 - 2024. All rights reserved.