QProcess 调用 ffmpeg来处理音频

news2024/12/26 11:01:31

项目场景:

在文章 qt 实现音视频的分贝检测系统中,实现的是边播放变解析音频数据来统计音频的分贝大小,并不满足实际项目的需求,有的视频声音正常,有的视频声音就偏低,即使放到最大音量声音也是比较小,本文的目的是直接通过对本地视频进行检测,拿出关键指标,来进行对音频处理

关键依赖:ffmpeg

因为依赖于ffmpeg的能力,所以第一步要安装ffmpeg环境,自行百度

步骤1,检测max_volume 值是否小于0dB

 ffmpeg -i 1.mp3  -filter_complex volumedetect -c:v copy -f null /dev/null

在这里插入图片描述
其中检测的关键指标就是 max_volume, 本次检测和处理的目标就是把 max_volume的值给提高到0dB;

步骤2,如何区分是音频文件还是视频文件

可以有多种方法,1可以通过后缀名来区分; 2 因为代码是用qt写的,可以用qt来实现,代码如下

QFileInfo f(1.mp3”);
if(f.completeSuffix() == "mp3" || f.completeSuffix() == "aac" || 
f.completeSuffix() == "amr" || f.completeSuffix() == "wav" || f.completeSuffix() == "wma" )
QMediaPlayer p;
p.audioAvailable()

步骤3,处理音频,使max_volume的值接近0dB

音频文件用以下指令

ffmpeg -i 1.mp3-af  "volume=5.8dB"  out.mp3

如果是视频文件,用以下指令:(保持视频信息不变,当然还设计到音频的编码格式)

ffmpeg -i 1.mp3-af  "volume=5.8dB" -c:v copy -c:a aac out.mp3

输出如下
在这里插入图片描述
在这里插入图片描述

程序设计思路

通过QProcess 调用 ffmpeg指令,检测max_volume小于0的文件,拿到文件列表,再通过ffmpeg指令来提高音频。关键代码如下:

dbdetectthread.h

#ifndef DBDETECTTHREAD_H
#define DBDETECTTHREAD_H

#include <QObject>
#include <QThread>
#include <QProcess>
#include <QStringList>

class DbDetectThread : public QThread
{
    Q_OBJECT
public:
    explicit DbDetectThread(QObject *parent = nullptr);
    void setList(const QStringList &list);
    virtual void run();
signals:
    void sigPath(const QString &p, float db);
    void sigMsg(const QString &p);
    void sigEnd();

public slots:
    void readStandardOutput();
    void readStandardError();
    void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
    void threadFinished(); //线程退出

private:
    QProcess *pCmdProcess;
    QStringList pathlist;
    QString curFile;
};

#endif // DBDETECTTHREAD_H

dbdetectthread.cpp

#include "dbdetectthread.h"
#include <QDebug>
DbDetectThread::DbDetectThread(QObject *parent)
    : QThread{parent}
{
    qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus");
}

void DbDetectThread::setList(const QStringList &list)
{
    pathlist = list;
}

//ffmpeg -i 2.wav -filter_complex volumedetect -c:v copy -f null /dev/null

//需要计算分贝相差值
//ffmpeg  -i 2.wav -filter:a "volume=80dB" output2.wav

void DbDetectThread::run()
{
    pCmdProcess = new QProcess();    //不要加this
    connect(pCmdProcess, &QProcess::readyReadStandardOutput, this, &DbDetectThread::readStandardOutput);
    connect(pCmdProcess, &QProcess::readyReadStandardError, this, &DbDetectThread::readStandardError);
    connect(pCmdProcess, QOverload<int , QProcess::ExitStatus >::of(&QProcess::finished), this, &DbDetectThread::processFinished);
    connect(this, &QThread::finished, this, &DbDetectThread::threadFinished);

    QStringList arguments;
    //arguments << "-i" << "C:/Users/wmm/Desktop/DbDetect/voice/input.mp4" << "-c:v" << "h264" << "-c:a" << "aac" << "C:/Users/wmm/Desktop/DbDetect/voice/output.mp4";
    //arguments << "-i" << "input.mp4" << "-c:v" << "h264" << "-c:a" << "aac" << "output.mp4";
    //arguments << "-i" << p << "-filter_complex"<< "volumedetect" <<  "-c:v" << "copy" << "-f" << "null" << "/dev/null";
    //QString cmd = QString("ffmpeg -i %1 -filter_complex volumedetect -c:v copy -f null /dev/null").arg(p);

    //QString cmd = QString("ffmpeg -i C:/Users/wmm/Desktop/DbDetect/voice/input.mp4 -filter_complex volumedetect -c:v copy -f null /dev/null");
    //QString cmd = "ping www.baidu.com -w 500";
    //QString result;
    foreach(auto p, pathlist)
    {
        curFile = p;
        qDebug() << "start detect " << curFile;
        QString cmd = QString("ffmpeg -i %1 -filter_complex volumedetect -c:v copy -f null /dev/null").arg(p);
        pCmdProcess->start(cmd/*,arguments*/);
        pCmdProcess->waitForFinished();
        sleep(1);
    }

}

void DbDetectThread::readStandardOutput() {
    qDebug() << "Standard output: " << pCmdProcess->readAllStandardOutput();
}

void DbDetectThread::readStandardError() {
    QString errorMessage = QString::fromUtf8(pCmdProcess->readAllStandardError());
    QStringList errlist = errorMessage.split("\r\n");
    //qDebug() << errlist.size();
    //qDebug() << errlist;

//    float num = 3.1415926;
//    QString str = QString::number(num, 'f', 2);

    foreach (auto p, errlist) {
        if(p.contains("max_volume"))
        {
            qDebug() << p;
            int pos = p.indexOf("max_volume");
            int pos2 = p.indexOf("dB",pos);
            QString val = p.mid(pos+11,pos2-11-pos);

            qDebug() <<val;
            float fval = val.toFloat();
            qDebug() << fval;

            if(fval <0)
            {
                qDebug() << "小于0";
                emit sigPath(curFile,fval);
            }
            else
            {
                qDebug() << "不小于0";
            }
        }
    }
        // 对 errorMessage 进行解析和处理...
    //qDebug() << "Standard error: " << pCmdProcess->readAllStandardError();
}

void DbDetectThread::processFinished(int exitCode, QProcess::ExitStatus exitStatus) {
    qDebug() << "Process finished with exit code" << exitCode << "and exit status" << exitStatus << ((QProcess*)QObject::sender())->arguments();
    emit sigMsg(QString("%1 检测完成,exitCode = %2, exitStatus = %3 ").arg(curFile).arg(exitCode).arg(exitStatus));
}

void DbDetectThread::threadFinished()
{
    qDebug() << __func__;
    emit sigEnd();
    pCmdProcess->deleteLater();
}

dbprocessthread.h

#ifndef DBPROCESSTHREAD_H
#define DBPROCESSTHREAD_H

#include <QObject>
#include <QThread>
#include <QProcess>
#include <QMap>
#include <QMediaPlayer>
class DbProcessThread : public QThread
{
    Q_OBJECT
public:
    explicit DbProcessThread(QObject *parent = nullptr);

    void setOutputDir(const QString &dir);
    void setMap(const QMap<QString,float> &map);
    virtual void run();
signals:
    void sigPath(const QString &p, float db);
    void sigMsg(const QString &p);
    void sigEnd();

public slots:
    void readStandardOutput();
    void readStandardError();
    void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
    void threadFinished(); //线程退出

private:
    QProcess *pCmdProcess;
    QMediaPlayer  mediaPlayer;
    QMap<QString,float> m_needProcessMap;
    QString m_outputDir;
    QString m_curSrcFile;
    QString m_curDesFile;
};

#endif // DBPROCESSTHREAD_H

dbprocessthread.cpp

#include "dbprocessthread.h"
#include <QDebug>
#include <QFileInfo>
DbProcessThread::DbProcessThread(QObject *parent)
    : QThread{parent}
{

}

void DbProcessThread::setOutputDir(const QString &dir)
{
    m_outputDir = dir;
}

void DbProcessThread::setMap(const QMap<QString, float> &map)
{
    m_needProcessMap = map;
}

void DbProcessThread::run()
{
    pCmdProcess = new QProcess();    //不要加this
    connect(pCmdProcess, &QProcess::readyReadStandardOutput, this, &DbProcessThread::readStandardOutput);
    connect(pCmdProcess, &QProcess::readyReadStandardError, this, &DbProcessThread::readStandardError);
    connect(pCmdProcess, QOverload<int , QProcess::ExitStatus >::of(&QProcess::finished), this, &DbProcessThread::processFinished);
    connect(this, &QThread::finished, this, &DbProcessThread::threadFinished);

    QMapIterator<QString, float> i(m_needProcessMap);
    while (i.hasNext()) {
        i.next();
        QFileInfo f(i.key());
        qDebug() << f.fileName() << m_outputDir+"/" + f.fileName();
        m_curSrcFile = i.key();
        m_curDesFile = m_outputDir+"/" + f.fileName();
        QStringList arguments;
        //arguments << "-i" << i.key() << "-c:v" << "h264" << "-c:a" << "aac" << m_outputDir+"/" + f.fileName();
        arguments << "-i" << i.key() << "-af" << QString("volume=%1dB").arg(qAbs(i.value())) << "-c:v copy" << " -c:a aac "  << m_outputDir+"/" + f.fileName();
        qDebug() << arguments;
        emit sigMsg(QString("正在处理...%1").arg(m_curSrcFile));

        if(f.completeSuffix() == "mp3" || f.completeSuffix() == "aac" || f.completeSuffix() == "amr" || f.completeSuffix() == "wav"\
                 || f.completeSuffix() == "wma" )
        {
            pCmdProcess->start(QString("ffmpeg -i %1 -af \"volume=%2dB\"  %3").arg(i.key()).arg(qAbs(i.value())).arg(m_outputDir+"/" + f.fileName())/*,arguments*/);
        }
        else {
            pCmdProcess->start(QString("ffmpeg -i %1 -af \"volume=%2dB\" -c:v copy  %3").arg(i.key()).arg(qAbs(i.value())).arg(m_outputDir+"/" + f.fileName())/*,arguments*/);
        }

        //pCmdProcess->start(QString("ffmpeg -i %1 -af \"volume=%2dB\" -c:v copy -c:a aac %3").arg(i.key()).arg(qAbs(i.value())).arg(m_outputDir+"/" + f.fileName())/*,arguments*/);
        pCmdProcess->waitForFinished();
        msleep(500);
    }

}

void DbProcessThread::readStandardOutput() {
    qDebug() << "Standard output: " << pCmdProcess->readAllStandardOutput();
}

void DbProcessThread::readStandardError() {
    qDebug() << "Standard error: " << pCmdProcess->readAllStandardError();
}

void DbProcessThread::processFinished(int exitCode, QProcess::ExitStatus exitStatus) {
    qDebug() << "Process finished with exit code" << exitCode << "and exit status" << exitStatus << ((QProcess*)QObject::sender())->arguments();
    emit sigMsg(QString("%1 处理完成,文件保存为%2,exitCode = %3, exitStatus = %4 ").arg(m_curSrcFile).arg(m_curDesFile).arg(exitCode).arg(exitStatus));
}

void DbProcessThread::threadFinished()
{
    qDebug() << __func__;
    emit sigEnd();
    pCmdProcess->deleteLater();
}

效果如图:
在这里插入图片描述
代码上传到此 https://download.csdn.net/download/u011942101/88299291

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/971804.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Apache实现weblogic集群配置

安装apache&#xff0c;安装相对稳定的版本。如果安装后测试能否正常启动&#xff0c;可以通过访问http://localhost/进行测试。安装Weblogic&#xff0c;参见文档将bea安装目录 weblogic81/server/bin 下的 mod_wl_20.so 文件copy到 apache安装目录下Apache2/modules/目录下A…

90、00后严选出的数据可视化工具:奥威BI工具

90、00后主打一个巧用工具&#xff0c;绝不低效率上班&#xff0c;因此当擅长大数据智能可视化分析的BI数据可视化工具出现后&#xff0c;自然而然地就成了90、00后职场人常用的数据可视化工具。 奥威BI工具三大特点&#xff0c;让职场人眼前一亮&#xff01; 1、零编程&…

【STM32】学习笔记-时间戳RTC

Unix时间戳 Unix 时间戳&#xff08;Unix Timestamp&#xff09;定义为从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数&#xff0c;不考虑闰秒 时间戳存储在一个秒计数器中&#xff0c;秒计数器为32位/64位的整型变量 世界上所有时区的秒计数器相同&#xff0c;不同时区通…

Arrays.asList 和 null 类型

一、Arrays.asList 类型简析 Arrays.asList() 返回的List 是它的内部类&#xff0c;不能使用 retainAll() 取交集&#xff0c;导致元素的删除&#xff0c;会报错。 List<String> list Arrays.asList(value.split(",")); 替换为> List<String> list…

物联网应用中蓝牙模块怎么选?_蓝牙模块厂家

在蓝牙模块选型前期&#xff0c;一定要了解应用场景以及需要实现的功能&#xff08;应用框图&#xff09;&#xff0c;以及功能实现过程中所能提供调用的接口&#xff08;主从设备&#xff0c;功能&#xff09;&#xff0c;考虑模块供电&#xff0c;尺寸&#xff0c;接收灵敏度…

leetcode每日一练-第53题-最大子数组和

一、思路 动态规划 二、解题方法 使用了两个变量 maxSum 和 currentSum 来分别记录全局的最大和和当前连续子数组的和。遍历数组时&#xff0c;我们不断更新 currentSum&#xff0c;并比较是否需要更新 maxSum。最后&#xff0c;maxSum 就是最大的连续子数组和。 三、code …

视频监控/视频汇聚/视频云存储EasyCVR平台接入国标GB协议后出现断流情况,该如何解决?

视频监控汇聚平台EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。安防监控平台EasyCVR既具备传统安防视频监控的能…

【js】防抖和节流的使用场景和区别:

文章目录 一、防抖 &#xff08;多次触发 只执行最后一次&#xff09;二、节流 &#xff08;规定时间内 只触发一次&#xff09;三、防抖和节流的使用场景【1】防抖&#xff08;debounce&#xff09;【2】节流&#xff08;throttle&#xff09; 一、防抖 &#xff08;多次触发 …

功率放大器主要要求有哪些

功率放大器是电子设备中常用的组件&#xff0c;用于将输入信号的功率放大到更高的水平。为了确保功率放大器的正常工作和性能表现&#xff0c;它需要满足一系列要求。下面西安安泰将详细介绍功率放大器的主要要求&#xff0c;希望大家可以对功率放大器有清晰的认识。 一、功率放…

hadoop3.3.1单机版环境搭建详细流程记录

1、在centos7中创建必要的目录&#xff1b; 2、上传JDK安装包到tools目录&#xff1b; 3、解压JDK到/opt/server/目录&#xff1b; tar -zxvf jdk-8u221-linux-x64.tar.gz -C /opt/server/ 4、“vim&#xff1a;未找到命令”的解决办法&#xff1b; 安装vim即可&#xff1b; …

2023年产业地产研究报告

第一章 行业概况 1.1 定义 产业地产是一种特殊类型的房地产&#xff0c;它以土地为基本要素&#xff0c;以企业为投资、开发、运营的主要主体。这种类型的房地产以区域“产、城、人”的有效聚合和持续发展为核心&#xff0c;产业运营和空间运营为主要盈利途径。产业地产的主要…

【串口通信】K210与STM32串口通信、K210与OpenMV串口通信

【串口通信】K210与STM32串口通信、K210与OpenMV串口通信 串口通信前言为何需要串口通信 K210如何进行串口通信K210串口配置K210串口发送相关定义K210串口发送测试K210串口接收相关定义K210串口接收测试 STM32如何进行串口通信STM32串口配置STM32串口发送相关定义STM32串口发送…

定时任务job (现成直接用)

1. 任务调度的2种方式 1. bean调用示例: 对应的类上加Component或Service注解, 类名.方法名(ryTask.ryNoParams) 类名首字母小写; 该类必须要在com.ruoyi 包下, 因为有校验 2. 权限类名调用示例: com.ruoyi.quartz.task.RyTask.ryNoParams 注意: class(类名)调用的时候, 只能调…

C++多态案例3---电脑组装

案例描述: 电脑主要组成部件为 CPU (用于计算) &#xff0c;显卡 (用于显示) &#xff0c;内存条 (用于存储)将每个零件封装出抽象基类&#xff0c;并且提供不同的厂商生产不同的零件&#xff0c;例如Intel厂商和Lenovo厂商创建电脑类提供让电脑工作的函数&#xff0c;并且调用…

uni-app 之 vue语法

uni-app 之 vue语法 image.png --- v-html 字符 --- image.png <template><view><view>{{title}}</view>--- v-html 字符 ---<view>{{title2}}</view><view v-html"title2"></view><view>{{arr}}</view&g…

【FusionInsight 迁移】HBase从C50迁移到6.5.1(02)C50上准备FTP Server

【FusionInsight 迁移】HBase从C50迁移到6.5.1&#xff08;02&#xff09;C50上准备FTP Server HBase从C50迁移到6.5.1&#xff08;02&#xff09;C50上准备FTP Server登录老集群FusionInsight C50的Manager准备FTP User准备FTP Server HBase从C50迁移到6.5.1&#xff08;02&am…

js+html实现打字游戏v2

实现逻辑&#xff0c;看jshtml实现打字游戏v1&#xff0c;在此基础之上增加了从文件读取到的单词&#xff0c;随机选取10个单词。 效果演示 上代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8">&l…

系统架构设计师(第二版)学习笔记----系统架构概述

【原文链接】系统架构设计师&#xff08;第二版&#xff09;学习笔记----系统架构概述 文章目录 一、系统架构的定义与发展历程1.1 架构的定义1.2 架构设计的作用1.3 架构设计产生的背景1.4 软件架构的发展历程1.5 模块化开发方法1.6 模块法方法分解模块遵循的原则1.7 软件工程…

SQLite简单介绍

一.简单介绍 SQLite是一款轻型的数据库&#xff0c;是遵守ACID的关系型数据库管理系统&#xff0c;它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的&#xff0c;而且已经在很多嵌入式产品中使用了它&#xff0c;它占用资源非常的低&…

CC-TAIX01 HONEYWELL 霍尼韦尔连接工厂热智商远程监测系统

CC-TAIX01 HONEYWELL 霍尼韦尔连接工厂热智商远程监测系统 -霍尼韦尔宣布霍尼韦尔连接工厂热智商,一种基于云的远程监测系统,旨在监测和管理关键的热过程数据。这是霍尼韦尔资产绩效管理(APM)投资组合的一部分。 热智商是工业和商业热应用的远程监测解决方案。它将燃烧设备连…