Hi!
I'm having the same problem: trying to figure out how to use the QtMultimedia module for playing video files.
Maybe we can share our efforts and get some progress together.
I'm using libvlc in order to decode video files: each time a new frame is ready, libvlc stores the RGB32 bytes representation in a preallocated buffer in memory, I'll call a pointer to this buffer "backendBuffer".
I thought that I could just subclass QAbstractVideoBuffer so as to have a wrapper for the backendBuffer and return it with the map funcion:
This is the header:
@
class VideoBuffer : public QAbstractVideoBuffer
{
public:
VideoBuffer(HandleType type = NoHandle);
virtual ~VideoBuffer();
uchar* map(MapMode mode, int* numBytes, int* bytesPerLine);
MapMode mapMode() const;
void unmap();
void setBackendBuffer(uchar* buffer, int frameWidth, int frameHeight);
int frameWidth() { return _frameWidth; };
int frameHeight() { return _frameHeight; };
private:
uchar* _backendBuffer;
int _frameWidth;
int _frameHeight;
};
@
and this is the definition:
@
VideoBuffer::VideoBuffer(HandleType type)
: QAbstractVideoBuffer(type)
{
}
VideoBuffer::~VideoBuffer()
{
}
uchar* VideoBuffer::map(MapMode mode, int* numBytes, int* bytesPerLine)
{
// I just ignore the MapMode
if (numBytes != NULL)
*numBytes = _frameWidth * _frameHeight * 4;
if (bytesPerLine != NULL)
*bytesPerLine = _frameWidth * 4;
return _backendBuffer; // should I return a copy of the backendBuffer?
}
QAbstractVideoBuffer::MapMode VideoBuffer::mapMode() const
{
return ReadOnly;
}
void VideoBuffer::unmap()
{
// I assume there's nothing to do if I don't return a copy of the bakendBuffer
}
void VideoBuffer::setBackendBuffer(uchar* buffer, int frameWidth, int frameHeight)
{
_backendBuffer = buffer;
_frameWidth = frameWidth;
_frameHeight = frameHeight;
}
@
The idea is to call VideoBuffer::setBackendBuffer(...) passing in the preallocated memory buffer which is filled in by libvlc, for instance:
@
_videoBuffer = new VideoBuffer;
_videoBuffer->setBackendBuffer(_vlcBufferDataPtr, _frameWidth, _frameHeight);
@
Now, each time a new frame is ready to be displayed (its RGB32 representation has been written in the backendBuffer), libvlc calls the following method with a pointer to the VideoBuffer that wraps the backendBuffer.
I create a QVideoFrame and then call QAbstractVideoSurface::present(...).
QAbstractVideoSurface code is exactly the one you can find in the Video Widget Example.
In the following code, videoSurface is a pointer to a QAbstractVideoSurface object.
@
void Controller::bufferReady(VideoBuffer* videoBuffer)
{
mutex.lock();
QSize frameSize( videoBuffer->frameWidth(), videoBuffer->frameHeight() );
QVideoFrame videoFrame( videoBuffer, frameSize, QVideoFrame::Format_RGB32 );
if (!videoFrame.isValid())
return; // false
QVideoSurfaceFormat currentSurfaceFormat = videoSurface->surfaceFormat();
if (videoFrame.pixelFormat() != currentSurfaceFormat.pixelFormat()
|| videoFrame.size() != currentSurfaceFormat.frameSize()) {
QVideoSurfaceFormat format(videoFrame.size(), videoFrame.pixelFormat());
if (!videoSurface->start(format))
return; // false;
}
if (!videoSurface->present(videoFrame))
{
videoSurface->stop();
return; // false;
} else {
return; // true;
}
mutex.unlock();
}
@
However, this code crashes...
Any idea why?
Thanks for any help!