jiangsheng

http://www.csdn.net/develop/author/netauthor/jiangsheng/
随笔 - 142, 评论 - 629, 引用 - 27

导航

关于

 
这下要维护3个BLOG了,faint 其他的地址:

所有的文章版权归原文作者所有,任何人需要转载文章,必须征得原文作者授权。
我的MVP配置

标签

每月存档

最新留言

广告

最近CSDN上的留言似乎都是这种形式

help?
http://expert.csdn.net/Expert/topic/???????????.xml

thank?you

这种形式

真是言简意赅啊

posted on 2003-10-29 14:55:00 by jiangsheng  评论(6) 阅读(1801)

沉痛悼念国姨宋美龄女士

看了看以前的新闻,发现关于宋美龄的屈指可数……现在才开始地毯式报道,谈论她爱不爱国,访问传记作者……

?

posted on 2003-10-25 12:48:00 by jiangsheng  评论(0) 阅读(1476)

今天把录制asf演示程序写完了……

在播放有多路视频的媒体的时候,Windows Media Player控件居然会弹出一个无法控制的窗口播放第二路视频。有人知道怎么用脚本控制Windows Media Player的这个窗口么?

http://jiangsheng.vicp.net/mydoc/HTMLPage1.htm

现在还有两个问题,一个是在CPU忙的时候声音变调和断续,另外一个是视频采集设备有时候启动超时。

posted on 2003-10-24 17:43:00 by jiangsheng  评论(4) 阅读(2389)

写篇文章真累

http://www.csdn.net/develop/read_article.asp?id=21702

最近这篇文章长长短短,写了两个礼拜吧。
写这篇文章的主要原因是想把网页分析做得更加灵活。这篇文章的基础是我以前为一个EBS游戏写的外挂,可以自动修改网页内容(主要是表单)和定时submit表单(有的网站的submit有时间限制)。以前的代码是用VC来写的,和网页的修改同步很不方便。很多功能,例如表单的自动填写和递交依赖于表单的结构,网页结构一变的话,就需要重新编译代码。所以这次重写的时候(那个EBS又改版了),想考虑做成类似于Outlook的邮件规则。但是在编写的时候,发现这样的规则编写起来实在是太繁琐了。其实这些规则用VB来写脚本的话,可能就几句话,例如判断浏览完成之后判断URL,自动填写和递交表单。

这是我使用VBS的原因。在程序中集成脚本解释器之后,网站改版的时候改脚本就可以了,虽然使用门槛要高些(要会编写脚本)。

主要碰见的技术问题是
脚本中的浏览器的事件处理代码不能执行(CHtmlView捕获了事件,所以要在CHtmlView里面转发事件)
移植MFCIE的代码到MDI的时候的菜单出现很多问题,主要是MDI的菜单替换,以及插入MDI系统菜单之后收藏夹的位置变化

移植部分MFC7的代码到MFC6,中间还结合了一大堆修复MFC6BUG的代码,真是faint
无法直接创建支持事件的CCmdTaget类(ActiveX好像可以……)
MFC的类向导不支持自动化中的默认参数
上面两个问题使得我不得不手动改ODL文件,结果造成无数问题……ODL还是能不改就不改吧
关闭窗口时出现非法操作(最后捕获了WindowClosing事件,Cancel掉了系统的处理之后自己关闭)
调用IE的表单的自动完成的时候,没做成功。好像和隐藏方法IShellUIHelper::AutoCompleteAttatch有关。
编辑网页源代码时文档结构的刷新有问题,被编辑的节点的Child集合在SetOutHTML之后长度变成0了,最后是刷新整个文档结构树才解决。IE的BUG?

posted on 2003-10-23 20:00:00 by jiangsheng  评论(4) 阅读(5312)

RGB16->RGB24

Jiangsheng wrote:

How to convert RGB565 to RGB24?
my conversion seems wrong

void  CScreenInput::CopyRGBPixels(DDSURFACEDESC* psdSrc,LPBYTE lpSrc,LPBYTE
lpDest,BOOL bInvert)
{
/*
*/
 DDPIXELFORMAT& rpfSrc=psdSrc->ddpfPixelFormat;

 DWORD dwHeight=psdSrc->dwHeight;
 DWORD dwWidth=psdSrc->dwWidth;

 long lPitchSrc=bInvert?-psdSrc->lPitch吐舌笑脸sdSrc->lPitch;
 long lPitchTgt=dwWidth*3;
 LPBYTE lpStart=bInvert?lpSrc+psdSrc->lPitch*(psdSrc->dwHeight-1):lpSrc;

 LPBYTE lpSrcLine=lpStart;
 LPBYTE lpTgtLine=lpDest;
 LPBYTE lpSrcPos;
 LPBYTE lpTgtPos;
 DWORD i,j;


 switch(rpfSrc.dwRGBBitCount){
 case 16:
  for(i = 0; i < dwHeight; i++) {
   lpSrcPos=lpSrcLine;
   lpTgtPos=lpTgtLine;
   for(j = 0; j < dwWidth; j++) {
    WORD wPixel=*(WORD*)lpSrcPos;
    *lpTgtPos=(wPixel&0xF800)/256;lpTgtPos++;//0x10000/0x800
    *lpTgtPos=(wPixel&0x07E0)/8;lpTgtPos++;//0x800/0x100
    *lpTgtPos=(wPixel&0x001F)*8;lpTgtPos++;//0x100/0x20
    lpSrcPos+=2;
   }
   lpSrcLine+=lPitchSrc;
   lpTgtLine+=lPitchTgt;
  }
  break;

Jan Michalowsky wrote:
Hi I can give u my translation part from 16bpp to 24bpp

if (th.BPP = 16) {

char *pTempData;
unsigned short a;

pTempData = new char[ImageSize];
memmove(pTempData, pImageData, ImageSize);
ImageSize = nWidth * nHeight * 3;

delete [] pImageData;
pImageData = new char[ImageSize];

for (i = 0; i < (ImageSize / 3); i++) {
a = (pTempData[i*2+1] << 8) |
(pTempData[i*2]);
pImageData[i*3]    = (char)
(((0x7C00 & a) >> 10) * (256 / (1 << 5)));
pImageData[i*3+1]  = (char)
(((0x03E0 & a) >> 5) * (256 / (1 << 5)));
pImageData[i*3+2]  = (char)((
0x001F & a) * (256 / (1 << 5)));
}

delete [] pTempData;
}

i don't know whether it is correct, but it seems so 眨眼笑脸


John Hornick [MSFT] wrote

Hi,

It looks like you're getting the right bits using the masks, but I'm not so
sure you're moving them to the right location.

When you AND with 0xf800 you will get only the 5 bits of R value, right?
Then you need to shift to the right 11 places before you can assign that to
the R byte in the 24bpp color. Similarly, once you get the 6 bits of G
value, you'll need to shift it to the right by 5 places before assigning
that value to the G part of the 24bpp color.

Thanks,
- John
Microsoft Developer Support
This posting is provided "AS IS" with no warranties, and confers no rights.
Visit http://www.microsoft.com/security for current information on security.

johan m錼tensson  wrote

>John Hornick [MSFT] wrote:

> Hi,
>
> It looks like you're getting the right bits using the masks, but I'm not so
> sure you're moving them to the right location.
>
> When you AND with 0xf800 you will get only the 5 bits of R value, right?
> Then you need to shift to the right 11 places before you can assign that to
> the R byte in the 24bpp color. Similarly, once you get the 6 bits of G
> value, you'll need to shift it to the right by 5 places before assigning
> that value to the G part of the 24bpp color.

Division by 256, div by 8 and mult by 8 transforms each of the colours
in 16 bit mode to (1111 1000), and since he assigns one byte at the time
for each colour, 3 consecutive bytes, 24 bits, will have been filled out
for each 2 bytes read. So as it seems to me, the bit shifting becomes
implicit: SHL 16 for red, SHL 8 for green and no shift for blue. End
result for white colour being:
1111 1000 1111 1000 1111 1000
   F   8    F   8      F   8

This seems like a decent result to me. You say "the conversion seems
wrong". In what way?
One thing you might want to change is the hard coded bitmasks. Jus
because you have 16 bpp doesn't mean you have RGB 565. It could also be
RGB 555. Also, some cards don't use RGB, but rather BGR. This doesn't
matter in this case, but it's good to keep in mind not all hardware
behave the way you might expect.
In these lines:
*lpTgtPos=(wPixel&0xF800)/256;lpTgtPos++;// this could actually be blue
*lpTgtPos=(wPixel&0x07E0)/8;lpTgtPos++;
*lpTgtPos=(wPixel&0x001F)*8;lpTgtPos++;//and this could be red
change the parenthezised parts to:
(wPixel & rpfSrc->ddpfPixelFormat.dwRBitMask)
(wPixel & rpfSrc->ddpfPixelFormat.dwGBitMask)
(wPixel & rpfSrc->ddpfPixelFormat.dwBBitmask)
RGB555 pixel bitmasks:
Red:   0111 1100 0000 0000
Green: 0000 0011 1110 0000
Blue:  0000 0000 0001 1111

In the case of RGB555, blue would have a highest maximum value, then red
and green would have the lowest max. The whole idea about using RGB565
is that the human eye is more sensitive to green, so not only does your
computation yield the wrong result in this case, but the net effect is
enhanced by how the eye works.
For RGB555 your computation would yield:
Red:   0111 1100 0000 0000:
          7   C    0    0
        (28672+3072=31744)/256 = 124
                  0111 1100
                    7    C

Green: 0000 0011 1110 0000:
          0    3   D     0
             (768 + 208=976)/8 = 122
                  0111 1010
                    7    A

Blue:  0000 0000 0001 1111:
                    1    F
                  1111 1000
                    F    8
--------------------------
24 bit result
0111 1100 0111 1010 111 1000
<  RED  > < GREEN > < BLUE  >


Finally the following line:
   long lPitchTgt=dwWidth*3;
assumes that pitch is (<number of pixels> * <pixels> / 8) bytes. This is
not true for all cards as some align memory a bit different. Therefore
grab pitch for an appropriate display mode (enumerate display modes or
something) and then do
long lPitchTgt = lpddsdTwoFour->lPitch;

Hopes this helps
johan
> In the case of RGB555, blue would have a highest maximum value, then red
> and green would have the lowest max. The whole idea about using RGB565
> is that the human eye is more sensitive to green, so not only does your
> computation yield the wrong result in this case, but the net effect is

Relized I only pointed out a possible problem without giving a solution.
You could change these lines:
*lpTgtPos=(wPixel&0xF800)/256;lpTgtPos++;// this could actually be blue
*lpTgtPos=(wPixel&0x07E0)/8;lpTgtPos++;
*lpTgtPos=(wPixel&0x001F)*8;lpTgtPos++;//and this could be red

into these:
// these DWORDS are just to enhance code reading
// as you could grab the values via pointers
// each time
DWORD RBM, GBM, BBM;
RBM = rpfSrc->ddpfPixelFormat.dwRBitMask;
GBM = rpfSrc->ddpfPixelFormat.dwGBitMask
BBM = rpfSrc->ddpfPixelFormat.dwBBitmask

// Multiply by max value (bit mask) for wanted bit depth
// 255 in the case of 24 bpp. Divide by current bitmask
*lpTgtPos=((wPixel & RBM) * 255) / RBM; lpTgtPos++;
*lpTgtPos=((wPixel & GBM) * 255) / GBM; lpTgtPos++;
*lpTgtPos=((wPixel & BBM) * 255) / BBM; lpTgtPos++;

I've heard that multiplication with 256 might yield erroneous results at
least when converting from 24 to 16 bpp. I've not tested this out
myself, but intuition tells me you could change one of the above lines to:
*lpTgtPos=( ( (wPixel & RBM) * 256) - 1) ) / RBM;
which in turn is a left shift by 8 bits.
*lpTgtPos=( ( (wPixel & RBM) << 8) - 1) ) / RBM;

jiangsheng wrote

this code works

void  CScreenInput::CopyRGBPixels(DDSURFACEDESC* psdSrc,LPBYTE lpSrc,LPBYTE
lpDest,BOOL bInvert)
{
 DDPIXELFORMAT& rpfSrc=psdSrc->ddpfPixelFormat;

 DWORD dwHeight=psdSrc->dwHeight;
 DWORD dwWidth=psdSrc->dwWidth;

 long lPitchSrc=bInvert?-psdSrc->lPitch吐舌笑脸sdSrc->lPitch;
 long lPitchTgt=dwWidth*3;
 LPBYTE lpStart=bInvert?lpSrc+psdSrc->lPitch*(psdSrc->dwHeight-1):lpSrc;

 LPBYTE lpSrcLine=lpStart;
 LPBYTE lpTgtLine=lpDest;
 LPBYTE lpSrcPos;
 LPBYTE lpTgtPos;
 DWORD i,j;

 switch(rpfSrc.dwRGBBitCount){
 case 16:
  DWORD RBM, GBM, BBM;
  RBM = rpfSrc.dwRBitMask;
  GBM = rpfSrc.dwGBitMask;
  BBM = rpfSrc.dwBBitMask;
  for(i = 0; i < dwHeight; i++) {
   lpSrcPos=lpSrcLine;
   lpTgtPos=lpTgtLine;
   for(j = 0; j < dwWidth; j++) {
    WORD wPixel=*(WORD*)lpSrcPos;
    *lpTgtPos=(( (wPixel & BBM) * 256) - 1) / BBM;lpTgtPos++;//0x100/0x20
    *lpTgtPos=(( (wPixel & GBM) * 256) - 1) / GBM;lpTgtPos++;//0x800/0x100
    *lpTgtPos=(( (wPixel & RBM) * 256) - 1) / RBM;lpTgtPos++;//0x10000/0x800
    lpSrcPos+=2;//16bpp
   }
   lpSrcLine+=lPitchSrc;
   lpTgtLine+=lPitchTgt;
  }
  break;

seems it should be BGR,not RGB to be renderd as normal
thanks all!

johan m錼tensson wrote

Glad it worked. However, if you plan on using your application on
computers that don't use the same graphics adapter this could mess
things up again as most of them use RGB. One way of ensuring device
independency is to use COLORREF since you always use this in the same
way. If you want to take this approach:
DWORD dwR, dwG, dwB;
dwR = (( (wPixel & RBM)...
...
dwB = (( (wPixel & BBM...
then use RGB(dwR, dwG, dwB) macro to create your COLORREF. Order of red,
green and blue never changes for this.

johan

posted on 2003-10-23 18:45:00 by jiangsheng  评论(1) 阅读(7106)

.Net Study

VC.Net的WizardBar没有了,OpenInclude功能也没有了,写程序好麻烦……

VC.Net的类向导在那里?

VC.Net的HTML编辑器好烂,还是用Frontpage好些。

posted on 2003-10-23 18:39:00 by jiangsheng  评论(1) 阅读(2166)

[03.09.25]ASF学习笔记

设置(Profile)

一个设置是一个ASF的配置(configuration)的描述数据集合。一个设置必须至少包含一个流的配置设置。

流信息
设置中的流信息包含流的比特率(bit rate),缓冲窗口和媒体属性的设置。视频和音频的流信息准确描述了文件中的媒体配置,包括压缩数据使用的编码和解码器(如果有的话)。

一个设置也包含很多创建ASF文件时使用的ASF的特性,这包括互斥、媒体优先级、带宽共享和数据单位扩展。

每次写文件时必须提供设置。你可以调用IWMWriter::SetProfile指定一个设置。

设置有三种形式,应用程序中设置对象包含的数据,XML文件,或者ASF文件头。

设置对象
可以用设置管理器创建空设置对象,然后从现有数据载入设置

XML文件
具有PRX扩展名.注意Windows Media 9 Series 中没有原来的系统设置(system profiles)也不再使用,而作为这种形式存在。保存自定义设置时必须保存成这种文件。

ASF文件头
ASF读者创建一个设置对象,然后从ASF文件头载入格式信息。但是修改文件头不会影响文件的内容。可以重新对文件编码来完成格式的修改。

使用设置编辑器
除了用Windows Media Format SDK之外,还可以用Windows Media Encoder 9 Series中包含的设置编辑器创建设置。在应用程序中使用IWMProfileManager::LoadProfileByData载入预定义的设置。但是,启用“视频大小:和输入相同”这个选项将设置视频的大小为0;Windows Media Encoder 9 Series可以识别并且处理这种情况,但是Windows Media Format SDK的写入对象不会自动处理,所以应用程序必须并且处理这种情况.

下面是一个XML格式的配置

<profile version="589824" storageformat="1" name="ICW" description="ICW Stream">
 // 73647561-0000-0010-8000-00AA00389B71  'auds' == WMMEDIATYPE_Audio
 <streamconfig majortype="{73647561-0000-0010-8000-00AA00389B71}" streamnumber="1" streamname="Audio Stream" inputname="Audio804" bitrate="1411200" bufferwindow="-1" reliabletransport="0" decodercomplexity="" rfc1766langid="zh-cn">
  // 00000001-0000-0010-8000-00AA00389B71            WMMEDIASUBTYPE_PCM
  <wmmediatype subtype="{00000001-0000-0010-8000-00AA00389B71}" bfixedsizesamples="1" btemporalcompression="0" lsamplesize="4">
     <waveformatex wFormatTag="1" nChannels="2" nSamplesPerSec="44100" nAvgBytesPerSec="176400" nBlockAlign="4" wBitsPerSample="16" />
    </wmmediatype>
   </streamconfig>
   // 73647561-0000-0010-8000-00AA00389B71  'auds' == WMMEDIATYPE_Audio
 <streamconfig majortype="{73646976-0000-0010-8000-00AA00389B71}" streamnumber="2" streamname="Video Stream" inputname="Video804" bitrate="4000" bufferwindow="1000" reliabletransport="0" decodercomplexity="AU" rfc1766langid="zh-cn">
    <videomediaprops maxkeyframespacing="80000000" quality="35" />
    // 56555949-0000-0010-8000-00AA00389B71  'YV12' ==  MEDIASUBTYPE_IYUV
  <wmmediatype subtype="{56555949-0000-0010-8000-00AA00389B71}" bfixedsizesamples="1" btemporalcompression="0" lsamplesize="0">
   <videoinfoheader dwbitrate="4000" dwbiterrorrate="0" avgtimeperframe="1000000">
      <rcsource left="0" top="0" right="0" bottom="0" />
      <rctarget left="0" top="0" right="0" bottom="0" />
      <bitmapinfoheader biwidth="0" biheight="0" biplanes="1" bibitcount="12" bicompression="IYUV" bisizeimage="0" bixpelspermeter="0" biypelspermeter="0" biclrused="0" biclrimportant="0" />
     </videoinfoheader>
    </wmmediatype>
   </streamconfig>
   // 73636d64-0000-0010-8000-00AA00389B71  'scmd' == WMMEDIATYPE_Script
 <streamconfig majortype="{73636D64-0000-0010-8000-00AA00389B71}" streamnumber="3" streamname="Script Stream" inputname="Script804" bitrate="2560" bufferwindow="-1" reliabletransport="0" decodercomplexity="" rfc1766langid="zh-cn">
  <wmmediatype subtype="{00000000-0000-0000-0000-000000000000}" bfixedsizesamples="0" btemporalcompression="0" lsamplesize="0">
  // 82f38a70-c29f-11d1-97ad-00a0c95ea850        WMSCRIPTTYPE_TwoStrings
    <WMSCRIPTFORMAT scripttype="{82F38A70-C29F-11D1-97AD-00A0C95EA850}" />
    </wmmediatype>
   </streamconfig>
</profile>

媒体采样(Media Sample)
媒体采样,或者采样,是一块数字媒体数据。采样是Windows Media Format SDK可以读写的数据的最小单位。采样内容由采样相关的媒体类型指出。对于视频,每个采样表示一个桢,每个单独采样中包含的数据量由创建ASF时指定的设置设置。
采样可以包含未压缩的数据,或者压缩过的数据,这时被称为流采样。创建ASF时,采样被传递给写入对象,写入对象使用相关的编码器压缩数据,并且写入ASF文件的数据段。播放时,读出对象读出压缩的数据,解压数据,并且提供未压缩格式的数据。
采样被封装在Windows Media Format SDK的自动分配的缓冲区对象中。需要的时候,你也可以自己分配缓冲区对象,使用它的读写特性。
这里的采样并非音频采样。通常,音频采样质量用每秒录制的采样数据数量表示,例如CD质量是44,100采样/秒,或者44.1 kHz。

输入,流和输出
输入对象是你用于写入文件的任何数字媒体流,必须是可以支持的格式。支持很多标准RGB和YUV作为视频输入格式,PCM作为音频输入格式。如果编码器不支持某种输入格式,那么写入对象会初始化一个辅助对象,转换输入流到可以支持的格式,例如调整色深转换、缩放,调整声音质量、采样率和频道数目。某些情况下,压缩格式的食品和音频可用于输入。输入也可以是其他格式,例如文字,脚本命令,图像,或者任意文件数据。

输出是读取对象传递给应用程序,提供用户体验的数据。一个输出等同于一个流。如果你使用互斥属性,那么所有互斥数据共享一个输出。

一个流是一个ASF文件中包含的数据。一个流的生命期中只有一种压缩设置。一个简单的ASF具有两种流:视频和音频。更加复杂的ASF文件可以包含两路音频和多路视频。音频可以有同样的压缩设置,但是内容不同,例如不同语言的讲解;视频可以有同样的内容,但是具有不同的压缩比例。格式是在设置对象中指定的。

某些输入可以是压缩过的,这时读取对象必须以流编号依次访问数据,而不是按输出顺序访问数据。

编号
流具有从1开始的编号,这是在设置中指定的。同时,流具有一个索引以在设置中枚举流。这两个数字并不相关,例如输入1并不一定是编号为1的流,编号为1的流并不一定是输入1,等等。

格式
每种媒体类型的全部信息。每个格式有一个主类型,例如音频或视频,并且可能有一个子类型。格式包含依赖于主类型的不同信息。视频和音频格式比其他格式需要更多信息。

输入格式
描述你传递给写入对象的数字媒体类型。如果ASF文件中的流是用编码器压缩,那么编码器只支持某些输入格式。使用Windows Media 音频和视频编码器时,可以使用写入对象枚举支持的输入格式。写到文件时,你有责任选择一个匹配输入媒体的输入格式。
某些格式不必匹配编码器指明的输入格式,编码器可以自行转换数据到需要的格式。

流格式
ASF文件中的数据保存形式。在设置中描述,可以符合或不符合输入、输出格式(例如使用了某种编码/解码器)。可能必须获得编码/解码器信息之后,才可以设置流格式

输出格式。
描述你传递给读出对象的数字媒体类型。如果ASF文件中的流是用编码器压缩,那么编码器只支持某些输出格式。使用Windows Media 音频和视频编码器时,可以使用读出对象枚举支持的输出格式。读出文件时,你有责任选择一个匹配输出媒体的输出格式。
某些格式不必匹配编码器指明的输出格式,编码器可以自行转换数据到需要的格式。

比特率(Bit Rate)
每秒传递给ASF的数据的数量,以位/秒(bps)或者千位/秒(kbps)为单位。经常与带宽混淆,带宽也以bps或者kbps为单位。
如果用户的带宽小于ASF的比特率,那么播放可能中断。通常,带宽不足会导致跳过某些采样,或者更多的数据缓冲时间。
每个ASF文件创建时被指定一个比特率,它基于文件中流的数量。不同的流可以有不同的比特率。比特率可以是常数(压缩的数据可以以基本同样的速度被传输)或者可变(保留压缩的数据质量,即使可能造成突发数据溢出)。
同一个内容可以被压缩成多个比特率不同的流,然后你可以配置他们为互斥的。这个属性叫多比特率(multiple bit rate), 或者MBR.

元数据
描述ASF文件或者文件内容的信息,位于文件头。元数据的项称为属性。每一个属性由名字和值组成。全局常数用于标识属性,例如ASF文件的标题被保存在 g_wszWMTitle 属性中。在Windows Media Format SDK 中定义了最常用的内建属性,但是你也可以定义自己的属性。由于其他开发者可能和你是用同样的名字,所以可能造成冲突。
一些全局属性可以被修改,例如g_wszWMSeekable属性(文档是否可以从任意点被读取)
一些属性纯粹用于信息用途,并且必须被设置,例如g_wszWMAuthor属性(作者)
属性可以被应用到整个文件或者单独的流。
你可以用Windows Media Format SDK编辑MP3文件的元数据,但是必须使用ID3-compliant属性保留与其他MP3应用程序的兼容性。

媒体时间
自第一个采样开始的时间计量方式,单位和SDK其他时间的单位一样,是100纳秒。它使得文件中不同的流可以被同步。你写入的每一个采样都必须有媒体时间。ASF文件数据段中每一个数据对象都有媒体时间。每一个输出的数据也都有媒体时间。

缓冲
读取对象打开流文件时从文件头的信息决定缓冲区大小。实际比特率是变化的,但是平均值应该是设置中指定的值。

缓冲窗口是以可以缓冲的数据时间长度来衡量的。例如,32Kbps的流,3秒的缓冲窗口,意味着缓冲区大小为 12,000字节(32000*3/8)。解码器限制了这个数值,所以缓冲窗口的平均比特率不大于流的比特率。
通常在设置中指定这个值,写入对象处理剩下的部分。写入压缩数据到流时,必须自己确定写入的速度不会超出这个值

ASF文件中的段
一个ASF文件中的段以对象的方式组织起来。一共有三种顶层对象,必须有的头对象(Head),数据对象(Data),以及可选的索引对象(Index)。

每个对象都以全球唯一标志(GUID)和大小开始。这些数字使得文件读者可以解析这些信息,并且载入到相应的对象。因为这些GUID,底层的对象可以以任何顺序排列,并且仍然可以被识别。这使得一个不完整的ASF文件仍然可被正确读取,只要有一个完整的文件头和至少一个数据对象。某些对象,例如流属性对象,可能有多个示例。

头对象包含文件的描述信息,同时是唯一的顶层对象容器。

数据对象以包的格式存储流数据。数据对象还具有文件ID和包总个数属性,但是对于流格式,包总个数属性没有意义。

每一个数据包包含发送时间和持续时间。这使得读者可以发现流传输的中断。
数据包的数据被封装到载荷(payloads)中。一个载荷可以包含一个或者多个媒体对象(media objects),媒体对象的一个例子是视频流的一个桢。大的媒体对象,例如视频流的一个关键桢,可能被扩展到多个载荷,甚至多个包。为了跟踪对象的片断,每个对象的段具有从0到255的编号。
除了数据之外,载荷也具有以毫秒为单位的时间戳。
所有的包具有头对象中指定的统一的大小。当一个包包含的数据少于指定大小时,用数据("padding" data )填充不足部分。

索引对象包含时间《-》关键桢的配对,以更有效地在文件中定位。因为它处于文件末尾,实时媒体不能访问这个对象。

使用回调方法
一些Windows Media Format SDK的接口的方法是异步执行的,很多这样的方法使用回调方法和应用程序通讯。

使用OnStatus回调
在Windows Media Format SDK中,IWMStatusCallback::OnStatus 被很多对象调用。OnStatus接收SDK操作状态的变化。每种对象可能有不同的方式连接到IWMStatusCallback。

使用事件进行同步调用
1 使用Platform SDK的API CreateEvent创建一个事件对象
2 实现回调函数,,捕获事件,并且调用SetEvent函数标记事件对象
3 在应用程序中调用WaitForSingleObject 、监视事件对象。如果你是在为Windows程序编写代码,你必须创建一个消息循环对用户操作做出相应。

使用上下文参数
Windows Media Format SDK的一些回调函数具有pvContext参数,这个值是你在异步操作启动时传递给对象的。
通常,多个对象使用同一个回调时传递对象指针作为这个参数。

使用设置
设置的主要目的是描述其中的对象,以及对象之间的关系。不管是否使用编码/解码器,某些流需要配置才可以工作。流的配置信息可以用IWMCodecInfo3 接口的方法获得,但是不要手动配置一个使用了Windows Media编码/解码器的流。
创建/编辑设置的步骤
1 创建空设置,或者打开旧设置
2 配置每个流,如果需要的话,使用从编码/解码器获得的数据
3 配置互斥(可选)
4 配置带宽共享(可选)
5 配置优先级(可选)

设计设置

选择编码方式
1-pass Constant Bit Rate (CBR) 直播的唯一选择。以预定的码流率编码,并且质量最低。
2-pass CBR 文件形式的流媒体,长度固定,质量比1-pass Constant Bit Rate (CBR)好
1-pass Variable Bit Rate (VBR) 需要指定质量时使用,本地播放或者下载后播放
2-pass VBR – unconstrained 需要指定带宽时使用,但是真实带宽占用可以偏离指定带宽,本地播放或者下载后播放
2-pass VBR – constrained 需要指定带宽时使用,但是真实带宽占用不能大于指定带宽,本地播放或者下载后播放

码流率
除了数据之外,分包也要占用一定的带宽。如果流包含数据单位扩展,那么这将大大增加流的码流率。
同时,除了应用程序之外的任何连接都和应用程序共享网络带宽,所以不能认为应用程序可以完全使用客户的网络带宽。

配置流
如果流是视频/音频,使用Windows Media编码/解码器,那么你必须使用IWMCodecInfo3的方法从编码/解码器获得流配置对象。
如果流是其他类型,使用IWMProfile::CreateNewStream.创建一个新的流配置对象。
每个流配置都必须设置名字、连接名和流序号(从1到63)。
可能会修改使用Windows Media编码/解码器的two-pass VBR 音频流的VBR设置。视频流无需修改配置。
根据类型配置其他类型流。所有的这种流需要设置比特率和缓冲窗口。
使用IWMProfile::AddStream. 将流添加到媒体。
大部分设置可以通过IWMMediaProps访问。这些设置保存在WM_MEDIA_TYPE 结构中。对于音频和视频,WM_MEDIA_TYPE结构指针指向媒体特定的更多信息,通常是WAVEFORMATEX 或者WMVIDEOINFOHEADER结构。视频有第三个结构BITMAPINFOHEADER描述了视频的桢。

从编码/解码器获得流配置信息
使用Windows Media编码/解码器的视频/音频流需要从编码/解码器获得流配置信息。尽管你可以自行设置这些配置,从编码/解码器获得流配置信息使得数据是准确的。除非文档推荐,否则不要修改获得的流配置信息。
可以从设置管理器的IWMCodecInfo, IWMCodecInfo2, 和IWMCodecInfo3接口获得信息。

枚举安装的编码/解码器
编码/解码器的编号从0开始,音频和视频的编码/解码器有独立的编号。

枚举编码/解码器支持的格式

配置音频流
不要手动修改获得的配置的质量设置,而应该用IWMPropertyVault接口修改。
音频流的缓冲窗口不应该设置得比视频流的缓冲窗口大,否则会造成播放不同步。通常,音频流的缓冲窗口是1.5-3秒,视频流的缓冲窗口是3-5秒。

配置视频流
除非是RGB24数据,否则大小应该是4的倍数,否则会有非法格式/非法配置等错误。

配置屏幕流
和视频流一样,但是如果复杂度设置为0,那么IWMVideoMediaProps::SetQuality设置的质量会被忽略。

图像流
包含JPEG形式的图像数据。

视频流的定位性能
可以使用IWMVideoMediaProps::SetMaxKeyFrameSpacing设置关键桢间隔。增加关键桢数目会降低视频质量。

未压缩的音视频格式
不能用于流,必须手动设置带宽,缓冲窗口应该设为0

配置其他流
通常,这种流只需要比特率和缓冲窗口和WM_MEDIA_TYPE 中的媒体主类型设置。但是某些类型的流还需要其他设置

脚本流
WM_MEDIA_TYPE的成员formattype 要设置为WMFORMAT_Script,指明pbFormat成员指向一个WMSCRIPTFORMAT 结构。
只有一种脚本媒体类型,WMSCRIPTTYPE_TwoStrings。

文件传输流
每个采样需要一个数据单位扩展,你需要实现一个数据单位扩展系统。
调用IWMStreamConfig2::AddDataUnitExtension添加数据单位扩展到流。
hr = pStreamConfig2->AddDataUnitExtension(CLSID_WMTPropertyFileName,
                                          -1, NULL, 0);

网页流
WM_MEDIA_TYPE.majortype WMMEDIATYPE_Filetransfer.
WM_MEDIA_TYPE.subtype WMMEDIASUBTYPE_WebStream.
WM_MEDIA_TYPE.bFixedSizeSamples False.
WM_MEDIA_TYPE.bTemporalCompression True.
WM_MEDIA_TYPE.lSampleSize 0.
WM_MEDIA_TYPE.formattype WMFORMAT_WebStream.
WM_MEDIA_TYPE.pUnk NULL.
WM_MEDIA_TYPE.cbFormat sizeof(WMT_WEBSTREAM_FORMAT).
WM_MEDIA_TYPE.pbFormat 一个配置好的WMT_WEBSTREAM_FORMAT结构的指针.
WMT_WEBSTREAM_FORMAT.cbSampleHeaderFixedData sizeof(WMT_WEBSTREAM_SAMPLE_HEADER).
WMT_WEBSTREAM_FORMAT.wVersion 1.
WMT_WEBSTREAM_FORMAT.wreserved 0.

文本流
媒体类型WMMEDIATYPE_TEXT

计算比特率和缓冲窗口
简单的办法是设置为数据长度/时间.但是图像和文件流可能突发数据很多,但是有很多空闲时间.缓冲窗口必须设置得足够大.需要的时候,可以适当增加这些值.

变码流率流

数据单位扩展

保存/重新使用配置
不要手动更改PRX文件。看起来很小的改变会使得配置无效。

互斥

流优先级

带宽共享

包大小

写ASF文件
使用IWMWriter::SetProfile对写入对象进行设置。但是,设置了之后,对设置对象的修改不会自动反映到写入对象,除非再次调用IWMWriter::SetProfile。
设置写入对象会复位全部头属性,所以必须在设置之后再修改这些属性。

输入

设置对象中的每个连接有一个输入号。除非配置中有互斥流,否则每个流有一个连接。互斥流共享连接。
写入流时需要用输入号来区别每个流,所以必须用连接名字来判断每个流的输入号。

枚举输入格式
SDK可以对输入进行预处理来判断输入的格式是否支持。

设置输入格式
找到符合数据的输入格式之后,可以调用IWMWriter::SetInputProps让它可以被写入对象使用。对于视频流,必须设置桢的大小。

其他类型的流和预压缩流
其他类型的流无需设置。
预压缩流需要设置输入格式为NULL。这个设置必须在BeginWriting之前完成。同时需要调用IWMHeaderInfo3::AddCodecInfo设置预压缩流的格式。

BeginWriting之前,还可以用IWMWriterAdvanced2::SetInputSetting设置和流无关的设置。

元数据
使用写入对象的IWMHeaderInfo 或者IWMHeaderInfo2接口访问元数据。必须在IWMWriter::BeginWriting之前完成元数据的写入。
注意,如果创建了写入对象而没有释放,然后再创建写入对象,一些元数据会被复制到新的对象中。

写入采样
写入采样之前要调用IWMWriter::BeginWriting.
1 用IWMWriter::AllocateSample分配缓冲区,并且获得其INSSBuffer接口
2 用INSSBuffer::GetBuffer获得缓冲区地址
3 复制数据到缓冲区中
4 用INSSBuffer::SetLength设置复制的数据长度
5 把缓冲区、输入编号和媒体时间传递给IWMWriter::WriteSample方法。音频数据持续时间是一样的,所以可以简单地在现有时间上加上一个常数。对于视频,需要根据桢率计算媒体时间。
WriteSample是异步调用,在下一次WriteSample调用之前可能没有结束。所以要在每次写入采样之前调用AllocateSample获取缓冲区对象。
所有采样写完之后,调用IWMWriter::EndWriting完成写入操作。
流数据应该几乎同时结束,否则某些流数据可能丢失。

写入压缩采样
使用IWMWriterAdvanced::WriteStreamSample 替代IWMWriter::WriteSample。

写入图像采样
必须用IWMWriterAdvanced2::SetInputSetting设置图像质量g_wszJPEGCompressionQuality,范围从1到100。图像采样压缩比通常很大,所以要使用尝试的方法设置缓冲窗口大小。

强制关键桢
使用INSSBuffer3::SetProperty设置缓冲区对象的WM_SampleExtensionGUID_OutputCleanPoint为TRUE。

读取

输出

默认方式下,每个采样有一个输出编号,对应于ASF文件中的一个流。读取者打开ASF文件时,为每个流赋予一个编号。通常对每个流都有一个输出。但是对于互斥的流,每一组互斥流只有一个输出。多码流率文件的情况,或者程序自行选择流的情况下,输出对应的流是由读取者决定的。
因为流的连接名字并未保留在文件中,读取者为每个流创建一个简单的连接名字,就是输出号的字符形式,例如"1","2","3"等等。
每个输出有由编码器决定的一个或者多个支持的输出格式,打开时默认是从媒体的子类型获得默认输出格式。

使用异步方式读取ASF文件
1 实现IWMReaderCallback,处理读取者的消息,OnStatus处理状态消息,OnSample处理解压过的数据
2 让读取者打开一个文件,为每个流设置一个输出号
3 从读取者获得输出格式信息
4 让读取者开始播放,采样在指定的媒体时间传递给OnSample,直到读取者被停止或者达到文件末尾
5 数据到达时,程序负责播放采样
6 播放结束之后,让读取者关闭。
如果采样是预压缩的,那么需要实现的是IWMReaderCallbackAdvanced::OnStreamSample 。IWMReaderCallbackAdvanced::OnStreamSample几乎和OnSample完全一样,除了它基于流编号而不是输出编号之外。在开始回放之前,获得读取者对象的IWMReaderAdvanced接口,为每个预压缩流流调用IWMReaderAdvanced::SetReceiveStreamSamples.

定位
一个ASF文件必须被适当的配置才可以定位到指定时间。默认情况下只有音频的文件可以定位,但是包含视频的文件需要有索引才可以。如果你不确定文件的创建方式,你可以调用用IWMHeaderInfo::GetAttributeByName,传递g_wszWMSeekable来获得是否可定位信息。
调用IWMReader::Start可以定位到指定时间。

[开发经验]

选择编码器
Windows Media
尽管在低码流率下的效果令人满意,但是编码时系统资源占用过高,同时在高码流率的情况下效果不甚理想。

Windows Media Video 9
Windows Media Video 9 Screen
对于格式比较挑剔,例如视频的规格必须是按双字对齐的。对于长时间的多媒体编码,有阶段性的质量变化(一段时间内桢率高,过一段时间桢率低)
Windows Media Audio 9
Windows Media Audio 9 Professional
系统资源占用过高致使采样不足的话会造成音调的变化,效果不可忍受。

自定义编码器
多种数据混合编码,避免了同步问题,但是不能单独为一种数据指定码流率和优先级等信息。

posted on 2003-10-23 18:25:00 by jiangsheng  评论(9) 阅读(11003)

[03.09.22] 本期微软最有价值专家名单出来了,VC区一个人都没有……



http://www.csdn.net/news/newstopic/13/13458.shtml

CSDN?VC区高手一个个离去……masterz也……http://expert.csdn.net/Expert/TopicView1.asp?id=2276518

一个人走在?孤单的长街……

今天也准备转向.Net了,暂时先看看VC.Net……

说起来蒋晟.Net这个网名也用了4年多,比微软还早……

posted on 2003-10-23 18:20:00 by jiangsheng  评论(2) 阅读(1933)

[03.9.20]CSDN编辑部游记

http://expert.csdn.net/Expert/TopicView1.asp?id=2284553


好不容易找到地方,26楼,我晕。
发现周末加班的很多,zdg和ghj1976都在,jiangtao后来也过来了,真是勤快啊
对于周末仍奋战在工作第一线的广大人民群众致以亲切的慰问!(慰问了一下午,主要是神聊……)
走的时候顺手A了本新出的《CSDN开发高手》,嘿嘿
P.S.用斑竹管理客户端发贴居然只能给100分,害得偶用IE又登录一遍,郁闷

?
和ghj1976谈了谈,发现再不学.Net就要被淘汰了
开始看MS?Press?-?Inside?C?Sharp?2nd?Edition
全是鸟语^_^bb

posted on 2003-10-23 18:19:00 by jiangsheng  评论(0) 阅读(1674)

[03.10.23]今天被蝈蝈拉过来了

人好多啊,把以前的那个搬完了再说

Ctrk+C,Ctrl+V先……

posted on 2003-10-23 18:09:00 by jiangsheng  评论(1) 阅读(1623)

Powered by: Joycode.MVC引擎 0.5.2.0