最近在分析播放视频(mkv 格式)引起显示异常的问题。
平台为: WinCE6.0;CPU 为 Telechips8902.
发现在主菜单/设置/多媒体类型选择等界面会出现问题;但在导航界面不会出现问题。所以分析问题的原因与主菜单等界面的显示方式有关,查看代码发现主菜单等界面使用 overlay 显示。
由于视频显示也采用 overlay 方式(怀疑 mkv 格式视频的显示比其它格式显示多使用一层 overlay 表面),可能是因为 overlay 表面使用冲突引起主菜单等显示异常的问题。需要分析视频显示的实现过程与 UI 的实现过程来确认是否是此原因?
UI 代码中 overlay 的实现是通过 IOCtrl 来实现的,没有通过系统标准的 overlay 访问接口。
Telechips 8902 共 2 层 overlay surface,视频播放使用一层(YUV);UI 的显示采用 IOCtrl 直接通过 OS 写屏操作,经测试发现使用一层 overlay(RGB) surface;此时如果视频播放的视频文件格式需要需要通过 overlay 显示 SUB-TITLE 时,与 UI 显示使用的 overlay 表面资源冲突。这样导致了如上问题的产生。
为了排除 UI 实现对上述结果的影响,采用 DirectDraw 示例工程 mosquito 与视频一起运行,看是否可以重现上述问题:
先运行 mosquito,界面出现蚊子飞的动画效果。此时,再运行 Telechips 的示例工程 TCMovieManager。先选择一首没有字幕的视频播放,发现视频与 mosquito 的效果(蚊子飞的动画)同时存在。此时将视频切换到带有字幕的视频,开始视频播放后,发现 mosquito 的效果(蚊子飞的动画)消失。这样就重现了 UI 界面与视频冲突的现象!
此问题,单独从应用层来分析比较难解决。
个人建议的方法:
(1)从 OS 入手,修改视频播放时对字幕(SUB-TITLE)的处理,字幕(SUB-TITLE)要不不显示、要不显示在视频 overlay 层上;
(2)考虑不再实现视频后台播放的功能。
平台为: WinCE6.0;CPU 为 Telechips8902.
发现在主菜单/设置/多媒体类型选择等界面会出现问题;但在导航界面不会出现问题。所以分析问题的原因与主菜单等界面的显示方式有关,查看代码发现主菜单等界面使用 overlay 显示。
由于视频显示也采用 overlay 方式(怀疑 mkv 格式视频的显示比其它格式显示多使用一层 overlay 表面),可能是因为 overlay 表面使用冲突引起主菜单等显示异常的问题。需要分析视频显示的实现过程与 UI 的实现过程来确认是否是此原因?
UI 代码中 overlay 的实现是通过 IOCtrl 来实现的,没有通过系统标准的 overlay 访问接口。
Telechips 8902 共 2 层 overlay surface,视频播放使用一层(YUV);UI 的显示采用 IOCtrl 直接通过 OS 写屏操作,经测试发现使用一层 overlay(RGB) surface;此时如果视频播放的视频文件格式需要需要通过 overlay 显示 SUB-TITLE 时,与 UI 显示使用的 overlay 表面资源冲突。这样导致了如上问题的产生。
为了排除 UI 实现对上述结果的影响,采用 DirectDraw 示例工程 mosquito 与视频一起运行,看是否可以重现上述问题:
先运行 mosquito,界面出现蚊子飞的动画效果。此时,再运行 Telechips 的示例工程 TCMovieManager。先选择一首没有字幕的视频播放,发现视频与 mosquito 的效果(蚊子飞的动画)同时存在。此时将视频切换到带有字幕的视频,开始视频播放后,发现 mosquito 的效果(蚊子飞的动画)消失。这样就重现了 UI 界面与视频冲突的现象!
此问题,单独从应用层来分析比较难解决。
个人建议的方法:
(1)从 OS 入手,修改视频播放时对字幕(SUB-TITLE)的处理,字幕(SUB-TITLE)要不不显示、要不显示在视频 overlay 层上;
(2)考虑不再实现视频后台播放的功能。
附部分 mosquito 的源代码,主要包括 overlay 层格式与初始化:
/*
* Telechips 8902 支持 2 层 overlay
* 只能创建一层 YUYV 的 overlay (可以再创建一层 RGB overlay)
* RGB 模式可以创建多个,模式与顺序没有不影响创建
*/
static DDPIXELFORMAT ddpfOverlayFormats[] = {
//{sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('Y','U','Y','V'),0,0,0,0,0}, // YUYV - Leo.Zheng Telechips 8902 可以支持
//{sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('U','Y','V','Y'),0,0,0,0,0}, // UYVY - Leo.Zheng Telechips 8902:Create No.1 surface return: 0x88760218
// {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00, 0x03e0, 0x001F, 0}, // 16-bit RGB 5:5:5
{sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0xF800, 0x07e0, 0x001F, 0}, // 16-bit RGB 5:6:5
};
#define PF_TABLE_SIZE (sizeof(ddpfOverlayFormats) / sizeof(ddpfOverlayFormats[0]))
//-----------------------------------------------------------------------------
// Name: InitApp()
// Desc: Do work required for every instance of the application:
// Create the window, initialize data
//-----------------------------------------------------------------------------
static HRESULT InitApp(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
WNDCLASS wc;
DDSURFACEDESC ddsd;
DDCAPS ddcaps;
HRESULT hRet;
DWORD dwUpdateFlags = 0;
DDOVERLAYFX ovfx;
DEVMODE DevMode;
// Check for rotation support by getting the rotation angles supported.
memset(&DevMode, 0, sizeof(DevMode));
DevMode.dmSize = sizeof(DevMode);
DevMode.dmFields = DM_DISPLAYQUERYORIENTATION;
if(DISP_CHANGE_SUCCESSFUL == ChangeDisplaySettingsEx(NULL, &DevMode, NULL, CDS_TEST, NULL))
{
g_RotationAngles = DevMode.dmDisplayOrientation;
}
else
{
OutputDebugString(L"MOSQUITO: Device does not support any rotation modes. Rotation disabled.");
g_RotationAngles = -1;
}
// Get the current rotation angle.
memset(&DevMode, 0, sizeof (DevMode));
DevMode.dmSize = sizeof (DevMode);
DevMode.dmFields = DM_DISPLAYORIENTATION;
if (DISP_CHANGE_SUCCESSFUL == ChangeDisplaySettingsEx(NULL, &DevMode, NULL, CDS_TEST, NULL))
{
g_CurrentAngle = DevMode.dmDisplayOrientation;
}
else
{
OutputDebugString(L"MOSQUITO: Unable to read current rotation. Rotation disabled.");
g_CurrentAngle = -1;
}
// Set up and register window class.
......
// Create the main DirectDraw object
hRet = DirectDrawCreate(NULL, &g_pDD, NULL);
if(hRet != DD_OK)
return InitFail(hWnd, hRet, TEXT("DirectDrawCreate FAILED"));
// Get normal mode.
hRet = g_pDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL);
if (hRet != DD_OK)
return InitFail(hWnd, hRet, TEXT("SetCooperativeLevel FAILED"));
// Get a primary surface interface pointer (only needed for init.)
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSPrimary, NULL);
if (hRet != DD_OK)
return InitFail(hWnd, hRet, TEXT("CreateSurface FAILED"));
// See if we can support overlays.
memset(&ddcaps, 0, sizeof(ddcaps));
ddcaps.dwSize = sizeof(ddcaps);
hRet = g_pDD->GetCaps(&ddcaps, NULL);
if (hRet != DD_OK)
return InitFail(hWnd, hRet, TEXT("GetCaps FAILED"));
if (ddcaps.dwOverlayCaps == 0)
return InitFail(hWnd, hRet, TEXT("Overlays are not supported in hardware!"));
/* // Leo.Zheng Add
if(!(capsDrv.dwCaps & DDCAPS_OVERLAY))
return FALSE;
*/
// Get alignment info to compute our overlay surface size.
rs.left = 0;
rs.top = 0;
rs.right = BUG_WIDTH;
rs.bottom = BUG_HEIGHT;
if (ddcaps.dwAlignSizeSrc != 0)
rs.right += rs.right % ddcaps.dwAlignSizeSrc;
// Create the overlay flipping surface. We will attempt the pixel formats
// in our table one at a time until we find one that jives.
int i = 0;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_FLIP;
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_BACKBUFFERCOUNT | DDSD_PIXELFORMAT;
ddsd.dwWidth = rs.right;
ddsd.dwHeight = rs.bottom;
ddsd.dwBackBufferCount = 1;
do
{ // Leo.Zheng MStar 2521 只创建 16-bit RGB 5:6:5 成功; 创建 16-bit RGB 5:5:5 失败.
ddsd.ddpfPixelFormat = ddpfOverlayFormats[i];
hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSOverlay, NULL); // Leo.Zheng 此处调用后引起使用 IOCtrl 显示在 LCD 上的消失
RETAILMSG(1,(L"[mosquito]Create No.%d surface return: 0x%X\r\n",i + 1,hRet));
}while(hRet != DD_OK && (++i < PF_TABLE_SIZE));
if(hRet != DD_OK)
return InitFail(hWnd, hRet, TEXT("Unable to create overlay surface!"));
// Load the images.
if (LoadBugImages() != DD_OK)
return InitFail(hWnd, hRet, TEXT("Unable to load images to overlay surface!"));
// Finish setting up the overlay.
int StretchFactor1000 = ddcaps.dwMinOverlayStretch > 1000 ? ddcaps.dwMinOverlayStretch : 1000;
rd.left=0;
rd.top=0;
// Adding 999 takes care of integer truncation problems.
rd.right = (rs.right * StretchFactor1000 + 999) / 1000;
rd.bottom = rs.bottom * StretchFactor1000 / 1000;
if (ddcaps.dwAlignSizeDest != 0)
rd.right = (int)((rd.right + ddcaps.dwAlignSizeDest - 1)/ ddcaps.dwAlignSizeDest) * ddcaps.dwAlignSizeDest;
// Set the flags we'll send to UpdateOverlay
dwUpdateFlags = DDOVER_SHOW;
// dwUpdateFlags = DDOVER_SHOW | DDOVER_DDFX; // Leo.Zheng DDOVER_DDFX WinCE 不支持
// Does the overlay hardware support source color keying?
// If so, we can hide the black background around the image.
// This probably won't work with YUV formats
memset(&ovfx, 0, sizeof(ovfx));
ovfx.dwSize = sizeof(ovfx);
if (ddcaps.dwOverlayCaps & DDOVERLAYCAPS_CKEYSRC) // MStar2521 不支持 color key
{
dwUpdateFlags |= DDOVER_KEYSRCOVERRIDE;
// Create an overlay FX structure so we can specify a source color key.
// This information is ignored if the DDOVER_SRCKEYOVERRIDE flag
// isn't set.
ovfx.dckSrcColorkey.dwColorSpaceLowValue=0; // black as the color key
ovfx.dckSrcColorkey.dwColorSpaceHighValue=0;
}
else
{
RETAILMSG(1,(L"[mosquito]cannot support color key: 0x%X(0x%x)\r\n",ddcaps.dwOverlayCaps,DDOVERLAYCAPS_CKEYSRC));
}
// Update the overlay parameters.
hRet = g_pDDSOverlay->UpdateOverlay(&rs, g_pDDSPrimary, &rd, dwUpdateFlags, &ovfx);
if (hRet != DD_OK)
{
// 在 MStar 2521 设备上运行第二个此程序实例时出错。
// 在 TeleChips 8902 设备上运行第三个此程序实例时出错。
return InitFail(hWnd, hRet, TEXT("Unable to show overlay surface: 0x%x!"),hRet);
}
// Set a bunch of position and velocity module vars.
g_nOverlayXPos = 0;
g_nOverlayYPos = 0;
g_nOverlayXVel = RANDOM_VELOCITY();
g_nOverlayYVel = RANDOM_VELOCITY();
g_nOverlayWidth = rd.right - rd.left;
g_nOverlayHeight = rd.bottom - rd.top;
// Set the "destination position alignment" global so we won't have to
// keep calling GetCaps() everytime we move the overlay surface.
g_dwOverlayXPositionAlignment = ddcaps.dwAlignBoundaryDest;
// Create a timer to flip the pages.
if (TIMER_ID != SetTimer(hWnd, TIMER_ID, TIMER_RATE, NULL))
return InitFail(hWnd, hRet, TEXT("SetTimer FAILED"));
return DD_OK;
}