Qt ffmpeg音视频转换工具

news/2024/7/10 21:20:31 标签: qt, ffmpeg, 开发语言

Qt ffmpeg音视频转换工具,QProcess方式调用ffmpeg,对音视频文件进行格式转换,支持常见的音视频格式,主要在于QProcess的输出处理以及转换的文件名和后缀的处理,可以进一步加上音视频剪切合并和音视频文件属性查询修改的功能。

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QTextCodec>
#include <QFileDialog>
#include <QMessageBox>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QFont font;
    font.setPixelSize(16);
    setFont(font);

    setWindowTitle(QStringLiteral("ffmpeg工具"));

    ui->listWidget->setMaximumWidth(200);
    connect(ui->listWidget, SIGNAL(clicked(QModelIndex)), this, SLOT(convert()));

    ui->checkBox->setChecked(true);

    mProcess = new QProcess;
    connect(mProcess, SIGNAL(readyReadStandardError()), this, SLOT(readError()));
    connect(mProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutput()));
    connect(mProcess, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finished(int,QProcess::ExitStatus)));

    mTimer = new QTimer(this);
    connect(mTimer, SIGNAL(timeout()), this, SLOT(updateTimer()));
    mTimer->start(1000);

    initListWidget();
}

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

void MainWindow::readError()
{
    QString str = mProcess->readAllStandardError().data();

    if (str == "\r")
    {
        ui->textBrowser->append(mTmpStr);
        mTmpStr.clear();
    }
    else
    {
        mTmpStr += str;
        if (str.contains("\r\n"))
        {
            ui->textBrowser->append(mTmpStr);
            mTmpStr.clear();
        }
    }
}

void MainWindow::readOutput()
{
    QByteArray qba = mProcess->readAllStandardOutput();
    QTextCodec* tc = QTextCodec::codecForName("System");
    QString str = tc->toUnicode(qba);

    if (str == "\r")
    {
        ui->textBrowser->append(mTmpStr);
        mTmpStr.clear();
    }
    else
    {
        mTmpStr += str;
        if (str.contains("\r\n"))
        {
            ui->textBrowser->append(mTmpStr);
            mTmpStr.clear();
        }
    }
}

void MainWindow::finished(int exitCode, QProcess::ExitStatus exitStatus)
{
    ui->textBrowser->append(QStringLiteral("finished : %1 %2").arg(exitCode).arg(exitStatus));
    mProcess->close();

    if (exitCode == 0 && exitStatus == 0)
    {
        informationMessageBox(QStringLiteral("提示"), QStringLiteral("%1\n转换\n%2\n完成").arg(mSourceFile).arg(mTargetFile));
    }
    else
    {
        informationMessageBox(QStringLiteral("提示"), QStringLiteral("%1\n转换\n%2\n失败").arg(mSourceFile).arg(mTargetFile));
    }
}

void MainWindow::updateTimer()
{
    if (!mTmpStr.isEmpty())
    {
        ui->textBrowser->append(mTmpStr);
        mTmpStr.clear();
    }
}

void MainWindow::initListWidget()
{
    QStringList nameLst;
    nameLst.append(QStringLiteral("FLAC转MP3")); // ffmpeg -i input.flac -ab 320k -map_metadata 0 -id3v2_version 3 output.mp3
    nameLst.append(QStringLiteral("M4A转MP3")); // ffmpeg -i 1.m4a -acodec libmp3lame -aq 0 123.mp3
    nameLst.append(QStringLiteral("WAV转MP3")); // ffmpeg -i input.wav -f mp3 -acodec libmp3lame -aq 0 output.mp3
    nameLst.append(QStringLiteral("APE转MP3")); // ffmpeg -i 1.ape -acodec libmp3lame -aq 0 123.mp3
    nameLst.append("");
    nameLst.append(QStringLiteral("MP4转M4A")); // ffmpeg -i test.mp4 -acodec copy -vn 123.m4a
    nameLst.append(QStringLiteral("MP4转AAC")); // ffmpeg -i test.mp4 -acodec copy -vn 123.aac
    nameLst.append(QStringLiteral("MP4转MP3")); // ffmpeg -i test.mp4 -acodec libmp3lame -aq 0 123.mp3
    nameLst.append("");
    nameLst.append(QStringLiteral("MP3转OGG")); // ffmpeg -i bb.mp3 -acodec libvorbis -ab 128k bb.ogg
    nameLst.append(QStringLiteral("MP3转WAV")); // ffmpeg -i input.mp3 -f wav output.wav

    QMap<QString, QString> cmdMap;
    cmdMap.insert(QStringLiteral("FLAC转MP3"), QStringLiteral("ffmpeg -i \"%1\" -ab 320k -map_metadata 0 -id3v2_version 3 -aq 0 \"%2\""));
    cmdMap.insert(QStringLiteral("M4A转MP3"), QStringLiteral("ffmpeg -i \"%1\" -acodec libmp3lame -aq 0 \"%2\""));
    cmdMap.insert(QStringLiteral("WAV转MP3"), QStringLiteral("ffmpeg -i \"%1\" -f mp3 -acodec libmp3lame -aq 0 \"%2\""));
    cmdMap.insert(QStringLiteral("APE转MP3"), QStringLiteral("ffmpeg -i \"%1\" -acodec libmp3lame -aq 0 \"%2\""));
    cmdMap.insert(QStringLiteral("MP4转M4A"), QStringLiteral("ffmpeg -i \"%1\" -acodec copy -vn \"%2\""));
    cmdMap.insert(QStringLiteral("MP4转AAC"), QStringLiteral("ffmpeg -i \"%1\" -acodec copy -vn \"%2\""));
    cmdMap.insert(QStringLiteral("MP4转MP3"), QStringLiteral("ffmpeg -i \"%1\" -acodec libmp3lame -aq 0 \"%2\""));
    cmdMap.insert(QStringLiteral("MP3转OGG"), QStringLiteral("ffmpeg -i \"%1\" -acodec libvorbis -ab 128k \"%2\""));
    cmdMap.insert(QStringLiteral("MP3转WAV"), QStringLiteral("ffmpeg -i \"%1\" -f wav \"%2\""));

    foreach (QString name, nameLst)
    {
        QListWidgetItem *item = new QListWidgetItem;
        if (!name.isEmpty())
        {
            item->setText(name);
            item->setData(Qt::UserRole, cmdMap.value(name));
        }
        else
        {
            item->setText("");
            item->setData(Qt::UserRole, "");
        }
        ui->listWidget->addItem(item);
    }
}

QString MainWindow::getFileSuffix(QString file)
{
    QString ret;

    if (file == "FLAC")
    {
        ret = QStringLiteral("flac");
    }
    else if (file == "MP3")
    {
        ret = QStringLiteral("mp3");
    }
    else if (file == "M4A")
    {
        ret = QStringLiteral("m4a");
    }
    else if (file == "WAV")
    {
        ret = QStringLiteral("wav");
    }
    else if (file == "APE")
    {
        ret = QStringLiteral("ape");
    }
    else if (file == "AAC")
    {
        ret = QStringLiteral("aac");
    }
    else if (file == "MP4")
    {
        ret = QStringLiteral("mp4");
    }
    else if (file == "OGG")
    {
        ret = QStringLiteral("ogg");
    }

    return ret;
}

void MainWindow::convert()
{
    QListWidgetItem *item = ui->listWidget->currentItem();
    QString tmp = item->data(Qt::UserRole).toString();

    if (mProcess->isOpen())
    {
        mProcess->close();
    }

    mSourceFile.clear();
    mTargetFile.clear();
    mSource.clear();
    mTarget.clear();
    mSourceSuffix.clear();
    mTargetSuffix.clear();

    if (!tmp.isEmpty())
    {
        mTitle = item->text();
        mCmd = tmp;
        setWindowTitle(QStringLiteral("ffmpeg工具 - %1").arg(mTitle));
    }
    else
    {
        mTitle.clear();
        mCmd.clear();
        setWindowTitle(QStringLiteral("ffmpeg工具"));
    }
}

bool MainWindow::informationMessageBox(const QString &title, const QString &text, bool isOnlyOk)
{
    QMessageBox msgBox(this);
    msgBox.setFont(this->font());
    msgBox.setIcon(QMessageBox::Information);
    msgBox.setWindowTitle(title);
    msgBox.setText(text);
    if (isOnlyOk)
    {
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setButtonText(QMessageBox::Ok, QStringLiteral("确定"));
    }
    else
    {
        msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
        msgBox.setButtonText(QMessageBox::Ok, QStringLiteral("确定"));
        msgBox.setButtonText(QMessageBox::Cancel, QStringLiteral("取消"));
    }

    return (msgBox.exec() == QMessageBox::Ok);
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    if (informationMessageBox(QStringLiteral("提示"), QStringLiteral("确定关闭"), false))
    {
        event->accept();
    }
    else
    {
        event->ignore();
    }
}

void MainWindow::on_pushButton_import_clicked()
{
    if (mTitle.isEmpty() || mCmd.isEmpty())
    {
        return;
    }

    mSource = mTitle.split(QStringLiteral("转"))[0];
    mTarget = mTitle.split(QStringLiteral("转"))[1];
    mSourceSuffix = getFileSuffix(mSource);
    mTargetSuffix = getFileSuffix(mTarget);

    if (mSourceSuffix.isEmpty() || mTargetSuffix.isEmpty())
    {
        informationMessageBox(QStringLiteral("提示"), QStringLiteral("不支持的文件格式"));
        return;
    }

    QString file = QFileDialog::getOpenFileName(this, QStringLiteral("打开%1文件").arg(mSource), QStringLiteral("."), QStringLiteral("%1文件(*.%2)").arg(mSource).arg(mSourceSuffix));
    if (!file.isEmpty())
    {
        mSourceFile = file;
        if (ui->checkBox->isChecked())
        {
            QString tmp = mSourceFile;
            mTargetFile = tmp.replace(QStringLiteral(".%1").arg(mSourceSuffix), QStringLiteral(".%1").arg(mTargetSuffix));
        }
    }
}

void MainWindow::on_pushButton_save_clicked()
{
    if (mSourceFile.isEmpty())
    {
        return;
    }

    QString file = QFileDialog::getSaveFileName(this, QStringLiteral("保存%1文件").arg(mTarget), mTargetFile, QStringLiteral("%1文件(*.%2)").arg(mTarget).arg(mTargetSuffix));
    if (!file.isEmpty())
    {
        mTargetFile = file;
    }
}

void MainWindow::on_pushButton_convert_clicked()
{
    if (mSourceFile.isEmpty() || mTargetFile.isEmpty())
    {
        return;
    }

    QString cmd = mCmd.arg(mSourceFile).arg(mTargetFile);
    ui->textBrowser->append("\n" + cmd + "\n");

    if (mProcess->isOpen())
    {
        mProcess->close();
    }

    mTmpStr.clear();
    mProcess->start(cmd);
}


http://www.niftyadmin.cn/n/5037154.html

相关文章

MySQL实现每日备份

1. 创建MySQL备份账号 创建账号并分配权限 CREATE USER backuplocalhost IDENTIFIED BY password; GRANT SELECT, SHOW VIEW, RELOAD, PROCESS, FILE, SUPER, LOCK TABLES ON *.* TO backuplocalhost; FLUSH PRIVILEGES;注&#xff1a;如果不在同一台机器将localhost改成备份…

手机号码携号转网API接口,轻松实现用户号码流转

携号转网是指用户可以将自己的手机号码从原来的运营商转移到其他运营商&#xff0c;以更好的服务、更低的资费和更多的优惠来吸引用户。而手机号码携号转网API接口&#xff0c;则是让开发者可以方便地实现用户号码流转的工具&#xff0c;下面就来介绍一下如何使用手机号码携号转…

JS判断字符串是否为json字符串,读取JSON数据 | js获取对象的方法 | 元素添加 class 属性

JS判断字符串是否为json字符串 form表单输入框需要进行json校验&#xff0c;确保数据为json字符串&#xff0c;通过使用try/catch和JSON.parse判断是否为json字符串&#xff0c;方法如下&#xff1a; const isJsonString str > {try {const toObj JSON.parse(str) // js…

《Java极简设计模式》第07章:装饰模式(Decorator)

作者&#xff1a;冰河 星球&#xff1a;http://m6z.cn/6aeFbs 博客&#xff1a;https://binghe.gitcode.host 文章汇总&#xff1a;https://binghe.gitcode.host/md/all/all.html 源码地址&#xff1a;https://github.com/binghe001/java-simple-design-patterns/tree/master/j…

使用hook提取模型的特征图

目录 一、实例化模型 二、查找想要提取的网络层 1.打印网络层 2.获取网络层的name

华为HCIA(五)

Vlan id 在802.1Q中 高级ACL不能匹配用户名和源MAC 2.4G频段被分为14个交叠的&#xff0c;错列的20MHz信道&#xff0c;信道编码从1到14&#xff0c;邻近的信道之间存在一定的重叠范围 STA通过Probe获取SSID信息 Snmp报文 网络管理设备异常发生时会发送trap报文 D类地址是…

Java 复习笔记 - 集合进阶篇:数据结构

文章目录 数据结构 概述常见的数据结构示例&#xff08;一&#xff09;数组&#xff08;Array&#xff09;&#xff08;二&#xff09;链表&#xff08;LinkedList&#xff09;&#xff08;三&#xff09;栈&#xff08;Stack&#xff09;&#xff08;四&#xff09;队列&#…

【pytest】conftest.py使用

1. 创建test_project 目录 test_project/sub/test_sub.py def test_baidu(test_url):print(fsub {test_url}) test_project/conftest.py 设置钩子函数 只对当前目录 和子目录起作用 import pytest #设置测试钩子函数 pytest.fixture() def test_url():return "http…