SmartLockerTools/Analyser/VideoPlayer.cpp

91 lines
2.6 KiB
C++
Raw Normal View History

2024-06-13 15:41:40 +08:00
#include "VideoPlayer.h"
#include "BoostLog.h"
#include <QImage>
extern "C" {
2024-09-05 22:33:07 +08:00
#include <libavdevice/avdevice.h>
#include <libavformat/avformat.h>
2024-06-13 15:41:40 +08:00
}
VideoPlayer::VideoPlayer() {
static bool init = false;
if (!init) {
avdevice_register_all();
init = true;
}
}
void VideoPlayer::setFrameCallback(FrameCallback &&callback) {
m_callback = std::move(callback);
}
void VideoPlayer::setErrorCallback(ErrorCallback &&callback) {
m_errorCallback = std::move(callback);
}
VideoPlayer::~VideoPlayer() {
close();
}
bool VideoPlayer::open(const std::string &deviceName) {
bool ret = true;
m_formatContext = avformat_alloc_context();
auto format = av_find_input_format("dshow");
AVDictionary *dictionary = nullptr;
// ffmpeg -f dshow -list_options true -i video="UVC Camera"
av_dict_set(&dictionary, "video_size", "800*600", 0);
std::ostringstream oss;
oss << "video=" << deviceName;
auto device = oss.str();
int status = avformat_open_input(&m_formatContext, "video=UVC Camera", format, &dictionary);
if (status != 0) {
char message[256] = {0};
av_make_error_string(message, sizeof(message), status);
LOG(error) << "open device[" << device << "] failed: " << status << "," << message;
ret = false;
} else {
m_exit = false;
m_thread = std::thread(&VideoPlayer::run, this);
}
av_dict_free(&dictionary);
return ret;
}
void VideoPlayer::close() {
m_exit = true;
if (m_thread.joinable()) {
m_thread.join();
}
avformat_close_input(&m_formatContext);
avformat_free_context(m_formatContext);
m_formatContext = nullptr;
}
void VideoPlayer::run() {
auto packet = av_packet_alloc();
while (!m_exit) {
auto status = av_read_frame(m_formatContext, packet);
if (status == 0) {
QImage image;
image.loadFromData(packet->data, packet->size);
if (!image.isNull() && m_callback) m_callback(image);
} else {
char message[256] = {0};
av_make_error_string(message, sizeof(message), status);
if (m_errorCallback) m_errorCallback(status, message);
LOG(error) << "av_read_frame() failed: " << status << "," << message;
if (status == -EIO) {
break;
}
}
av_packet_unref(packet);
}
av_packet_free(&packet);
QImage image(800, 600, QImage::Format_RGB888);
image.fill(Qt::black);
if (m_callback) m_callback(image);
}