VideoOutput + QQuickView::SizeRootObjectToView + Qt::PortraitOrientation



  • I'm trying to preview the front facing camera at maximum resolution in an upright orientation locked to the device's screen. This is using QT 5.5 in a QML application adapted from the qmlvideofilter sample.

    I'm using the following C++:

        view.setResizeMode( QQuickView::SizeRootObjectToView );
        view.reportContentOrientationChange(Qt::PortraitOrientation);
    

    And the VideoOutput + Camera QML shown below (see comments):

      Camera {
        id: camera
        position: Camera.FrontFace
        objectName: "CameraObject"
      }
    
      QTRenderGL {
        id: qtrendergl
      }
    
      VideoOutput {
        id: output    
        source: camera
        objectName: "VideoOutput"    
        focus : visible
        filters: [ infofilter, videofilter ]
        anchors.fill: parent
        anchors.centerIn: parent
        anchors.margins: 0
        fillMode: VideoOutput.PreserveAspectFit
    
        // Using this C++ for fixed upright orientation:
        //
        // QObject* qmlCamera = root->findChild<QObject*>("CameraObject");
        // QCamera* camera = qvariant_cast<QCamera*>(qmlCamera->property("mediaObject"));
        // QCameraInfo cameraInfo(*camera);
        // qmlVideoOutput->setProperty("rotation", cameraInfo.orientation());
        // rotation: 0
    
        // Enabling autoOrientation in combination with
        //
        //     fillMode: VideoOutput.PreserveAspectFit
        //
        // provides the stretch to fit behavior I am looking for, except I don't want the
        // varying device orientation landscale/portrait switching.  When I specify an
        // upright rotation manually (in C++ or QML) then the VideoOutput does not stretch
        // to fit the screen (i.e., no VideoOutput.PreserveAspectFit) properly.
        //
        //     autoOrientation: true
      }
    

    For configuration A (autoOrientation: true + fillMode.VideoOutput.PreserveAspectFit) I get the behavior I'm looking for when the phone is upright, but the screen switches to landscape orientation when I rotate the phone, which I don't want.

    When I use configuration B, basically fillMode.VideoOutput.PreserveAspectFit with a manually specified upright camera rotation, such as QML rotation: 90 or C++ qmlVideoOutput->setProperty("rotation", cameraInfo.orientation()) and view.reportContentOrientationChange(Qt::PortraitOrientation) then I get the upright camera output and locked screen orientation I want, but I don't see the aspect ratio preserving stretch.

    Here is an example of the output for configuration A.

    Here is an example of the output for configuration B (note the wide border).

    I feel I probably need to either: 1) find a QT way to override VideoOutput in QML/C++ (inheritance, signal/slot); or 2) leave the QML Camera + VideOutput (with filter) configured as is, since it is mostly working, but disable the final rendering and draw the frames directly in OpenGL using my own class via abeforeRendering() signal. The later option would have some advantages, since it would allow me to compensate for arbitrary geometric changes to the output QVideoFrame texture in my custom OpenGL VideoFilterRunnable without breaking the stretching behavior . (Any approach that gives me the desired output would be fine.) It seems the direct drawing could be accomplished using another class registered in QML and configured for the beforeRendering() signal like this:

    connect(window(), SIGNAL(beforeRendering()), m_renderer, SLOT(paint()), Qt::DirectConnection);
    

    if I can get my output QVideoFrame to the new rendering class. I grabbed some code as a place holder for this from the QT squircle sample in my project here. That still needs the QTVideoFrame input and a way to disable the defaultVideoOutputrendering. Any hints on this approach, or a fix for the defaultVideoOutput rendering would be greatly appreciated. The full sample (adapted from the qmlvideofilter) is available on github here.



  • Did you try scaling the video output when defining the rotation ?

    VideoOutput {
            id: viewfinder
            anchors.fill : parent
            source: camera
            rotation : 90
            transformOrigin: Item.Center
            fillMode : VideoOutput.PreserveAspectCrop
            scale : height/width
            
        }
    

    One could also use the "orientation" property of the VideoOutput.



  • @Charby said:

    scale : height/width

    Excellent. scale : height/width is exactly what I needed. Thanks. Somehow I missed that (probably basic QML) property in my search. I'll need to set this adaptively in order to deal with different phones. The following C++ variation gives me exactly the fixed orientation and scale I wanted (I'm guessing this could also be done in QML) :

        QQuickItem* root = view.rootObject();
        
        QObject* qmlCamera = root->findChild<QObject*>("CameraObject");
        assert(qmlCamera != nullptr);
        
        QCamera* camera = qvariant_cast<QCamera*>(qmlCamera->property("mediaObject"));
        assert(camera != nullptr);
        
        QObject * qmlVideoOutput = root->findChild<QObject*>("VideoOutput");
        assert(qmlVideoOutput);
    
        const QCameraInfo cameraInfo(*camera);
        const bool hasTranspose = (cameraInfo.orientation() / 90) % 2;
        const auto &resolution = camera->viewfinderSettings().resolution();
        double scale = hasTranspose ? double(resolution.width())/resolution.height() : 1.0;
        qmlVideoOutput->setProperty("scale", scale);
        qmlVideoOutput->setProperty("rotation", cameraInfo.orientation());
    


  • Glad this helped !
    You are right, this would be achieved in QML (which would keep the C++ backend agnostic of the UI which is more in line with QtQuick I think...)

    I think something similar would go in QML :

        Camera {
            id: camera
        }
        VideoOutput {
            property bool hasTranspose : (camera.orientation / 90) % 2
            anchors.fill : parent
            source: camera
            rotation : camera.orientation
            transformOrigin: Item.Center
            fillMode : VideoOutput.PreserveAspectCrop
            scale : hasTranspose ? camera.viewfinder.resolution.height / camera.viewfinder.resolution.width : 1.0
            
            
        }
    

    Maybe the following could also be satisfactory :

    Camera {
            id: camera
        }
        VideoOutput {
            anchors.fill : parent
            source: camera
            orientation: camera.orientation
            
        }
    


  • @Charby

    Even better (and much cleaner). After inverting the -camera.orientation it works beautifully. Thanks again.

      VideoOutput {
        id: output    
        source: camera
        objectName: "VideoOutput"    
        filters: [ infofilter, videofilter ]
        anchors.fill: parent
        orientation: -camera.orientation
      }
    


  • @dhirvonen said:

    @Charby said:

    scale : height/width

    Excellent. scale : height/width is exactly what I needed. Thanks. Somehow I missed that (probably basic QML) property in my search.

    Actually I can't find this part in documentation too. There is no scale property in VideoOutput: http://doc.qt.io/qt-5/qml-qtmultimedia-videooutput.html In fact I know that VideoOutput inherits from QQuickItem: https://github.com/hunter-packages/Qt/blob/84a5846a20da62e2e2c73c1218927f8746c42de6/qtmultimedia/src/multimedia/qtmultimediaquicktools_headers/qdeclarativevideooutput_p.h#L54 QQuickItem has scale property: http://doc.qt.io/qt-5/qquickitem.html#scale-prop but I don't see height/width.



  • scale, height and width are Item (qquickitem) inhereted properties.
    Just to avoid any misunderstanding : "height/width" is not a property name but just height divided by width.



  • @Charby said:

    "height/width" is not a property name but just height divided by width.

    Okay, I see. Thanks for clarification. So the only one issue I see left here is that there is no such inherited members shown in documentation:



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.