DirctorShow 获取AVI文件的所有帧

本文介绍了一种使用DirectShow从AVI视频文件中提取每一帧的方法。通过详细步骤和代码示例,指导读者如何配置环境并实现帧的保存。

首先很感谢 http://www.vckbase.com/document/viewdoc/?id=976 这位作者。谢谢他那么耐心的讲解 directorshow 提取 AVI 帧。我这篇文章是想再整理一下,希望能对初学者有帮助。

需要安装 DirectX9.0bSDK ,我安装了一个 exe 版本的。很奇怪,我去安装目录查了一下,只是一个 Doc 文件,之后又去下载了一个 DirectShowSDKinDirectX9.0b 版本的,结果看到我要的 Lib Include 文件。我将他们放在 VC 安装目录,并在 VC 中加入他们的目录,方法是:菜单 ->Tools->Options->Directories 中,在 show directories for 中选择 include files

Directories 中加入 Directorshow include 文件路径。然后将 show directories for 选择 Library files ,相同的加入 lib 路径进去。好!配置环境好了。

       建立一个 Dlg 文件工程。主要代码,大家还是下载上面那个链接中的源码。

       需要修改的地方有:

1.       修改 bmp 文件保存路径。

 

void CFrameGrabberDlg::OnSaveBrowse()

{

        char szDir[MAX_PATH];

        BROWSEINFO bi;

        ITEMIDLIST *pidl;

        bi.hwndOwner = this->m_hWnd;

        bi.pidlRoot = NULL;

        bi.pszDisplayName = szDir;

        bi.lpszTitle = " 请选择受控的目录 ";//strDlgTitle;

        bi.ulFlags = BIF_RETURNONLYFSDIRS;

        bi.lpfn = NULL;

        bi.lParam = 0;

        bi.iImage = 0;

        pidl = SHBrowseForFolder(&bi);

        if(pidl == NULL)

         return;

        if(!SHGetPathFromIDList(pidl, szDir))

         return;

        m_editSaveDir.Format("%s//",szDir);

 

        UpdateData(FALSE);

}

2.       修改主要的函数

 

HRESULT CFrameGrabberDlg::GrabFrameFromMovie()

{

       HRESULT hr;

       // 定义 IMediaDet 接口实例

       CComPtr< IMediaDet > pDet;

       hr = CoCreateInstance( CLSID_MediaDet, NULL, CLSCTX_INPROC_SERVER,

              IID_IMediaDet, (void**) &pDet );

       if (FAILED(hr))

              return hr;

      

       // 将影片文件名转换成 BSTR 类型

       CComBSTR openBSTR(m_editOpenDir);

       // 设置 IMediaDet 接口的文件关联

       hr = pDet->put_Filename(openBSTR);

       if (FAILED(hr))

              return hr;

      

       // 从影片中检索视频流和音频流

       long lStreams;

    hr = pDet->get_OutputStreams(&lStreams);

    if (FAILED(hr))

              return hr;

      

       // 取出影片的视频流,因为帧的信息是保存在视频流中的

       bool bFound = false;

       for (int i=0; i<lStreams; i++)

       {

              GUID major_type;

              hr = pDet->put_CurrentStream(i);

              if (SUCCEEDED(hr))

                     hr = pDet->get_StreamType(&major_type);

              if (FAILED(hr))

                     break;

              if (major_type == MEDIATYPE_Video)

              {

                     bFound = true;

                     break;

              }

       }

       if (!bFound)

              return VFW_E_INVALIDMEDIATYPE;

      

       long width = 0, height = 0; // 存储位图的宽和高(单位:象素)

    AM_MEDIA_TYPE mt;

    hr = pDet->get_StreamMediaType(&mt);

 

    if (SUCCEEDED(hr))

    {

        if ((mt.formattype == FORMAT_VideoInfo) &&

            (mt.cbFormat >= sizeof(VIDEOINFOHEADER)))

        {

                     // 得到 VIDEOINFOHEADER 结构指针, VIDEOINFOHEADER 结构包含一些与视频

                     // 有关的信息,其中含有 BITMAPINFORHEADER 结构

            VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)(mt.pbFormat);

            width = pVih->bmiHeader.biWidth;

            height = pVih->bmiHeader.biHeight;

        }

        else

            hr = VFW_E_INVALIDMEDIATYPE;

        MyFreeMediaType(mt); // 释放 AM_MEDIA_TYPE 结构

    }

    if (FAILED(hr))

              return hr;

 

       double totalTime,dRate;

       pDet->get_FrameRate(&dRate); // 获取帧播放的速率

       pDet->get_StreamLength(&totalTime);

        // 将第一帧保存为指定路径的位图文件

       for(i=0;i<totalTime*dRate;i++)

       {

        CString str;

         str.Format("%sbmpfile%d.bmp",m_editSaveDir,i);

         double position = (double)(i/dRate);

         CComBSTR saveBSTR(str);

         hr = pDet->WriteBitmapBits(position, width, height, saveBSTR);

        }

 

       if (FAILED(hr))

              return hr;

 

       return S_OK;

}

就好了。黑体是修改了的。这样就完成了对 avi 每一帧的提取了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值