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

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

时间:2023-09-16 18:13:33浏览次数:35  
标签:播放器 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://www.cnblogs.com/navysummer/p/17707053.html

相关文章

  • PyQt中绘制折线图
    在PyQt中,可以使用matplotlib库来绘制折线图。 importsysfromPyQt5.QtWidgetsimportQApplication,QMainWindow,QVBoxLayout,QWidgetfrommatplotlib.figureimportFigurefrommatplotlib.backends.backend_qt5aggimportFigureCanvasQTAggasFigureCanvasimport......
  • springboot安卓音乐播放器
    开发环境及工具:大等于jdk1.8,大于mysql5.5,idea(eclipse),AndroidStudio技术说明:springbootmybatisandroid代码注释齐全,没有多余代码,适合学习(毕设),二次开发,包含论文技术相关文档。功能介绍:用户端:登录注册首页显示搜索音乐,轮播图,音乐列表点击音乐进入音乐详情(以及展示评论信息),可以点......
  • QT基础教学(窗口组件)
    (文章目录)前言本篇文章将带大家学习QT中的窗口组件。资料合集地微信公众号:优质程序猿一、窗口组件窗口组件是在图形用户界面(GUI)应用程序中用于创建和管理窗口的可视化元素。窗口组件提供了用户与应用程序交互的界面,包括各种控件、布局和事件处理机制等。在Qt中,窗口组件主......
  • Qt For OpenHarmony
    本文转载自 OpenHarmony TSC 官方微信公众号《峰会回顾第29期 | Qt For OpenHarmony》演讲嘉宾 | 蔡万苍回顾整理 | 廖   涛排版校对 | 李萍萍嘉宾简介蔡万苍,13年C++/Qt开发相关工作经验,曾任职Qt公司,担任技术支持、Qt咨询师,协助国内多家Qt企业版用户完成基于Qt的软......
  • Qt For OpenHarmony
     本文转载自 OpenHarmony TSC 官方微信公众号《峰会回顾第29期 | Qt For OpenHarmony》 演讲嘉宾 | 蔡万苍回顾整理 | 廖   涛排版校对 | 李萍萍  嘉宾简介蔡万苍,13年C++/Qt开发相关工作经验,曾任职Qt公司,担任技术支持、Qt咨询师,协助国内多家Qt企......
  • Qt/C++音视频开发53-本地摄像头推流/桌面推流/文件推流/监控推流等
    一、前言编写这个推流程序,最开始设计的时候是用视频文件推流,后面陆续增加了监控摄像头推流(其实就是rtsp视频流)、网络电台和视频推流(一般是rtmp或者http开头m3u8结尾的视频流)、本地摄像头推流(本地USB摄像头或者笔记本自带摄像头等)、桌面推流(将当前运行环境的系统桌面抓拍推流)。按......
  • ffmpeg裁剪视频
    ffmpeg命令格式:usage:ffmpeg[options][[infileoptions]-iinfile]...{[outfileoptions]outfile}...crop的参数格式为w:h:x:y (注意,宽:高写在前面)w:h为输出视频的宽和高,x:y标记输入视频中的某点,将该点作为基准点,向右下进行裁剪得到输出视频。如果xy不写的话,默......
  • ubuntu编译ffmpeg扩展支持FLV-H265
    1.编译x264:  1)gitclonehttp://git.videolan.org/git/x264.git  2)./configure--enable-shared--disable-asm  3)make&&makeinstall2.编译x265:  1)wgethttp://ftp.videolan.org/pub/videolan/x265/x265-2.7.tar.bz2  2)tarxvfx265-2.7.tar.b......
  • TQT113平台虚拟机镜像使用手册
    ▲点击上方“广州天嵌”关注公众号后回复TQT113_CORE获取板卡wiki资料本文介绍如何使用我司提供的虚拟机镜像,搭建虚拟机环境,构建编译TQT113_COREB开发板的开发环境。注意事项:若用户没有搭建过调试和开发环境,或已有我司其他开发平台或其他厂商的测试开发环境的,请先严格按照本手册搭......
  • TQT113平台虚拟机镜像使用手册
    本文介绍如何使用我司提供的虚拟机镜像,搭建虚拟机环境,构建编译TQT113_COREB开发板的开发环境。注意事项:若用户没有搭建过调试和开发环境,或已有我司其他开发平台或其他厂商的测试开发环境的,请先严格按照本手册搭建成功后再进行测试调试开发等内容操作,避免因为环境不一致导致测试和......