yurikhan: (Default)
[personal profile] yurikhan

Нет, всё-таки бардак творится в мире Windows.

Допустим, нам надо показать пользователю AVI-файл. Покадрово. При этом нам понадобится с кадрами в процессе показывания ещё что-то делать, поэтому вариант «бросить на форму медиаплеерный контрол» не канает.

Значит, берём MSDN в руки, и вперёд. Там есть такой раздельчик — Video for Windows. И вроде как всё выглядит довольно просто. Открыть файл, взять у него первый видеопоток, получить у потока декомпрессор:

void CChildView::OnFileOpen()
{
  CFileDialog fd(TRUE, ".avs", 0, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
    "Video files (*.avi;*.avs)|*.avi;*.avs|"
    "All files (*.*)|*.*||", GetParent(), 0);
  if (IDOK != fd.DoModal()) return;
  ASSERT_SUCCESS(AVIFileOpen(&m_pAviFile, fd.GetFileName(), OF_READ | OF_SHARE_DENY_WRITE, 0));
  ASSERT_SUCCESS(AVIFileGetStream(m_pAviFile, &m_pAviStream, streamtypeVIDEO, 0));
  m_pGetFrame = ASSERT_NOTNULL(AVIStreamGetFrameOpen(m_stream, ???));
  m_pos = 0;
  Invalidate();
}

???: Здесь нам предлагают дать указатель на структуру BITMAPINFOHEADER, заполненную форматом, в котором мы бы хотели получать декомпрессированные данные. При этом утверждается, что, если оно не умеет разжимать в этот формат, то вернёт NULL.

Кроме того, есть ещё такое специальное значение AVIGETFRAMEF_BESTDISPLAYFMT, которое обещает разжимать в тот формат, который наиболее подходит дисплею.

Замечательно. Берём это волшебное значение, и поехали.

Теперь нужно научиться показывать кадры. MSDN настоятельно рекомендует для этого использовать функции DrawDib. Хорошо.

void CChildView::OnPaint()
{
  CPaintDC dc(this);
  if (!m_getFrame) return;
  LPVOID pFrame = ASSERT_NOTNULL(AVIStreamGetFrame(m_getFrame, m_pos));
  LPBITMAPINFOHEADER pHeader = reinterpret_cast<LPBITMAPINFOHEADER>(pFrame);
  LPVOID pData = reinterpret_cast<BYTE*>(pFrame) +
    pHeader->biSize + // пропустить заголовок
    pHeader->biClrUsed * sizeof(RGBQUAD); // и сколько там у него цветов в палитре
  ASSERT_TRUE(DrawDibDraw(m_hDrawDib, dc, 
    0, 0, pHeader->biWidth, pHeader->biHeight, 
    pHeader, pData, 
    0, 0, pHeader->biWidth, pHeader->biHeight, 0));
}

Что не так на этой картинке?

Да вроде бы всё работает, рисуется, кадры сменяются.

Теперь переключаемся из 32-битного цвета в 16-битный. Перезапускаем программу. И привет:

Assertion failed: DrawDibDraw: The operation completed successfully.

Убираем AVIGETFRAMEF_BESTDISPLAYFMT, ставим вместо него NULL, всё работает.

Смотрим, чего там такое нам дают. Выясняется, что в 32-битном цвете нам всегда дают 32-битную картинку, тогда как в 16-битном по умолчанию дают 24-битную, а «наиболее подходящий» формат — 16-битный. И когда приходит время эту 16-битную картинку рисовать на экран, DrawDibDraw вызывает SetDIBitsToDevice, которая вызывает какие-то функции видеодрайвера, которые её не осиливают. Хотя, если самому позвать SetDIBitsToDevice, то что-то рисуется. Хотя и с неправильными цветами.

Спасибо хоть, что в синьку не падают.

Date: 2006-10-06 19:43 (UTC)
From: [identity profile] beldmit.livejournal.com
А 16-битка небось до сих пор бывает 5-5-5 и 5-6-5?

Profile

yurikhan: (Default)
Yuri Khan

August 2018

S M T W T F S
   1234
567891011
12131415161718
19202122232425
26 2728293031 

Links

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated 2026-02-06 12:31
Powered by Dreamwidth Studios