最近在分析播放视频(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)考虑不再实现视频后台播放的功能。
附部分 mosquito 的源代码,主要包括 overlay 层格式与初始化:
1 /* 2 * Telechips 8902 支持 2 层 overlay 3 * 只能创建一层 YUYV 的 overlay (可以再创建一层 RGB overlay) 4 * RGB 模式可以创建多个,模式与顺序没有不影响创建 5 */ 6 static DDPIXELFORMAT ddpfOverlayFormats[] = { 7 //{sizeof(DDPIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('Y','U','Y','V'),0,0,0,0,0}, // YUYV - Leo.Zheng Telechips 8902 可以支持 8 //{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 9 // {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00, 0x03e0, 0x001F, 0}, // 16-bit RGB 5:5:5 10 {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0xF800, 0x07e0, 0x001F, 0}, // 16-bit RGB 5:6:5 11 }; 12 13 #define PF_TABLE_SIZE (sizeof(ddpfOverlayFormats) / sizeof(ddpfOverlayFormats[0])) 14 15 16 17 //----------------------------------------------------------------------------- 18 // Name: InitApp() 19 // Desc: Do work required for every instance of the application: 20 // Create the window, initialize data 21 //----------------------------------------------------------------------------- 22 static HRESULT InitApp(HINSTANCE hInstance, int nCmdShow) 23 { 24 HWND hWnd; 25 WNDCLASS wc; 26 DDSURFACEDESC ddsd; 27 DDCAPS ddcaps; 28 HRESULT hRet; 29 DWORD dwUpdateFlags = 0; 30 DDOVERLAYFX ovfx; 31 DEVMODE DevMode; 32 33 // Check for rotation support by getting the rotation angles supported. 34 memset(&DevMode, 0, sizeof(DevMode)); 35 DevMode.dmSize = sizeof(DevMode); 36 DevMode.dmFields = DM_DISPLAYQUERYORIENTATION; 37 if(DISP_CHANGE_SUCCESSFUL == ChangeDisplaySettingsEx(NULL, &DevMode, NULL, CDS_TEST, NULL)) 38 { 39 g_RotationAngles = DevMode.dmDisplayOrientation; 40 } 41 else 42 { 43 OutputDebugString(L"MOSQUITO: Device does not support any rotation modes. Rotation disabled."); 44 g_RotationAngles = -1; 45 } 46 47 // Get the current rotation angle. 48 memset(&DevMode, 0, sizeof (DevMode)); 49 DevMode.dmSize = sizeof (DevMode); 50 DevMode.dmFields = DM_DISPLAYORIENTATION; 51 if (DISP_CHANGE_SUCCESSFUL == ChangeDisplaySettingsEx(NULL, &DevMode, NULL, CDS_TEST, NULL)) 52 { 53 g_CurrentAngle = DevMode.dmDisplayOrientation; 54 } 55 else 56 { 57 OutputDebugString(L"MOSQUITO: Unable to read current rotation. Rotation disabled."); 58 g_CurrentAngle = -1; 59 } 60 61 // Set up and register window class. 62 ...... 63 64 // Create the main DirectDraw object 65 hRet = DirectDrawCreate(NULL, &g_pDD, NULL); 66 if(hRet != DD_OK) 67 return InitFail(hWnd, hRet, TEXT("DirectDrawCreate FAILED")); 68 69 // Get normal mode. 70 hRet = g_pDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL); 71 if (hRet != DD_OK) 72 return InitFail(hWnd, hRet, TEXT("SetCooperativeLevel FAILED")); 73 74 // Get a primary surface interface pointer (only needed for init.) 75 memset(&ddsd, 0, sizeof(ddsd)); 76 ddsd.dwSize = sizeof(ddsd); 77 ddsd.dwFlags = DDSD_CAPS; 78 ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; 79 hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSPrimary, NULL); 80 if (hRet != DD_OK) 81 return InitFail(hWnd, hRet, TEXT("CreateSurface FAILED")); 82 83 // See if we can support overlays. 84 memset(&ddcaps, 0, sizeof(ddcaps)); 85 ddcaps.dwSize = sizeof(ddcaps); 86 hRet = g_pDD->GetCaps(&ddcaps, NULL); 87 if (hRet != DD_OK) 88 return InitFail(hWnd, hRet, TEXT("GetCaps FAILED")); 89 90 if (ddcaps.dwOverlayCaps == 0) 91 return InitFail(hWnd, hRet, TEXT("Overlays are not supported in hardware!")); 92 /* // Leo.Zheng Add 93 if(!(capsDrv.dwCaps & DDCAPS_OVERLAY)) 94 return FALSE; 95 */ 96 97 // Get alignment info to compute our overlay surface size. 98 rs.left = 0; 99 rs.top = 0; 100 rs.right = BUG_WIDTH; 101 rs.bottom = BUG_HEIGHT; 102 if (ddcaps.dwAlignSizeSrc != 0) 103 rs.right += rs.right % ddcaps.dwAlignSizeSrc; 104 105 // Create the overlay flipping surface. We will attempt the pixel formats 106 // in our table one at a time until we find one that jives. 107 int i = 0; 108 memset(&ddsd, 0, sizeof(ddsd)); 109 ddsd.dwSize = sizeof(ddsd); 110 ddsd.ddsCaps.dwCaps = DDSCAPS_OVERLAY | DDSCAPS_FLIP; 111 ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_BACKBUFFERCOUNT | DDSD_PIXELFORMAT; 112 ddsd.dwWidth = rs.right; 113 ddsd.dwHeight = rs.bottom; 114 ddsd.dwBackBufferCount = 1; 115 do 116 { // Leo.Zheng MStar 2521 只创建 16-bit RGB 5:6:5 成功; 创建 16-bit RGB 5:5:5 失败. 117 ddsd.ddpfPixelFormat = ddpfOverlayFormats[i]; 118 hRet = g_pDD->CreateSurface(&ddsd, &g_pDDSOverlay, NULL); // Leo.Zheng 此处调用后引起使用 IOCtrl 显示在 LCD 上的消失 119 RETAILMSG(1,(L"[mosquito]Create No.%d surface return: 0x%X ",i + 1,hRet)); 120 }while(hRet != DD_OK && (++i < PF_TABLE_SIZE)); 121 if(hRet != DD_OK) 122 return InitFail(hWnd, hRet, TEXT("Unable to create overlay surface!")); 123 124 // Load the images. 125 if (LoadBugImages() != DD_OK) 126 return InitFail(hWnd, hRet, TEXT("Unable to load images to overlay surface!")); 127 128 // Finish setting up the overlay. 129 int StretchFactor1000 = ddcaps.dwMinOverlayStretch > 1000 ? ddcaps.dwMinOverlayStretch : 1000; 130 131 rd.left=0; 132 rd.top=0; 133 // Adding 999 takes care of integer truncation problems. 134 rd.right = (rs.right * StretchFactor1000 + 999) / 1000; 135 rd.bottom = rs.bottom * StretchFactor1000 / 1000; 136 if (ddcaps.dwAlignSizeDest != 0) 137 rd.right = (int)((rd.right + ddcaps.dwAlignSizeDest - 1)/ ddcaps.dwAlignSizeDest) * ddcaps.dwAlignSizeDest; 138 139 // Set the flags we'll send to UpdateOverlay 140 dwUpdateFlags = DDOVER_SHOW; 141 // dwUpdateFlags = DDOVER_SHOW | DDOVER_DDFX; // Leo.Zheng DDOVER_DDFX WinCE 不支持 142 143 // Does the overlay hardware support source color keying? 144 // If so, we can hide the black background around the image. 145 // This probably won't work with YUV formats 146 memset(&ovfx, 0, sizeof(ovfx)); 147 ovfx.dwSize = sizeof(ovfx); 148 if (ddcaps.dwOverlayCaps & DDOVERLAYCAPS_CKEYSRC) // MStar2521 不支持 color key 149 { 150 dwUpdateFlags |= DDOVER_KEYSRCOVERRIDE; 151 152 // Create an overlay FX structure so we can specify a source color key. 153 // This information is ignored if the DDOVER_SRCKEYOVERRIDE flag 154 // isn't set. 155 ovfx.dckSrcColorkey.dwColorSpaceLowValue=0; // black as the color key 156 ovfx.dckSrcColorkey.dwColorSpaceHighValue=0; 157 } 158 else 159 { 160 RETAILMSG(1,(L"[mosquito]cannot support color key: 0x%X(0x%x) ",ddcaps.dwOverlayCaps,DDOVERLAYCAPS_CKEYSRC)); 161 } 162 163 // Update the overlay parameters. 164 hRet = g_pDDSOverlay->UpdateOverlay(&rs, g_pDDSPrimary, &rd, dwUpdateFlags, &ovfx); 165 if (hRet != DD_OK) 166 { 167 // 在 MStar 2521 设备上运行第二个此程序实例时出错。 168 // 在 TeleChips 8902 设备上运行第三个此程序实例时出错。 169 return InitFail(hWnd, hRet, TEXT("Unable to show overlay surface: 0x%x!"),hRet); 170 } 171 172 // Set a bunch of position and velocity module vars. 173 g_nOverlayXPos = 0; 174 g_nOverlayYPos = 0; 175 g_nOverlayXVel = RANDOM_VELOCITY(); 176 g_nOverlayYVel = RANDOM_VELOCITY(); 177 g_nOverlayWidth = rd.right - rd.left; 178 g_nOverlayHeight = rd.bottom - rd.top; 179 180 // Set the "destination position alignment" global so we won't have to 181 // keep calling GetCaps() everytime we move the overlay surface. 182 g_dwOverlayXPositionAlignment = ddcaps.dwAlignBoundaryDest; 183 184 // Create a timer to flip the pages. 185 if (TIMER_ID != SetTimer(hWnd, TIMER_ID, TIMER_RATE, NULL)) 186 return InitFail(hWnd, hRet, TEXT("SetTimer FAILED")); 187 188 return DD_OK; 189 }