#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();
}