如何将解码缓冲区从 ffmpeg 映射到 QVideoFrame?
How to map a decoded buffer from ffmpeg into QVideoFrame?
我正在尝试将解码后的 ffmpeg 缓冲区放入 QFrame
,这样我就可以将此帧放入 QAbstractVideoBuffer
,然后将此缓冲区放入 QMediaPlayer
。
这是 VideoSurface 的代码。根据QT的文档,我只需要实现这两个函数:构造函数和bool present
,它将框架处理成名为frame
的QVideoFrame
QList<QVideoFrame::PixelFormat> VideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const
{
Q_UNUSED(handleType);
// Return the formats you will support
return QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_YUV420P;
}
bool VideoSurface::present(const QVideoFrame &frame)
{
//Q_UNUSED(frame);
std:: cout << "VideoSurface processing 1 frame " << std::endl;
QVideoFrame frametodraw(frame);
if(!frametodraw.map(QAbstractVideoBuffer::ReadOnly))
{
setError(ResourceError);
return false;
}
// Handle the frame and do your processing
const size_t bufferSize = 398304;
uint8_t frameBuffer[bufferSize];
this->mediaStream->receiveFrame(frameBuffer, bufferSize);
//Frame is now in frameBuffer, we must put into frametodraw, I guess
// ------------What should I do here?-------------
frametodraw.unmap();
return true;
}
看看this->mediaStream.decodeFrame(frameBuffer, bufferSize)
。此行将新的 h264 帧解码为 YUV420P 格式的 frameBuffer
。
我的想法是使用 map
函数然后尝试使用 frametodraw.bits()
函数接收缓冲区指针并尝试将此指针指向另一个东西,但我不认为这是方式。我想我应该将 frameBuffer
的内容复制到这个指针,但是这个指针没有告诉我它的大小,例如,所以我想这也不是办法。
所以...我应该如何将缓冲区映射到名为 frame
的 QVideoFrame
?
我还注意到,当我将 VideoSurface
实例放入 QMediaPlayer
时,从未调用 present
。我觉得有些不对劲,即使 player->play()
这很重要。
我也没有frameBuffer
里面解码后图片的大小,我只有它的总大小。我觉得这应该也是个问题。
我还注意到 QMediaPlayer
不是可显示的元素...那么哪个 Widget 会显示我的视频?这对我来说很重要。
我认为您误解了每个 class 的作用。您正在子classing QAbstractVideoSurface,它应该有助于访问准备好呈现的数据。在本方法中,您将获得一个已经解码的 QVideoFrame。如果您想在屏幕上显示此内容,则需要在 VideoSurface class.
中实现它
您可以在 QMediaPlayer 上设置 VideoSurface,媒体播放器已经处理了视频的解码和像素格式的协商。您在 VideoSurface 中收到的 QVideoFrame 已经具有来自媒体播放器的 height/width 和像素格式。媒体播放器的典型用途是让它加载和解码文件,并让它与视频小部件一起显示在屏幕上。
如果您需要使用自己的自定义 ffmpeg 解码器,我的建议是将帧从 yuv420 转换为 rgb(libswscale?),创建您自己的自定义小部件,您也可以传递帧数据并渲染它在将其加载到 QPixmap 后使用 QPainter 在屏幕上显示。
我正在尝试将解码后的 ffmpeg 缓冲区放入 QFrame
,这样我就可以将此帧放入 QAbstractVideoBuffer
,然后将此缓冲区放入 QMediaPlayer
。
这是 VideoSurface 的代码。根据QT的文档,我只需要实现这两个函数:构造函数和bool present
,它将框架处理成名为frame
QVideoFrame
QList<QVideoFrame::PixelFormat> VideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const
{
Q_UNUSED(handleType);
// Return the formats you will support
return QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_YUV420P;
}
bool VideoSurface::present(const QVideoFrame &frame)
{
//Q_UNUSED(frame);
std:: cout << "VideoSurface processing 1 frame " << std::endl;
QVideoFrame frametodraw(frame);
if(!frametodraw.map(QAbstractVideoBuffer::ReadOnly))
{
setError(ResourceError);
return false;
}
// Handle the frame and do your processing
const size_t bufferSize = 398304;
uint8_t frameBuffer[bufferSize];
this->mediaStream->receiveFrame(frameBuffer, bufferSize);
//Frame is now in frameBuffer, we must put into frametodraw, I guess
// ------------What should I do here?-------------
frametodraw.unmap();
return true;
}
看看this->mediaStream.decodeFrame(frameBuffer, bufferSize)
。此行将新的 h264 帧解码为 YUV420P 格式的 frameBuffer
。
我的想法是使用 map
函数然后尝试使用 frametodraw.bits()
函数接收缓冲区指针并尝试将此指针指向另一个东西,但我不认为这是方式。我想我应该将 frameBuffer
的内容复制到这个指针,但是这个指针没有告诉我它的大小,例如,所以我想这也不是办法。
所以...我应该如何将缓冲区映射到名为 frame
的 QVideoFrame
?
我还注意到,当我将 VideoSurface
实例放入 QMediaPlayer
时,从未调用 present
。我觉得有些不对劲,即使 player->play()
这很重要。
我也没有frameBuffer
里面解码后图片的大小,我只有它的总大小。我觉得这应该也是个问题。
我还注意到 QMediaPlayer
不是可显示的元素...那么哪个 Widget 会显示我的视频?这对我来说很重要。
我认为您误解了每个 class 的作用。您正在子classing QAbstractVideoSurface,它应该有助于访问准备好呈现的数据。在本方法中,您将获得一个已经解码的 QVideoFrame。如果您想在屏幕上显示此内容,则需要在 VideoSurface class.
中实现它您可以在 QMediaPlayer 上设置 VideoSurface,媒体播放器已经处理了视频的解码和像素格式的协商。您在 VideoSurface 中收到的 QVideoFrame 已经具有来自媒体播放器的 height/width 和像素格式。媒体播放器的典型用途是让它加载和解码文件,并让它与视频小部件一起显示在屏幕上。
如果您需要使用自己的自定义 ffmpeg 解码器,我的建议是将帧从 yuv420 转换为 rgb(libswscale?),创建您自己的自定义小部件,您也可以传递帧数据并渲染它在将其加载到 QPixmap 后使用 QPainter 在屏幕上显示。