在imx6.0开发板上实现录屏功能
在imx6.0开发板上实现录屏功能
嵌入式linux上采用gst1.0视频流开发库,应用程序框架采用QT5 qml实现。
整体流程:实现gst pipeline加摄像头数据投射到qmlglsink上做图像显示后,将qmlglsink的数据流抓图。将每帧的图片push进appsrc,起一条gst的appsrc到filesink的流生成本地视频。(qmlglsink/appsrc/filesink均是硬件支持的gst元件由开发板厂家驱动提供用gst-inspect-1.0可以查看元件属性)
1、将qmlglsink的qmlItem装在Rectangle类型中。
main.qml
...
Rectangle {
id:canvasvis
z:0
color: "black"
anchors.fill: parent
GstGLVideoItem {
id: video
objectName: "videoItem"
anchors.centerIn: parent
width: parent.width
height: parent.height
}
}
2、设置定时器定时抓屏
main.qml
...
Timer{
id:recordTimer
interval: 1000/15
running: false
repeat: true
onTriggered: {
screenrecorder.screenGrab(root); //root为qml根目录抓取含UI的整个目录
//screenrecorder.itemGrab(canvasvis); //抓取Item的截图
}
}
——————
3、对应C++的实现函数
screenRecorder.cpp
...
void screenRecorder::screenGrab(QQuickWindow *rootWindow)
{
QImage image = rootWindow->grabWindow();
//image = image.convertToFormat(QImage::Format_RGB16);
//qDebug()<<"convertToFormat:"<<image.format();
emit incomingRec(image);
}
void screenRecorder::itemGrab(QQuickItem *item)
{
// Default size
QSharedPointerresult = item->grabToImage();
QSignalSpy spy(result.data(), SIGNAL(ready()));
QTRY_VERIFY(spy.size() > 0);
QVERIFY(!result->url().isEmpty());
QTime time;
time.start();
QImage image = result->image().convertToFormat(QImage::Format_RGB16);
emit incomingRec(image);
}
以上之列了部分关键代码,gst起流appsrc到filesink部分详见gst命令行()、注册cpp类型为qml使用等没有详细写。详细代码见:
实际使用的测试问题
1、gst流设为PLAYING状态不成功,current状态为ready,pending状态为playing。返回结果为:async。
原因:appsrc的数据源没有实际数据,向appsrc元件属性的”push-buffer“未成功。
2、QT的抓图函数性能达不到要求
每次抓图push的整个动作要求在1000/30ms内完成,后来降低到1000/15ms内完成仍然不能100%完成。执行率80%左右。所以实际录制的15帧视频有缺帧,效果类似快进的效果。
QImage image = rootWindow->grabWindow();
抓整个window的图,15帧每秒勉强可以同步完成。
注意image出来的默认格式为:QImage::Format_RGBX8888,生成视频时除了注意appsrc的帧率外,format属性也要对应设置为Format_RGBA。
qt的官方解释:Warning: Calling this function will cause performance problems.
QSharedPointer
result = item->grabToImage(); 抓单个Item的图像数据,15帧也很难完成。
qt的官方解释:
The grab happens asynchronously and the signal QQuickItemGrabResult::ready() is emitted when the grab has been completed.
首先这个函数是异步完成的,完成后有ready()信号。实测1000/30ms的速率调用的话,软件直接卡死一直没有ready()信号发出。
Note: This function will render the item to an offscreen surface and copy that surface from the GPU's memory into the CPU's memory, which can be quite costly. For "live" preview, use layers or ShaderEffectSource.
其次,这个函数对cpu也有占用硬件资源使用情况不好。
注意image出来的默认格式为:QImage::Format_RGBA8888_Premultiplied(与QImage::Format_RGBX8888不同),如果不手动调用QT的转换函数:image = image.convertToFormat(QImage::Format_RGB16);
还没有找到appsrc的合适格式对应。
测试实例
在录整个屏幕的情况比较好,且没有使用QT的image = image.convertToFormat(QImage::Format_RGB16);
15帧每秒的mp4格式录屏性能:
录制方式|帧率|录屏时间|实际帧数|实际文件时间
--|:--😐--|:--|:
抓图整个window|15|30s|365|24s
问题思考
后续为保证录屏文件流畅不缺帧,qt的抓屏函数还是不能使用。抓屏速率也取决与定时器的周期是否稳定,整体流程数据和难和gst pipeline 1000/30s的录制速率一致。
只有采用gst imxsrc硬件做数据源,才能保证速率一致。
但是目前还有录制UI绘图的要求,是个矛盾...