众所周知,Opencv 在图像处理方面具有无与伦比的优势,但其在视频解码这块实在不敢恭维,智能识别 AVI 封装和少数几种 编码格式。
其实 OpenCV 解码也是引用的 FFmpeg,不过编译时估计做了限制。
下面的代码实现的功能是,,FFmpeg 解码视频,然后将每一帧转换为 OpenCV 可以识别的图像格式,在 MFC 图片空间中显示。
配置:VS2008,OpenCV2.4.4,FFmpeg 为11月末的最新版本。
至于工程配置,自己根据实际情况斟酌。
主线程解码存在锁死情况,所以采用了定时器。便于后期的图像处理。
//Dlg.h
#pragma once
#ifndef INT64_C
#define INT64_C(c) (c##LL)
#define UINT64_C(c) (c##LL)
#endif
#ifdef __cplusplus
extern "C"{
#endif
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#ifdef __cplusplus
}
#endif
#include "cv.h"
#include "highgui.h"
#include "CvvImage.h"
#pragma comment(lib, "swscale.lib")
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "avformat.lib")
// CMFC_FFmpegDlg 对话框
class CMFC_FFmpegDlg : public CDialog
{
// 构造
public:
CMFC_FFmpegDlg(CWnd* pParent = NULL); // 标准构造函数
// 对话框数据
enum { IDD = IDD_MFC_FFMPEG_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 实现
protected:
HICON m_hIcon;
// 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedBload();
afx_msg void OnTimer(UINT nIDEvent);
public:
void DrawPicToHDC(IplImage *img, UINT ID);
char * filename;
int videoStream;
int frameFinished;
int numBytes;
uint8_t * buffer;
AVPacket * packet;
AVFrame * pFrameRGB;
AVFrame * pFrame;
AVCodec * pCodec;
AVCodecContext * pCodecCtx;
AVFormatContext * pFormatCtx;
};
//Dlg.cpp
void CMFC_FFmpegDlg::OnBnClickedBload()
{
// TODO: 在此添加控件通知处理程序代码
CFileDialog dlgFile(
TRUE, NULL, NULL,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR,
"视频文件格式AVI file format (*.*)|*.*|", NULL);
CString filein;
if(dlgFile.DoModal() != IDOK)
{
filein = "";
return;
}
filein = dlgFile.GetPathName();
filename = (LPSTR)(LPCSTR)filein;
AfxMessageBox(filename);
av_register_all();
avformat_network_init();
pFormatCtx = avformat_alloc_context();
if(avformat_open_input(&pFormatCtx, filename, NULL, NULL)!=0)
{
AfxMessageBox("open input file faile !");
return ;
}
AfxMessageBox("open input file !");
for(int i=0; i<pFormatCtx->nb_streams; i++)
{
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
break;
}
}
if(videoStream == -1)
{
AfxMessageBox("could not find video stream !");
return ;
}
AfxMessageBox("find video stream !");
pCodecCtx=pFormatCtx->streams[videoStream]->codec;
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL)
{
AfxMessageBox("could not find decoder");
return ;
}
AfxMessageBox("find decoder");
if(avcodec_open2(pCodecCtx, pCodec,NULL)<0)
{
AfxMessageBox("could not open decoder");
return ;
}
AfxMessageBox("open decoder");
av_dump_format(pFormatCtx, 0, filename, 0);
pFrame=avcodec_alloc_frame();
pFrameRGB=avcodec_alloc_frame();
packet=(AVPacket *)av_malloc(sizeof(AVPacket));
if(pFrameRGB==NULL)
{
AfxMessageBox("open mem faile");
return ;
}
numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
cvNamedWindow("video", 1);
SetTimer(1, 10, NULL);
}
//Dlg.cpp
void CMFC_FFmpegDlg::OnTimer(UINT nIDEvent)
{
if(av_read_frame(pFormatCtx, packet)>=0)
{
if(packet->stream_index==videoStream)
{
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, packet);
if(frameFinished)
{
struct SwsContext * img_convert_ctx;
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
if(img_convert_ctx == NULL)
{
AfxMessageBox("Cannot initialize the conversion context !");
return ;
}
static uchar *p = NULL;
p = pFrame->data[1];
pFrame->data[1] = pFrame->data[2];
pFrame->data[2] = p;
sws_scale(img_convert_ctx,
pFrame->data, pFrame->linesize, 0, pCodecCtx->height,
pFrameRGB->data, pFrameRGB->linesize);
if (img_convert_ctx)
{
sws_freeContext (img_convert_ctx);
img_convert_ctx = NULL;
}
IplImage * Image;
CvSize Size = cvSize(pCodecCtx->width, pCodecCtx->height);
Image = cvCreateImage(Size, IPL_DEPTH_8U, 3);
memcpy(Image->imageData, buffer, pCodecCtx->width*pCodecCtx->height*24/8);
Image->widthStep = pCodecCtx->width*3;
Image->origin = 0;
cvShowImage("video", Image);
DrawPicToHDC(Image, IDC_PIC);
UpdateData(FALSE);
cvReleaseImage( &Image);
}
}
}
}
void CMFC_FFmpegDlg::DrawPicToHDC(IplImage *img, UINT ID)
{
CDC *pDC = GetDlgItem(ID)->GetDC();
HDC hDC= pDC->GetSafeHdc();
CRect rect;
GetDlgItem(ID)->GetClientRect(&rect);
CvvImage cimg;
cimg.CopyOf(img,1);
cimg.DrawToHDC(hDC,&rect);
ReleaseDC(pDC);
}
原文地址:http://blog.csdn.net/u010477528/article/details/41746491