Здравствуйте, cencio, Вы писали:
C>собственно сабж.
C>Пишу плеер интегрированный в прогу на основе VMR9 renderless (там еще много чего рисуется,без renderless не обойтись). Возникли проблемы с
C>проигрыванием WMV-HD файлов — сильно тормозит на видео клипах с разрешением 1280х720 и 1920х1080 — около 10 фпс и звук рваный , а в WMP10
C>показывается нормально, при этом замечено что WMP Classic в VMR9 renderless ведет себя также. В коде который обрабатывает полученые кадры
C>исправить ничего не выходит — IVMRImagePresenter9::PresentImage выдает новые кадры по 10 штук в секунду, не больше
10 вместо 60? Что-то не так с аллокатором-презентером
Допустим, что проблема именно в видео, а не в декодере и не в Вашей процедуре отрисовки не-видео частей. В XP2 серпаке мы добавили новый интерфейс, IVMRSurfaceAllocatorEx9, подробнее
здесь. Пользоваться им довольно легко: вместо IVMRSurfaceAllocator9 в Вашем allocator-presenter'e. Там только один метод добавлен, GetSurfaceEx. VMR9 вызывает этот метод точно так же, как он вызывал GetSurface, но в данном случае он передает дополнительный параметр RECT* lprcDst. Это прямоугольник, куда выводится видео. Это позволяет оптимизировать композицию видео (деинтерлейсинг+блендинг), так что в идеале аллокатор-презентер не должен более трансформировать этот прямоугольник, а просто выводить как есть.
//
// * CAllocatorPresenterEx9::GetSurfaceEx
//
STDMETHODIMP
CAllocatorPresenterEx9::GetSurfaceEx(
DWORD_PTR dwUserID,
DWORD SurfaceIndex,
DWORD SurfaceFlags,
IDirect3DSurface9** lplpSurface,
RECT* lprcDst
)
{
HRESULT hr = S_OK;
hr = GetSurface( dwUserID, SurfaceIndex, SurfaceFlags, lplpSurface );
if( FALSE == m_fFullScreen )
{
*lprcDst = m_rcMovieDestinationRect;
m_rcMovieSourceSize = *lprcDst;
}
else
{
memcpy( lprcDst, &(m_rcDesktopRect), sizeof( RECT ));
}
return hr;
}
Далее, в методе PresentSurface, рисуем этот прямоугольник вот так:
m_pDirectDrawSwapChainFrontBuffer->Present( &m_rcMovieSrcSize,
&m_rcMovieDstSize,
NULL, NULL, 0 );
(мы используем две swap chains; VMR9 всегда пишет в m_pDirectDrawSwapChainDecode, мы всегда рисуем m_pDirectDrawSwapChainFrontBuffer, меняем эти чейнс либо вручную либо они сами меняются местами, в зависимости от установок swapping видео девайса.
Наконец, из приложения управляем этим прямоугольником как показано ниже, при начальной инициализации и на каждое сообщение WM_SIZE; здесь m_hVideo видеоокно, m_pAP наш аллокатор
HRESULT Player::SetVideoWindow()
{
HRESULT hr = S_OK;
RECT rcDest; // client area of the video window
RECT rcVideo = rcDest; // rectangle for the video position
GetClientRect(m_hVideo, &rcDest);
if( !m_pAP )
return S_OK;
// ...
{
RECT rcMovie;
SIZE ar;
m_pAP->GetMoviePosition( & rcMovie ); // читаем m_rcMovieSourceSize из аллокатора-презентера
ar.cx = rcMovie.right - rcMovie.left;
ar.cy = rcMovie.bottom - rcMovie.top;
LetterBoxRect( ar, rcDest, &rcVideo ); // сохранить аспект
m_pAP->SetMoviePosition( &rcVideo ); // пишем m_rcMovieDestinationRect а аллокатор-презентер
m_pAP->PresentImage( 0, NULL );
HBRUSH brushBlack = CreateSolidBrush( RGB(0x00, 0x00, 0x00));
PaintClippedArea( m_hVideo, brushBlack, rcVideo, rcDest ); // зарисовать оставшиеся полосы по краям
}
else
{
hr = m_pAP->SetMoviePosition( &rcVideo );
}
return hr;
}
Этот прием может дать довольно ощутимое улучшение производительности. Однако я также отсоветовал бы использовать слишком много рисования не-видео в презентере. HD есть HD, и у презентера очень немного времени на прорисовку. Другим качественным улучшением будет использование YUV-mixing mode у VMR9 (подробнее
здесь). Это накладывает определенные ограничения на клиентскую программу, но дает наиболее оптимальную производительность. Не все карточки поддерживают этот режим, его весьма желательно имплементировать в клиенте, но обязательно дублировать обычным режимом.
С уважением,
Денис Евсеев
Media Technology group
Microsoft
This posting is provided "AS IS" with no warranties, and confers no rights. You assume all risk for your use.
© 2005 Microsoft Corporation. All rights reserved.