0

In QML, you can capture the screen to an image file with grabToImage https://doc.qt.io/qt-6/qml-qtquick-item.html#grabToImage-method

We have a requirement on doing a screen capture of a video file. We checked Qt QML Multimedia but could not figure out to do this.

Please provide suggestions on how we may be able to implement screen capture to video file?

Stephen Quan
  • 21,481
  • 4
  • 88
  • 75
Deepak R
  • 29
  • 6
  • Welcome to stackoverflow. Please checkout the [tour], [editing help](https://stackoverflow.com/editing-help) and [ask]. – Marcelo Paco Apr 14 '23 at 05:38
  • One technique that I've used, is (1) set up a timer that triggers frequently, e.g. every 1000 milliseconds, (2) do screenshots with grabToImage(), (3) join the screenshots using ffmpeg producing either an animated GIF or an MP4 video file. – Stephen Quan Apr 15 '23 at 10:39
  • I don't think that Qt provides some screen recorder. You probably can do it yourself or using some external tool, like [Gstreamer](https://stackoverflow.com/questions/33747500/using-gstreamer-to-capture-screen-and-show-it-in-a-window). – folibis Apr 16 '23 at 05:21

1 Answers1

1

Below is an example of capturing 5 seconds of an application at 10fps (i.e. 50 frames in total) and using an external tool (e.g. FFmpeg) to produce an animated GIF.

First, the application uses Timer combined with grabToImage to capture frames at a regular intervals. When we got 5 seconds worth, i.e. 50 frames, we stop the Timer.

Page {
    id: page
    width: 400
    height: 600
    Frame {
        id: frame
        anchors.centerIn: parent
        width: 200
        height: 200
        background: Rectangle { color: "#848895" }
        Node {
            id: standAloneScene
            DirectionalLight { ambientColor: Qt.rgba(1.0, 1.0, 1.0, 1.0) }
            Node {
                id: node
                Model {
                    source: "#Cube"
                    materials: [
                        DefaultMaterial {
                            diffuseMap: Texture {
                                sourceItem: Image {
                                    source: "https://stephenquan.github.io/images/qt/madewithqt.png"
                                }
                            }
                        }
                    ]
                }
            }
            OrthographicCamera {
                id: cameraOrthographicFront
                y: 800; z: 1000
                Component.onCompleted: lookAt(node)
            }
        }
        View3D {
            anchors.fill: parent
            importScene: standAloneScene
            camera: cameraOrthographicFront
        }
        NumberAnimation {
            target: node
            property: "eulerRotation.y"
            loops: Animation.Infinite
            running: true
            from: 720; to: 0
            duration: 10000
        }
    }
    Button {
        y: parent.height * 3 / 4
        anchors.horizontalCenter: parent.horizontalCenter
        text: qsTr("Record (%1)").arg(recordTimer.frame)
        enabled: !recordTimer.running
        onClicked: {
            recordTimer.stop();
            recordTimer.frame = 0;
            recordTimer.interval = 100; // 100ms === 10fps
            recordTimer.maxFrames = 50; // number of frames (total 5 seconds)
            recordTimer.start();
        }
    }
    Timer {
        id: recordTimer
        property int frame: -1
        property int maxFrames: 100
        interval: 100
        running: false
        repeat: true
        onTriggered: frame.grabToImage(function (result) {
            result.saveToFile(`C:/Temp/record${recordTimer.frame}.png`);
            if (++recordTimer.frame >= recordTimer.maxFrames) recordTimer.stop();
        } );
    }
}

Next, I use FFMPEG which I've installed the binaries to C:\ffmpeg\bin. With a bit of Google-fu, you can find where to download (e.g. https://ffmpeg.org/download.html).

Then, I can produce an MP4 using the following script:

  • -y - means overwrite any previous output file
  • -f image2 - means the source may be a series of images
  • -r 10 - specifies 10fps
  • -i record%%d.png - supplies the wildcard match for the source images
  • -vb 3000k - means allow high resolution video frames
  • -an - means we are not interested in including audio in our output
  • -vcodec mpeg4 - change the output MP4 video codec from x264 (default) to MPEG4
  • screengrab.mp4 - specifies the name of the output MPEG4 file
REM MAKEMP4.BAT
set path=%PATH%;C:\ffmpeg\bin
ffmpeg -y -f image2 -r 10 -i "C:/Temp/record%%d.png" -vb 3000k -an -vcodec mpeg4 C:/Temp/screengrab.mp4

If I want to produce an 8-bit animating GIF, I need to produce a palette.png which can be done by doing a preliminary pass:

REM MAKEGIF.BAT
set path=%PATH%;C:\ffmpeg\bin
ffmpeg -y -f image2 -r 10 -i "C:/Temp/record%%d.png" -vf "palettegen" C:/Temp/palette.png
ffmpeg -y -f image2 -r 10 -i "C:/Temp/record%%d.png" -i C:/Temp/palette.png -lavfi "paletteuse" C:/Temp/screengrab.gif

The following animated GIF was generated using the above command:

screengrab.gif

Stephen Quan
  • 21,481
  • 4
  • 88
  • 75