首页 > 其他分享 >Qt和ffmpeg结合制作全能解码播放器

Qt和ffmpeg结合制作全能解码播放器

时间:2023-10-27 13:34:44浏览次数:40  
标签:播放器 swrContext Qt av packet videoCodecContext qDebug include ffmpeg

#include <QCoreApplication>
#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include <QVideoWidget>
#include <QAudioOutput>
#include <QDebug>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // 初始化FFmpeg
    av_register_all();

    QWidget window;
    window.setWindowTitle("视频播放器");
    QVBoxLayout *layout = new QVBoxLayout(&window);

    // 创建QVideoWidget
    QVideoWidget *videoWidget = new QVideoWidget;
    layout->addWidget(videoWidget);

    // 创建QAudioOutput
    QAudioOutput *audioOutput = new QAudioOutput;
    QIODevice *audioDevice = audioOutput->start();

    window.show();

    // 打开视频文件
    AVFormatContext *formatContext = nullptr;
    if (avformat_open_input(&formatContext, "your_video_file.mp4", nullptr, nullptr) != 0)
    {
        qDebug() << "无法打开视频文件";
        return a.exec();
    }

    // 查找流信息
    if (avformat_find_stream_info(formatContext, nullptr) < 0)
    {
        qDebug() << "无法获取流信息";
        avformat_close_input(&formatContext);
        return a.exec();
    }

    // 查找视频流和音频流
    int videoStreamIndex = -1;
    int audioStreamIndex = -1;
    for (int i = 0; i < formatContext->nb_streams; i++)
    {
        if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            videoStreamIndex = i;
        }
        else if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
        {
            audioStreamIndex = i;
        }
    }

    if (videoStreamIndex == -1 || audioStreamIndex == -1)
    {
        qDebug() << "无法找到视频或音频流";
        avformat_close_input(&formatContext);
        return a.exec();
    }

    // 创建视频解码器上下文
    AVCodecContext *videoCodecContext = avcodec_alloc_context3(nullptr);
    if (!videoCodecContext)
    {
        qDebug() << "无法分配视频解码器上下文";
        avformat_close_input(&formatContext);
        return a.exec();
    }

    // 设置视频解码器参数
    if (avcodec_parameters_to_context(videoCodecContext, formatContext->streams[videoStreamIndex]->codecpar) < 0)
    {
        qDebug() << "无法设置视频解码器参数";
        avcodec_free_context(&videoCodecContext);
        avformat_close_input(&formatContext);
        return a.exec();
    }

    // 查找视频解码器
    AVCodec *videoCodec = avcodec_find_decoder(videoCodecContext->codec_id);
    if (!videoCodec)
    {
        qDebug() << "无法找到视频解码器";
        avcodec_free_context(&videoCodecContext);
        avformat_close_input(&formatContext);
        return a.exec();
    }

    // 打开视频解码器
    if (avcodec_open2(videoCodecContext, videoCodec, nullptr) < 0)
    {
        qDebug() << "无法打开视频解码器";
        avcodec_free_context(&videoCodecContext);
        avformat_close_input(&formatContext);
        return a.exec();
    }

    // 创建音频解码器上下文
    AVCodecContext *audioCodecContext = avcodec_alloc_context3(nullptr);
    if (!audioCodecContext)
    {
        qDebug() << "无法分配音频解码器上下文";
        avcodec_free_context(&videoCodecContext);
        avformat_close_input(&formatContext);
        return a.exec();
    }

    // 设置音频解码器参数
    if (avcodec_parameters_to_context(audioCodecContext, formatContext->streams[audioStreamIndex]->codecpar) < 0)
    {
        qDebug() << "无法设置音频解码器参数";
        avcodec_free_context(&videoCodecContext);
        avcodec_free_context(&audioCodecContext);
        avformat_close_input(&formatContext);
        return a.exec();
    }

    // 查找音频解码器
    AVCodec *audioCodec = avcodec_find_decoder(audioCodecContext->codec_id);
    if (!audioCodec)
    {
        qDebug() << "无法找到音频解码器";
        avcodec_free_context(&videoCodecContext);
        avcodec_free_context(&audioCodecContext);
        avformat_close_input(&formatContext);
        return a.exec();
    }

    // 打开音频解码器
    if (avcodec_open2(audioCodecContext, audioCodec, nullptr) < 0)
    {
        qDebug() << "无法打开音频解码器";
        avcodec_free_context(&videoCodecContext);
        avcodec_free_context(&audioCodecContext);
        avformat_close_input(&formatContext);
        return a.exec();
    }

    // 创建解码帧
    AVFrame *videoFrame = av_frame_alloc();
    AVFrame *audioFrame = av_frame_alloc();
    if (!videoFrame || !audioFrame)
    {
        qDebug() << "无法分配解码帧";
        avcodec_free_context(&videoCodecContext);
        avcodec_free_context(&audioCodecContext);
        avformat_close_input(&formatContext);
        return a.exec();
    }

    // 创建解码包
    AVPacket packet;
    av_init_packet(&packet);

    // 创建视频转换上下文
    SwsContext *swsContext = sws_getContext(
        videoCodecContext->width, videoCodecContext->height, videoCodecContext->pix_fmt,
        videoCodecContext->width, videoCodecContext->height, AV_PIX_FMT_RGB24,
        SWS_BILINEAR, nullptr, nullptr, nullptr);

    // 创建音频重采样上下文
    SwrContext *swrContext = swr_alloc();
    if (!swrContext)
    {
        qDebug() << "无法分配音频重采样上下文";
        avcodec_free_context(&videoCodecContext);
        avcodec_free_context(&audioCodecContext);
        avformat_close_input(&formatContext);
        return a.exec();
    }

    // 设置音频重采样参数
    av_opt_set_int(swrContext, "in_channel_layout", audioCodecContext->channel_layout, 0);
    av_opt_set_int(swrContext, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
    av_opt_set_int(swrContext, "in_sample_rate", audioCodecContext->sample_rate, 0);
    av_opt_set_int(swrContext, "out_sample_rate", 44100, 0);
    av_opt_set_sample_fmt(swrContext, "in_sample_fmt", audioCodecContext->sample_fmt, 0);
    av_opt_set_sample_fmt(swrContext, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);

    // 初始化音频重采样上下文
    if (swr_init(swrContext) < 0)
    {
        qDebug() << "无法初始化音频重采样上下文";
        avcodec_free_context(&videoCodecContext);
        avcodec_free_context(&audioCodecContext);
        avformat_close_input(&formatContext);
        swr_free(&swrContext);
        return a.exec();
    }

    // 分配音频重采样缓冲区
    uint8_t *audioBuffer = nullptr;
    int audioBufferLength = av_samples_alloc(&audioBuffer, nullptr, 2, 44100, AV_SAMPLE_FMT_S16, 0);

    // 读取并显示视频帧和播放音频
    while (av_read_frame(formatContext, &packet) >= 0)
    {
        if (packet.stream_index == videoStreamIndex)
        {
            if (avcodec_send_packet(videoCodecContext, &packet) < 0)
            {
                qDebug() << "无法发送视频解码包";
                break;
            }

            if (avcodec_receive_frame(videoCodecContext, videoFrame) == 0)
            {
                // 将视频帧转换为RGB格式
                sws_scale(swsContext, (const uint8_t *const *)videoFrame->data, videoFrame->linesize, 0, videoCodecContext->height, videoFrame->data, videoFrame->linesize);

                // 将RGB帧显示在QVideoWidget上
                QImage img(videoFrame->data[0], videoCodecContext->width, videoCodecContext->height, videoFrame->linesize[0], QImage::Format_RGB888);
                QPixmap pixmap = QPixmap::fromImage(img);
                videoWidget->setAspectRatioMode(Qt::KeepAspectRatio);
                videoWidget->setPixmap(pixmap);
                videoWidget->update();
            }
        }
        else if (packet.stream_index == audioStreamIndex)
        {
            if (avcodec_send_packet(audioCodecContext, &packet) < 0)
            {
                qDebug() << "无法发送音频解码包";
                break;
            }

            if (avcodec_receive_frame(audioCodecContext, audioFrame) == 0)
            {
                // 重采样音频帧
                swr_convert(swrContext, &audioBuffer, audioBufferLength, (const uint8_t **)audioFrame->data, audioFrame->nb_samples);

                // 将音频帧写入音频设备
                audioDevice->write((const char *)audioBuffer, audioBufferLength);
            }
        }
        av_packet_unref(&packet);
    }

    // 释放资源
    av_free(audioBuffer);
    av_frame_free(&audioFrame);
    av_frame_free(&videoFrame);
    swr_free(&swrContext);
    sws_freeContext(swsContext);
    avcodec_close(videoCodecContext);
    avcodec_free_context(&videoCodecContext);
    avcodec_close(audioCodecContext);
    avcodec_free_context(&audioCodecContext);
    avformat_close_input(&formatContext);

    return a.exec();
}

  



标签:播放器,swrContext,Qt,av,packet,videoCodecContext,qDebug,include,ffmpeg
From: https://blog.51cto.com/navysummer/8053042

相关文章

  • Qt之分裂器(QSplitter)
    一、QSplitter概述QSplitter是Qt中的一个布局管理器,允许用户在应用程序窗口中创建可拖动的分隔器,以便调整多个子窗口或控件的大小。它是一种非常有用的布局管理器,用于创建可分隔的多个部分,通常用于分割、重新排列和管理用户界面中的多个区域。以下是有关QSplitter的详细介......
  • Linux下安装Qt6的问题及解决
    Linux下安装完Qt6,新建Qt/QtQuickCMake工程编译出现如下错误:Foundpackageconfigurationfile:Qt6Config.cmakebutitsetQt6FOUNDtoFALSEsopackage"Qt6"isconsideredtobeNOTFOUND.Reasongivenbypackage:FailedtofindrequiredQtcomponen"Quick&......
  • Qt Creator常用快捷键及技巧提升编码效率
    转:https://blog.csdn.net/luoyayun361/article/details/105431913https://blog.csdn.net/u_topian/article/details/130366561https://blog.csdn.net/Zeek_0114/article/details/98938547代码编辑1.定义触发片段打开工具->选项->文本编辑器->片段,右侧点击添加2///三个斜杠......
  • qt 设置背景图片,图片出现锯齿
    qt给控件添加背景图片,通过有3种方式background-image;border-image;image其中通常用border-image;image。使用border-image,会出现图片失真,锯齿状严重ui->pushButton->setStyleSheet(“QPushButton{border-image:url(:/images/XXX.png);}”);使用image,会有边框,不适合qpushBu......
  • 通讯 --- C# .NET CORE MQTT 心跳服务
    转自:https://www.cnblogs.com/hkzw/p/17689443.htmlMQTT服务可以自行学习,这里只是记录一下写的结果,粘贴即用。首先引入包 MQTTnet,注意这个包这里的代码是4.0一下版本我用的3.1.2版本的4.以上是另外的写法,该内容中4不支持我 直接下降版本到3.1.2可以了。如果你一......
  • ASP.NET Core 使用 MQTTnet 实现 MQTT 通讯协议
    转自:https://www.twle.cn/t/19383MQTT是啥呢?MQTT,英文全称 MessageQueuingTelemetryTransport,是一种基于 发布/订阅 模式的轻量级的消息传输协议,由IBM公司出品。物联网兴起后,MQTT因为够轻量,低带宽和低延时而被推上浪潮之巅。其实,MQTT几乎就是专门为网络受限设备、低......
  • Captura录屏软件怎样解决FFmpeg解析错误问题
    Captura怎样解决FFmpeg解析错误问题?captura软件里大家在进行屏幕录制的工作得时候都会用到captura软件,软件得功能可以满足大家的需求,可以轻松的录制屏幕,进行屏幕截屏等,但是又小伙伴在使用的时候发现了一些问题,那么怎么解决这个问题呢?还不清楚的小伙伴赶紧来看看吧!Captura解决......
  • FFmpeg 下载安装教程及介绍
    一、下载安装(1)进入官网 https://www.ffmpeg.org/ (2)根据自己的电脑选择对应系统进行点击。我选定是windows,选择下面出现的“Windowsbuildsfromgyan.dev”,  (3)在稳定版本中选择一个进行下载, 4)等待下载完成, (5)下载完成压缩文件之后,解压文件。(6)将bin文件夹添加到Wi......
  • Captura 下载安装及在Captura配置FFmpeg(录屏软件)
    一、下载安装(1)下载地址 https://github.com/MathewSachin/Captura/releases(2) 点击下载Captura-Setup.exe,等待下载完成, (3)双击进行安装,会弹出安装流程页面, 这里我发现Captura安装时没有中文语言选项,就默认English吧, 直接点击“OK”,  可以根据自己需求改变安装路径,......
  • Qt开发之图形视图
    一、GraphicsView框架结构Qt的GraphicsView框架是一个用于2D图形渲染和交互的框架,它为开发者提供了一种灵活的方式来创建自定义的图形界面和场景。以下是QtGraphicsView框架的主要组件和结构分析:场景(Scene):QGraphicsScene是GraphicsView的核心概念之一。场景充当图形项(Item)的......