摄像头开启之前需要注册以下模块,否则无法正常工作。

  1. ‌av_register_all()‌  功能:注册所有封装器(muxer)、解封装器(demuxer)和协议处理器(protocol).‌
  2. avcodec_register_all()‌    功能:注册所有编解码器(encoder/decoder)、硬件加速器(hwaccel)等
  3. ‌avdevice_register_all()‌     功能:注册输入/输出设备

usbcamera.cpp 

#include "usbcamera.h"
#include <QDebug>
#include "QThread"

USBCamera::USBCamera(QObject *parent) : QObject(parent) {

}

bool USBCamera::openDevice(const QString &devicePath) {

    av_register_all();
    avcodec_register_all();
    avdevice_register_all();
   AVDictionary *options = nullptr;
   av_dict_set(&options, "input_format", "yuyv422", 0);  // 或"yuyv422"
   av_dict_set(&options, "video_size", "800x600", 0);
   av_dict_set(&options, "framerate", "30", 0);

   AVInputFormat *inputFormat =
   #ifdef Q_OS_LINUX
       av_find_input_format("v4l2");
   #else
       av_find_input_format("dshow");
   #endif

   if(avformat_open_input(&m_formatCtx,
       devicePath.toUtf8(), inputFormat, &options) != 0) {
       qWarning() << "Failed to open camera";
       return false;
   }
    qWarning() << " open camera";
   if(avformat_find_stream_info(m_formatCtx, nullptr) < 0) {
       qWarning() << "No stream found";
       return false;
   }
 qWarning() << "stream found";
   // 查找视频流
   for(unsigned i = 0; i < m_formatCtx->nb_streams; i++) {
       if(m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
           m_videoStreamIndex = i;
           break;
       }
   }
    qDebug()<<"m_videoStreamIndex"<<m_videoStreamIndex;

    // 获取视频流的编解码参数
    AVCodecParameters *codecParams = m_formatCtx->streams[m_videoStreamIndex]->codecpar;
    qDebug() << "Codec ID:" << codecParams->codec_id;
    qDebug() << "Codec name:" << avcodec_get_name(codecParams->codec_id);
    AVCodec *encoder =  avcodec_find_encoder(codecParams->codec_id);
    if(encoder) {
        qWarning() << "encoder codec";
    }
    // 查找对应的解码器
    const AVCodec *decoder = avcodec_find_decoder(codecParams->codec_id);
    if(!decoder) {
        qWarning() << "Unsupported codec";
        return false;
    }

//    // 分配解码器上下文
    m_codecCtx = avcodec_alloc_context3(decoder);
    if(!m_codecCtx) {
        qWarning() << "Failed to allocate codec context";
        return false;
    }
    // 将流参数复制到解码器上下文
    if(avcodec_parameters_to_context(m_codecCtx, codecParams) < 0) {
        qWarning() << "Failed to copy codec parameters";
        return false;
    }

    // 打开解码器
    if(avcodec_open2(m_codecCtx, decoder, nullptr) < 0) {
        qWarning() << "Failed to open codec";
        return false;
    }


   return m_videoStreamIndex >= 0;
}


void USBCamera::startCapture() {
    // 初始化帧和转换上下文
    qDebug()<<"USBCamera"<<QThread::currentThread();
    m_running=true;
    AVFrame *frame = av_frame_alloc();
    AVFrame *rgb565Frame = av_frame_alloc();
    uint8_t *rgb565Buffer = nullptr;
    AVPacket packet;

    // 获取源视频参数
    int srcWidth = m_codecCtx->width;
    int srcHeight = m_codecCtx->height;
    qDebug()<<"w+h"<<srcWidth<<srcHeight;
    // 分配RGB565缓冲区
    int rgb565Size = av_image_get_buffer_size(AV_PIX_FMT_RGB565, srcWidth, srcHeight, 1);
    rgb565Buffer = (uint8_t*)av_malloc(rgb565Size * sizeof(uint8_t));
    av_image_fill_arrays(rgb565Frame->data, rgb565Frame->linesize,
                        rgb565Buffer, AV_PIX_FMT_RGB565, srcWidth, srcHeight, 1);

    // 创建SWS转换上下文(YUV→RGB565)
    SwsContext *swsCtx = sws_getContext(
        srcWidth, srcHeight, m_codecCtx->pix_fmt,
        srcWidth, srcHeight, AV_PIX_FMT_RGB565,
        SWS_BILINEAR, nullptr, nullptr, nullptr);

    while(m_running) {
       int  ret = av_read_frame(m_formatCtx, &packet);
        if (ret < 0) {
            if (ret != AVERROR_EOF) {
                qWarning() << "av_read_frame error:";
            }
            continue;
        }
        if(packet.stream_index == m_videoStreamIndex) {
            // 发送解码包
            if(avcodec_send_packet(m_codecCtx, &packet) < 0) {
                av_packet_unref(&packet);
                continue;
            }

            // 接收解码帧
            while(avcodec_receive_frame(m_codecCtx, frame) == 0) {
                // 格式转换
                sws_scale(swsCtx,
                         frame->data, frame->linesize,
                         0, frame->height,
                         rgb565Frame->data, rgb565Frame->linesize);

                // 创建QImage(RGB565格式)
                QImage img(rgb565Frame->data[0],
                          srcWidth, srcHeight,
                          rgb565Frame->linesize[0],
                          QImage::Format_RGB16);  // RGB16对应RGB565
                qDebug()<<"frameReceived";
                emit frameReceived(img.copy());  // 必须复制数据
            }
        }
        av_packet_unref(&packet);
    }

    // 资源释放
    sws_freeContext(swsCtx);
    av_frame_free(&frame);
    av_frame_free(&rgb565Frame);
    av_free(rgb565Buffer);
}


void USBCamera::stopCapture() {
    m_running = false;
}

void USBCamera::init()
{
    if(this->openDevice("/dev/video0"))
            this->startCapture();
}

USBCamera::~USBCamera() {
   stopCapture();
   if(m_formatCtx) avformat_close_input(&m_formatCtx);
}

 usbcamera.h

#ifndef USBCAMERA_H
#define USBCAMERA_H


#include <QObject>
#include <QImage>
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavdevice/avdevice.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
}

class USBCamera : public QObject
{
    Q_OBJECT
public:
    explicit USBCamera(QObject *parent = nullptr);
    ~USBCamera();

    bool openDevice(const QString &devicePath);
    void startCapture();
    void stopCapture();
    void init();
signals:
    void frameReceived(const QImage &frame);

private:
    AVFormatContext *m_formatCtx = nullptr;
    AVCodecContext *m_codecCtx = new AVCodecContext();
    int m_videoStreamIndex = -1;
    bool m_running = false;
};

#endif // USBCAMERA_H

mianwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QTimer>
#include <sys/ioctl.h>  // 必须包含的核心头文件
#include <fcntl.h>      // 文件控制选项
#include <unistd.h>     // POSIX标准头文件


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    qDebug()<<ui->label->size();
//    capture = new V4L2Capture(this);
//    int ret=capture->openDevice("/dev/video0", 800, 600);
//        if (ret<0) {
//            qWarning() << "Failed to open camera"<<ret;
//            return;
//        }

//        connect(capture, &V4L2Capture::frameReady, this, &MainWindow::updateFrame);
//        capture->startCapture();

//        QTimer *timer = new QTimer(this);
//        connect(timer, &QTimer::timeout, capture, &V4L2Capture::processFrame);
//        timer->start(33); // ~30fps

        qDebug()<<"ui"<<QThread::currentThread();
        // 1. 创建无父对象的实例
        m_camera = new USBCamera(nullptr);
        connect(m_camera,&USBCamera::frameReceived,this,&MainWindow::updateFrame);
        // 2. 创建并配置线程
        thread = new QThread();
        m_camera->moveToThread(thread);

        // 3. 使用lambda确保所有操作在线程中执行
        connect(thread, &QThread::started,m_camera,&USBCamera::init);

        // 4. 启动线程
        thread->start();


//        cameraThread = new CameraThread(this);
//        connect(cameraThread, &CameraThread::frameReady,
//                this, &MainWindow::updateFrame);
//        cameraThread->start();

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::updateFrame(const QImage& image) {
    qDebug()<<"updateFrame"<<image;
    ui->label->setPixmap(QPixmap::fromImage(image).scaled(
    ui->label->size(), Qt::IgnoreAspectRatio));
}

mianwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "v4l2capture.h"
#include "usbcamera.h"
#include "camerathread.h"
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    V4L2Capture *capture;
    USBCamera *m_camera;
    CameraThread *cameraThread;
    QThread *thread;
private slots:
    void updateFrame(const QImage& image);

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐