//ffmpegDecode.h

#ifndef __FFMPEG_DECODE_H__
#define __FFMPEG_DECODE_H__ #include "global.h" extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
//图像转换结构需要引入的头文件
#include "libswscale/swscale.h"
}; class ffmpegDecode
{
public:
ffmpegDecode(char * file = NULL);
~ffmpegDecode(); cv::Mat getDecodedFrame();
cv::Mat getLastFrame();
int readOneFrame();
int getFrameIndex(){return m_framIndex;}; private:
AVFrame *pAvFrame;
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx;
AVCodec *pCodec; int i;
int videoindex;
int m_framIndex;
char *filepath;
int ret, got_picture;
SwsContext *img_convert_ctx;
int y_size;
AVPacket *packet; cv::Mat *pCvMat; bool m_initResult; bool init();
bool openDecode();
void prepare();
void get(AVCodecContext *pCodecCtx, SwsContext *img_convert_ctx,AVFrame *pFrame); public:
bool getInitResult(); }; #endif
//ffmpegDecode.cpp

#include "ffmpegDecode.h"
#include <QDebug> int time_out = ;
int firsttimeplay = ;
int interrupt_cb(void *ctx)
{
// do something time_out++;
if (time_out > ) {
time_out=;
if (firsttimeplay) {
firsttimeplay=;
return -;//这个就是超时的返回
}
}
return ;
} ffmpegDecode :: ~ffmpegDecode()
{
pCvMat->release(); pCvMat->release();
//释放本次读取的帧内存
av_free_packet(packet);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx);
} ffmpegDecode :: ffmpegDecode(char * file)
{
firsttimeplay = ;
pAvFrame = NULL/**pFrameRGB = NULL*/;
pFormatCtx = NULL;
pCodecCtx = NULL;
pCodec = NULL; pCvMat = new cv::Mat();
i=;
videoindex=;
m_framIndex =;
ret = ;
got_picture = ;
img_convert_ctx = NULL;
y_size = ;
packet = NULL; if (NULL == file)
{
filepath = "rtsp://admin:admin123@192.168.10.239:554";
}
else
{
filepath = file;
} m_initResult = false;
if(init())
{
if(openDecode())
{
prepare();
m_initResult =true;
}
} } bool ffmpegDecode::getInitResult()
{
return m_initResult;
} bool ffmpegDecode :: init()
{
printf("init start...\n");
//ffmpeg注册复用器,编码器等的函数av_register_all()。
//该函数在所有基于ffmpeg的应用程序中几乎都是第一个被调用的。只有调用了该函数,才能使用复用器,编码器等。
//这里注册了所有的文件格式和编解码器的库,所以它们将被自动的使用在被打开的合适格式的文件上。注意你只需要调用 av_register_all()一次,因此我们在主函数main()中来调用它。如果你喜欢,也可以只注册特定的格式和编解码器,但是通常你没有必要这样做。
av_register_all();
avformat_network_init();
// pFormatCtx = avformat_alloc_context();
// pFormatCtx->interrupt_callback.callback = interrupt_cb;//--------注册回调函数 // pFormatCtx->interrupt_callback.opaque = pFormatCtx;
//打开视频文件,通过参数filepath来获得文件名。这个函数读取文件的头部并且把信息保存到我们给的AVFormatContext结构体中。
//最后2个参数用来指定特殊的文件格式,缓冲大小和格式参数,但如果把它们设置为空NULL或者0,libavformat将自动检测这些参数。 AVDictionary* options = NULL;
av_dict_set(&options, "rtsp_transport", "tcp", );
av_dict_set(&options, "stimeout", "", ); //设置超时断开连接时间,单位微秒 if(avformat_open_input(&pFormatCtx,filepath,NULL,&options)!=)
{
printf("无法打开文件\n");
return false;
} //查找文件的流信息,avformat_open_input函数只是检测了文件的头部,接着要检查在文件中的流的信息
if(avformat_find_stream_info(pFormatCtx,&options)<)
{
printf("Couldn't find stream information.\n");
return false;
}
printf("init finished...\n"); return true;
} bool ffmpegDecode :: openDecode()
{
printf("openDecode start...\n");
//在库里面查找支持该格式的解码器
videoindex = -;
for(i=; i<pFormatCtx->nb_streams; i++)
{
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
videoindex=i;
break;
}
}
if(videoindex==-)
{
printf("Didn't find a video stream.\n");
return false;
}
pCodecCtx=pFormatCtx->streams[videoindex]->codec; //在库里面查找支持该格式的解码器
pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec==NULL)
{
printf("Codec not found.\n");
return false;
} //打开解码器
if(avcodec_open2(pCodecCtx, pCodec,NULL) < )
{
printf("Could not open codec.\n");
return false;
}
printf("openDecode finished\n"); return true;
} void ffmpegDecode :: prepare()
{
//printf("prepare int\n");
//分配一个帧指针,指向解码后的原始帧
pAvFrame=av_frame_alloc();
y_size = pCodecCtx->width * pCodecCtx->height;
//分配帧内存
packet=(AVPacket *)av_malloc(sizeof(AVPacket));
av_new_packet(packet, y_size); //输出一下信息-----------------------------
printf("文件信息-----------------------------------------\n");
av_dump_format(pFormatCtx,,filepath,);
//av_dump_format只是个调试函数,输出文件的音、视频流的基本信息了,帧率、分辨率、音频采样等等
//printf("prepare out\n");
} int ffmpegDecode :: readOneFrame()
{
int result = ;
pCvMat->release();
result = av_read_frame(pFormatCtx, packet);
return result;
} cv::Mat ffmpegDecode :: getDecodedFrame()
{
readOneFrame();
if(packet->stream_index==videoindex)
{
//解码一个帧
ret = avcodec_decode_video2(pCodecCtx, pAvFrame, &got_picture, packet);
if(ret < )
{
printf("解码错误\n");
return cv::Mat();
}
if(got_picture)
{
m_framIndex++;
//根据编码信息设置渲染格式
if(img_convert_ctx == NULL){
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
}
//----------------------opencv
if (pCvMat->empty())
{
pCvMat->create(cv::Size(pCodecCtx->width, pCodecCtx->height),CV_8UC3);
} if(img_convert_ctx != NULL)
{
get(pCodecCtx, img_convert_ctx, pAvFrame);
}
}
}
av_free_packet(packet);
return *pCvMat; }
cv::Mat ffmpegDecode :: getLastFrame()
{
ret = avcodec_decode_video2(pCodecCtx, pAvFrame, &got_picture, packet);
if(got_picture)
{
//根据编码信息设置渲染格式
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL); if(img_convert_ctx != NULL)
{
get(pCodecCtx, img_convert_ctx,pAvFrame);
}
}
return *pCvMat;
} void ffmpegDecode :: get(AVCodecContext * pCodecCtx, SwsContext * img_convert_ctx, AVFrame * pFrame)
{
if (pCvMat->empty())
{
pCvMat->create(cv::Size(pCodecCtx->width, pCodecCtx->height),CV_8UC3);
} AVFrame *pFrameRGB = NULL;
uint8_t *out_bufferRGB = NULL;
pFrameRGB = av_frame_alloc(); //给pFrameRGB帧加上分配的内存;
int size = avpicture_get_size(AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);
out_bufferRGB = new uint8_t[size];
avpicture_fill((AVPicture *)pFrameRGB, out_bufferRGB, AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height); //YUV to RGB
sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, , pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize); memcpy(pCvMat->data,out_bufferRGB,size); delete[] out_bufferRGB;
av_free(pFrameRGB);
}
//crtspdecodethread.h

#ifndef CRTSPDECODETHREAD_H
#define CRTSPDECODETHREAD_H #include <QThread>
#include <QMutex>
#include "ffmpegDecode.h" class CRTSPDecodeThread : public QThread
{
Q_OBJECT public:
CRTSPDecodeThread(QObject* parent);
~CRTSPDecodeThread(); void SetCameraParam(QString, int, int cameraID);
void run(); signals:
void SendVideoFrame(cv::Mat);
void SendDetectFrame(cv::Mat); private:
ffmpegDecode* m_pVdoDecode;
bool m_isExist;
unsigned long m_FrameCount;
int m_detectInterval; VideoCapture m_VideoCap; QString m_cameraURL;
QMutex m_Mutex; int m_cameraID;
bool m_decodeInitResult;
}; #endif // CRTSPDECODETHREAD_H
//crtspdecodethread.cpp

#include "crtspdecodethread.h"
#include "ffmpegDecode.h"
#include <QDebug>
#include <QDateTime>
#include <queue>
#include <QMutexLocker> extern bool g_ImportLib;
std::queue<ST_IMGINFO> g_OrgImgQueue; CRTSPDecodeThread::CRTSPDecodeThread(QObject* parent):QThread(parent)
{
m_isExist = false;
} CRTSPDecodeThread::~CRTSPDecodeThread()
{
requestInterruption();
quit();
wait(); m_isExist = true;
} void CRTSPDecodeThread::SetCameraParam(QString strURL, int iInterval, int cameraID)
{
m_cameraID = cameraID;
m_detectInterval = iInterval;
m_cameraURL =strURL;
if(m_cameraURL == "USB")
{
bool bRet = m_VideoCap.open();
if(!bRet)
{
qDebug()<<"打开USB摄像头失败...";
}
}
else
{
m_pVdoDecode = new ffmpegDecode((char*)strURL.toStdString().c_str());
m_decodeInitResult = m_pVdoDecode->getInitResult();
} } void CRTSPDecodeThread::run()
{ m_FrameCount = ; cv::Mat img;
unsigned long iRTSPOfflineTick = GetTickCount();
while(!isInterruptionRequested())
{
if(m_isExist)
{
break;
} if(m_cameraURL == "USB")
{
m_VideoCap>>img;
}
else
{
if(m_decodeInitResult)
{
img =m_pVdoDecode->getDecodedFrame();
}
} if(!img.empty())
{
m_FrameCount++;
//cvtColor(img, img, COLOR_BGR2RGB);
iRTSPOfflineTick = GetTickCount(); emit SendVideoFrame(img); if(m_FrameCount % m_detectInterval == )
{ ST_IMGINFO imgInfo;
img.copyTo(imgInfo.img); imgInfo.camera_id =m_cameraID;// m_pManager->GetCameraID(); QDateTime dtTime;
imgInfo.time = dtTime.currentDateTime().toString("yyyy-MM-dd HH:mm:ss"); QMutexLocker lock(&m_Mutex);
g_OrgImgQueue.push(imgInfo); } img.release();
}
else
{
qDebug()<<"获取原始视频帧失败..."; if( (GetTickCount() -iRTSPOfflineTick ) > *)
{
qDebug()<<"重新打开视频流..."; iRTSPOfflineTick = GetTickCount(); if(m_cameraURL == "USB")
{
bool bRet = m_VideoCap.open();
if(!bRet)
{
qDebug()<<"打开USB摄像头失败...";
}
}
else
{
delete m_pVdoDecode;
m_pVdoDecode = NULL; m_pVdoDecode = new ffmpegDecode((char*)m_cameraURL.toStdString().c_str());
m_decodeInitResult = m_pVdoDecode->getInitResult();
}
}
}
}
}

Qt FFMPEG+OpenCV开启摄像头的更多相关文章

  1. 项目实战:Qt+Ffmpeg+OpenCV相机程序(打开摄像头、支持多种摄像头、分辨率调整、翻转、旋转、亮度调整、拍照、录像、回放图片、回放录像)

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  2. QT creator中使用opencv采集摄像头信息

    之前在QT creator上成功编译了opencv,由于课题需要,需要采集摄像头的信息.故搜集了网上的一些资料,依葫芦画瓢的照着做了一下,终于简单的成功采集了信息. 打开QTcreator,新建一个w ...

  3. QT与openCV,与PCL结合!

    (1):详解QT多媒体框架:给予视频播放器 原文链接:http://mobile.51cto.com/symbian-271123.htm 对于使用主框架的QT程序,实现Qimage的转换可借鉴下面程 ...

  4. Opencv——将摄像头拍摄写成视频文件

    这里主要利用了Opencv打开摄像头的代码,以及写入视频的函数,只是这里要注意的是摄像头好像没有帧率,在cvCreateVideoWriter,时要自己设置 #include"cv.h&qu ...

  5. openCV 调用摄像头

    OpenCV调用摄像头 环境 python:python3.6 摄像头:网络摄像头 Python库:openCV # -*- coding: utf-8 -*- # @author leone # @ ...

  6. Raspberry Pi 4B 使用OpenCV访问摄像头picamera模块

    目录 1.OpenCV安装 (1)安装依赖 (2)下载OpenCV源码 (3)安装pip (4)安装Python虚拟机 (5)编译OpenCV (6)验证安装 2.使用OpenCV和Python控制摄 ...

  7. 基于opencv网络摄像头在ubuntu下的视频获取

     基于opencv网络摄像头在ubuntu下的视频获取 1  工具 原料 平台 :UBUNTU12.04 安装库  Opencv-2.3 2  安装编译运行步骤 安装编译opencv-2.3  参 ...

  8. OpenCv调用摄像头拍照代码

    近期在研究OpenCv对摄像头的调用.现将代码贴出,供大家批评指正. 1.申明 #include"./opencv2/opencv.hpp" #ifdef _DEBUG #prag ...

  9. 基于opencv在摄像头ubuntu根据视频获取

     基于opencv在摄像头ubuntu根据视频获取 1  工具 原料 平台 :UBUNTU12.04 安装库  Opencv-2.3 2  安装编译执行步骤 安装编译opencv-2.3  參考h ...

随机推荐

  1. 适用于 Windows 的自定义脚本扩展

    自定义脚本扩展在 Azure 虚拟机上下载并执行脚本. 此扩展适用于部署后配置.软件安装或其他任何配置/管理任务. 可以从 Azure 存储或 GitHub 下载脚本,或者在扩展运行时将脚本提供给 A ...

  2. Oracle EBS OM 保留订单

    DECLARE l_header_rec OE_ORDER_PUB.Header_Rec_Type; l_line_tbl OE_ORDER_PUB.Line_Tbl_Type; l_action_r ...

  3. Linux 补丁生成与使用

    我们在升级Linux 内核的时候,难免会接触到补丁的知识.下面对如何生成补丁和如何打补丁作讲解. 生成补丁: 制作 hello.c 和 hello_new.c 两个文件如如下所示. ➜ diff ls ...

  4. python基础学习1

    一.python第一个程序 print("hello world") 二.变量的命名规则 1. 字母数字下划线组成 2. 不能以数字开头,不能含有特殊字符和空格 3. 不能以保留字 ...

  5. 读高性能JavaScript编程 第四章 Conditionals

    if else 和 switch    &&    递归 if else 和 switch 一般来说,if-else 适用于判断两个离散的值或者判断几个不同的值域.如果判断多于两个离散 ...

  6. Emmm,从删库到跑路系列之.......Root权限的重要性

    中午导入了一个.SQL文件,晚上查navicat的数据库死活打不开 错误代码1030,想起来中午导入了mysql数据库的user表,而那里面什么也没有... 默默删掉了data,然后emmm --in ...

  7. [BUG] python实例化N次类,调用类函数log会输出N遍的bug 解决办法

    最近再写DOU用例时,采用的是 unittest测试框架,就涉及到将其它所有模块需要全部在一个 .py文件中进行实例化,然后再运行时发现在控制台中同一个日志信息会打印多次(实例化几次,同一消息就会打印 ...

  8. 基础知识整理汇总 - Java学习(一)

    java 语言规范及相关文档资源 Java源码:安装目录下 src.zip 文件 java文档:https://docs.oracle.com/en/java/ 语言规范:http://docs.or ...

  9. 基于duxshop遍历无限级分销用户的纵向递归

    /**获取基准数据 * @param $ids 父id 多个逗号分隔 * @return array */ public function saleBase($ids) { $data=$this-& ...

  10. BZOJ4236:JOIOJI(乱搞)

    Description JOIOJI桑是JOI君的叔叔.“JOIOJI”这个名字是由“J.O.I”三个字母各两个构成的. 最近,JOIOJI桑有了一个孩子.JOIOJI桑想让自己孩子的名字和自己一样由 ...