技术标签: C++ c++ RK驱动开发 linux系统编程 数据结构
RK3568 重新封装V4l2为一个C++ Camera管理类 (基于RK编译环境,纯linux环境得小伙伴可以自己阅读代码做出对应得修改主要修改(CameraReader.cpp CameraReader,h thread.h))
CameraReader.cpp
/*
* Copyright 2015 Rockchip Electronics Co. LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define MODULE_TAG "CameraReader"
#include "mpp_log.h"
#include "mpp_mem.h"
#include "CameraReader.h"
CameraReader::CameraReader(const char *device, RK_U32 bufcnt, RK_U32 width, RK_U32 height, MppFrameFormat fmt)
:thread(device),
mBufcnt(bufcnt),
mWidth(width),
mHeight(height),
mFmt(fmt)
{
strcpy(mDevice,device);
}
// Wrap ioctl() to spin on EINTR
RK_S32 CameraReader::Ioctl(RK_S32 fd, RK_S32 req, void* arg)
{
struct timespec poll_time;
RK_S32 ret;
while ((ret = ioctl(fd, req, arg))) {
if (ret == -1 && (EINTR != errno && EAGAIN != errno)) {
// mpp_err("ret = %d, errno %d", ret, errno);
break;
}
// 10 milliseconds
poll_time.tv_sec = 0;
poll_time.tv_nsec = 10000000;
nanosleep(&poll_time, NULL);
}
return ret;
}
// Create a new context to capture frames from <fname>.
// Returns NULL on error.
RK_S32 CameraReader::Init(const char *device, RK_U32 bufcnt, RK_U32 width, RK_U32 height, MppFrameFormat format)
{
struct v4l2_capability cap;
struct v4l2_format vfmt;
struct v4l2_requestbuffers req;
struct v4l2_buffer buf;
enum v4l2_buf_type type;
RK_U32 i;
RK_U32 buf_len = 0;
mCtx = mpp_calloc(CamSource, 1);
if (!mCtx)
return -1;
mCtx->bufcnt = bufcnt;
mCtx->fd = open(device, O_RDWR, 0);
if (mCtx->fd < 0) {
mpp_err_f("Cannot open device\n");
goto FAIL;
}
// Determine if fd is a V4L2 Device
if (0 != Ioctl(mCtx->fd, VIDIOC_QUERYCAP, &cap)) {
mpp_err_f("Not v4l2 compatible\n");
goto FAIL;
}
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) && !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)) {
mpp_err_f("Capture not supported\n");
goto FAIL;
}
if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
mpp_err_f("Streaming IO Not Supported\n");
goto FAIL;
}
// Preserve original settings as set by v4l2-ctl for example
vfmt = (struct v4l2_format) {0};
vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)
vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
vfmt.fmt.pix.width = width;
vfmt.fmt.pix.height = height;
if (MPP_FRAME_FMT_IS_YUV(format)) {
vfmt.fmt.pix.pixelformat = V4L2_yuv_cfg[format - MPP_FRAME_FMT_YUV];
} else if (MPP_FRAME_FMT_IS_RGB(format)) {
vfmt.fmt.pix.pixelformat = V4L2_RGB_cfg[format - MPP_FRAME_FMT_RGB];
}
if (!vfmt.fmt.pix.pixelformat)
vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;
type = (v4l2_buf_type) vfmt.type;
mCtx->type = (v4l2_buf_type) vfmt.type;
if (-1 == Ioctl(mCtx->fd, VIDIOC_S_FMT, &vfmt)) {
mpp_err_f("VIDIOC_S_FMT\n");
goto FAIL;
}
if (-1 == Ioctl(mCtx->fd, VIDIOC_G_FMT, &vfmt)) {
mpp_err_f("VIDIOC_G_FMT\n");
goto FAIL;
}
mpp_log("get width %d height %d", vfmt.fmt.pix.width, vfmt.fmt.pix.height);
// Request memory-mapped buffers
req = (struct v4l2_requestbuffers) {0};
req.count = mCtx->bufcnt;
req.type = type;
req.memory = V4L2_MEMORY_MMAP;
if (-1 == Ioctl(mCtx->fd, VIDIOC_REQBUFS, &req)) {
mpp_err_f("Device does not support mmap\n");
goto FAIL;
}
if (req.count != mCtx->bufcnt) {
mpp_err_f("Device buffer count mismatch\n");
goto FAIL;
}
// mmap() the buffers into userspace memory
for (i = 0 ; i < mCtx->bufcnt; i++) {
buf = (struct v4l2_buffer) {0};
buf.type = type;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
struct v4l2_plane planes[FMT_NUM_PLANES];
buf.memory = V4L2_MEMORY_MMAP;
if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {
buf.m.planes = planes;
buf.length = FMT_NUM_PLANES;
}
if (-1 == Ioctl(mCtx->fd, VIDIOC_QUERYBUF, &buf)) {
mpp_err_f("ERROR: VIDIOC_QUERYBUF\n");
goto FAIL;
}
mCtx->fbuf[i].start = mmap(NULL, buf.length,
PROT_READ | PROT_WRITE, MAP_SHARED,
mCtx->fd, buf.m.offset);
if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == buf.type) {
// tmp_buffers[n_buffers].length = buf.m.planes[0].length;
buf_len = buf.m.planes[0].length;
mCtx->fbuf[i].start =
mmap(NULL /* start anywhere */,
buf.m.planes[0].length,
PROT_READ | PROT_WRITE /* required */,
MAP_SHARED /* recommended */,
mCtx->fd, buf.m.planes[0].m.mem_offset);
} else {
buf_len = buf.length;
mCtx->fbuf[i].start =
mmap(NULL /* start anywhere */,
buf.length,
PROT_READ | PROT_WRITE /* required */,
MAP_SHARED /* recommended */,
mCtx->fd, buf.m.offset);
}
if (MAP_FAILED == mCtx->fbuf[i].start) {
mpp_err_f("ERROR: Failed to map device frame buffers\n");
goto FAIL;
}
struct v4l2_exportbuffer expbuf = (struct v4l2_exportbuffer) {0} ;
// xcam_mem_clear (expbuf);
expbuf.type = type;
expbuf.index = i;
expbuf.flags = O_CLOEXEC;
if (Ioctl(mCtx->fd, VIDIOC_EXPBUF, &expbuf) < 0) {
mpp_err_f("get dma buf failed\n");
goto FAIL;
} else {
mpp_log("get dma buf(%d)-fd: %d\n", i, expbuf.fd);
MppBufferInfo info;
memset(&info, 0, sizeof(MppBufferInfo));
info.type = MPP_BUFFER_TYPE_EXT_DMA;
info.fd = expbuf.fd;
info.size = buf_len & 0x07ffffff;
info.index = (buf_len & 0xf8000000) >> 27;
mpp_buffer_import(&mCtx->fbuf[i].buffer, &info);
}
mCtx->fbuf[i].export_fd = expbuf.fd;
}
for (i = 0; i < mCtx->bufcnt; i++ ) {
struct v4l2_plane planes[FMT_NUM_PLANES];
buf = (struct v4l2_buffer) {0};
buf.type = type;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
buf.memory = V4L2_MEMORY_MMAP;
if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {
buf.m.planes = planes;
buf.length = FMT_NUM_PLANES;
}
if (-1 == Ioctl(mCtx->fd, VIDIOC_QBUF, &buf)) {
mpp_err_f("ERROR: VIDIOC_QBUF %d\n", i);
Deinit(mCtx);
goto FAIL;
}
}
// Start capturing
if (-1 == Ioctl(mCtx->fd, VIDIOC_STREAMON, &type)) {
mpp_err_f("ERROR: VIDIOC_STREAMON\n");
Deinit(mCtx);
goto FAIL;
}
//skip some frames at start
for (i = 0; i < mCtx->bufcnt; i++ ) {
RK_S32 idx = GetFrame(mCtx);
if (idx >= 0)
PutFrame(mCtx, idx);
}
code = new RkH264Encode();
code->start();
return MPP_OK;
FAIL:
Deinit(mCtx);
mCtx = NULL;
return MPP_NOK;
}
// Free a context to capture frames from <fname>.
// Returns NULL on error.
MPP_RET CameraReader::Deinit(CamSource *ctx)
{
struct v4l2_buffer buf;
enum v4l2_buf_type type;
RK_U32 i;
if (NULL == ctx)
return MPP_OK;
if (ctx->fd < 0)
return MPP_OK;
// Stop capturing
type = ctx->type;
Ioctl(ctx->fd, VIDIOC_STREAMOFF, &type);
// un-mmap() buffers
for (i = 0 ; i < ctx->bufcnt; i++) {
buf = (struct v4l2_buffer) {0};
buf.type = type;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
Ioctl(ctx->fd, VIDIOC_QUERYBUF, &buf);
if (ctx->fbuf[buf.index].buffer) {
mpp_buffer_put(ctx->fbuf[buf.index].buffer);
}
munmap(ctx->fbuf[buf.index].start, buf.length);
}
// Close v4l2 device
close(ctx->fd);
MPP_FREE(ctx);
return MPP_OK;
}
// Returns a pointer to a captured frame and its meta-data. NOT thread-safe.
RK_S32 CameraReader::GetFrame(CamSource *ctx)
{
struct v4l2_buffer buf;
enum v4l2_buf_type type;
type = ctx->type;
buf = (struct v4l2_buffer) {0};
buf.type = type;
buf.memory = V4L2_MEMORY_MMAP;
struct v4l2_plane planes[FMT_NUM_PLANES];
if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {
buf.m.planes = planes;
buf.length = FMT_NUM_PLANES;
}
if (-1 == Ioctl(ctx->fd, VIDIOC_DQBUF, &buf)) {
mpp_err_f("VIDIOC_DQBUF\n");
return MPP_NOK;
}
if (buf.index > ctx->bufcnt) {
mpp_err_f("buffer index out of bounds\n");
return MPP_NOK;
}
if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type)
buf.bytesused = buf.m.planes[0].bytesused;
return buf.index;
}
// It's OK to capture into this framebuffer now
MPP_RET CameraReader::PutFrame(CamSource *ctx, RK_S32 idx)
{
struct v4l2_buffer buf;
enum v4l2_buf_type type;
if (idx < 0)
return MPP_OK;
type = ctx->type;
buf = (struct v4l2_buffer) {0};
buf.type = type;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = idx;
struct v4l2_plane planes[FMT_NUM_PLANES];
if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {
buf.m.planes = planes;
buf.length = FMT_NUM_PLANES;
}
// Tell kernel it's ok to overwrite this frame
if (-1 == Ioctl(ctx->fd, VIDIOC_QBUF, &buf)) {
mpp_err_f("VIDIOC_QBUF\n");
return MPP_OK;
}
return MPP_OK;
}
MppBuffer CameraReader::Frame2Buf(CamSource *ctx, RK_S32 idx)
{
if (idx < 0)
return NULL;
return ctx->fbuf[idx].buffer;
}
RK_S32 CameraReader::Open(){
return Init(mDevice, mBufcnt,mWidth, mHeight, mFmt);
}
bool CameraReader::readyToRun(){
return Open()==MPP_OK;
}
void CameraReader::start(){
run();//线程开始跑
}
//线程主体函数
bool CameraReader::threadLoop(){
//printf("threadLoop\n");
static FILE *fp = NULL;
static int count = 0;
int index = GetFrame(mCtx);
if(index == MPP_NOK){
usleep(2000);
return true;
}
Frame2Buf(mCtx,index)//在这里出数据
/×code->write();
while(code->dealImageCompletes()){
usleep(10);
}×/
PutFrame(mCtx,index);
return true;
}
CameraReader.h
/*
* Copyright 2015 Rockchip Electronics Co. LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __CAMERA_READER_H__
#define __CAMERA_READER_H__
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/select.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include "mpp_frame.h"
#include "thread.h"
#include "RkH264Encode.h"
typedef struct CamSource CamSource;
typedef struct CamFrame_t {
void *start;//ÍŒÏñÊýŸÝ¿ªÊŒ¶Î
size_t length;
RK_S32 export_fd;
RK_S32 sequence;
MppBuffer buffer;
} CamFrame;
struct CamSource {
RK_S32 fd; // Device handle
RK_U32 bufcnt; // # of buffers
enum v4l2_buf_type type;
MppFrameFormat fmt;
CamFrame fbuf[10];// frame buffers
};
static RK_U32 V4L2_yuv_cfg[MPP_FMT_YUV_BUTT] = {
V4L2_PIX_FMT_NV12,
0,
V4L2_PIX_FMT_NV16,
0,
V4L2_PIX_FMT_YVU420,
V4L2_PIX_FMT_NV21,
V4L2_PIX_FMT_YUV422P,
V4L2_PIX_FMT_NV61,
V4L2_PIX_FMT_YUYV,
V4L2_PIX_FMT_YVYU,
V4L2_PIX_FMT_UYVY,
V4L2_PIX_FMT_VYUY,
V4L2_PIX_FMT_GREY,
0,
0,
0,
};
static RK_U32 V4L2_RGB_cfg[MPP_FMT_RGB_BUTT - MPP_FRAME_FMT_RGB] = {
V4L2_PIX_FMT_RGB565,
0,
V4L2_PIX_FMT_RGB555,
0,
V4L2_PIX_FMT_RGB444,
0,
V4L2_PIX_FMT_RGB24,
V4L2_PIX_FMT_BGR24,
0,
0,
V4L2_PIX_FMT_RGB32,
V4L2_PIX_FMT_BGR32,
0,
0,
};
#define FMT_NUM_PLANES 1
class CameraReader : public threadBase{
private:
CamSource *mCtx = NULL;
char mDevice[20];
RK_U32 mBufcnt;
RK_U32 mWidth;
RK_U32 mHeight;
MppFrameFormat mFmt;
RkH264Encode *code;
// Create a new context to capture frames from <fname>. Returns NULL on error.
RK_S32 Init(const char *device, RK_U32 bufcnt, RK_U32 width, RK_U32 height, MppFrameFormat fmt);
RK_S32 Open();
// Stop capturing and free a context.
MPP_RET Deinit(CamSource *ctx);
RK_S32 Ioctl(RK_S32 fd, RK_S32 req, void* arg);
// Returns the next captured frame and its meta-data.
RK_S32 GetFrame(CamSource *ctx);
// Tells the kernel it's OK to overwrite a frame captured
MPP_RET PutFrame(CamSource *ctx, RK_S32 idx);
MppBuffer Frame2Buf(CamSource *ctx, RK_S32 idx);
bool readyToRun();
bool threadLoop();
public:
CameraReader(const char *device, RK_U32 bufcnt, RK_U32 width, RK_U32 height, MppFrameFormat fmt);
void start();
};
#endif /* __CAMERA_READER_H__ */
main_test
#include <string.h>
#include "rk_mpi.h"
#include "mpp_env.h"
#include "mpp_mem.h"
#include "mpp_time.h"
#include "mpp_debug.h"
#include "mpp_common.h"
#include "CameraReader.h"
int main(){
CameraReader *camera1 = new CameraReader("/dev/video0", 10, 1920, 1080, MPP_FMT_YUV420SP);
camera1->start();//线程开始
while(1){
usleep(33333);
}
}
mpp/mpp-develop/test/CMakeLists.txt
....
# new dec multi unit test
add_mpp_test(mpi_dec_multi c)
#add
add_mpp_test(main cpp)
...
mpp/mpp-develop/util/CMakeLists.txt
# vim: syntax=cmake
# ----------------------------------------------------------------------------
# add libvpu implement
# ----------------------------------------------------------------------------
include_directories(${PROJECT_SOURCE_DIR}/mpp/base/inc)
add_library(utils STATIC
mpp_enc_roi_utils.c
mpi_enc_utils.c
mpi_dec_utils.c
mpp_opt.c
utils.c
iniparser.c
dictionary.c
camera_source.c
CameraReader.cpp
thread.cpp
thread.h
)
target_link_libraries(utils mpp_base)
此类继承于threadBase在我上一片文章有linux下 C++ 封装一个简洁管理方便线程类_hmbbPdx_的博客-程序员宅基地
文章浏览阅读1k次。通过使用ajax方法跨域请求是浏览器所不允许的,浏览器出于安全考虑是禁止的。警告信息如下:不过jQuery对跨域问题也有解决方案,使用jsonp的方式解决,方法如下:$.ajax({ async:false, url: 'http://www.mysite.com/demo.do', // 跨域URL ty..._nginx不停的xhr
文章浏览阅读2k次。关于在 Oracle 中配置 extproc 以访问 ST_Geometry,也就是我们所说的 使用空间SQL 的方法,官方文档链接如下。http://desktop.arcgis.com/zh-cn/arcmap/latest/manage-data/gdbs-in-oracle/configure-oracle-extproc.htm其实简单总结一下,主要就分为以下几个步骤。..._extproc
文章浏览阅读1.5w次。linux下没有上面的两个函数,需要使用函数 mbstowcs和wcstombsmbstowcs将多字节编码转换为宽字节编码wcstombs将宽字节编码转换为多字节编码这两个函数,转换过程中受到系统编码类型的影响,需要通过设置来设定转换前和转换后的编码类型。通过函数setlocale进行系统编码的设置。linux下输入命名locale -a查看系统支持的编码_linux c++ gbk->utf8
文章浏览阅读750次。今天准备从生产库向测试库进行数据导入,结果在imp导入的时候遇到“ IMP-00009:导出文件异常结束” 错误,google一下,发现可能有如下原因导致imp的数据太大,没有写buffer和commit两个数据库字符集不同从低版本exp的dmp文件,向高版本imp导出的dmp文件出错传输dmp文件时,文件损坏解决办法:imp时指定..._imp-00009导出文件异常结束
文章浏览阅读143次。当下是一个大数据的时代,各个行业都离不开数据的支持。因此,网络爬虫就应运而生。网络爬虫当下最为火热的是Python,Python开发爬虫相对简单,而且功能库相当完善,力压众多开发语言。本次教程我们爬取前程无忧的招聘信息来分析Python程序员需要掌握那些编程技术。首先在谷歌浏览器打开前程无忧的首页,按F12打开浏览器的开发者工具。浏览器开发者工具是用于捕捉网站的请求信息,通过分析请求信息可以了解请..._初级python程序员能力要求
文章浏览阅读7.6k次,点赞2次,收藏6次。@Service标注的bean,类名:ABDemoService查看源码后发现,原来是经过一个特殊处理:当类的名字是以两个或以上的大写字母开头的话,bean的名字会与类名保持一致public class AnnotationBeanNameGenerator implements BeanNameGenerator { private static final String C..._@service beanname
文章浏览阅读6.9w次,点赞73次,收藏463次。1.前序创建#include<stdio.h>#include<string.h>#include<stdlib.h>#include<malloc.h>#include<iostream>#include<stack>#include<queue>using namespace std;typed_二叉树的建立
文章浏览阅读7.1k次。在Asp.net上使用Excel导出功能,如果文件名出现中文,便会以乱码视之。 解决方法: fileName = HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8);_asp.net utf8 导出中文字符乱码
文章浏览阅读2.1k次,点赞4次,收藏23次。第一次实验 词法分析实验报告设计思想词法分析的主要任务是根据文法的词汇表以及对应约定的编码进行一定的识别,找出文件中所有的合法的单词,并给出一定的信息作为最后的结果,用于后续语法分析程序的使用;本实验针对 PL/0 语言 的文法、词汇表编写一个词法分析程序,对于每个单词根据词汇表输出: (单词种类, 单词的值) 二元对。词汇表:种别编码单词符号助记符0beginb..._对pl/0作以下修改扩充。增加单词
文章浏览阅读773次。我在使用adb.exe时遇到了麻烦.我想使用与bash相同的adb.exe shell提示符,所以我决定更改默认的bash二进制文件(当然二进制文件是交叉编译的,一切都很完美)更改bash二进制文件遵循以下顺序> adb remount> adb push bash / system / bin /> adb shell> cd / system / bin> chm..._adb shell mv 权限
文章浏览阅读6.8k次,点赞12次,收藏125次。1. 单目相机标定引言相机标定已经研究多年,标定的算法可以分为基于摄影测量的标定和自标定。其中,应用最为广泛的还是张正友标定法。这是一种简单灵活、高鲁棒性、低成本的相机标定算法。仅需要一台相机和一块平面标定板构建相机标定系统,在标定过程中,相机拍摄多个角度下(至少两个角度,推荐10~20个角度)的标定板图像(相机和标定板都可以移动),即可对相机的内外参数进行标定。下面介绍张氏标定法(以下也这么称呼)的原理。原理相机模型和单应矩阵相机标定,就是对相机的内外参数进行计算的过程,从而得到物体到图像的投影_相机-投影仪标定
文章浏览阅读2.2k次。文章目录Wayland 架构Wayland 渲染Wayland的 硬件支持简 述: 翻译一篇关于和 wayland 有关的技术文章, 其英文标题为Wayland Architecture .Wayland 架构若是想要更好的理解 Wayland 架构及其与 X (X11 or X Window System) 结构;一种很好的方法是将事件从输入设备就开始跟踪, 查看期间所有的屏幕上出现的变化。这就是我们现在对 X 的理解。 内核是从一个输入设备中获取一个事件,并通过 evdev 输入_wayland