我需要使用OpenCV制作小型视频播放器,它必须支持以下功能。关键' p'在键盘上 - 暂停/取消暂停,' q' - 退出,左右箭头键 - 在暂停时直接和反向播放视频。所以问题是当我尝试显示高质量的视频时,我按住箭头键几秒钟它不会运行,但冻结然后在我释放键后跳转到当前帧。我试图通过在this_thread::sleep
之后添加cv::imshow()
来解决此问题,以便有时间绘制,但它根本没有帮助。所以这是代码。另外,我有一些理由使用boost代替C ++ 11,所以没关系。
main.cpp
#include "VideoPlayer.hpp"
#include <iostream>
int main(int argc, char *argv[])
{
if (argc < 2) {
std::cerr << "Video file full name required as argument." << std::endl;
}
VideoPlayer vp(argv[1]);
if (!vp.play())
return 1;
return 0;
}
VideoPlayer.hpp
#pragma once
#include <opencv/cxcore.hpp>
#include <opencv/highgui.h>
#include <string>
class VideoPlayer
{
public:
VideoPlayer(const std::string &video, const std::string &windowName = "Output window",
unsigned int delay = 30);
bool play();
private:
cv::VideoCapture videoCapture_;
std::string windowName_;
unsigned int delay_;
private:
bool processKey(int key);
void setFrame(int frameNum);
};
VideoPlayer.cpp
#include "VideoPlayer.hpp"
#include <iostream>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread.hpp>
VideoPlayer::VideoPlayer(const std::string &video, const std::string &windowName,
unsigned int delay)
: videoCapture_(video)
, windowName_(windowName)
, delay_(delay)
{}
bool VideoPlayer::play()
{
if (!videoCapture_.isOpened()) {
std::cerr << "Unable to open video." << std::endl;
return false;
}
cv::namedWindow(windowName_);
for (;;) {
cv::Mat frame;
videoCapture_ >> frame;
cv::imshow(windowName_, frame);
int key = cv::waitKey(delay_);
if (processKey(key))
break;
}
return true;
}
bool VideoPlayer::processKey(int key)
{
if (key == 'p') {
for (;;) {
int pausedKey = cv::waitKey(0);
if (pausedKey == 'p') {
break;
} else if (pausedKey == 'q') {
return true;
} else if (pausedKey == 65363) {
int frameNum = videoCapture_.get(CV_CAP_PROP_POS_FRAMES);
setFrame(frameNum);
} else if (pausedKey == 65361) {
int frameNum = videoCapture_.get(CV_CAP_PROP_POS_FRAMES);
setFrame(frameNum - 2);
}
}
} else if (key == 'q') {
return true;
}
return false;
}
void VideoPlayer::setFrame(int frameNum)
{
if (frameNum > 0 && frameNum < videoCapture_.get(CV_CAP_PROP_FRAME_COUNT)) {
std::cerr << frameNum << std::endl;
videoCapture_.set(CV_CAP_PROP_POS_FRAMES, frameNum);
cv::Mat frame;
videoCapture_ >> frame;
cv::imshow(windowName_, frame);
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
}
}
我还使用带有锁的std::queue
创建了一个带有缓冲区的多线程实现,但它并没有解决问题。我尝试使用boost::lockfree::queue
,但由于一些奇怪的行为,我无法完成它。如果有必要,我稍后会分享这段代码。
所以,如果有人知道一些好的做法,如何避免这个问题,请帮助我。
用boost::this_thread::sleep(boost::posix_time::milliseconds(10));
替换cv::waitKey(0)
是不好的,因为这会让我在箭头键上按两次短按来更改一帧,但它没有帮助,因为按住键会非常快地跳过它。所以下面的代码有所帮助,但它太奇怪了,每个视频都需要选择times
。
void VideoPlayer::setFrame(int frameNum)
{
if (frameNum > 0 && frameNum < videoCapture_.get(CV_CAP_PROP_FRAME_COUNT)) {
std::cerr << frameNum << std::endl;
videoCapture_.set(CV_CAP_PROP_POS_FRAMES, frameNum);
cv::Mat frame;
videoCapture_ >> frame;
cv::imshow(windowName_, frame);
int times = 7;
for (int i = 0; i < times; i++)
cv::waitKey(10);
}
}
另外,我无法使用Qt或其他东西,只有C ++ 03使用boost和OpenCV。
我想我需要一些技巧让cv::waitKey(time)
等待time
是否按下任何键。