当前位置: 首页 > ds >正文

MP4视频文件播放Demo(附源码)

以下是作者总结的MP4播放demo,视频播放跑在GPU上,同时也支持通过固定频率进行抽帧抽取帧图像保存。话不多说上代码:

1、初始化

void videoPlayerClass::initWidget()
{/*改变视频输出区域尺寸*/ui.widget->setMinimumSize(ui.widget->height() * ((float)16 / 9), ui.widget->height());ui.widget->setMaximumSize(ui.widget->height() * ((float)16 / 9), ui.widget->height());
}

2、加载视频

/*加载本地视频*/
void videoPlayerClass::openVideo(QString videoFilePath, int frequency, QString imagePath)
{if (m_isPlaying && timer->isActive()){m_isPlaying = false;ui.horizontalSlider_progressBar->setValue(0);ui.pushButton_play->setStyleSheet("background-color:transparent;color:#FFFFFF;background-image: url(:/style/image/play.png);");timer->stop(); closeVideo();}m_videoFilePath = videoFilePath;m_frequency = frequency;m_recordImagePath = imagePath;/*按照固定频率截取视频图片*/if (frequency > 0){videoToPictureFrequency(m_videoFilePath, frequency);}/*改变视频输出区域尺寸*/ui.widget->setMinimumSize(ui.widget->height() * ((float)16 / 9), ui.widget->height());ui.widget->setMaximumSize(ui.widget->height() * ((float)16 / 9), ui.widget->height());// Initialize FFmpegav_register_all();if (formatContext) avformat_close_input(&formatContext);avformat_open_input(&formatContext, m_videoFilePath.toStdString().c_str(), nullptr, nullptr);avformat_find_stream_info(formatContext, nullptr);// Find video streamfor (unsigned int i = 0; i < formatContext->nb_streams; i++) {if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {videoStreamIndex = i;AVCodecParameters *codecParameters = formatContext->streams[i]->codecpar;AVCodec *codec = avcodec_find_decoder(codecParameters->codec_id);codecContext = avcodec_alloc_context3(codec);avcodec_parameters_to_context(codecContext, codecParameters);avcodec_open2(codecContext, codec, nullptr);frame = av_frame_alloc();packet = av_packet_alloc();duration = formatContext->duration; // 获取视频总时长ui.horizontalSlider_progressBar->setMaximum(duration / AV_TIME_BASE); // 设置进度条最大值ui.label_videoTime->setText("00:00:00/" + QTime::fromMSecsSinceStartOfDay(duration / AV_TIME_BASE * 1000).toString("HH:mm:ss"));break;}}QPixmap pixmap_orgin = extractFirstFrame(m_videoFilePath.toStdString().c_str());ui.widget->setCurrentImage(pixmap_orgin.toImage());
}

3、视频抽帧

/*按照固定频率提取图像*/
void videoPlayerClass::videoToPictureFrequency(QString videoPath, int frequency)
{cv::VideoCapture cap(videoPath.toStdString().c_str()); // 打开视频文件if (!cap.isOpened()) {std::cerr << "Error: Could not open video file." << std::endl;return;}int frameCount = 0;double fps = cap.get(cv::CAP_PROP_FPS); // 获取视频的帧率double totalcount = cap.get(cv::CAP_PROP_FRAME_COUNT); // 获取视频的帧率int interval = 0; // 计算提取帧的间隔/*小数部分大于或等于0.5,建议向上取整*/if (fps / frequency - std::floor(fps / frequency) >= 0.5){interval = std::ceil(fps / frequency);}else{interval = std::floor(fps / frequency);}cv::Mat frame;while (cap.read(frame)){if (static_cast<int>(frameCount % interval) == 0){std::string filename = m_recordImagePath.toStdString() +  "/output_" + std::to_string(frameCount / interval) + ".png";cv::imwrite(filename, frame); // 保存帧为图片}frameCount++;}cap.release();
}

4、定时刷新页面

// 设置定时器
timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &videoPlayerClass::updateProgress);
timer->start();/*更新视频图像显示*/
void videoPlayerClass::updateProgress()
{if (!m_isPlaying) return;// Read frames and update progressif (av_read_frame(formatContext, packet) >= 0){if (packet->stream_index == videoStreamIndex) {avcodec_send_packet(codecContext, packet);if (avcodec_receive_frame(codecContext, frame) == 0) {// Convert frame to QImageint numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, codecContext->width, codecContext->height, 1);uint8_t *buffer = (uint8_t *)av_malloc(numBytes);swsContext = sws_getContext(codecContext->width, codecContext->height,codecContext->pix_fmt,codecContext->width, codecContext->height,AV_PIX_FMT_RGB24,SWS_BILINEAR, nullptr, nullptr, nullptr);uint8_t *dest[1] = { buffer };int destLinesize[1] = { 3 * codecContext->width };sws_scale(swsContext, frame->data, frame->linesize, 0, codecContext->height, dest, destLinesize);currentFrameImage = QImage(buffer, codecContext->width, codecContext->height, QImage::Format_RGB888);ui.widget->setCurrentImage(currentFrameImage);av_free(buffer);sws_freeContext(swsContext);currentTime = frame->pts * av_q2d(formatContext->streams[videoStreamIndex]->time_base);ui.horizontalSlider_progressBar->setValue(currentTime); // 更新进度条ui.label_videoTime->setText(QTime::fromMSecsSinceStartOfDay(currentTime * 1000).toString("HH:mm:ss") + "/" + QTime::fromMSecsSinceStartOfDay(duration / AV_TIME_BASE * 1000).toString("HH:mm:ss"));update(); // 刷新图像显示return; // 处理完一帧后退出}}}else{av_packet_unref(packet);on_pushButton_stop_clicked();}
}

以上是播放本地视频的主要函数。完整的demo源代码请下载https://download.csdn.net/download/he1234519/90926849?spm=1001.2014.3001.5503

注:如果本文章对您有所帮助,请点赞收藏支持一下,谢谢。^_^

版权声明:本文为博主原创文章,转载请附上博文链接。

http://www.xdnf.cn/news/9673.html

相关文章:

  • 头歌之动手学人工智能-Pytorch 之autograd
  • 算法 Arrays.sort()函数自定义排序(Comparator 接口)
  • [网页五子棋][匹配模块]服务器开发、用户管理器(创建匹配请求/响应对象、处理连接成功、处理下线)
  • 根据jvm源码剖析类加载机制
  • Python爬虫实战:研究Tornado框架相关技术
  • [Vue组件]半环进度显示器
  • 小猴子摆玩具
  • 计算机网络第一章计算机网络概述(竟成)
  • 小白成长之路-Linux操作系统-进程管理
  • 【机器人编程基础】python中的常用数据类型
  • ElasticSearch查询指定时间内出现的次数/2秒内出现的次数
  • 我们来学mysql -- 输出一份“数据备份还原”sh脚本
  • 手写字魔法消除1:数据集说明(含下载链接)
  • Kruskal算法剖析与py/cpp/Java语言实现
  • linux中基础IO(上)
  • 浅谈 JavaScript 性能优化
  • 深度解析 Nginx 配置:从性能优化到 HTTPS 安全实践
  • YOLOv8性能提升:引入华为GhostNetv1特征提取网络
  • 第五章 宽松内存一致性模型 A Primer on Memory Consistency and Cache Coherence - 2nd Edition
  • Houdini learning Record
  • Python中的跨域资源共享(CORS)处理
  • CRTP学习笔记与指南
  • MySQL8.4主从复制
  • Mysql学习笔记之事务
  • 大数据未来发展的趋势与挑战
  • 深入详解(0020,0052) Frame of Reference UID在序列空间定位中的定义与作用
  • 【机器学习基础】机器学习入门核心算法:GBDT(Gradient Boosting Decision Tree)
  • 20250528-C#知识:强制类型转换
  • PostgreSQL 数据完整性检查工具对比:amcheck 与 pg_checksums
  • TCP连接数统计脚本