DirectShow开发笔记与问题记录(2018.3.12更新)

本博文主要记录本人在使用DirectShow框架,进行播放器、流媒体处理开发过程中遇到的问题以及解决的方法。一方面作为笔记,方便日后参考,另一方面也记录一些疑难杂症,供大家查询。


问题:

1.使用Qt进行DirectShow开发时,遇上“无法解析的外部符号”

此部分错误包括“cocreateinstance”及“sysfree”等一些com件常用的操作。

本人此前已include相关的dshow.h和windows.h头文件,也在pro文件里面,添加了lib。此时,右键可以查找到报错的方法对应的头文件及定义。

解决:

网上有人指出,在Qt里面,构建——qmake(包含清理和重构)一次,如果pro文件引入正确,一般可以解决。

但我qmake多次,仍报错,包括清理生成的目录及重启Qt。最后发现是,VS下默认缺省添加的一些lib没有引入。

在我加入以下lib之后,qmake后成功运行。

kernel32.lib \
    user32.lib \
    gdi32.lib \
    winspool.lib \
    comdlg32.lib \
    advapi32.lib \
    shell32.lib \
    ole32.lib \
    oleaut32.lib \
    uuid.lib \
    odbc32.lib \
    odbccp32.lib\
这边再说一下普遍的排除过程:

1.首先确定对应的lib添加进了pro中。(无法解析的外部符号,意指无法根据头文件找到对应的库)

2.尝试qmake及清理重构工程

3.pro中顺序,先INCLUDEPATH,再LIBS

4.检查库的版本,是否与Qt编译版本对应(win32及64)


2.开发DirectShow Filter的时候,遇上dll无法注册,显示“模块加载失败……找不到指定模块”

模块 加载失败,请确保该二进制存储在指定的路径中,或者调试它以检查该二进制或相关的.DLL文件是否有问题。找不到指定模块

DirectShow开发笔记与问题记录(2018.3.12更新)_第1张图片

问题描述:

进行一个转换filter开发的时候,一开始继承“CTransInplaceFilter”进行开发。此时过程中一切正常,而后发现需要更改输出格式,并重新分配Allocate和buffer大小,因此更改了继承,选择使用“CTransformFilter”进行开发。

更换了父类之后,修改了构造函数和createInstance等参数后,未进行调试,直接继续进行开发。

1.调试的时候,发现graphstudionext中选中Filter双击,无法再界面中出现Filter框体。

2.添加了断点,发现没有触发任何的构造、创建实例函数。

3.graphstudionext无法注销filter的注册,regsvr32无法注册也无法注销filter的注册(DLL)。

4.期间代码未做任何删减,仅有必要的函数override。

该问题除了无法正常注册filter.dll外,若已注册filter,则无法在链路中创建初始化。


解决:

通过拷贝项目,进行回滚测试,定位到了两个函数引起了DLL注册错误。

BreakConnect(PIN_DIRECTION dir)

CompleteConnect(PIN_DIRECTION direction, IPin *pReceivePin)

我在这两个函数里面调用了外部的FFMpeg库。

此时,我想起我没有将FFMpeg库对应的dll文件拷贝到工程生成的程序目录中。

因此,这是一个由于Filter(COM件)内包含了外部库调用,依赖库找不到dll文件引起的注册失败问题。

将FFMpeg的DLL文件拷贝到release(生成)的目录中,com件正常注册通过。


妈的,又遇到这个问题了,然后我居然忘记我上次解决的时候留下了笔记。一模一样的问题,使用了外部库,但是没有把dill文件与filter.dll放到同一个文件夹,导致只要使用了那个库,filter就没办法注册,注册了也没办法初始化。

3.使用DirectShow开发格式转换软件,使用Avi Muxer和File Writer,播放完成后自动停止链路。

之前在做DirectShow Filter用于VR的投影格式转换。后期需要做一个格式转换软件,因此考虑使用现成的DirectShow框架进行开发。

使用了x264+AVI Muxer+File Writer完成AVI媒体的封装。

此时,使用类似播放视频一样的链路进行控制的时候,会遇到两个问题:

1.IMediaSeeking,进度条

2.播放结束后自动暂停

与一般播放文件不一样的是,格式转换的DirectShow,需要使用Muxer封装Filter的IMediaSeeking接口。因为实际sample传递时,推Sample结束了,但Muxer可能还在运转封装。因此,使用Muxer的Seeking才是正确的进度。

当Sample全部传送完毕,链路应该要自动停止,完成写文件并释放。

此时,GraphStudioNext中完成封装写入会自动停止链路流动,但编程的时候,如果不使用pContrl->Stop(),链路并不会停止。因此,需要判断链路状态,并在完成封装写入后,停止链路。

此时,使用pControl的state或者判断Seeking的进度都是不完善的。IMediaControl的state反应的是控制的状态,而Seeking存在CurrentPosition不等于Duration的情况。

此时,应该使用IMediaEvent,获得链路播放状态。其中,EC_COMPLETE为链路播放完成时的枚举state。

  long evCode, param1, param2;
  bool bComplete = false;
  if (!pEvent) return;

  //得到所有的事件
  while (SUCCEEDED(pEvent->GetEvent(&evCode, ¶m1, ¶m2, 0))
  {
    pEvent->FreeEventParams(evCode, param1, param2);
    switch(evCode)
    {
      case EC_USERABORT:
      case EC_ERRORABORT:
      case EC_COMPLETE:
        bComplete = true;
        break;
    }
  }
  if (bComplete)
  {
    pControl->Stop(); // Important! You must stop the graph!

    //关掉事件通报.
    pEvent->SetNotifyWindow(NULL, 0, 0);
    pEvent->Release();
    pEvent = NULL;
    SendDlgItemMessage(IDC_PROGRESS1, PBM_SETPOS, 0, 0);
    KillTimer(hwnd, nIDEvent);
  }

3.VS2017建立DirectShow工程的Error

环境:VS2017 工具集V141

SDK:DirectX9.0

报错如下:


videoctl.h文件中

严重性 代码 说明 项目 文件 禁止显示状态

错误 C3244 “CAggDirectDraw::~CAggDirectDraw(void)”: 该方法是由“<未知>”引入的,而不是“IDirectDraw” YUVWriter g:\coding\dx9sdk\samples\c++\directshow\baseclasses\videoctl.h 54

严重性 代码 说明 项目 文件 禁止显示状态

错误 C3254 “CAggDirectDraw”: 类包含显式重写“{dtor}”,但并不从包含函数声明的接口派生 YUVWriter g:\coding\dx9sdk\samples\c++\directshow\baseclasses\videoctl.h 54

严重性 代码 说明 项目 文件 禁止显示状态

错误 C2385 对“{dtor}”的访问不明确 YUVWriter g:\coding\dx9sdk\samples\c++\directshow\baseclasses\videoctl.h 54

代码部分如下:

class CAggDirectDraw : public IDirectDraw, public CUnknown
{
protected:

    LPDIRECTDRAW m_pDirectDraw;

public:

    DECLARE_IUNKNOWN
    STDMETHODIMP NonDelegatingQueryInterface(REFIID riid,void **ppv);

    // Constructor and destructor

    CAggDirectDraw(TCHAR *pName,LPUNKNOWN pUnk) ://报错部分
        CUnknown(pName,pUnk),
        m_pDirectDraw(NULL) { };

    virtual CAggDirectDraw::~CAggDirectDraw() { };//报错部分

    // Set the object we should be aggregating
    void SetDirectDraw(LPDIRECTDRAW pDirectDraw) {
        m_pDirectDraw = pDirectDraw;
    }

    // IDirectDraw methods…………下面不写了

transip.h文件中

严重性 代码 说明 项目 文件 禁止显示状态
错误 C4596 “Copy”: 成员声明中的非法限定名 YUVWriter g:\coding\dx9sdk\samples\c++\directshow\baseclasses\transip.h 214
严重性 代码 说明 项目 文件 禁止显示状态
错误(活动) E0427 成员声明中不允许限定名 YUVWriter g:\Coding\dx9sdk\Samples\C++\DirectShow\BaseClasses\transip.h 214

代码如下:

protected:

    IMediaSample * CTransInPlaceFilter::Copy(IMediaSample *pSource);//报错部分

combaseapi.h文件中

严重性 代码 说明 项目 文件 禁止显示状态
错误 C2760 语法错误: 意外的令牌“标识符”,预期的令牌为“类型说明符” YUVWriter c:\program files (x86)\windows kits\8.1\include\um\combaseapi.h 229

代码如下:

extern "C++"
{
    template _Post_equal_to_(pp) _Post_satisfies_(return == pp) void** IID_PPV_ARGS_Helper(T** pp) 
    {
#pragma prefast(suppress: 6269, "Tool issue with unused static_cast")
        static_cast(*pp);    // make sure everyone derives from IUnknown
        return reinterpret_cast(pp);
    }    
}

我用该SDK开发维护了多个DirectShow Filter,出问题的时候,我用以前开发的工程,一点点对着配置看。include、lib没有配错,工程也是正常的,但是就只有新的工程报错,旧的Filter工程正常。

然后,发现了一个比较简单的解决方案——

解决方案一:

将工程平台工具集,设定为V141(VS2017)之前的版本,如V120或V140,都可以解决这个问题。

但是,我以前工程都是在V141工具集下开发,没有任何异常。

抱着钻牛角尖的心理,一点点比对,终于发现问题所在。

简单看了一下报错的代码。其实语法是没有问题的,其中两个头文件,在类的定义里面,使用了“类名::方法”定义自身方法。这与某些C++规范要求是不太一致的。此时考虑可能是因为平台版本对语法检查的问题。

于是,对比发现了核心的问题

解决方案二:

“工程属性”——“C/C++”——"符合模式"——勾选“否”

DirectShow开发笔记与问题记录(2018.3.12更新)_第2张图片

问题解决了~


你可能感兴趣的:(DirectShow,多媒体)