///
// ReadBMP.cpp
#include <afxdlgs.h>
#include <process.h>
#include "resource.h"
#include "ReadBMP.h"
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
CMyApp theApp;
char g_buffer[1024 * 1024 * 15];
BOOL CMyApp::InitInstance()
{
m_pMainWnd = new CMainWindow;
m_pMainWnd->ShowWindow(m_nCmdShow);
return TRUE;
}
CMainWindow::CMainWindow()
{
LPCTSTR lpszClassName = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW,
::LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW+2), theApp.LoadIcon(IDI_MAIN));
CreateEx(NULL, lpszClassName, "BMP文件浏览器",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL);
}
BEGIN_MESSAGE_MAP(CMainWindow, CWnd)
ON_WM_CREATE()
//ON_WM_PAINT()
ON_WM_DESTROY()
ON_COMMAND(FILE_OPEN, OnFileOpen)
END_MESSAGE_MAP()
void CMainWindow::PostNcDestroy()
{
delete this;
}
BOOL CMainWindow::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
::SetMenu(m_hWnd, ::LoadMenu(theApp.m_hInstance, (LPCTSTR)IDR_MAIN));
m_hClientDC = ::GetDC(m_hWnd);
// 初始化内存DC
m_hMemDC = ::CreateCompatibleDC(m_hClientDC);
m_nHeight = 0;
m_nWidth = 0;
bRun = FALSE;
return TRUE;
}
void CMainWindow::OnPaint()
{
// 这里一不要用m_hClientDC,因为m_hClientDC在有效之前OnPaint()就被调用了。
CPaintDC dc(this);
::BitBlt(dc, 0, 0, m_nWidth, m_nHeight, m_hMemDC, 0, 0, SRCCOPY);
}
void CMainWindow::OnDestroy()
{
bRun = FALSE;
::WaitForSingleObject(m_hThread, INFINITE);
::DeleteDC(m_hMemDC);
}
void CMainWindow::OnFileOpen()
{
CFileDialog file(TRUE);
if(file.DoModal() == IDOK)
{
strcpy(strFile, file.GetFileName());
bRun = FALSE;
::WaitForSingleObject(m_hThread, INFINITE);
bRun = TRUE;
m_hThread = (HANDLE)_beginthreadex(NULL, 0, playThread, (void*)this, 0, NULL);
}
}
void CMainWindow::av_create_bmp(CWnd *pWnd, uint8_t *pRGBBuffer, int width, int height, int bpp, char *text)
{
CMainWindow* CMainWnd = (CMainWindow*)pWnd;
BITMAPFILEHEADER bmpheader;
BITMAPINFO bmpinfo;
bmpheader.bfType = ('M'<<8)|'B';
bmpheader.bfReserved1 = 0;
bmpheader.bfReserved2 = 0;
bmpheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bmpheader.bfSize = bmpheader.bfOffBits + width*height*bpp/8;
bmpinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpinfo.bmiHeader.biWidth = width;
bmpinfo.bmiHeader.biHeight = -height;
bmpinfo.bmiHeader.biPlanes = 1;
bmpinfo.bmiHeader.biBitCount = bpp;
bmpinfo.bmiHeader.biCompression = BI_RGB;
bmpinfo.bmiHeader.biSizeImage = 0;
bmpinfo.bmiHeader.biXPelsPerMeter = 100;
bmpinfo.bmiHeader.biYPelsPerMeter = 100;
bmpinfo.bmiHeader.biClrUsed = 0;
bmpinfo.bmiHeader.biClrImportant = 0;
char *tmpinf = g_buffer + sizeof(BITMAPFILEHEADER);
char *tmpbit = g_buffer + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
memcpy(g_buffer, &bmpheader, sizeof(BITMAPFILEHEADER));
memcpy(tmpinf, &bmpinfo, sizeof(BITMAPINFOHEADER));
memcpy(tmpbit, pRGBBuffer, width*height*bpp/8);
// 创建一个与指定DC兼容的未初始化的位图,选入到内存兼容DC中
HBITMAP hBitmap = ::CreateCompatibleBitmap(CMainWnd->m_hClientDC, width, height);
// 将位图选入内存DC中
::SelectObject(CMainWnd->m_hMemDC, hBitmap);
// 把象图像据放到建立的设备中
::SetDIBitsToDevice(CMainWnd->m_hMemDC, 0, 0, width, height, 0, 0, 0, height, tmpbit, (BITMAPINFO *)tmpinf, DIB_RGB_COLORS);
static unsigned int lasttime = 0;
static unsigned int cnt = 0;
static char szCnt[100];
unsigned int time = 0;
unsigned int tmp = 0;
if(cnt == 0)
{
lasttime = ::GetTickCount();
cnt++;
}
else
{
time = ::GetTickCount() - lasttime;
cnt++;
if(time > 1000)
{
sprintf(szCnt, "FPS: %d (%d %d)", cnt, width, height);
cnt = 0;
}
}
::TextOut(CMainWnd->m_hMemDC, 20, 20, szCnt, strlen(szCnt));
if (text != NULL)::TextOut(CMainWnd->m_hMemDC, 20, 50, text, strlen(text));
::BitBlt(CMainWnd->m_hClientDC, 0, 0, width, height, CMainWnd->m_hMemDC, 0, 0, SRCCOPY);
::DeleteObject(hBitmap);
}
UINT CMainWindow::playThread(LPVOID pWnd)
{
CMainWindow* pMainWnd = (CMainWindow*)pWnd;
AVFormatContext* pFormatCtx = NULL;
AVCodecContext* pCodecCtx = NULL;
AVCodec* pCodec = NULL;
AVFrame* pFrame = NULL;
AVFrame* pFrameRGB = NULL;
SwsContext* pSWSCtx = NULL;
AVPacket packet; //E:\\Media\\44.mp4
const char *filename = pMainWnd->strFile;
int i, videoStream;
int numBytes, frameFinished;
uint8_t *buffer = NULL;
av_register_all();
if(av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL)!=0)
{
pMainWnd->MessageBox("av_open_input_file error!");
return 0;
}
if(av_find_stream_info(pFormatCtx)<0)
{
pMainWnd->MessageBox("av_find_stream_info error!");
return 0;
}
dump_format(pFormatCtx, 0, filename, false);
videoStream = -1;
for(i = 0; i < pFormatCtx->nb_streams; i++)
{
if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO)
{
videoStream=i;
break;
}
}
if(videoStream==-1)
{
pMainWnd->MessageBox("Didn't find a video stream!");
return 0;
}
// 得到视频流编码上下文的指针
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
// 寻找视频流的解码器
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL)
{
pMainWnd->MessageBox("Didn't find the video decoder!");
return 0;
}
// 通知解码器我们能够处理截断的bit流--ie,
// bit流帧边界可以在包中
// 打开解码器
if(avcodec_open(pCodecCtx, pCodec) < 0)
{
pMainWnd->MessageBox("Can't open the video decoder!");
return 0;
}
pFrame = avcodec_alloc_frame();
unsigned int time = 0x88888888;
while(av_read_frame(pFormatCtx,&packet)>=0 && pMainWnd->bRun == TRUE)
{
//time = ::GetTickCount();
if(packet.stream_index==videoStream)
{
avcodec_decode_video(pCodecCtx, pFrame, &frameFinished,packet.data, packet.size);
if(frameFinished)
{
// if(pFrame->key_frame==1) pMainWnd->m_nWidth, pMainWnd->m_nHeight
{
// 图像大小发生变化
if (pMainWnd->m_nWidth != pCodecCtx->width || pMainWnd->m_nHeight != pCodecCtx->height)
{
if(pFrameRGB){ av_free(pFrameRGB);pFrameRGB = NULL;}
if(buffer != NULL){ av_free(buffer);buffer = NULL; }
if(pSWSCtx){ sws_freeContext(pSWSCtx);pSWSCtx = NULL; }
pFrameRGB = avcodec_alloc_frame();
numBytes = avpicture_get_size(PIX_FMT_BGR24, pCodecCtx->width,pCodecCtx->height);
buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_BGR24,pCodecCtx->width, pCodecCtx->height);
pSWSCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
pMainWnd->Invalidate();
}
sws_scale(pSWSCtx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
pMainWnd->m_nWidth = pCodecCtx->width;
pMainWnd->m_nHeight = pCodecCtx->height;
int a = 30 - (::GetTickCount() - time);
char szCnt[100];
sprintf(szCnt, "a = %d pts = %d", a, packet.pts);
if(a > 0)Sleep(a);
av_create_bmp(pMainWnd, pFrameRGB->data[0], pCodecCtx->width, pCodecCtx->height, 24, szCnt);
time = ::GetTickCount();
}
}
}
av_free_packet(&packet);
}
av_free(buffer);
// 释放 RGB 图象
av_free(pFrameRGB);
// 释放YUV 帧
av_free(pFrame);
sws_freeContext(pSWSCtx);
// 关闭解码器(codec)
avcodec_close(pCodecCtx);
// 关闭视频文件
av_close_input_file(pFormatCtx);
pMainWnd->m_nWidth = 0;
pMainWnd->m_nHeight = 0;
pMainWnd->bRun = FALSE;
return 0;
}
/
// ReadBMP.h文件
#include <afxwin.h>
#include "avcodec.h"
#include "avformat.h"
#include "swscale.h"
class CMyApp : public CWinApp
{
public:
virtual BOOL InitInstance();
};
class CMainWindow : public CWnd
{
public:
CMainWindow();
private:
static void av_create_bmp(CWnd *pWnd, uint8_t *pRGBBuffer, int width, int height, int bpp, char *text);
static UINT __stdcall playThread(LPVOID pWnd);
protected:
HDC m_hClientDC;
HDC m_hMemDC; // 与客户区兼容的内存DC句柄
int m_nWidth; // BMP图像的宽度static
int m_nHeight; // BMP图像的高度static
HANDLE m_hThread;
BOOL bRun;
char strFile[500];
protected:
virtual void PostNcDestroy();
afx_msg BOOL OnCreate(LPCREATESTRUCT);
afx_msg void OnPaint();
afx_msg void OnDestroy();
afx_msg void OnFileOpen();
DECLARE_MESSAGE_MAP()
};