关于使用DirectX在QGraphicsView上播放视频的探索

来源:互联网 发布:懒人起床闹钟软件 编辑:程序博客网 时间:2024/04/19 16:11

最近注意到有人遇到了一个我半年前遇到的问题,我将半年前自己的探索写出来供大家参考,希望对大家有帮助,如果有错误的地方希望不吝指教。如果解决了问题,请告诉我。

大约半年前遇到了此问题,使用DirectX在QGraphicsView上播放视频。

由于当时项目比较急,一直没有解决。后来就换了QMdiarea代替了QGraphicsView框架,实现了directx通过窗口句柄(即WInId)播放视频的功能。


问题描述:使用QGraphicsProxyWidget 直接将一个视频窗口Widget加入 QGraphicsView,无法显示画面,不使用QGraphicsProxyWidget,视屏播放很正常


代码:

VideoMainWindow *videoWnd = new VideoMainWindow(); //播放视频的widget    CustomProxy *proxyVideo = new CustomProxy;    proxyVideo->setWidget(videoWnd);    proxyVideo->setCacheMode(QGraphicsItem::DeviceCoordinateCache);    _scene->addItem(proxyVideo);



如果去掉代理,视频正常,加上代理,只有窗口,不会显示画面。

在那几天我找到的唯一的相关的资料列举如下:


参考网址:(From:http://blog.csdn.net/ajaxhe/article/details/7316011#comments)

参考链接1:http://doc.qt.nokia.com/4.7-snapshot/demos-qmediaplayer.html
官方提供的小例子是入门的好资源
参考链接2:http://blog.csdn.net/huihui1988/article/details/5725955
网友提供的一个Qt使用QGraphicsView实现滑动窗体效果,参考了有关QGraphicsView的使用。其实在官方提供的qmediaplayer可以正常显示视频,但加入QGraphicsView是为了在视频上输出一些其他的信息。
参考链接3:http://hi.baidu.com/david_jun/blog/item/7391fb3c5c3566d3d462255e.html/cmtid/7a281bea440172f4b3fb955b
参考链接3提供了一个在VideoWidget上附着透明控件的思路,也是这篇文章让我尝试了QGraphicsView,效果良好,原理上可以解决我之前遇到的一个DirectDraw控制的widget上显示文字的问题(还没有来得及测试)。关于这个问题,请参考:http://www.qtcn.org/bbs/read.php?tid=47175

从链接2中,关于QGraphicsView与视频播放,但是只是用来输出一些其他信息,和winId没有任何关系,所以一直没有找到相关的任何资料。

当使用时可以判断出窗口句柄是可变的,如果窗口句柄发生了变化,DirectX所拥有的原来的窗口句柄就会变得无效,自然没有画面。后来我发现有一个事件:QEvent::WinIdChange可以捕捉一个QWidget窗口句柄的变化。我没有去尝试。先下班回家了,未完待续。。。if (!q->isWindow()) { QWidget *parent = q->parentWidget(); 也就是graphicsItem会一直向上找到isWindow()为true的窗体,然后返回此窗体的句柄,QGraphicsView框架所有的子项都是没有winid的,实际返回的应该是上层类的句柄,所以无法用direct渲染视频


后来只能看QGraphicsView源代码:

我发现QGraphicsProxyWidget 继承 QGraphicsItem 和 QObject,并非QWidget或QPaintDevice再看一下QGraphicsWidget的paintEvent手册文档:
void QGraphicsWidget::paintWindowFrame ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget *widget = 0 ) [virtual]This virtual function is called by QGraphicsScene to draw the window frame for windows using painter, option, and widget, in local coordinates. The base implementation uses the current style to render the frame and title bar.You can reimplement this function in a subclass of QGraphicsWidget to provide custom rendering of the widget's window frame.这就说明ProxyWidget没有窗口句柄,而是渲染出来的
附上QWidget WinId代码:WId QWidget::winId() const{    if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {#ifdef ALIEN_DEBUG        qDebug() << "QWidget::winId: creating native window for" << this;#endif        QWidget *that = const_cast<QWidget*>(this);#ifndef Q_WS_QPA        that->setAttribute(Qt::WA_NativeWindow);#endif        that->d_func()->createWinId();        return that->data->winid;    }    return data->winid;}void QWidgetPrivate::createWinId(WId winid){    Q_Q(QWidget);#ifdef ALIEN_DEBUG    qDebug() << "QWidgetPrivate::createWinId for" << q << winid;#endif    const bool forceNativeWindow = q->testAttribute(Qt::WA_NativeWindow);    if (!q->testAttribute(Qt::WA_WState_Created) || (forceNativeWindow && !q->internalWinId())) {#ifndef Q_WS_QPA        if (!q->isWindow()) {            QWidget *parent = q->parentWidget();            QWidgetPrivate *pd = parent->d_func();            if (forceNativeWindow && !q->testAttribute(Qt::WA_DontCreateNativeAncestors))                parent->setAttribute(Qt::WA_NativeWindow);            if (!parent->internalWinId()) {                pd->createWinId();            }            for (int i = 0; i < pd->children.size(); ++i) {                QWidget *w = qobject_cast<QWidget *>(pd->children.at(i));                if (w && !w->isWindow() && (!w->testAttribute(Qt::WA_WState_Created)                                            || (!w->internalWinId() && w->testAttribute(Qt::WA_NativeWindow)))) {                    if (w!=q) {                        w->create();                    } else {                        w->create(winid);                        // if the window has already been created, we                        // need to raise it to its proper stacking position                        if (winid)                            w->raise();                    }                }            }        } else {            q->create();        }#else        Q_UNUSED(winid);        q->create();#endif //Q_WS_QPA    }}