原来Qt从视频中获取每一帧数据如此简单

有时候需要在视频上画图,所以需要能获取到每一帧视频数据。

以前从视频文件或视频流中得到帧,一般都是使用qt + ffmpeg或qt + vlc。

qt对显示处理视频大体有以下方法:

1. QMediaPlayer + QVideoWidget

这种方法只适合简单的显示视频功能,不适合对视频进行处理(比如画图)

2. QMediaPlayer + QGraphicsVideoItem + QGraphicsScene + QGraphicsView

这种方法功能强大,除了显示视频功能,还可以做复杂的图形处理(具体可以查看QGraphicsScene的使用)

3. QMediaPlayer + QAbstractVideoSurface

这种方法比较简单,是我下面要介给的。可以获取到每一帧视频数据,基本可以实现与qt + ffmpeg或qt + vlc相同的效果。

 

自定义VideoSurface:

  1.  

class VideoSurface : public QAbstractVideoSurface

  • {

  • Q_OBJECT

  •  
  • public:

  • VideoSurface(QObject *parent = Q_NULLPTR);

  • ~VideoSurface();

  •  
  • QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const;

  • bool present(const QVideoFrame &frame);

  •  
  • signals:

  • void frameAvailable(QVideoFrame &frame);

  •  
  • };

实现如下:

  1. VideoSurface::VideoSurface(QObject *parent)

  2. : QAbstractVideoSurface(parent)

  3. {

  4. }

  5.  
  6. VideoSurface::~VideoSurface()

  7. {

  8. }

  9.  
  10. QList<QVideoFrame::PixelFormat> VideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const

  11. {

  12. QList<QVideoFrame::PixelFormat> listPixelFormats;

  13.  
  14. listPixelFormats << QVideoFrame::Format_ARGB32

  15. << QVideoFrame::Format_ARGB32_Premultiplied

  16. << QVideoFrame::Format_RGB32

  17. << QVideoFrame::Format_RGB24

  18. << QVideoFrame::Format_RGB565

  19. << QVideoFrame::Format_RGB555

  20. << QVideoFrame::Format_ARGB8565_Premultiplied

  21. << QVideoFrame::Format_BGRA32

  22. << QVideoFrame::Format_BGRA32_Premultiplied

  23. << QVideoFrame::Format_BGR32

  24. << QVideoFrame::Format_BGR24

  25. << QVideoFrame::Format_BGR565

  26. << QVideoFrame::Format_BGR555

  27. << QVideoFrame::Format_BGRA5658_Premultiplied

  28. << QVideoFrame::Format_AYUV444

  29. << QVideoFrame::Format_AYUV444_Premultiplied

  30. << QVideoFrame::Format_YUV444

  31. << QVideoFrame::Format_YUV420P

  32. << QVideoFrame::Format_YV12

  33. << QVideoFrame::Format_UYVY

  34. << QVideoFrame::Format_YUYV

  35. << QVideoFrame::Format_NV12

  36. << QVideoFrame::Format_NV21

  37. << QVideoFrame::Format_IMC1

  38. << QVideoFrame::Format_IMC2

  39. << QVideoFrame::Format_IMC3

  40. << QVideoFrame::Format_IMC4

  41. << QVideoFrame::Format_Y8

  42. << QVideoFrame::Format_Y16

  43. << QVideoFrame::Format_Jpeg

  44. << QVideoFrame::Format_CameraRaw

  45. << QVideoFrame::Format_AdobeDng;

  46.  
  47. //qDebug() << listPixelFormats;

  48.  
  49. // Return the formats you will support

  50. return listPixelFormats;

  51. }

  52.  
  53. bool VideoSurface::present(const QVideoFrame &frame)

  54. {

  55. // Handle the frame and do your processing

  56. if (frame.isValid())

  57. {

  58. QVideoFrame cloneFrame(frame);

  59. emit frameAvailable(cloneFrame);

  60.  
  61. return true;

  62. }

  63.  
  64. return false;

  65. }

看了上面的代码就知道,只需要外部连接frameAvailable信号就可以获取到每一帧数据。

具体使用:

  1. QMediaPlayer *mediaPlayer = new QMediaPlayer;

  2. VideoSurface *videoSurface = new VideoSurface;

  3. mediaPlayer->setVideoOutput(videoSurface);

  4. mediaPlayer->setMedia(QUrl("rtsp://admin:admin@192.168.1.112"));

  5. mediaPlayer->play();

把frameAvailable信号与显示窗口的槽连接,比如:

connect(videoSurface, SIGNAL(frameAvailable(QVideoFrame &)), this, SLOT(ProcessFrame(QVideoFrame &)));

  1. void QtVideoTest::ProcessFrame(QVideoFrame &frame)

  2. {

  3. qDebug() << "=============ProcessFrame===============";

  4. qDebug() << "width : " << frame.width() << " height : " << frame.height();

  5. qDebug() << "start time : " << frame.startTime()/1000 << "ms";

  6. qDebug() << "end time : " << frame.endTime()/1000 << "ms";

  7. qDebug() << "pixelFormat :" << frame.pixelFormat();

  8.  
  9. frame.map(QAbstractVideoBuffer::ReadOnly);

  10. QImage recvImage(frame.bits(), frame.width(), frame.height(), QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat()));

  11.  
  12. qDebug() << "frame data size :" << frame.mappedBytes();

  13. frame.unmap();

  14. }

如上,QVideoFrame转QImage,拿QImage进行画图操作就简单了。

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
您可以使用OpenCV的VideoCapture类来从多个视频文件获取一帧数据。以下是一个简单的示例代码,它从16个视频文件获取一帧数据并将其保存到一个Mat对象: ```cpp #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main(int argc, char** argv) { // 打开16个视频文件 vector<VideoCapture> captures; for (int i = 0; i < 16; ++i) { VideoCapture cap("video" + to_string(i) + ".mp4"); if (!cap.isOpened()) { cerr << "Cannot open video file " << i << endl; return -1; } captures.push_back(cap); } // 获取每个视频的第一帧 vector<Mat> frames; for (int i = 0; i < 16; ++i) { Mat frame; captures[i] >> frame; if (!frame.empty()) { frames.push_back(frame); } else { cerr << "Cannot read frame from video file " << i << endl; return -1; } } // 将所有帧拼接成一个大图像 Mat combined(frames.size() * frames[0].rows, frames[0].cols, CV_8UC3); for (int i = 0; i < frames.size(); ++i) { Mat roi(combined, Rect(0, i * frames[0].rows, frames[i].cols, frames[i].rows)); frames[i].copyTo(roi); } // 显示结果 namedWindow("First Frames", WINDOW_NORMAL); imshow("First Frames", combined); waitKey(0); destroyAllWindows(); return 0; } ``` 在这个示例,我们首先打开16个视频文件并将它们存储在一个vector。然后,我们循环遍历每个视频文件,使用VideoCapture类来获取一帧数据,并将其存储在一个Mat对象。最后,我们将所有帧拼接成一个大图像,并将其显示在一个窗口
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值