4

I'm trying to write a QML plugin that reads frames from a video (using a custom widget to do that task, NOT QtMultimedia/Phonon), and each frame is converted to a QImage RGB888, and then displayed on a QGLWidget (for performance reasons). Right now nothing is draw to the screen and the screen stays white all the time.

It's important to state that I already have all of this working without QGLWidget, so I know the issue is setting up and drawing on QGLWidget.

The plugin is being registered with:

qmlRegisterType<Video>(uri,1,0,"Video");

so Video is the main class of the plugin. On it's constructor we have:

Video::Video(QDeclarativeItem* parent)
: QDeclarativeItem(parent), d_ptr(new VideoPrivate(this))
{    
    setFlag(QGraphicsItem::ItemHasNoContents, false);            

    Q_D(Video);
    QDeclarativeView* view = new QDeclarativeView;
    view->setViewport(&d->canvas()); // canvas() returns a reference to my custom OpenGL Widget
}

Before I jump to the canvas object, let me say that I overloaded Video::paint() so it calls canvas.paint() while passing QImage as parameter, I don't know if this is the right way to do it so I would like some advice on this:

void Video::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
    Q_UNUSED(painter);
    Q_UNUSED(widget);
    Q_UNUSED(option);

    Q_D(Video);
    // I know for sure at this point "d->image()" is valid, but I'm hiding the code for clarity
    d->canvas().paint(painter, option, d->image());
}

The canvas object is declared as GLWidget canvas; and the header of this class is defined as:

class GLWidget : public QGLWidget
{
    Q_OBJECT
public:        
    explicit GLWidget(QWidget* parent = NULL);
    ~GLWidget();

    void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QImage* image);
};

Seems pretty simple. Now, the implementation of QGLWidget is the following:

GLWidget::GLWidget(QWidget* parent)
: QGLWidget(QGLFormat(QGL::SampleBuffers), parent)
{
   // Should I do something here?
   // Maybe setAutoFillBackground(false); ???
}

GLWidget::~GLWidget()
{
}

And finally:

void GLWidget::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QImage* image)
{
   // I ignore painter because it comes from Video, so I create a new one:
   QPainter gl_painter(this);


   // Perform drawing as Qt::KeepAspectRatio

   gl_painter.fillRect(QRectF(QPoint(0, 0), QSize(this->width(), this->height())), Qt::black);

   QImage scaled_img = image->scaled(QSize(this->width(), this->height()), _ar, Qt::FastTransformation);

   gl_painter.drawImage(qRound(this->width()/2)  - qRound(scaled_img.size().width()/2),
                        qRound(this->height()/2) - qRound(scaled_img.size().height()/2),
                        scaled_img); 
}

What am I missing?

I originally asked this question on Qt Forum but got no replies.

karlphillip
  • 92,053
  • 36
  • 243
  • 426

2 Answers2

5

Solved. The problem was that I was trying to create a new GL context within my plugin when I should be retrieving the GL context from the application that loaded it.

This code was very helpful to understand how to accomplish that.

By the way, I discovered that the stuff was being draw inside view. It's just that I needed to execute view->show(), but that created another window which was not what I was looking for. The link I shared above has the answer.

karlphillip
  • 92,053
  • 36
  • 243
  • 426
  • Do you still have the source? I am currently facing a similar problem and the link goes to 404. – Hyndrix Dec 29 '11 at 19:05
  • I will try to paste it here when i can. – karlphillip Dec 29 '11 at 19:38
  • 2
    [Here it is](https://gitorious.org/peregrine/peregrine/blobs/master/qml-plugin/videooutput/qmlvideo.cpp) – karlphillip Dec 29 '11 at 19:49
  • Dead link. New one too that is. – Moustachio Nov 15 '20 at 22:59
  • This thread has almost 9 years of age. The repository where the reference code was originally published DIED and is long gone. This is the last time I'll track down a similar source code on the Internet for reference. [Here it is](https://github.com/longwei/qmlvideo/blob/study2/qmlvideo.cpp). Good luck from now on. – karlphillip Nov 15 '20 at 23:11
0

I think that you have to draw on your glwidget using the opengl functions.

One possible way is to override your paintGL() method in GLWidget and then draw your image with glDrawPixels().

glClear(GL_COLOR_BUFFER_BIT);
glDrawPixels(buffer.width(), buffer.height(), GL_RGBA, GL_UNSIGNED_BYTE, buffer.bits());

Where buffer is a QImage object that needs to be converted using QGLWidget::converrtToGLFormat() static method.

Look at this source for reference: https://github.com/nayyden/ZVector/blob/master/src/GLDebugBufferWidget.cpp

BenMorel
  • 34,448
  • 50
  • 182
  • 322
  • 1
    For some reason, `GLWidget::paintGL()` is not being called, even if I change on `Video::paint()` for it to execute `d->canvas().update(); d->canvas().repaint();` – karlphillip Dec 09 '11 at 15:26
  • One stupid suggestion I might give is to add a new public method to your GLWidget and in that method call paintGL() and updateGL() but then you will have to type cast the canvas when you want to call it. – Rangel Ivanov Dec 09 '11 at 16:05
  • I really don't want to use OpenGL calls directly, that's why I'm not overloading GL methods like `paintGL()`. – karlphillip Dec 09 '11 at 16:15
  • If you are still interested, this problem has been solved. You can check my answer if you would like. – karlphillip Dec 13 '11 at 12:32