最近搞那个SDL播放用USB摄像头采集的数据,其实YUV的数据格式有很多种,一般都要针对相应的格式取得帧数据来给SDL描绘才行。我的摄像头取得的数据是YUY2的,大概过程如下所示:
bool CSDL_playerDlg::InitSDL(HWND m_hWnd) { //初始化,这里主要是把SDL的窗口嵌入到MFC的控件中 char sdl_var[64]; sprintf(sdl_var,"SDL_WINDOWID=0x%1x",m_hWnd);//在窗口初始化时加入InitSDL(this->GetDlgItem(IDC_STATIC)->GetSafeHwnd()); SDL_putenv(sdl_var); char *myvalue = SDL_getenv("SDL_WINDOWID"); //让SDL取得窗口ID atexit(SDL_Quit); pscreen = SDL_SetVideoMode(WIDTH,HEIGHT,24,SDL_SWSURFACE); //设置播放模式 if(pscreen == NULL) { TRACE("error SDL SetVideoMode! - %s", SDL_GetError()); return false; } poverlay = SDL_CreateYUVOverlay(WIDTH,HEIGHT,SDL_YUY2_OVERLAY,pscreen); //创建绘制YUV数据的句柄 if(poverlay == NULL) { TRACE("error SDL CreateYUVOverlay! - %s", SDL_GetError()); return false; } return TRUE; } bool CSDL_playerDlg::flip(unsigned char *src,int width,int height) //描绘YUV数据的过程 { SDL_Rect rect; rect.w = WIDTH; rect.h = HEIGHT; rect.x = 0; rect.y = 0; SDL_LockSurface(pscreen); SDL_LockYUVOverlay(poverlay); pbuff = (unsigned char*)poverlay->pixels[0];
//SDL 的 YUY2 是采用的一个平面的存储方式,即 YUV 三分量交叉存放,此时只有 poverlay->pixels[0] 这个地址有效 memcpy(pbuff,src,WIDTH*HEIGHT*2); SDL_UnlockYUVOverlay(poverlay); SDL_UnlockSurface(pscreen); SDL_DisplayYUVOverlay(poverlay,&rect); return 0; } int CSDL_playerDlg::DisplayYuvFile(unsigned char *frame,uint32_t frame_len ) { int used_bytes = 0; used_bytes = dec.dec_main(frame,out_buffer,frame_len ); //这里是解码传来的一帧数据,传输用的是RTP flip(out_buffer,WIDTH,HEIGHT);//播放一帧数据 SDL_Delay(40); return 0; }
其实过程什么的很简单,主要是针对对应的格式就OK了,假如是YUV420的话上述相应代码就变成
outy = out_buffer; outu = out_buffer+width*height*5/4; outv = out_buffer+width*height; for(int y = 0;y < pscreen->h && y < poverlay->h; y++) { op[0] = poverlay->pixels[0]+poverlay->pitches[0]*y; op[1] = poverlay->pixels[1]+poverlay->pitches[1]*(y/2); op[2] = poverlay->pixels[2]+poverlay->pitches[2]*(y/2); memcpy(op[0],outy+y*width,width); if(y%2 == 0) { memcpy(op[1],outu+width/2*y/2,width/2); memcpy(op[2],outv+width/2*y/2,width/2); } }
只要 知道你所要播放的文件的像素存储方式,正确地取出数据,其他步骤就简单了,另外数据解码用的XVID。在这里分享一下少少的经验,也给自己几天来的工作留下个纪念。