//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. [Java] 用 Comparator 实现排序

    最近正好用到Comparator,发现能对不同类型的对象进行排序(当然排序依据还是基本类型),也不用自己实现排序算法,用起来很方便,所以简单记录一下. 本文地址:http://www.cnblogs. ...

  2. C# 获得目录下所有文件或指定文件类型文件(包含所有子文件夹)

    public partial class FileGet { /// <summary> /// 私有变量 /// </summary> private static List ...

  3. 报错:java.net.bindexception: address already in use: jvm_bind:8080

    原因:8080端口被占用 这说明80端口(该端口是Tomcat的监听端口)已经被其他程序占用,先用命令提示符 " netstat -ano " 命令显示端口状态,再在结果中找到端口 ...

  4. Linux中 /proc/[pid] 目录各文件简析

    Linux 内核提供了一种通过 proc 文件系统,在运行时访问内核内部数据结构.改变内核设置的机制.proc 文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间.它以文件系统的方式为访问系 ...

  5. 推荐一个国外C开发的PHP框架--Phalcon,性能相当好

    本人亲自配置测试后.性能相当不错.不过有一点.使用极不符合国人习惯,甚至和大多数主流PHP框架如Zend Framework,Yii,Ci,Thinkphp都不一样. Phalcon 是一个开源的,全 ...

  6. 在Ubuntu17.04中遇到无法清空回收站解决方法

    在Ubuntu17.04下,遇到清空回收站文件时报错,提示”Failed to delete the item from the trash”,无法清空回收站. 回收站其实就是一个文件夹,存放着被删掉 ...

  7. 【转】Spring学习---Spring 学习总结

    什么是Spring ? Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson在其著作Expert One-On-One J2EEDev ...

  8. October 20th 2017 Week 42nd Friday

    My life is in these books. Read these and know my heart. 我的人生就在这些书中,读完他们就能读懂我的心. Some people say tha ...

  9. 关于MVC开发时,无法找到area的问题记录

    解决方法: 检查area=admin 的dll是否生成,一般都是admin域生成dll导致

  10. java如何对map进行排序详解(map集合的使用)

    今天做统计时需要对X轴的地区按照地区代码(areaCode)进行排序,由于在构建XMLData使用的map来进行数据统计的,所以在统计过程中就需要对map进行排序. 一.简单介绍Map 在讲解Map排 ...