Практика проекта: Qt реализует транскодер аудио и видео FFmpeg.
Практика проекта: Qt реализует транскодер аудио и видео FFmpeg.
Предисловие

В этой статье описывается процесс разработки использования Qt для реализации проекта транскодера аудио и видео FFmepg.

1. Пересадите файлы, связанные с FFmpeg.

1. Сначала создайте проект Qt и выберите MSVC2017 32bit в качестве его компилятора.

2. Скопируйте библиотеки и исходные файлы, связанные с FFmpeg, в текущий каталог.

3. Закомментируйте функцию готовых_app_arguments (нам будет удобно указать соответствующие параметры транскодирования при дальнейшем запуске)

4. Скопируйте некоторые необходимые файлы динамической библиотеки dll в каталог отладки.

5. Скопируйте файлы аудио- и видеоматериалов в build-QtVideoConverterFFmpeg431-Desktop_Qt_5_14_2_MinGW_32_bit-Debugв каталоге(НажмитебегатьАвтоматически созданный каталог)

2. Нарисуйте интерфейс пользовательского интерфейса

Нарисуйте простой интерфейс пользовательского интерфейса, эффект будет следующим:

Он включает в себя рамку, кнопку, индикатор выполнения, метку, виджет таблицы, поле со списком, редактирование строки и другие связанные элементы управления.

3. Реализуйте простое транскодирование

1、существоватьНачать перекодированиекнопка clicked Добавьте следующий код в функцию слота:

Язык кода:javascript
копировать
void Widget::on_pushButton_Running_clicked()
{
    qDebug() << "hello,ffmpeg";

    QString currentPath = QDir::current().path();

       qDebug() << "Current path:" << currentPath;

    char* arrParams[10] = { 0 };
    for (int k = 0; k < 10; k++) {
        arrParams[k] = new char[64]();
    }
    strcpy(arrParams[0], "QtVideoConverter.exe");
    strcpy(arrParams[1], "-i");
    strcpy(arrParams[2], "SampleVideo_1280x720_20mb.mp4");
    strcpy(arrParams[3], "-vcodec");
    strcpy(arrParams[4], "libx264");
    strcpy(arrParams[5], "-acodec");
    strcpy(arrParams[6], "copy");
    strcpy(arrParams[7], "-y");
    strcpy(arrParams[8], "SampleVideo_1280x720_20mb.flv");

    main_ffmpeg431(9, arrParams);

    AVGeneralMediaInfo* avmi = new AVGeneralMediaInfo();
    for (int k = 0; k < 10; k++) {
        delete[] arrParams[k];
        avmi = NULL;
    }
}

2. Нажмите «Выполнить», и вы увидите следующий интерфейс.

В настоящее время функция индикатора выполнения не реализована. Нажмите на транскодирование, чтобы. build-QtVideoConverter-Desktop_Qt_5_14_2_MSVC2017_32bit-Debug В каталоге вы увидите, что перекодирование прошло успешно. flv документ

4. Оптимизация функции

1. Контроль планировки и благоустройства

Язык кода:javascript
копировать
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->setStyleSheet("background-color:#F0F0F0;");   // Настройка внешнего вида окон компонентов
    // qss, похоже на css
    ui->lblLogoText->setStyleSheet("color:#009100;font-style:italic;font-weight:bold;font-size:30px;");

    // frame цвет фона
    ui->frameTop->setStyleSheet("background-color:#C4E1FF;");

    // кнопкацвет фона
    ui->pushButton_Running->setStyleSheet("background-color:#C4E1FF;font-weight:bold;font-size:30px;color:#009100;border:2px groove gray;border-radius:10px;padding:2px 4px;");
}

// Линии сетки скрыты, а ячейки нельзя редактировать.
    ui->tableWidget_FileList->verticalHeader()->setHidden(true); // Установите скрытое имя строки (обратите внимание, что это имя строки, а не вся строка)
    ui->tableWidget_FileList->setShowGrid(false); // Определяет, отображается ли сетка между элементами данных в представлении.
    ui->tableWidget_FileList->setEditTriggers(QAbstractItemView::NoEditTriggers); // Сделайте эту форму доступной только для чтения пользователям

Эффект следующий:

2. Интерфейс масштабирования

Фильтр событий: (двойной щелчок, полноэкранный режим)

Язык кода:javascript
копировать
// Фильтр событий: (двойной щелчок, полноэкранный режим)
bool Widget::eventFilter(QObject *obj, QEvent *event)
{
    // Укажите элемент управления
    if (obj == ui->frameTop || obj == ui->lblLogoText || obj == ui->lblLogoImage) {
        //  QEvent::MouseButtonPress,QEvent::MouseButtonDblClick
        if (event->type() == QEvent::MouseButtonDblClick) {
            QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
            if (mouseEvent->button() == Qt::LeftButton) {
                // QMessageBox::information(this, "Нажмите", "Нажмите меня поймал", QMessageBox::Yes | QMessageBox::No | QMessageBox::Yes);
                if (!this->isMaximized()) {
                    this->showMaximized();
                } else {
                    this->showNormal();
                }
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    } else {
        // pass the event on to the parent class
        return Widget::eventFilter(obj, event);
    }
}

Эффект:

Клавиша ESC для выхода из полноэкранного режима

Язык кода:javascript
копировать
// Кнопка: (esc — выход из полноэкранного режима)
void Widget::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
        case Qt::Key_Escape:
        if (this->isMaximized()) {
            this->showNormal();
        }
        break;
    default:
        QWidget::keyPressEvent(event);
    }
}

3. Реализуйте перетаскивание

Нажмите мышь, не отпуская ее, затем переместите мышь, чтобы перетащить, и отпустите мышь, чтобы завершить перетаскивание.

Язык кода:javascript
копировать
// тащитьдействовать---begin
void Widget::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        m_bDrag = true;
        // Получить начальное положение мыши
        mouseStartPoint = event->globalPos(); // Значение смещения мыши относительно верхнего левого угла (0,0) всего экрана при возникновении события.
        // mouseStartPoint = event->pos(); // Мышь активна относительно текущего события, когда событие происходит. Значение смещения верхнего левого угла виджета (0,0)
        // Получить начальное положение окна
        windowTopLeftPoint = this->frameGeometry().topLeft(); // По-прежнему представляет верхний левый угол всего экрана.

        qDebug() << "mouseStartPoint" << mouseStartPoint.x() << mouseStartPoint.y();
        qDebug() << "windowTopLeftPoint" << windowTopLeftPoint.x() << windowTopLeftPoint.y();
    }
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    if (m_bDrag) {
        // Получить расстояние, пройденное мышью
        QPoint distance = event->globalPos() - mouseStartPoint;
        // QPoint distance = event->pos() - mouseStartPoint;
        // Изменить положение окна
        this->move(windowTopLeftPoint + distance);
        qDebug() << "move" << windowTopLeftPoint + distance;
    }
}

void Widget::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        m_bDrag = false;
    }
}
// тащитьдействовать--end

Эффект следующий:

4. Разбор файлов

Нажмите выбиратьдокумент кнопка,Выберите документ для перекодирования,Вы можете проанализировать соответствующую информацию выбранного документа.

Язык кода:javascript
копировать
void Widget::on_pushButton_AddFile_clicked()
{
    // Определите класс диалогового окна документа
    QFileDialog *fileDialog = new QFileDialog(this);
    // Определить заголовок диалогового окна документа
    fileDialog->setWindowTitle(tr("Открытьдокумент")); // Функция tr(): Qt автоматически выберет соответствующий документ перевода на основе текущей языковой среды и переведет строку на соответствующий язык.
    // Установить путь по умолчанию
    fileDialog->setDirectory(".");
    // Установить фильтр документов
    fileDialog->setNameFilter(tr("video(*.mp4 *.flv *.mkv);;All files(*.*)"));
    // В настройках можно выбрать несколько документов. По умолчанию можно выбрать только один документ. QFileDialog::ExistingFiles
    fileDialog->setFileMode(QFileDialog::ExistingFile);
    // Установить режим просмотра
    fileDialog->setViewMode(QFileDialog::Detail);

    if (fileDialog->exec()) {
        QString strFileName = fileDialog->selectedFiles()[0];
        qDebug() << strFileName;
        QFileInfo fileinfo;
        fileinfo = QFileInfo(strFileName);

        // Вставить элемент данных
        ui->tableWidget_FileList->setRowCount(1);
        ui->tableWidget_FileList->setItem(0, 0, new QTableWidgetItem(fileinfo.fileName())); // документ名        ui->tableWidget_FileList->setItem(0, 1, new QTableWidgetItem(fileinfo.suffix()));   // суффикс

        AVGeneralMediaInfo avmi;
        std::string str = strFileName.toStdString();
        const char *chFilename = str.c_str();
        get_avgeneral_mediainfo(&avmi, chFilename);
        ui->tableWidget_FileList->setItem(0, 2, new QTableWidgetItem(QString(QLatin1String(avmi.videoCodecName))));
        ui->tableWidget_FileList->setItem(0, 3, new QTableWidgetItem(QString(QLatin1String(avmi.audioCodecName))));
        char chDuration[128] = {0};
        sprintf(chDuration, "%lld", avmi.duration);
        ui->tableWidget_FileList->setItem(0, 4, new QTableWidgetItem(QString(QLatin1String(chDuration))));
        ui->tableWidget_FileList->setItem(0, 5, new QTableWidgetItem(strFileName));
    }
}

Эффект следующий:

5. Запускайте независимые темы

tcworkthread.h

Язык кода:javascript
копировать
#ifndef TCWORKTHREAD_H
#define TCWORKTHREAD_H

#include <QThread>
extern "C" {
#include "ffmpeg.h"
}

#define MAX_CMDLINE_ARGC_COUNT 100

// Параметры транскодирования
typedef struct __TCParams {
    char inFilename[512];
    char videoCodecName[256];
    char audioCodecName[256];
    char muxerName[256];

    // Определена конструкция без параметров function__TCParams(), в которой вызывается закрытая функция-член с именем __init().
    // Функция конструктора будет автоматически вызываться при создании экземпляра структуры, поэтому при создании объекта TCParams функция __init() будет автоматически выполнена.
    __TCParams() {
        __init();
    }

    void __init() {
        memset(inFilename, 0, 512);
        memset(videoCodecName, 0, 256);
        memset(audioCodecName, 0, 256);
        memset(muxerName, 0, 256);
    }

} TCParams;

class TCWorkThread : public QThread
{
public:
    TCWorkThread();

private:
    virtual void run(); // поток обработки задач
    TCParams *m_pTCParams;

public:
    int workCount;  // считать
    void SetTCParams(TCParams *params);

signals:

public slots:

};

tcworkthread.c

Язык кода:javascript
копировать
#include "tcworkthread.h"
#include <QDebug>

TCWorkThread::TCWorkThread()
{
    workCount = 0;
    m_pTCParams = nullptr;
}

void TCWorkThread::SetTCParams(TCParams *params)
{
    m_pTCParams = params;
}

// run() 重新выполнить
void TCWorkThread::run()
{
    if (m_pTCParams == nullptr) {
        return;
    }

    // by lp, все параметры жестко закодированы и предназначены только для справки.

    char* arrParams[MAX_CMDLINE_ARGC_COUNT] = { 0 };
    for (int k = 0; k < MAX_CMDLINE_ARGC_COUNT; k++) {
        arrParams[k] = new char[1024]();
    }
    char strOutName[512] = {0};

    strcpy(arrParams[0], "QtVideoConverter.exe");
    strcpy(arrParams[1], "-i");
    strcpy(arrParams[2], m_pTCParams->inFilename);
    strcpy(arrParams[3], "-vcodec");
    strcpy(arrParams[4], m_pTCParams->videoCodecName);
    strcpy(arrParams[5], "-acodec");
    strcpy(arrParams[6], m_pTCParams->audioCodecName);
    strcpy(arrParams[7], "-y");

    sprintf(strOutName, "SampleVideo_1280x720_20mb.%s", m_pTCParams->muxerName);
    strcpy(arrParams[8], strOutName);

    // Подготовьте параметры
    main_ffmpeg431(9, arrParams);

    for (int k = 0; k < MAX_CMDLINE_ARGC_COUNT; k++) {
        delete[] arrParams[k];  // Не забудьте освободить выделенную память
        arrParams[k] = NULL;
    }
}

6. Запустите таймер

Язык кода:javascript
копировать
// Функция обработки событий таймера
// Получайте информацию о ходе транскодирования в реальном времени
// Текущий прогресс 1.00 Когда, killTimer
void Widget::timerEvent(QTimerEvent *event)
{
    int nPrg = (int)(get_tc_progress() * 100);
    qDebug() << "progress:" << nPrg;
    ui->progressBar_tcprg->setValue(nPrg);
    if (nPrg >= 100) {
        killTimer(m_TimerID1);
    }
}

7. Конечный операционный эффект

будет местный mp3 документ Конвертировать в flv документ

5. Приложение

Прикреплен веб-сайт с шестнадцатеричными цветовыми кодами.:Шестнадцатеричные таблицы цветового кода, диаграммы и палитры

6. Самовывоз ресурсов

Связь:Транскодер аудио и видео на основе QT и ffmpeg

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose