在 Android 中运行的 QML 相机死了

Posted

技术标签:

【中文标题】在 Android 中运行的 QML 相机死了【英文标题】:QML Camera running in Android dies 【发布时间】:2015-11-13 14:22:30 【问题描述】:

我正在开发一个使用 QML Camera 元素的应用程序。问题是,在拍摄了一些照片后,相机会死机并且在我重新打开应用程序之前不再工作。谁能帮帮我?

我尝试在camera.start() 之前使用camera.cameraState = Camera.LoadedState,在camera.stop() 之后使用camera.cameraState = Camera.UnloadedState,但它杀死了我的整个应用程序,而不仅仅是相机。

Ps:到目前为止,我只是在 android 中测试过它。我将看看它是否也发生在 ios 中。

这是完整的代码:

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

#include <QtQml>

#include "processaimagem.h"
#include "provedorimagem.h"

int main(int argc, char *argv[])

    QGuiApplication app(argc, argv);

    qmlRegisterType<processaImagem>("ProcessaImagemQml", 1, 0, "ProcessaImagem");

    QQmlApplicationEngine engine;

    provedorImagem *provedorImg = new provedorImagem;

    engine.rootContext()->setContextProperty("ProvedorImagem", provedorImg);

    engine.addImageProvider("provedor", provedorImg);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();

main.qml

import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls 1.3
import QtMultimedia 5.4

import ProcessaImagemQml 1.0

Window 
    visible: true

    width: 360
    height: 640

    maximumHeight: 640
    minimumHeight: 640

    maximumWidth: 360
    minimumWidth: 360

    title: "Camera Preview Test"

    Rectangle 
        id: principal

        anchors.fill: parent

        ProcessaImagem 
            id: processaImagem

            caminhoImagem: camera.caminhoPreview
            caminhoSalvar: camera.caminhoSalvar
            rectRecorte: camera.rectRecorte
            tamanhoImagem: camera.tamanhoImagem
            anguloOrientacaoCamera: camera.orientation
            posicaoCamera: camera.position

            onCaminhoImagemChanged: 
                rectRecorte = cameraView.mapRectToSource(Qt.rect(cameraView.x, cameraView.y, cameraView.width, cameraView.height));
                tamanhoImagem = Qt.size(cameraView.sourceRect.width, cameraView.sourceRect.height);
                ProvedorImagem.carregaImagem(processaImagem.carregaImagem());
            

            onCaminhoSalvarChanged: 
                removeImagemSalva();
            
        

        Rectangle 
            id: cameraRectangle

            width: parent.width
            height: parent.width

            anchors.top: parent.top

            color: "lightGrey"

            visible: true

            Camera 
                id: camera

                property string caminhoPreview: ""
                property string caminhoSalvar: ""
                property int numeroImagem: 0

                captureMode: Camera.CaptureStillImage

                imageCapture 
                    onImageCaptured: 
                        camera.caminhoPreview = preview;

                        camera.stop();

                        imagemPreview.source = "image://provedor/imagemEditada_" + camera.numeroImagem.toString();

                        camera.numeroImagem = camera.numeroImagem + 1;

                        imagemPreviewRectangle.visible = true;

                        cameraRectangle.visible = false;
                    

                    onImageSaved: 
                        camera.caminhoSalvar = path;
                    
                
            

            VideoOutput 
                id: cameraView

                visible: true

                focus: visible

                anchors.fill: parent

                source: camera
                orientation: camera.orientation
                fillMode: VideoOutput.PreserveAspectCrop
            
        

        Rectangle 
            id: imagemPreviewRectangle

            width: parent.width
            height: parent.width

            anchors.top: parent.top

            color: "lightGrey"

            visible: false

            Image 
                id: imagemPreview

                fillMode: Image.PreserveAspectFit

                anchors.fill: parent
            
        

        Rectangle 
            id: controleRectangle

            width: parent.width
            height: parent.height - cameraRectangle.height

            color: "grey"

            anchors.top: cameraRectangle.bottom

            Button 
                id: tirarFotoButton

                text: "Tirar foto"

                anchors.left: parent.left
                anchors.top: parent.top

                onClicked: 
                    camera.imageCapture.capture();
                
            

            Button 
                id: novaFotoButton

                text: "Tirar nova foto"

                anchors.right: parent.right
                anchors.top: parent.top

                onClicked: 
                    camera.start();

                    imagemPreviewRectangle.visible = false;

                    cameraRectangle.visible = true;
                
            
        
    

processaimagem.h

#ifndef PROCESSAIMAGEM_H
#define PROCESSAIMAGEM_H

#include <QObject>
#include <QImage>
#include <QQmlEngine>
#include <QQmlContext>
#include <QQuickImageProvider>
#include <QFile>

#include "provedorimagem.h"

class processaImagem : public QObject

    Q_OBJECT

    Q_PROPERTY(QString caminhoImagem READ caminhoImagem WRITE setCaminhoImagem NOTIFY caminhoImagemChanged)
    Q_PROPERTY(QString caminhoSalvar READ caminhoSalvar WRITE setCaminhoSalvar NOTIFY caminhoSalvarChanged)
    Q_PROPERTY(QRect rectRecorte READ rectRecorte WRITE setRectRecorte NOTIFY rectRecorteChanged)
    Q_PROPERTY(QSize tamanhoImagem READ tamanhoImagem WRITE setTamanhoImagem NOTIFY tamanhoImagemChanged)
    Q_PROPERTY(int anguloOrientacaoCamera READ anguloOrientacaoCamera WRITE setAnguloOrientacaoCamera NOTIFY anguloOrientacaoCameraChanged)
    Q_PROPERTY(int posicaoCamera READ posicaoCamera WRITE setPosicaoCamera NOTIFY posicaoCameraChanged)

public slots:
    QImage carregaImagem();
    void removeImagemSalva();

public:
    processaImagem(QObject *parent = 0);

    QString caminhoImagem() const;
    void setCaminhoImagem(const QString valor);

    QString caminhoSalvar() const;
    void setCaminhoSalvar(const QString valor);

    QRect rectRecorte() const;
    void setRectRecorte(const QRect valor);

    QSize tamanhoImagem() const;
    void setTamanhoImagem(const QSize valor);

    int anguloOrientacaoCamera() const;
    void setAnguloOrientacaoCamera(const int valor);

    int posicaoCamera() const;
    void setPosicaoCamera(const int valor);

private:
    QString p_caminhoImagem = "";
    QString p_caminhoSalvar = "";
    QRect p_rectRecorte = QRect(0, 0, 0, 0);
    QSize p_tamanhoImagem = QSize(0, 0);
    int p_anguloOrientacaoCamera = 0;
    int p_posicaoCamera = 0;

signals:
    void caminhoImagemChanged();
    void caminhoSalvarChanged();
    void rectRecorteChanged();
    void tamanhoImagemChanged();
    void anguloOrientacaoCameraChanged();
    void posicaoCameraChanged();
;

#endif // PROCESSAIMAGEM_H

processaimagem.cpp

#include "processaimagem.h"

#include <QDebug>

processaImagem::processaImagem(QObject *parent)




QImage processaImagem::carregaImagem()

    QUrl caminhoImagem(p_caminhoImagem);
    QQmlEngine *engine = QQmlEngine::contextForObject(this)->engine();
    QQmlImageProviderBase *imageProviderBase = engine->imageProvider(caminhoImagem.host());
    QQuickImageProvider *imageProvider = static_cast<QQuickImageProvider*>(imageProviderBase);


    QSize imageSize;
    QString imageId = caminhoImagem.path().remove(0, 1);
    QImage imagem = imageProvider->requestImage(imageId, &imageSize, imageSize);

    if(imagem.isNull())
    
        qDebug() << "Erro ao carregar a imagem";
        imagem = QImage();
    
    else
    
        if((p_anguloOrientacaoCamera == 90) || (p_anguloOrientacaoCamera == 270))
        
            int larguraImagem = p_tamanhoImagem.width();
            int alturaImagem = p_tamanhoImagem.height();

            p_tamanhoImagem.setWidth(alturaImagem);
            p_tamanhoImagem.setHeight(larguraImagem);

            int recorteX = p_rectRecorte.x();
            int recorteY = p_rectRecorte.y();
            int recorteLargura = p_rectRecorte.width();
            int recorteAltura = p_rectRecorte.height();

            p_rectRecorte.setRect(recorteY, recorteX, recorteAltura, recorteLargura);

            if(imagem.size().width() > imagem.size().height())
            
                QTransform rotacao;
                rotacao.rotate(360 - p_anguloOrientacaoCamera);
                imagem = imagem.transformed(rotacao);

                qDebug() << "Rodou";
            
        

        if(imagem.width() != p_tamanhoImagem.width())
        
            imagem = imagem.scaled(p_tamanhoImagem);
        

        imagem = imagem.copy(p_rectRecorte);
    

    return imagem;


void processaImagem::removeImagemSalva()

    QFile::remove(p_caminhoSalvar);


QString processaImagem::caminhoImagem() const

    return p_caminhoImagem;


void processaImagem::setCaminhoImagem(const QString valor)

    if (valor != p_caminhoImagem)
    
        p_caminhoImagem = valor;
        emit caminhoImagemChanged();
    


QString processaImagem::caminhoSalvar() const

    return p_caminhoSalvar;


void processaImagem::setCaminhoSalvar(const QString valor)

    if (valor != p_caminhoSalvar)
    
        p_caminhoSalvar = valor;
        emit caminhoSalvarChanged();
    


QRect processaImagem::rectRecorte() const

    return p_rectRecorte;


void processaImagem::setRectRecorte(const QRect valor)

    bool alterou = false;

    if (valor.x() != p_rectRecorte.x())
    
        p_rectRecorte.setX(valor.x());
        alterou = true;
    

    if (valor.y() != p_rectRecorte.y())
    
        p_rectRecorte.setY(valor.y());
        alterou = true;
    

    if (valor.width() != p_rectRecorte.width())
    
        p_rectRecorte.setWidth(valor.width());
        alterou = true;
    

    if (valor.height() != p_rectRecorte.height())
    
        p_rectRecorte.setHeight(valor.height());
        alterou = true;
    

    if(alterou)
    
        emit rectRecorteChanged();
    


QSize processaImagem::tamanhoImagem() const

    return p_tamanhoImagem;


void processaImagem::setTamanhoImagem(const QSize valor)

    bool alterou = false;

    if (valor.width() != p_tamanhoImagem.width())
    
        p_tamanhoImagem.setWidth(valor.width());
        alterou = true;
    

    if (valor.height() != p_tamanhoImagem.height())
    
        p_tamanhoImagem.setHeight(valor.height());
        alterou = true;
    

    if(alterou)
    
        emit tamanhoImagemChanged();
    


int processaImagem::anguloOrientacaoCamera() const

    return p_anguloOrientacaoCamera;


void processaImagem::setAnguloOrientacaoCamera(const int valor)

    if (valor != p_anguloOrientacaoCamera)
    
        p_anguloOrientacaoCamera = valor;
        emit anguloOrientacaoCameraChanged();
    


int processaImagem::posicaoCamera() const

    return p_posicaoCamera;


void processaImagem::setPosicaoCamera(const int valor)

    if (valor != p_posicaoCamera)
    
        p_posicaoCamera = valor;
        emit posicaoCameraChanged();
    

provedorimagem.h

#ifndef PROVEDORIMAGEM_H
#define PROVEDORIMAGEM_H

#include <QObject>
#include <QImage>
#include <QQuickImageProvider>

class provedorImagem : public QObject, public QQuickImageProvider

    Q_OBJECT

public:
    provedorImagem();

    QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize);

public slots:
    void carregaImagem(QImage imagemRecebida);

private:
    QImage imagem;
;

#endif // PROVEDORIMAGEM_H

provedorimagem.cpp

#include "provedorimagem.h"

#include <QDebug>

provedorImagem::provedorImagem() : QQuickImageProvider(QQuickImageProvider::Image)




QImage provedorImagem::requestImage(const QString &id, QSize *size, const QSize &requestedSize)

    if(imagem.isNull())
    
        qDebug() << "Erro ao prover a imagem";
    

    return imagem;


void provedorImagem::carregaImagem(QImage imagemRecebida)

    imagem = imagemRecebida;

【问题讨论】:

【参考方案1】:

你为什么在imageCapture 中使用camera.stop()。您将 imagemPreviewRectangle.visible 设置为 true 并将 cameraRectangle.visible 设置为 false。尝试在imageCapturenovaFotoButton 中注释掉camera.stop()camera.start() 并告诉结果。

【讨论】:

我正在使用camera.stop() 在不需要相机时停止使用资源。这是问题的原因吗? 我猜。删除 start () 和 stop() 后它是否工作? 是的,它正在工作。我会多尝试一点来重现错误,我会告诉你结果。 问题又出现了。我认为这可能是我捕捉图片的速度比 QML 清理垃圾的速度要快。我如何在资源非常有限的智能手机中对其进行测试,它正在使用大量内存。会是这样吗? 这可能是计算机上没有发生此类问题的原因。它使用了多少(百分比)?资源有限是什么意思?

以上是关于在 Android 中运行的 QML 相机死了的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 Qt 在 Android 和桌面中使用相机

使用 Detox 在 Android 上设置相机权限

Kitkat 中的 Android 相机 API 2

如何在 QML QVideoFilterRunnable 中访问相机?

QML 在 ListView 中显示的相机照片被破坏

QML 相机尺寸问题