#include "VideoPlayer.h" #include "BoostLog.h" #include extern "C" { #include "libavdevice/avdevice.h" #include "libavformat/avformat.h" } 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); }