ffmpeg 3.4.12版本 使用QT连接usb摄像头
·
摄像头开启之前需要注册以下模块,否则无法正常工作。
- av_register_all() 功能:注册所有封装器(muxer)、解封装器(demuxer)和协议处理器(protocol).
- avcodec_register_all() 功能:注册所有编解码器(encoder/decoder)、硬件加速器(hwaccel)等
- 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
更多推荐
所有评论(0)