众所周知,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