#include "VideoPlayer.h" #include "BoostLog.h" #include extern "C" { #include #include } 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(); #ifdef WIN32 constexpr auto format = "dshow"; std::ostringstream oss; oss << "video=@device_pnp_" << deviceName; auto device = oss.str(); #else constexpr auto format = "v4l2"; auto &device = deviceName; #endif auto inputFormat = av_find_input_format(format); AVDictionary *dictionary = nullptr; // clang-format off // ffplay -f dshow -i video="@device_pnp_\\?\usb#vid_3346&pid_0001&mi_00#6&6ff22b9&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global" // ffmpeg -f dshow -list_options true -i video="UVC Camera" // clang-format on av_dict_set(&dictionary, "video_size", "800*600", 0); int status = avformat_open_input(&m_formatContext, device.c_str(), inputFormat, &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 { av_dump_format(m_formatContext, 0, device.c_str(), 0); // for (unsigned int i = 0; i < m_formatContext->nb_streams; i++) { // AVStream *stream = m_formatContext->streams[i]; // if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { // std::cout << "当前分辨率: " << stream->codecpar->width << "x" << stream->codecpar->height << std::endl; // } // } 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); QTransform transform; transform.rotate(90); image = image.transformed(transform); 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); }