索尼wifi控制相机开发总结(六):命令线程及预览帧流线程的说明及实现

本文介绍了一种使用QT框架实现线程的方法,通过CommandThread和GetLiveViewStreamThread两个实例展示了如何处理异步转同步的问题及获取实时视频流数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        这两个线程的实现,是被QT开发者骂的实现,虽然是没有什么问题,可是总感觉怪怪的,因此,我外部客户端用了QT开发者推荐的做法moveToThread,开始前总结两个线程之前,先稍微总结一下QThread的用法吧:

        1. 是我这两个线程实现的做法,继承QThread,重载run函数,在run中做while(true)的循环,设置跳出循环标志位,然后在while循环中进行操作。

        2. 是我外部控制用的做法,继承QObject类,将该类moveToThread(QThread *),然后要放入线程的操作写在槽函数中,每次通过信号槽来触发线程进行操作,通过回调函数或是信号槽来返回处理结果给外部。这样使用起来很方便,并且不用担心程序关闭时,线程还没完全退出的问题。

CommandThread的实现

        主要的功能在于将异步转同步的问题,由于和相机交互一定是一去一回的交互方式,应该等到上一个命令响应成功以后,再发送下一个命令,但由于http的通讯是异步的,因此,线程需要一个队列保存待处理的命令请求,每当相机返回命令的响应的以后,去检查队列是否有待处理的命令,如果有则继续发送,否则阻塞自己,直到有新命令入队列将其唤醒。在新命令来的时候,如果队列已经有待处理的命令,或是目前正在等待最后一个命令的相应的话,就需要入队,否则说明命令线程处于阻塞状态,将命令入队并唤醒线程。

        CommandThread.h:              

#ifndef COMMANDTHREAD_H
#define COMMANDTHREAD_H
#include <QThread>
#include <QQueue>
#include <QWaitCondition>
#include <QMutex>
#include "httpexecutor.h"

/*Error code*/
#define Command_Response_Error 0x2007

namespace xfhttpcamera {
class CommandThreadCallback
{
public:
    CommandThreadCallback() {}
    virtual void commandError(HttpExecutor *exec, QString error, int errorCode){
        Q_UNUSED(exec);
        Q_UNUSED(error);
        Q_UNUSED(errorCode);
        throw std::runtime_error("un-implement.");
    }

    virtual void commandSuccess(HttpExecutor *exec) {
        Q_UNUSED(exec);
        throw std::runtime_error("un-implement.");
    }

    virtual void executeCommandData(HttpExecutor *exec, QVariant &data) {
        Q_UNUSED(exec);
        Q_UNUSED(data);
        throw std::runtime_error("un-implement.");
    }
};
class CommandThread : public QThread, public HttpExecutorCallback
{
    Q_OBJECT
public:
    CommandThread(QNetworkAccessManager *manager, QObject *paren = 0);

    void enqueue(HttpExecutor *exec);

    virtual void responseError(ResponseException &exception);

    virtual void response();

    virtual void responseData(QVariant &data);

    void setCallback(CommandThreadCallback *callback);
signals:
    void newCommandEnqueue();
private slots:
    void executeNewCommand();
private:
    QNetworkAccessManager *_manager;
    CommandThreadCallback *_callback;
    QQueue<HttpExecutor *> _commandQueue;
    QWaitCondition _commandWaitCondition;
    QMutex _mutex;
    friend class HttpSonyCamera;
};
}
#endif // COMMANDTHREAD_H

         CommandThread.cpp:

#include "commandthread.h"
namespace xfhttpcamera {
CommandThread::CommandThread(QNetworkAccessManager *manager, QObject *paren):
    QThread(paren)
{
    _manager = manager;
    connect(this, &CommandThread::newCommandEnqueue, this, &CommandThread::executeNewCommand, Qt::ConnectionType::QueuedConnection);
}

void CommandThread::enqueue(HttpExecutor *exec)
{
    QMutexLocker locker(&_mutex);
    _commandWaitCondition.wakeOne();
    exec->moveToThread(this);
    if(_commandQueue.isEmpty()){
        _commandQueue.enqueue(exec);
        emit newCommandEnqueue();
    }else
        _commandQueue.enqueue(exec);

}

void CommandThread::responseError(ResponseException &exception)
{
    QString err = "Error code:" + QString::number(exception.code,16) + " Error message:" + exception.message;
    HttpExecutor *exec = _commandQueue.dequeue();
    _callback->commandError(exec, err, Command_Response_Error);
}

void CommandThread::response()
{
    QMutexLocker locker(&_mutex);
    HttpExecutor *exec = _commandQueue.dequeue();
    _callback->commandSuccess(exec);
    if(_commandQueue.isEmpty())
        _commandWaitCondition.wait(&_mutex);
    else{
        HttpExecutor *nextExec = _commandQueue.head();
        nextExec->setCallback(this);
        nextExec->execute(_manager);
    }
}

void CommandThread::responseData(QVariant &data)
{
    HttpExecutor *exec = _commandQueue.head();
    _callback->executeCommandData(exec, data);
}

void CommandThread::setCallback(CommandThreadCallback *callback)
{
    _callback = callback;
}

void CommandThread::executeNewCommand()
{
    qDebug() << "command thread:" << QThread::currentThreadId();
    HttpExecutor *nextExec = _commandQueue.head();
    nextExec->setCallback(this);
    nextExec->execute(_manager);
}
}

GetLiveViewStreamThread实现

        这里就是去不断处理get返回回来的数据,没有什么好说的,直接上代码。

        GetLiveViewStreamThread.h:

#ifndef GETLIVEVIEWSTREAMTHREAD_H
#define GETLIVEVIEWSTREAMTHREAD_H
#include <QThread>
#include <QWaitCondition>
#include <QMutex>
#include "getliveviewstreamexecutor.h"

/*Error code*/
#define Get_Live_View_Response_Error 0x2006

namespace xfhttpcamera {
class GetLiveViewStreamThreadCallback
{
public:
    GetLiveViewStreamThreadCallback() {}
    virtual void liveViewError(sonyrx::GetLiveViewStreamExecutor *exec, QString error, int errorCode){
        Q_UNUSED(exec);
        Q_UNUSED(error);
        Q_UNUSED(errorCode);
        throw std::runtime_error("un-implement.");
    }

    virtual void liveViewStopped(sonyrx::GetLiveViewStreamExecutor *exec) {
        Q_UNUSED(exec);
        throw std::runtime_error("un-implement.");
    }

    virtual void liveViewDataGet(QByteArray &data) {
        Q_UNUSED(data);
        throw std::runtime_error("un-implement.");
    }
};

class GetLiveViewStreamThread : public QThread, public HttpExecutorCallback
{
    Q_OBJECT
public:
    GetLiveViewStreamThread(sonyrx::GetLiveViewStreamExecutor *exec, QNetworkAccessManager *manager, QObject *parent = 0);

    virtual void responseError(ResponseException &exception);

    virtual void response();

    virtual void responseData(QVariant &data);

    void setCallback(GetLiveViewStreamThreadCallback *callback);

    sonyrx::GetLiveViewStreamExecutor *liveViewExecutor(){return _exec;}
protected:
    void run();
private:
    sonyrx::GetLiveViewStreamExecutor *_exec;
    QNetworkAccessManager *_manager;
    GetLiveViewStreamThreadCallback *_callback;
};
}
#endif // GETLIVEVIEWSTREAMTHREAD_H

        GetLiveViewStreamThread.cpp:           

#include "getliveviewstreamthread.h"
namespace xfhttpcamera {
GetLiveViewStreamThread::GetLiveViewStreamThread(sonyrx::GetLiveViewStreamExecutor *exec, QNetworkAccessManager *manager, QObject *parent):
    QThread(parent)
{
    exec->moveToThread(this);
    _exec = exec;
    _manager = manager;
}

void GetLiveViewStreamThread::responseError(ResponseException &exception)
{
    QString err = "Error code:" + QString::number(exception.code,16) + " Error message:" + exception.message;
    _callback->liveViewError(_exec, err, Get_Live_View_Response_Error);
}

void GetLiveViewStreamThread::response()
{
    _callback->liveViewStopped(_exec);
}

void GetLiveViewStreamThread::responseData(QVariant &data)
{
    QByteArray imageData = data.toByteArray();
    _callback->liveViewDataGet(imageData);
}

void GetLiveViewStreamThread::setCallback(GetLiveViewStreamThreadCallback *callback)
{
    _callback = callback;
}

void GetLiveViewStreamThread::run()
{
    _exec->setCallback(this);
    _exec->execute(_manager);
    exec();
}
}

总结

        两个线程和相机(主线程)之间有一个问题就是,QT的封装类QNetworkAccessManager应该作为一个单例来使用,可是在调用其get和post的方法时候,创建的QNetworkReply会有问题,因为QNetworkAccessManager是在主线程创建的,可是现在是在子线程运行,这时候QNetworkAccessManager去new的时候就会抛出警告,提示试图在一个非挂载线程new操作,因此,Camera在调度的时候,需要将QNetworkAccessManager调用moveToThread()来解决这个问题。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值