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
注:如果本文章对您有所帮助,请点赞收藏支持一下,谢谢。^_^
版权声明:本文为博主原创文章,转载请附上博文链接。