Я делаю устройство записи экрана (без звука), используя Win32s Sink Writer для кодирования серии растровых изображений в файл MP4.
По какой-то причине скорость воспроизведения видео увеличивается (по-видимому) пропорционально ширине видео.
Из этого поста я понял, что, скорее всего, потому, что я неправильно вычисляю размер буфера. Разница здесь в том, что проблема с воспроизведением видео была исправлена после правильного расчета размера аудио буфера, но, поскольку я вообще не кодирую звук, я не уверен, что из него извлечь.
Я также пытался прочитать , как работает буфер , но я действительно в растерянности относительно того, как размер буфера вызывает разные скорости воспроизведения.
Вот пастбина для всего кода, я действительно не могу отследить проблему больше, чем размер буфера и / или индекс / продолжительность кадра.
т.е.: В зависимости от ширины переменной-члена 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;
}
И, наконец, средство записи кадров, которое фактически загружает биты в буфер, а затем записывает данные в Sink Writer.
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
- Битрейт: 15 000 000
- Формат выходной кодировки: H264 (MP4)