www.pudn.com > H264Player(FFMPEG).zip > H264PlayerDlg.cpp, change:2007-09-16,size:15404b


// H264PlayerDlg.cpp : implementation file 
// 
 
#include "stdafx.h" 
#include "H264Player.h" 
#include "H264PlayerDlg.h" 
 
//进行H264解码的包含文件、定义以及变量 
#include "h264.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#endif 
 
//AS by tiany for test on 20060403 
int FindStartCode (unsigned char *Buf, int zeros_in_startcode) 
{ 
  int info; 
  int i; 
 
  info = 1; 
  for (i = 0; i  zeros_in_startcode; i++) 
    if(Buf[i] != 0) 
      info = 0; 
 
  if(Buf[i] != 1) 
    info = 0; 
  return info; 
} 
 
int getNextNal(FILE* inpf, unsigned char* Buf) 
{ 
	int pos = 0; 
	int StartCodeFound = 0; 
	int info2 = 0; 
	int info3 = 0; 
 
	while(!feof(inpf) && (Buf[pos++]=fgetc(inpf))==0); 
 
 
	while (!StartCodeFound) 
	{ 
		if (feof (inpf)) 
		{ 
//			return -1; 
			return pos-1; 
		} 
		Buf[pos++] = fgetc (inpf); 
		info3 = FindStartCode(&Buf[pos-4], 3); 
		if(info3 != 1) 
			info2 = FindStartCode(&Buf[pos-3], 2); 
		StartCodeFound = (info2 == 1 || info3 == 1); 
	} 
	fseek (inpf, -4, SEEK_CUR); 
	return pos - 4; 
} 
 
//H.264全局变量 
AVCodec *codec;			  // Codec 
AVCodecContext *c;		  // Codec Context 
AVFrame *picture;		  // Frame	 
 
///////////////////////////////////////////////////////////////////////////// 
 
//进行YUV->RGB转换以及显示视频的函数 
//用来显示的全局变量 
unsigned char *src[3]; 
BOOL PlayingVideo=FALSE; 
unsigned char *clp = NULL; 
unsigned char *clp1; 
int width,height; 
unsigned char bufRGB[80000]; 
 
//进行YUV->RGB转换的函数 
long int crv_tab[256]; 
long int cbu_tab[256]; 
long int cgu_tab[256]; 
 
long int cgv_tab[256]; 
long int tab_76309[256]; 
 
void init_dither_tab () 
{ 
  long int crv, cbu, cgu, cgv; 
  int i; 
 
  crv = 104597; 
  cbu = 132201;                 /* fra matrise i global.h */ 
  cgu = 25675; 
  cgv = 53279; 
 
  for (i = 0; i  256; i++) 
  { 
    crv_tab[i] = (i - 128) * crv; 
    cbu_tab[i] = (i - 128) * cbu; 
    cgu_tab[i] = (i - 128) * cgu; 
    cgv_tab[i] = (i - 128) * cgv; 
    tab_76309[i] = 76309 * (i - 16); 
  } 
  if (!(clp = (unsigned char *)malloc(sizeof(unsigned char)*1024))) 
  { 
    AfxMessageBox("安排解码码表内存失败!"); 
  } 
  clp1 = clp; 
 
  clp += 384; 
 
  for (i = -384; i  640; i++) 
    clp[i] = (i  0) ? 0 : ((i > 255) ? 255 : i); 
} 
 
void ConvertYUVtoRGB (unsigned char *src0, unsigned char *src1, unsigned char *src2, 
                      unsigned char *dst_ori,int width,int height) 
 
{ 
 
  int y11, y21; 
  int y12, y22; 
  int y13, y23; 
  int y14, y24; 
  int u, v; 
  int i, j; 
  int c11, c21, c31, c41; 
  int c12, c22, c32, c42; 
  unsigned int DW; 
  unsigned int *id1, *id2; 
  unsigned char *py1, *py2, *pu, *pv; 
  unsigned char *d1, *d2; 
 
  d1 = dst_ori; 
  d1 += width * height * 3 - width * 3; 
  d2 = d1 - width * 3; 
 
  py1 = src0; 
  pu = src1; 
  pv = src2; 
  py2 = py1 + width; 
 
  id1 = (unsigned int *) d1; 
  id2 = (unsigned int *) d2; 
 
  for (j = 0; j  height; j += 2) 
  { 
    /* line j + 0 */ 
    for (i = 0; i  width; i += 4) 
    { 
      u = *pu++; 
      v = *pv++; 
      c11 = crv_tab[v]; 
      c21 = cgu_tab[u]; 
      c31 = cgv_tab[v]; 
      c41 = cbu_tab[u]; 
      u = *pu++; 
      v = *pv++; 
      c12 = crv_tab[v]; 
      c22 = cgu_tab[u]; 
      c32 = cgv_tab[v]; 
      c42 = cbu_tab[u]; 
 
      y11 = tab_76309[*py1++];  /* (255/219)*65536 */ 
      y12 = tab_76309[*py1++]; 
      y13 = tab_76309[*py1++];  /* (255/219)*65536 */ 
      y14 = tab_76309[*py1++]; 
 
      y21 = tab_76309[*py2++]; 
      y22 = tab_76309[*py2++]; 
      y23 = tab_76309[*py2++]; 
      y24 = tab_76309[*py2++]; 
 
      /* RGBR */ 
      DW = ((clp[(y11 + c41) >> 16])) | 
        ((clp[(y11 - c21 - c31) >> 16]) < 8) | 
        ((clp[(y11 + c11) >> 16]) < 16) | 
        ((clp[(y12 + c41) >> 16]) < 24); 
      *id1++ = DW; 
 
      /* GBRG */ 
      DW = ((clp[(y12 - c21 - c31) >> 16])) | 
        ((clp[(y12 + c11) >> 16]) < 8) | 
        ((clp[(y13 + c42) >> 16]) < 16) | 
        ((clp[(y13 - c22 - c32) >> 16]) < 24); 
      *id1++ = DW; 
 
      /* BRGB */ 
      DW = ((clp[(y13 + c12) >> 16])) | 
        ((clp[(y14 + c42) >> 16]) < 8) | 
        ((clp[(y14 - c22 - c32) >> 16]) < 16) | 
        ((clp[(y14 + c12) >> 16]) < 24); 
      *id1++ = DW; 
 
      /* RGBR */ 
      DW = ((clp[(y21 + c41) >> 16])) | 
        ((clp[(y21 - c21 - c31) >> 16]) < 8) | 
        ((clp[(y21 + c11) >> 16]) < 16) | 
        ((clp[(y22 + c41) >> 16]) < 24); 
      *id2++ = DW; 
 
      /* GBRG */ 
      DW = ((clp[(y22 - c21 - c31) >> 16])) | 
        ((clp[(y22 + c11) >> 16]) < 8) | 
        ((clp[(y23 + c42) >> 16]) < 16) | 
        ((clp[(y23 - c22 - c32) >> 16]) < 24); 
      *id2++ = DW; 
 
      /* BRGB */ 
      DW = ((clp[(y23 + c12) >> 16])) | 
        ((clp[(y24 + c42) >> 16]) < 8) | 
        ((clp[(y24 - c22 - c32) >> 16]) < 16) | 
        ((clp[(y24 + c12) >> 16]) < 24); 
      *id2++ = DW; 
    } 
    id1 -= (9 * width) >> 2; 
    id2 -= (9 * width) >> 2; 
    py1 += width; 
    py2 += width; 
  } 
} 
 
 
// CAboutDlg dialog used for App About 
 
class CAboutDlg : public CDialog 
{ 
public: 
	CAboutDlg(); 
 
// Dialog Data 
	enum { IDD = IDD_ABOUTBOX }; 
 
	protected: 
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support 
 
// Implementation 
protected: 
	DECLARE_MESSAGE_MAP() 
}; 
 
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) 
{ 
} 
 
void CAboutDlg::DoDataExchange(CDataExchange* pDX) 
{ 
	CDialog::DoDataExchange(pDX); 
} 
 
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) 
END_MESSAGE_MAP() 
 
 
// CH264PlayerDlg dialog 
 
 
 
 
CH264PlayerDlg::CH264PlayerDlg(CWnd* pParent /*=NULL*/) 
	: CDialog(CH264PlayerDlg::IDD, pParent) 
{ 
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 
} 
 
void CH264PlayerDlg::DoDataExchange(CDataExchange* pDX) 
{ 
	CDialog::DoDataExchange(pDX); 
} 
 
BEGIN_MESSAGE_MAP(CH264PlayerDlg, CDialog) 
	ON_WM_SYSCOMMAND() 
	ON_WM_PAINT() 
	ON_WM_QUERYDRAGICON() 
	//}}AFX_MSG_MAP 
	ON_BN_CLICKED(IDC_BUTTON_PLAY, &CH264PlayerDlg::OnBnClickedButtonPlay) 
	ON_WM_DESTROY() 
	ON_MESSAGE(WM_DISPLAY_FRAME,OnDisplayFrameMsg)	 
	ON_MESSAGE(WM_DECODE_COMPLETE,OnDecodeCompleteMsg) 
END_MESSAGE_MAP() 
 
 
// CH264PlayerDlg message handlers 
 
BOOL CH264PlayerDlg::OnInitDialog() 
{ 
	CDialog::OnInitDialog(); 
 
	// Add "About..." menu item to system menu. 
 
	// IDM_ABOUTBOX must be in the system command range. 
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 
	ASSERT(IDM_ABOUTBOX  0xF000); 
 
	CMenu* pSysMenu = GetSystemMenu(FALSE); 
	if (pSysMenu != NULL) 
	{ 
		CString strAboutMenu; 
		strAboutMenu.LoadString(IDS_ABOUTBOX); 
		if (!strAboutMenu.IsEmpty()) 
		{ 
			pSysMenu->AppendMenu(MF_SEPARATOR); 
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 
		} 
	} 
 
	// Set the icon for this dialog.  The framework does this automatically 
	//  when the application's main window is not a dialog 
	SetIcon(m_hIcon, TRUE);			// Set big icon 
	SetIcon(m_hIcon, FALSE);		// Set small icon 
 
	// TODO: Add extra initialization here 
	//初始化视频窗口 
	// Adjust display windows	 
 
	// For remote video display window 
	wnd=this->GetDlgItem(IDC_REMOTEVIDEO);	// Video display window 
   	bwnd=this->GetDlgItem(IDC_REMOTEBORDER); // Border window... 
   	bwnd->GetWindowRect(brect); 
	ScreenToClient(brect); 
 
	remote_wnd_x=brect.TopLeft().x+(brect.Width()-IMAGE_WIDTH)/2; 
	remote_wnd_y=brect.TopLeft().y+(brect.Height()-IMAGE_HEIGHT)/2; 
	 
	// Centre the remote video window 
	wnd->SetWindowPos(&wndTop,remote_wnd_x-4,remote_wnd_y-4,IMAGE_WIDTH+9,IMAGE_HEIGHT+9,SWP_SHOWWINDOW | SWP_DRAWFRAME); 
 
	// Initialize DIB for drawing... 
	// Setup bmpinfo structure yourself 
	m_bmpinfo=new BITMAPINFO; 
	m_bmpinfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER); 
	m_bmpinfo->bmiHeader.biWidth=IMAGE_WIDTH; 
	m_bmpinfo->bmiHeader.biHeight=IMAGE_HEIGHT; 
	m_bmpinfo->bmiHeader.biPlanes=1; 
	m_bmpinfo->bmiHeader.biBitCount=24; 
	m_bmpinfo->bmiHeader.biCompression=0; 
	m_bmpinfo->bmiHeader.biSizeImage=0; 
	m_bmpinfo->bmiHeader.biXPelsPerMeter=0; 
	m_bmpinfo->bmiHeader.biYPelsPerMeter=0; 
	m_bmpinfo->bmiHeader.biClrUsed=0; 
	m_bmpinfo->bmiHeader.biClrImportant=0; 
	// Get Dialog DC 
	m_hdc=this->GetDC()->m_hDC; 
	hdib=::DrawDibOpen(); 
	if(hdib!=NULL) 
	{ 
	  
		::DrawDibBegin(hdib, 
					   m_hdc, 
					   -1,				// don't stretch 
					   -1,				// don't stretch 
					   &m_bmpinfo->bmiHeader, 
					   IMAGE_WIDTH,         // width of image 
					   IMAGE_HEIGHT,        // height of image 
					   0				 
					   ); 
	 
	} 
 
	//初始化显示 
	width=IMAGE_WIDTH;height=IMAGE_HEIGHT; 
	//bufRGB = (unsigned char *)malloc(sizeof(unsigned char)*(3 * width * height)); 
	init_dither_tab(); 
 
	m_bDecoding=FALSE; 
	hDecodeThread=NULL; 
 
	FileName=""; 
 
	return TRUE;  // return TRUE  unless you set the focus to a control 
} 
 
void CH264PlayerDlg::OnSysCommand(UINT nID, LPARAM lParam) 
{ 
	if ((nID & 0xFFF0) == IDM_ABOUTBOX) 
	{ 
		CAboutDlg dlgAbout; 
		dlgAbout.DoModal(); 
	} 
	else 
	{ 
		CDialog::OnSysCommand(nID, lParam); 
	} 
} 
 
// If you add a minimize button to your dialog, you will need the code below 
//  to draw the icon.  For MFC applications using the document/view model, 
//  this is automatically done for you by the framework. 
 
void CH264PlayerDlg::OnPaint() 
{ 
	if (IsIconic()) 
	{ 
		CPaintDC dc(this); // device context for painting 
 
		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); 
 
		// Center icon in client rectangle 
		int cxIcon = GetSystemMetrics(SM_CXICON); 
		int cyIcon = GetSystemMetrics(SM_CYICON); 
		CRect rect; 
		GetClientRect(&rect); 
		int x = (rect.Width() - cxIcon + 1) / 2; 
		int y = (rect.Height() - cyIcon + 1) / 2; 
 
		// Draw the icon 
		dc.DrawIcon(x, y, m_hIcon); 
	} 
	else 
	{ 
		CDialog::OnPaint(); 
	} 
} 
 
// The system calls this function to obtain the cursor to display while the user drags 
//  the minimized window. 
HCURSOR CH264PlayerDlg::OnQueryDragIcon() 
{ 
	return static_cast<HCURSOR>(m_hIcon); 
} 
 
 
//解码线程 
DWORD CH264PlayerDlg::DecodeThread(void *pDlg) 
{ 
	CH264PlayerDlg* pDialog=(CH264PlayerDlg*)pDlg; 
 
	FILE * inpf; 
	//FILE * outf; 
	int nWrite; 
	int i,p; 
	int nalLen; 
	unsigned char* Buf; 
	int  got_picture, consumed_bytes;  
	unsigned char *DisplayBuf; 
	DisplayBuf=new unsigned char[60000]; 
 
	int i_frames=0; 
	int StartTime,EndTime; 
	CHAR fps[20]; 
	 
	char outfile[] = "test.pgm"; 
	char *file; 
	file=new char[256]; 
	/*for(i=0;i<pDialog->FileName.GetLength();i++) 
	{ 
		file[i]=pDialog->FileName.GetAt(i); 
	}*/ 
	sprintf(file,"E:\\yuv samples\\fore.264"); 
	inpf = fopen("E:\\yuv samples\\test5.264", "rb"); 
	delete file; 
	//outf = fopen("out.yuv", "wb"); 
 
	nalLen = 0; 
	Buf = (unsigned char*)calloc ( 1000000, sizeof(char)); 
 
 
	avcodec_init();  
	avcodec_register_all();  
	codec = avcodec_find_decoder(CODEC_ID_H264); 
 
	if (!codec)  { 
		return 0;  
	}  
		//allocate codec context 
    c = avcodec_alloc_context();  
 
	if(!c){ 
		return 0; 
	} 
	//open codec 
    if (avcodec_open(c, codec)  0) { 
		return 0;  
	}  
	 
	//allocate frame buffer 
    picture   = avcodec_alloc_frame(); 
	if(!picture){ 
		return 0; 
	} 
 
	StartTime=GetTickCount(); 
 
	while(!feof(inpf)) 
	{ 
		 
		nalLen = getNextNal(inpf, Buf); 
 
		//try to decode this frame 
//		consumed_bytes= decode_frame(c, picture, &got_picture, Buf, nalLen);  
//		if (got_picture > 0) 
//	       c->frame_number++; 
 
		consumed_bytes= avcodec_decode_video(c, picture, &got_picture, Buf, nalLen); 
 
		if(consumed_bytes > 0) 
		{ 
			/* 
			for(i=0; i<c->height; i++) 
				fwrite(picture->data[0] + i * picture->linesize[0], 1, c->width, outf); 
			for(i=0; i<c->height/2; i++) 
				fwrite(picture->data[1] + i * picture->linesize[1], 1, c->width/2, outf); 
			for(i=0; i<c->height/2; i++) 
				fwrite(picture->data[2] + i * picture->linesize[2], 1, c->width/2, outf); 
				*/ 
			p=0; 
			for(i=0; i<c->height; i++) 
			{ 
				memcpy(DisplayBuf+p,picture->data[0] + i * picture->linesize[0], c->width); 
				p+=c->width; 
			} 
			for(i=0; i<c->height/2; i++) 
			{ 
				memcpy(DisplayBuf+p,picture->data[1] + i * picture->linesize[1], c->width/2); 
				p+=c->width/2; 
			} 
			for(i=0; i<c->height/2; i++) 
			{ 
				memcpy(DisplayBuf+p,picture->data[2] + i * picture->linesize[2], c->width/2); 
				p+=c->width/2; 
			} 
			//向窗口发送消息显示画面 
			pDialog->SendMessage(WM_DISPLAY_FRAME,(WPARAM)DisplayBuf,(LPARAM)p); 
			i_frames++; 
		} 
	} 
 
	EndTime=GetTickCount(); 
 
	if(inpf) 
		fclose(inpf); 
 
	/* 
	if(outf) 
		fclose(outf); 
		*/ 
 
	if(c) { 
		avcodec_close(c);  
		av_free(c); 
		c = NULL; 
	}  
	if(picture) { 
		av_free(picture); 
		picture = NULL; 
	} 
 
	if(Buf) 
	{ 
		free(Buf); 
		Buf = NULL; 
	}     
 
	delete DisplayBuf;	 
 
	sprintf(fps,"%f fps",(float)(1000*i_frames)/(float)(EndTime-StartTime)); 
	AfxMessageBox(fps); 
 
	pDialog->SendMessage(WM_DECODE_COMPLETE,(WPARAM)NULL,(LPARAM)NULL); 
 
    return 0; 
} 
 
void CH264PlayerDlg::DisplayVideo(unsigned char* displaybuf) 
{ 
	ConvertYUVtoRGB ((unsigned char*)displaybuf,(unsigned char*)(displaybuf+25344),(unsigned char*)(displaybuf+31680),bufRGB,width,height); 
	 
	unsigned char* rgbdata=bufRGB; 
	 
	::DrawDibDraw(hdib, 
				  m_hdc, 
				  remote_wnd_x,		// dest : left pos 
				  remote_wnd_y,		// dest : top pos 
				  -1,					 // don't zoom x 
				  -1,					 // don't zoom y 
				  &m_bmpinfo->bmiHeader,			 // bmp header info 
				  rgbdata,					 // bmp data 
				  0,					 // src :left 
				  0,					 // src :top 
				  IMAGE_WIDTH,				 // src : width 
				  IMAGE_HEIGHT,				 // src : height 
				  DDF_SAME_DRAW			 // use prev params.... 
				  ); 
} 
 
LONG CH264PlayerDlg::OnDisplayFrameMsg(WPARAM wParam,LPARAM lParam) 
{ 
	unsigned char* DisplayBuf=(unsigned char*)wParam; 
	int length=(int)lParam; 
 
	int i; 
	for(i=0;i<length/38016;i++) 
	{ 
		DisplayVideo(DisplayBuf+i*38016); 
	} 
 
	return 1; 
} 
 
LONG CH264PlayerDlg::OnDecodeCompleteMsg(WPARAM wParam,LPARAM lParam) 
{ 
	SetDlgItemText(IDC_BUTTON_PLAY,_T("解码")); 
	//停止编码线程 
	if(hDecodeThread) 
	{ 
		TerminateThread(hDecodeThread,0); 
		CloseHandle(hDecodeThread); 
		hDecodeThread=NULL; 
	} 
	m_bDecoding=FALSE; 
 
	return 1; 
} 
 
void CH264PlayerDlg::OnBnClickedButtonPlay() 
{ 
	if(!m_bDecoding) 
	{ 
		//获取输入文件和输出文件名称 
		CFileDialog FileDlg1(TRUE,NULL,NULL,OFN_HIDEREADONLY,TEXT("264 Files(*.264)|*.264||")); 
		//FileDlg1.m_pOFN->lpstrTitle="请选择需要解码的文件"; 
		if(FileDlg1.DoModal()==IDOK) 
		{ 
			FileName=FileDlg1.GetPathName(); 
		} 
		else 
		{ 
			return; 
		} 
 
		//如果有的话,停止解码线程 
		if(hDecodeThread) 
		{ 
			TerminateThread(hDecodeThread,0); 
			CloseHandle(hDecodeThread); 
			hDecodeThread=NULL; 
		} 
 
		//开始解码线程 
		m_bDecoding=TRUE; 
		SetDlgItemText(IDC_BUTTON_PLAY,_T("停止解码")); 
		hDecodeThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)DecodeThread,(void *)this,0,&dwThreadID); 
	} 
	else 
	{ 
		SetDlgItemText(IDC_BUTTON_PLAY,_T("解码")); 
		//停止编码线程 
		if(hDecodeThread) 
		{ 
			TerminateThread(hDecodeThread,0); 
			CloseHandle(hDecodeThread); 
			hDecodeThread=NULL; 
		} 
		m_bDecoding=FALSE; 
	} 
} 
 
void CH264PlayerDlg::OnDestroy() 
{ 
	CDialog::OnDestroy(); 
 
	// TODO: Add your message handler code here 
	if(m_bmpinfo) 
	{ 
		delete m_bmpinfo; 
	} 
	// Close graphics.... 
	if(hdib!=NULL) 
	{ 
		::DrawDibEnd(hdib); 
		::DrawDibClose(hdib); 
	} 
 
	free(clp1); 
}