宁静以致远
zgf的blog
<2010年3月>
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910

留言簿(17)

随笔分类

随笔档案

文章档案

友情链接

资料收藏

搜索

最新评论

阅读排行榜

评论排行榜

 
VC知识库BLOG   首页  新随笔  联系  聚合  登录 
  随笔-37 文章-8 评论-121 Trackbacks-0
2009年12月21日
        播放的过程一般是:读取码流、解码,显示格式转换,显示。其中“显示格式转换”是指YUV到RGB的转换。因为大部分解码器输出的格式是YV12格式的,而framebuf的格式是RGB格式的。“显示格式转换”虽然过程简单,却极耗时间。在200M Hz的arm cpu上单解352x288的mpeg4视频,能达到24fps。如果转换成RGB输出就只有12fps多一点了。幸运的是一般嵌入式cpu显示部分都有单独的video层,可以直接接收yuv数据。这样可以去掉“显示格式转换”步骤,性能直接提升一倍。不幸的是我用的芯片的video层格式只支持yuv422打包格式。写到这我再一次忍不住bs  n下中星微。同样是用arm核做cpu,怎么就比别人差一大截呢。其实只要稍微用点心就可以做好的事。
发表于 2009-12-21 13:20 zgf的blog 阅读(1055) | 评论 (1)编辑 收藏
2009年12月18日
今天安装PB6后创建一个ce6的项目,结果点击完成后又弹回创建窗口,在任务栏显示项目创建失败。
在网上搜索大部分都是说IE7的安全导致的。vs2005 sp1已修正了这个问题。可是我既没装IE7,也安装了
SP1补丁。找了好久,终于发现了一个方法:
运行
x:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.exe /ResetSkipPkgs
然后再新建项目
发表于 2009-12-18 18:12 zgf的blog 阅读(583) | 评论 (0)编辑 收藏
2009年11月7日
    按上一篇文章的步骤,原本以为已编译完成。谁知在生成安装包的时候出问题了。

1.  安装NSIS,这是个制作安装包的编译器。我用的是2.45汉化版。
2.  用NSIS打开trunk\bin\distrib下的ffdshow.nsi文件,然后编译。这时NSIS提示找不到libavcodec.dll文件
3.  原来还少了几个工程。用vs2005继续编译以下几个工程。
ffdshow\src\ffmpeg\libavcodec.vcproj
ffdshow\src\mplayer\libmplayer_dll.vcproj
ffdshow\src\codecs\x264\ff_x264.vcproj
ffdshow\src\codecs\libmpeg2\libmpeg2_ff.vcproj
4. 再执行步骤2,应该可以生成ffdshow的安装包。


    至此ffdshow编译完全了。参考ffdshow.nsi文件,完全可以将ffshow的安装集成到自己的程序中。也就是说,只要加上UI就可以很容易做出个像暴风那样的播放器了。
发表于 2009-11-07 20:32 zgf的blog 阅读(773) | 评论 (1)编辑 收藏
 

1. 用TortoiseSVN从 https://ffdshow.svn.sourceforge.net/svnroot/ffdshow下载最新的ddshow源代码
2. 安装好direct2008sdk,包括编译baseclass和添加到vs2005的库包含路径
3. 下载nasm-2.07-win32.zip,解压后将nasm.exe复制到vsvs2005安装目录下的vc\bin目录下。例如,我机器的目录是E:\Program Files\Microsoft Visual Studio 8\VC\bin。
  并改名为nasmw.exe

4. 打开ffdshow_2005.sln,点生成解决方案。
5. 这时会遇到链接不到dinput.lib库的错误。在ffdshow项目上右键,选择属性,将链接库中的dinput.lib改为dinput8.lib
6. 修改如下代码
    1)搜索DIRECTINPUT_VERSION,将#define DIRECTINPUT_VERSION 0x0300
改为#define DIRECTINPUT_VERSION 0x0800
    2)将TkeyboardDirect.h中的
struct IDirectInput;
struct IDirectInputDevice;
改为:
struct IDirectInput8;
struct IDirectInputDevice8;
     3) 将TkeyboardDirect.h中的
 IDirectInput *di;
 IDirectInputDevice *did;
改为:
 IDirectInput8 *di;
 IDirectInputDevice8 *did;
     4)将TkeyboardDirect.cpp中的
DirectInputCreate(0,DIRECTINPUT_VERSION,&di,NULL);if (!di) return;
改为
 DirectInput8Create(0,DIRECTINPUT_VERSION,IID_IDirectInput8,(void**)&di,NULL);if (!di) return;
7. 再重新生成解决方案。应该可以成功了

发表于 2009-11-07 08:30 zgf的blog 阅读(777) | 评论 (0)编辑 收藏
2009年3月12日
     前几天同事用sf上的一个网络类库写了个服务器。一测试发现性能很差。最多每秒才能处理500次请求,并且是在网络很好的情况下,隔两个交换机后客户端就只能收到200次/秒的正确响应了。同事忙着做其它事,改进服务器的任务就交给我了。
     项目中客户端的请求仅是有20bytes的数据,并且只有一小部分需要服务器回复500bytes左右的数据。综合考虑各种网络模型后我决得IOCP模型更适合当前的应用。
     IOCP模型的使用方法很多资料都有。《windows网络编程》(第二版)讲得很好。随书光盘中有使用IOCP模型的简单但很好的例子。我的服务器程序写完时还没看到这个示例,正被其它示例代码里的锁弄的晕头转向。当看到这个示例后发现那些锁都是多余的。剩下的代码基本上差不多。

     有点不同的是PER_IO_DATA的处理上。所有的例子在往完成端口投递请求时都先分配了一个PER_IO_DATA,请求处理后马上释放。考虑到我的应用中所有请求全部是短连接,并且数据量很小,我觉得分配和释放是浪费的。每个PER_IO_DATA对应一个socket,当socket关闭后这个PER_IO_DATA不必释放,而是用来准备接受下一个连接socket。
     下面是我写的工作线程代码:
DWORD WINAPI ServerWorkerThread(LPVOID lpparam)
{
    CIocpServer 
* pServer = (CIocpServer*)lpparam;
    DWORD BytesTransferred;
    SOCKET socket;
    LPPER_IO_OPERATION_DATA PerIoData;
    BOOL close_socket 
= FALSE;
    
int ret;
    
while(pServer->bRun)
    
{
        ret 
= GetQueuedCompletionStatus(pServer->CompletionPort, &BytesTransferred,
            (LPDWORD)
&socket, (LPOVERLAPPED *&PerIoData, INFINITE);
        
if (ret == ERROR_SUCCESS)
        
{
            DWORD last_error 
= GetLastError();
            
if(last_error == ERROR_SUCCESS)
                
return 0;                //完成端口被关闭,退出
            if(ERROR_NETNAME_DELETED == last_error   
                
|| ERROR_OPERATION_ABORTED == last_error)
                close_socket 
= TRUE;    //socket被关闭 或者 操作被取消
            else
                
continue;
        }


        
if (BytesTransferred == 0)
        
{
            
if(socket == 0 && PerIoData == 0)
                
break;

            closesocket(PerIoData
->socket);

            pServer
->Accept(PerIoData);

            
continue;
        }


        
if(PerIoData->eType == IO_EVENT_ACCEPT)
        
{
            setsockopt(PerIoData
->socket,SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char*)&(pServer->m_server), sizeof(pServer->m_server) ) ;

            
if(CreateIoCompletionPort((HANDLE) PerIoData->socket, pServer->CompletionPort, (DWORD) PerIoData->socket,0== NULL)
                printf(
"CreateIoCompletionPort error:%d ", GetLastError());

            ret 
= pServer->Recv(PerIoData,BytesTransferred);
        }

        
else if(PerIoData->eType == IO_EVENT_WSARECV)
        
{
            ret 
= pServer->Recv(PerIoData,BytesTransferred);
        }

        
else if(PerIoData->eType == IO_EVENT_WSASEND)
        
{
            ret 
= pServer->Send(PerIoData,BytesTransferred);
        }


        
if(ret == FALSE)
        
{
            closesocket(PerIoData
->socket);
            pServer
->Accept(PerIoData);

        }

    }


    
return 0;
}


      可以看到,每个AccepteEx接入的客户端连接对应着一个PER_IO_DATA,并伴随着该连接的整个生命周期。当连接结束后,PER_IO_DATA马上又通过投递AccepteEx准备下一个连接。这样可以避免平凡的分配和释放内存。
发表于 2009-03-12 00:01 zgf的blog 阅读(2181) | 评论 (4)编辑 收藏
2009年3月11日

        服务器在1G内存,奔腾E2140(双核 1.6G),windows xp系统的机器上每秒能处理1万次左右的TCP短连接请求。网络流量为20M/s 。CPU占用率80-90% 。以前没专门做过服务器软件,也不知道性能怎么样。
        下面是客户端测试线程代码。每个客户端跑200个线程,共运行了两个测试客户端。

while(1)
{
if (!(sock.Connect("192.168.1.8",SYNC_PORT)))
{
    nMsgError++;
    MySleep(100);
    continue;
}

dwRet = sock.Send((char *)&syncmsg, sizeof(MsgUpdateSync_T));
if (dwRet < 0)
{
  MySleep(100);
  nDownloadError++;
  wprintf(L"Send Update Sync Msg Failed ");
  sock.Disconnect();
  continue;
}

else
{ 
  nOk++;
  sock.Disconnect();
  continue;
}

}

          实际运行时每个客户成功的请求大约5000次/秒,失败的大约100次/秒。   服务端内存消耗4M。
发表于 2009-03-11 22:39 zgf的blog 阅读(2565) | 评论 (4)编辑 收藏
2008年9月27日
vmware文件可以到http://www.namipan.com/downfile/cepc.rar/84f4653dda89d02ef820fa11da631450e29a0f639e468100下载。
里面有做好的wince6系统。支持网络和U盘。光驱的支持懒得去修改了。
bsp就不上传了。因为更本就是cepc。
就是说用cepc的bsp可以直接编译出vmware能跑的nk.bin。 但网络,U盘和光驱都都有问题。需要参考
如何制作支持VMWare的Windows CE BSP》文章做修改。

顺便上传一张浏览网页的截图:
发表于 2008-09-27 08:50 zgf的blog 阅读(1329) | 评论 (0)编辑 收藏
2008年9月20日

    前几天还特意找wince下读写ini文件的函数,却意外的在ce的源代码中发现了。有需要的可以参考一下


//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//

#include "iniutil.h"


BOOL ReadIni(LPCWSTR pwszSection, LPCWSTR pwszKey, LPWSTR pwszValue, size_t cchValue, LPCWSTR pwszIniFile)
{
   // GetPrivateProfileString is unavailable on CE

   BOOL bSuccess = FALSE;
   FILE * fin;
   WCHAR wszLine[256];
   LPWSTR pwsz = NULL;

   if (!pwszIniFile ||
      !pwszSection ||
      !pwszKey ||
      !pwszValue ||
      !cchValue)
   {
      goto leave;
   }

   fin = _wfopen(pwszIniFile, L"r");
   if (fin)
   {
      while (fgetws(wszLine, lengthof(wszLine), fin))
      {
         if (!wcsstr(wszLine, pwszSection)) // Section
         {
            continue;
         }

         while (fgetws(wszLine, lengthof(wszLine), fin)) // Key & Value
         {
            pwsz = wcschr(wszLine, L'=');
            if (!pwsz)
            {
               continue;
            }

            *pwsz = L'\0'; // Erase the '='

            if (0 != _wcsicmp(wszLine, pwszKey)) // Key
            {
               continue;
            }

            pwsz++; // Point to the value

            bSuccess = SUCCEEDED(StringCchCopyEx(
                                    pwszValue,
                                    cchValue,
                                    pwsz,
                                    &pwsz,
                                    NULL,
                                    0
                                    ));

            if (bSuccess)
            {
               if (*--pwsz == L'\n')
               {
                  *pwsz = L'\0';
               }
            }
         }
      }

      fclose(fin);
   }

leave:
   return bSuccess;
}


BOOL WriteIni(LPCWSTR pwszSection, LPCWSTR pwszKey, LPWSTR pwszValue, size_t cchValue, LPCWSTR pwszIniFile)
{
   // WritePrivateProfileString is unavailable on CE

   BOOL bSuccess = FALSE;
   BOOL bReplace;
   FILE * fin;
   fpos_t posSrc;
   fpos_t posDest;
   size_t cchLine;
   size_t cchNewLine;
   WCHAR wszLine[256];
   WCHAR wszNewLine[256];
   LPWSTR pwsz = NULL;
   DWORD dwAttrib;

   if (!pwszIniFile ||
      !pwszSection ||
      !pwszKey ||
      (!pwszValue && cchValue) ||
      (cchValue >= lengthof(wszLine)))
   {
      goto leave;
   }

   dwAttrib = GetFileAttributes(pwszIniFile);
   if (dwAttrib == -1)
   {
      goto leave;
   }

   SetFileAttributes(pwszIniFile, dwAttrib & ~FILE_ATTRIBUTE_READONLY);

   fin = _wfopen(pwszIniFile, L"r+");
   if (fin)
   {
      bReplace = FALSE;
      cchNewLine = 0;

      while (fgetws(wszLine, lengthof(wszLine), fin))
      {
         if (!wcsstr(wszLine, pwszSection)) // Section
            continue;

         if (fgetpos(fin, &posSrc) || fgetpos(fin, &posDest))
         {
            goto closeFile;
         }

         while (fgetws(wszLine, lengthof(wszLine), fin)) // Key & Value
         {
            cchLine = wcslen(wszLine);

            pwsz = wcschr(wszLine, L'=');
            if (!pwsz)
            {
               goto nextLine;
            }

            *pwsz = L'\0'; // Erase the '='

            if (0 != _wcsicmp(wszLine, pwszKey)) // Key
            {
               *pwsz = L'='; // Add the '=' back
               goto nextLine;
            }

            *pwsz = L'='; // Add the '=' back
            pwsz++; // Point to the value

            // Clear Key & Value on NULL or empty string
            if (!pwszValue || !cchValue)
            {
               bReplace = TRUE;
               cchLine = 0;
               goto nextLine;
            }

            // Do not overwritte more than the number of read characters.
            size_t cchKey = (pwsz - wszLine);
            if (SUCCEEDED(StringCchCopyNEx(
                                    wszNewLine,
                                    lengthof(wszNewLine),
                                    wszLine,
                                    cchKey,
                                    &pwsz,
                                    &cchNewLine,
                                    0
                                    )) &&
               SUCCEEDED(StringCchCopyNEx(
                                    pwsz,
                                    cchNewLine,
                                    pwszValue,
                                    min((cchLine - cchKey), cchValue),
                                    &pwsz,
                                    &cchNewLine,
                                    STRSAFE_IGNORE_NULLS
                                    )))
            {
               bReplace = TRUE;

               BOOL bAppendNewLine = FALSE;
               if (wszLine[cchLine-1] == L'\n')
               {
                  cchLine--;
                  bAppendNewLine = TRUE;
               }

               // See if there are remaining characters to copy
               if (cchValue > (cchLine - cchKey))
               {
                  if (bAppendNewLine)
                  {
                     cchLine++;
                  }

                  pwszValue += (cchLine - cchKey);
                  if (FAILED(StringCchCopyNEx(
                                       wszLine,
                                       lengthof(wszLine),
                                       pwszValue,
                                       (cchValue - (cchLine - cchKey)),
                                       &pwsz,
                                       &cchLine,
                                       0
                                       )) ||
                     (bAppendNewLine &&
                     FAILED(StringCchCopy(pwsz, cchLine, L"\n"))) ||
                     FAILED(StringCchLength(wszLine, lengthof(wszLine), &cchLine)))
                  {
                     bReplace = FALSE;
                  }
               }
               else
               {
                  if (bAppendNewLine &&
                     FAILED(StringCchCopy(pwsz, cchNewLine, L"\n")))
                  {
                    bReplace = FALSE;
                  }
                  cchLine = 0;
               }

               if (FAILED(StringCchLength(wszNewLine, lengthof(wszNewLine), &cchNewLine)))
               {
                  bReplace = FALSE;
               }
            }

nextLine:
            if (bReplace)
            {
               BOOL bEOF = (BOOL)feof(fin);

               // Save read offset, then restore write offset
               if (fgetpos(fin, &posSrc) || fsetpos(fin, &posDest))
               {
                  goto closeFile;
               }

               if (cchNewLine)
               {
                  bSuccess = (WEOF != fputws(wszNewLine, fin));
                  if (cchLine &&
                     SUCCEEDED(StringCchCopyN(
                                          wszNewLine,
                                          lengthof(wszLine),
                                          wszLine,
                                          cchLine
                                          )))
                  {
                     cchNewLine = cchLine;
                  }
                  else
                  {
                     cchNewLine = 0;
                  }
               }
               else if (cchLine)
               {
                  bSuccess = (WEOF != fputws(wszLine, fin));
                  cchLine = 0;
               }

               // Save write offset, then restore read offset
               if (fgetpos(fin, &posDest) ||
                  bEOF ||
                  fsetpos(fin, &posSrc))
               {
                  goto closeFile;
               }
            }
            else
            {
               // Just update read and write offsets
               if (fgetpos(fin, &posSrc) || fgetpos(fin, &posDest))
               {
                  goto closeFile;
               }
            }
         }
      }

closeFile:
      if (bReplace && !fsetpos(fin, &posDest))
      {
         if (cchNewLine)
         {
            bSuccess = (WEOF != fputws(wszNewLine, fin));
         }
         SetEndOfFile(_fileno(fin));
      }

      fclose(fin);
   }

   SetFileAttributes(pwszIniFile, dwAttrib);

leave:
   return bSuccess;
}

发表于 2008-09-20 14:41 zgf的blog 阅读(3804) | 评论 (8)编辑 收藏
2008年8月26日
        网上有wince5版本的cepc。我参考他的过程做了个ce6.0版本的。
发表于 2008-08-26 07:06 zgf的blog 阅读(3181) | 评论 (6)编辑 收藏
2008年7月14日

        本来不想用ttf字体的。因为变态的硬件工程师只接了4M Bytes的nor flash。除去系统和驱动,给应用程序剩下的空间只有2M。这年头2M的flash够干嘛呀!  但新的客户要求程序更花哨,更漂亮,添加了很多效果。其中不同大小的字就有几种。如果用点阵字库,一种字体也需要创建多种字库。而客户给的汉仪菱心体ttf字库才1.5M bytes。综合比较觉得使用ttf字体在存储空间上会划算一些。 参照http://www.minigui.org/cgi-bin/lb5000/topic.cgi?forum=6&topic=5548帖子的步骤终于添加了ttf的支持。步骤如下

1 . 安装freetype-1.3.1库
      手动编译成动态库后 编译minigui程序总是报错误error: no memory region specified for loadable section `.plt'  。 我只好编译成静态库libttf.a。将库拷贝到编译器的连接库目录。在编译器的inlcude目录下创建freetype1目录。并将头文件拷贝到该目录下。

2. 启用ttf
     可以按常规make menuconfig中启用。我直接修改config.h文件,找到#undef  _TTF_SUPPORT, 改为#define _TTF_SUPPORT 1 ,找到#undef  _UNICODE_SUPPORT, 改为#define _UNICODE_SUPPORT 1 。 然后make install编译minigui库

3. MiniGUI.cfg文件修改
     将arial.ttf和stxinwei.ttf 拷贝到设备的/uar/local/lib/minigui/res/fonts目录下。
    truetypefonts改为
[truetypefonts]
font_number=2
name0=ttf-arial-rrncnn-0-0-ISO8859-1
fontfile0=/usr/local/lib/minigui/res/font/arial.ttf
name1=ttf-stxinwei-rrncnn-0-0-GB2312
fontfile1=/usr/local/lib/minigui/res/font/stxinwei.ttf

4. 应用程序编写

    HWND hwnd;
    HDC hdc;
    HWND timeedit, spin;
    SIZE size;
    
    /* 创建编辑框使用的逻辑字体 */
    timefont = CreateLogFont ("ttf", "stxinwei", "GB2312",
    FONT_WEIGHT_REGULAR, FONT_SLANT_ROMAN, FONT_SETWIDTH_NORMAL,
    FONT_SPACING_CHARCELL, FONT_UNDERLINE_NONE, FONT_STRUCKOUT_NONE,
    30, 0);

    spin = CreateWindow (CTRL_SLEDIT,
    "nihao?",
    WS_VISIBLE,
    10241,
    0, 250, 400, 200, hWnd, 0);  

    SetWindowFont (spin, timefont); 


    注意CreateLogFont 创建的字体大小好像不能超过32。超过后显示汉字会异常。还没有查原因。英文则可以更大。另外不知是不是库的问题,我的应用程序在不使用ttf库前,9M的空闲内存可以跑好几次。而使用ttf库后,仅仅连接了ttf库,跑一次都经常内存不够。也不知道什么原因。




发表于 2008-07-14 21:24 zgf的blog 阅读(3441) | 评论 (2)编辑 收藏