QT software development: qpprocess starts the process, completes the interaction and obtains the output

Posted by Fed51 on Mon, 10 Jan 2022 23:50:41 +0100

1, Qpprocess introduction

The qpprocess class is used to start external programs and communicate with them.

Qpprocess allows processes to be treated as I/O devices. Processes can be written and read in the same way as accessing a network connection using qtcsocket. You can then write the standard input of the process by calling write() and read the standard output by calling read(), readLine(), and getChar(). Because qpprocess inherits QIODevice, it can also be used as an input source for QXmlReader or to generate data to be uploaded using qnetwork access manager.

When the process exits, qpprocess re enters the NotRunning state (initial state) and issues finished().
The finished() signal provides the exit code and exit status of the process as parameters. You can also call exitCode() to obtain the exit code of the last completed process and exitStatus() to obtain its exit status. If an error occurs at any point in time, qpprocess will send an erroreoccurred() signal. You can also call error() to find the last error type and state() to find the current process state.

A process has two predefined output channels: the standard output channel (stdout) provides regular console output, and the standard error channel (stderr) usually provides errors printed by the process. These channels represent two independent data streams. You can switch between them by calling setReadChannel(). When data is available on the current read channel, qpprocess issues readyRead(). It also issues readyReadStandardOutput() when new standard output data is available and readyReadStandardError() when new standard error data is available. Instead of calling read(), readLine(), or getChar(), you can explicitly read all the data of either channel by calling readAllStandardOutput() or readAllStandardError().

Qpprocess provides a set of functions that allow it to be used without an event loop by suspending the calling thread until some signals are issued:
waitForStarted() blocks until the process starts.
waitForReadyRead() blocks until new data is available for reading on the current read channel.
waitForBytesWrite() blocks until a payload's data is written to the process.
waitForFinished() blocks until the process completes.
Calling these functions from the main thread (the thread calling QApplication:: exec() may cause the user interface to freeze.

The following describes the usage scenarios and methods of qpprocess through several examples.

1. The first example calls the ipconfig command to obtain local IP information, demonstrates how to block the execution of the command and get the output of the command, and solves the problem of Chinese garbled output.

2. The second example calls ffmpge to obtain the information of video files, and demonstrates how to block the execution of commands and get the output of commands.

3. The third example calls the ping command Ping Baidu to obtain the network connection and demonstrates how to obtain the output of the command in real time.

4. The fourth example calls the ffmpge command to complete video transcoding. It demonstrates how to obtain the output of the command in real time and write data to the process to complete the interaction -- > that is, how to exit the execution of the ffmpge command normally halfway.

2, Usage example: call ipconfig under windows to obtain the system IP

#include <QProcess>
#include <QTextCodec>

QProcess process;
process.start("ipconfig");
process.waitForFinished();
process.waitForReadyRead();
QByteArray qba  = process.readAll();

//Solve the problem of Chinese garbled code
QTextCodec* pTextCodec = QTextCodec::codecForName("System");
assert(pTextCodec != nullptr);
QString str = pTextCodec->toUnicode(qba);

qDebug("%s\n",str.toStdString().c_str());

Output results:

Windows IP to configure


WLAN adapter WLAN:

   Connect specific DNS suffix . . . . . . . : 
   Local link IPv6 address. . . . . . . . : fe80::f887:2337:ca8f:e8d5%10
   IPv4 address . . . . . . . . . . . . : 10.0.0.4
   Subnet mask  . . . . . . . . . . . . : 255.255.255.0
   Default gateway. . . . . . . . . . . . . : 10.0.0.1

Ethernet adapter Ethernet:

   Media status  . . . . . . . . . . . . : Media disconnected
   Connect specific DNS suffix . . . . . . . : 

WLAN adapter local connection* 1:

   Media status  . . . . . . . . . . . . : Media disconnected
   Connect specific DNS suffix . . . . . . . : 

WLAN adapter local connection* 4:

   Media status  . . . . . . . . . . . . : Media disconnected
   Connect specific DNS suffix . . . . . . . : 

ethernet adapter  VMware Network Adapter VMnet1:

   Connect specific DNS suffix . . . . . . . : 
   Local link IPv6 address. . . . . . . . : fe80::5c33:8a5b:a8a6:3026%19
   IPv4 address . . . . . . . . . . . . : 192.168.112.1
   Subnet mask  . . . . . . . . . . . . : 255.255.255.0
   Default gateway. . . . . . . . . . . . . : 

ethernet adapter  VMware Network Adapter VMnet8:

   Connect specific DNS suffix . . . . . . . : 
   Local link IPv6 address. . . . . . . . : fe80::754a:6573:6487:c8f0%18
   IPv4 address . . . . . . . . . . . . : 192.168.24.1
   Subnet mask  . . . . . . . . . . . . : 255.255.255.0
   Default gateway. . . . . . . . . . . . . : 

3, Usage example: call ffmpge to view video file information

#include <QProcess>
#include <QTextCodec>


QProcess process;
process.start("D:\\linux-share-dir\\C++_v5\\ECRS_Object\\Release\\ffprobe.exe -v quiet -of json -i D:/123.mp4  -show_streams ");
process.waitForFinished();
process.waitForReadyRead();
QByteArray qba  = process.readAll();

QTextCodec* pTextCodec = QTextCodec::codecForName("System");
assert(pTextCodec != nullptr);
QString str = pTextCodec->toUnicode(qba);

qDebug("%s\n",str.toStdString().c_str());

Output results:

{
    "streams": [
        {
            "index": 0,
            "codec_name": "aac",
            "codec_long_name": "AAC (Advanced Audio Coding)",
            "profile": "LC",
            "codec_type": "audio",
            "codec_time_base": "1/88200",
            "codec_tag_string": "mp4a",
            "codec_tag": "0x6134706d",
            "sample_fmt": "fltp",
            "sample_rate": "88200",
            "channels": 2,
            "channel_layout": "stereo",
            "bits_per_sample": 0,
            "r_frame_rate": "0/0",
            "avg_frame_rate": "0/0",
            "time_base": "1/44100",
            "start_pts": 0,
            "start_time": "0.000000",
            "duration_ts": 4142070,
            "duration": "93.924490",
            "bit_rate": "127916",
            "max_bit_rate": "132760",
            "nb_frames": "4045",
            "disposition": {
                "default": 1,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0
            },
            "tags": {
                "creation_time": "2015-04-30T02:43:22.000000Z",
                "language": "und",
                "handler_name": "GPAC ISO Audio Handler"
            }
        },
        {
            "index": 1,
            "codec_name": "h264",
            "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
            "profile": "Main",
            "codec_type": "video",
            "codec_time_base": "2349/70450",
            "codec_tag_string": "avc1",
            "codec_tag": "0x31637661",
            "width": 1280,
            "height": 720,
            "coded_width": 1280,
            "coded_height": 720,
            "has_b_frames": 0,
            "sample_aspect_ratio": "1:1",
            "display_aspect_ratio": "16:9",
            "pix_fmt": "yuv420p",
            "level": 51,
            "chroma_location": "left",
            "refs": 1,
            "is_avc": "true",
            "nal_length_size": "4",
            "r_frame_rate": "25/1",
            "avg_frame_rate": "35225/2349",
            "time_base": "1/30000",
            "start_pts": 0,
            "start_time": "0.000000",
            "duration_ts": 2818800,
            "duration": "93.960000",
            "bit_rate": "581978",
            "bits_per_raw_sample": "8",
            "nb_frames": "1409",
            "disposition": {
                "default": 1,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0
            },
            "tags": {
                "creation_time": "2015-04-30T02:43:23.000000Z",
                "language": "und",
                "handler_name": "GPAC ISO Video Handler"
            }
        }
    ]
}

4, Usage example: call ping command to get real-time output

To obtain the standard output of the process in real time, you need to associate the readyReadStandardOutput signal; And process needs dynamic new.

4.1 makes a simple ui interface

4.2 cpp file code

#ifndef WIDGET_H
#define WIDGET_H
#include <QProcess>
#include <QTextCodec>

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    QProcess *process;

private slots:

    void slot_readyRead();

    void on_pushButton_start_clicked();

    void on_pushButton_stop_clicked();

    void on_pushButton_exit_clicked();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

4.3 .h document code

#ifndef WIDGET_H
#define WIDGET_H
#include <QProcess>
#include <QTextCodec>

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    QProcess *process;

private slots:

    void slot_readyRead();

    void on_pushButton_start_clicked();

    void on_pushButton_stop_clicked();

    void on_pushButton_exit_clicked();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

4.4 operation effect

 

5, Use example: call ffmpge command to complete video transcoding

The following example demonstrates how to call the ffmpge command to complete video transcoding, and obtain the transcoding progress output in real time. After parsing, you can make a progress bar interface, and write commands to the process (writing q can interrupt the execution of ffmpge, save and exit normally) to interact with the ffmpge process.

5.1 UI interface

 5.2 widget.h code

#ifndef WIDGET_H
#define WIDGET_H
#include <QProcess>
#include <QTextCodec>

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    QProcess *process;

private slots:

    void slot_readyRead();

    void on_pushButton_start_clicked();

    void on_pushButton_stop_clicked();

    void on_pushButton_exit_clicked();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

5.3 widget.cpp code

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    process=new QProcess(this);
    QObject::connect(process,SIGNAL(readyReadStandardOutput()),this, SLOT(slot_readyRead()));
    process->setProcessChannelMode(QProcess::MergedChannels);
}


Widget::~Widget()
{
    delete ui;
}


/*
Project: untitled1
 Date: July 28, 2021
 Author: brother DS Bruce Lee
 Environment: win10 Qt5 12.6 MinGW32
 Function: start transcoding
*/
void Widget::on_pushButton_start_clicked()
{
    //process->start("C:/FFMPEG/ffmpeg_x86_4.2.2/bin/ffmpeg.exe -i \"D:/test1080.flv\" -y -qscale 0 -vcodec libx264 -acodec aac -ac 1 -ar 22050  -b:v 0 -s 1280x720 -r 25 \"D:/linux-share-dir/video_file/test/out.mp4\"");
    process->start(ui->lineEdit_start->text());
}


/*
Project: untitled1
 Date: July 28, 2021
 Author: brother DS Bruce Lee
 Environment: win10 Qt5 12.6 MinGW32
 Function: data readable
*/
void Widget::slot_readyRead()
{
    QByteArray qba  = process->readAllStandardOutput();
    QTextCodec* pTextCodec = QTextCodec::codecForName("System");
    assert(pTextCodec != nullptr);
    QString str = pTextCodec->toUnicode(qba);
    ui->plainTextEdit->insertPlainText(str);
}


/*
Project: untitled1
 Date: July 28, 2021
 Author: brother DS Bruce Lee
 Environment: win10 Qt5 12.6 MinGW32
 Function: write data
*/
void Widget::on_pushButton_stop_clicked()
{
    process->write(ui->lineEdit_write->text().toLocal8Bit());
}

/*
Project: untitled1
 Date: July 28, 2021
 Author: brother DS Bruce Lee
 Environment: win10 Qt5 12.6 MinGW32
 Function: stop command
*/
void Widget::on_pushButton_exit_clicked()
{
    process->close();
    process->waitForFinished();
}

5.4 program operation effect

 

 

 

Topics: Qt