- 2024-07-01
-
加入了学习《[高精度实验室] ADC系列 3&4 : 误差与噪声》,观看 5 动手实验 - ADC 噪声
- 2024-03-28
-
回复了主题帖:
【Luckfox幸狐 RV1106 Linux 开发板使用】 SC3336拍摄
LOI-T_T-o 发表于 2024-3-27 17:44
你好,新手不太懂,求教一下。我SDK编译好了,按你的教程,偏绿的图片也拍出来了,那个simple_venc_jpeg文 ...
这个就是SDK下的例程代码,直接修改就行,然后编译SDK就好了,编译完成后在对应的输出路径下就有最后的程序了
在你设置好SDK的编译环境之后进入/luckfox-pico/media/samples路径下执行make
然后同级目录下的out/bin里就有对应的输出程序
- 2024-02-25
-
发表了主题帖:
【Luckfox幸狐 RV1106 Linux 开发板使用】USB外接 USB摄像头 EC20
本帖最后由 0x4C 于 2024-2-25 18:57 编辑
本篇实现USB HOST 下使用USB摄像头和4G模块
1、配置USB摄像头
涉及修改的东西有点多,也记录一下SDK的编译流程,这里重新拉SDK编译,参考链接SDK 环境部署 | LUCKFOX WIKI
git clone https://gitee.com/LuckfoxTECH/luckfox-pico.git
安装交叉编译工具链:
cd {SDK_PATH}/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/
source env_install_toolchain.sh
选择编译目标平台:
./build.sh lunch
我是用的板载的flash
开始编译:
./build.sh
编译后打包固件:
./build.sh firmware
得到基础的SDK包
进入设备树文件路径,修改 <SDK目录>/sysdrv/source/kernel/arch/arm/boot/dts/rv1106g-luckfox-pico-pro-max.dts 将USB配置为USB HOST模式
&usbdrd_dwc3 {
status = "okay";
dr_mode = "host";
};
接下来修改内核配置
cd ~/SDK目录/sysdrv/source/kernel
cp ./arch/arm/configs/luckfox_rv1106_linux_defconfig .config
make ARCH=arm menuconfig
按下 ‘/’进行搜索。
进入搜索栏,输入搜索内容回车
显示搜索相关内容,按数字1-N进行选择。
依次搜索并使能以下选项
SCSI
SCSI_UFSHCD
BLK_DEV_SD
USB_STORAGE
USB_MASS_STORAGE
USB_EHCI_HCD
SCSI
SCSI_UFSHCD
BLK_DEV_SD
USB_STORAGE
USB_MASS_STORAGE
USB_EHCI_HCD
退出界面前先save一下
保存config,回到SDK目录下,并重新编译内核。
make ARCH=arm savedefconfig
cp defconfig arch/arm/configs/luckfox_rv1106_linux_defconfig
cd ~/SDK目录
./build.sh kernel
打包固件
./build.sh firmware
下载固件到板子上(先按住板子上的boot键再按住reset键)
这里要注意一点,电脑的USB供电功率一般比较低,我这里使用开关电源额外提供5v电源输入,特别是后面做EC20联网的时候供电不足会直接导致板子重启,卡了我很长的时间
USB使用一个USB扩展坞扩展
之前的固件烧录后插入USB扩展坞:
接下来继续修改内核配置来支持USB摄像头:
在内核中启用UVC驱动,可通过搜索关键字"Webcam"
在搜索结果中找到并勾选"USB Video Class (UVC)",最后保存并退出。
编译内核 打包固件 下载固件(尝试用串口下载了一下固件,最大波特率下载,奇慢无比,同时有概率写入失败:)) 插入USB摄像头:
可以看见已经生成了对应的设备节点:
写个程序用V4L2抓个图吧:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <linux/types.h>
#include <linux/videodev2.h>
#include <malloc.h>
#include <math.h>
#include <string.h>
#include <sys/mman.h>
#include <errno.h>
#include <assert.h>
#include <linux/videodev2.h>
int main(int argc, char** argv)
{
printf("********************************start***************************************\n");
int cameraFd;/* 定义一个设备描述符 */
cameraFd = open("/dev/video21", O_RDWR);
if(cameraFd < 0){
perror("video设备打开失败\n");
return -1;
}
else{
printf("video设备打开成功\n");
}
printf("********************************1***************************************\n");
struct v4l2_capability vcap;
ioctl(cameraFd, VIDIOC_QUERYCAP, &vcap);
if (!(V4L2_CAP_VIDEO_CAPTURE & vcap.capabilities)) {
perror("Error: No capture video device!\n");
return -1;
}
printf("********************************2***************************************\n");
struct v4l2_fmtdesc fmtdesc;
fmtdesc.index = 0;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
printf("摄像头支持所有格式如下:\n");
while(ioctl(cameraFd,VIDIOC_ENUM_FMT,&fmtdesc) == 0){
printf("v4l2_format%d:%s\n",fmtdesc.index,fmtdesc.description);
fmtdesc.index++;
}
printf("********************************3***************************************\n");
struct v4l2_frmsizeenum frmsize;
frmsize.index = 0;
frmsize.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
// printf("MJPEG格式支持所有分辨率如下:\n");
// frmsize.pixel_format = V4L2_PIX_FMT_MJPEG;
// while(ioctl(cameraFd,VIDIOC_ENUM_FRAMESIZES,&frmsize) == 0){
// printf("frame_size<%d*%d>\n",frmsize.discrete.width,frmsize.discrete.height);
// frmsize.index++;
// }
printf("YUYV422格式支持所有分辨率如下:\n");
frmsize.pixel_format = V4L2_PIX_FMT_MJPEG;
while(ioctl(cameraFd,VIDIOC_ENUM_FRAMESIZES,&frmsize) == 0){
printf("frame_size<%d*%d>\n",frmsize.discrete.width,frmsize.discrete.height);
frmsize.index++;
}
printf("********************************4***************************************\n");
// struct v4l2_frmivalenum frmival;
// frmival.index = 0;
// frmival.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
// frmival.pixel_format = V4L2_PIX_FMT_MJPEG;
// frmival.width = 640;
// frmival.height = 480;
// while(ioctl(cameraFd,VIDIOC_ENUM_FRAMEINTERVALS,&frmival) == 0){
// printf("frame_interval under frame_size <%d*%d> support %dfps\n",frmival.width,frmival.height,frmival.discrete.denominator / frmival.discrete.numerator);
// frmival.index++;
// }
struct v4l2_frmivalenum frmival;
frmival.index = 0;
frmival.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
frmival.pixel_format = V4L2_PIX_FMT_MJPEG;
frmival.width = 2592;
frmival.height = 1944;
while(ioctl(cameraFd,VIDIOC_ENUM_FRAMEINTERVALS,&frmival) == 0){
printf("frame_interval under frame_size <%d*%d> support %dfps\n",frmival.width,frmival.height,frmival.discrete.denominator / frmival.discrete.numerator);
frmival.index++;
}
printf("********************************5***************************************\n");
// struct v4l2_format vfmt;
// vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
// vfmt.fmt.pix.width = 640;
// vfmt.fmt.pix.height = 480;
// vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
// if(ioctl(cameraFd,VIDIOC_S_FMT,&vfmt) < 0){
// perror("设置格式失败\n");
// return -1;
// }
// // 检查设置参数是否生效
// if(ioctl(cameraFd,VIDIOC_G_FMT,&vfmt) < 0){
// perror("获取设置格式失败\n");
// return -1;
// }
// else if(vfmt.fmt.pix.width == 640 && vfmt.fmt.pix.height == 480 && vfmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG){
// printf("设置格式生效,实际分辨率大小<%d * %d>,图像格式:Motion-JPEG\n",vfmt.fmt.pix.width,vfmt.fmt.pix.height);
// }
// else{
// printf("设置格式未生效\n");
// }
struct v4l2_format vfmt;
vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vfmt.fmt.pix.width = 2592;
vfmt.fmt.pix.height = 1944;
vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
if(ioctl(cameraFd,VIDIOC_S_FMT,&vfmt) < 0){
perror("设置格式失败\n");
return -1;
}
// 检查设置参数是否生效
if(ioctl(cameraFd,VIDIOC_G_FMT,&vfmt) < 0){
perror("获取设置格式失败\n");
return -1;
}
else if(vfmt.fmt.pix.width == 2592 && vfmt.fmt.pix.height == 1944 && vfmt.fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG){
printf("设置格式生效,实际分辨率大小<%d * %d>,图像格式:Motion-JPEG\n",vfmt.fmt.pix.width,vfmt.fmt.pix.height);
}
else{
printf("设置格式未生效\n");
}
printf("********************************6***************************************\n");
struct v4l2_requestbuffers reqbuf;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.count = 3; //3个帧缓冲
reqbuf.memory = V4L2_MEMORY_MMAP;
if(ioctl(cameraFd,VIDIOC_REQBUFS,&reqbuf) < 0){
perror("申请缓冲区失败\n");
return -1;
}
printf("********************************7***************************************\n");
// 将帧缓冲映射到进程地址空间
void *frm_base[3]; //映射后的用户空间的首地址
unsigned int frm_size[3];
struct v4l2_buffer buf;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
// 将每一帧对应的缓冲区的起始地址保存在frm_base数组中,读取采集数据时,只需直接读取映射区即可
for(buf.index=0;buf.index<3;buf.index++){
ioctl(cameraFd, VIDIOC_QUERYBUF, &buf);
frm_base[buf.index] = mmap(NULL,buf.length,PROT_READ | PROT_WRITE,MAP_SHARED,cameraFd,buf.m.offset);
frm_size[buf.index] = buf.length;
if(frm_base[buf.index] == MAP_FAILED){
perror("mmap failed\n");
return -1;
}
// 入队操作
if(ioctl(cameraFd,VIDIOC_QBUF,&buf) < 0){
perror("入队失败\n");
return -1;
}
}
printf("********************************8***************************************\n");
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl(cameraFd, VIDIOC_STREAMON, &type) < 0){
perror("开始采集失败\n");
return -1;
}
printf("********************************9***************************************\n");
struct v4l2_buffer readbuffer;
readbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
readbuffer.memory = V4L2_MEMORY_MMAP;
if(ioctl(cameraFd, VIDIOC_DQBUF, &readbuffer) < 0){
perror("读取帧失败\n");
}
// 保存这一帧,格式为jpg
FILE *file = fopen("v4l2_cap.jpg","w+");
fwrite(frm_base[readbuffer.index],buf.length,1,file);
fclose(file);
printf("********************************10***************************************\n");
// 停止采集
if (ioctl(cameraFd, VIDIOC_STREAMOFF, &type) < 0){
perror("停止采集失败\n");
return -1;
}
// 释放映射
for(int i=0;i<3;i++){
munmap(frm_base[i],frm_size[i]);
}
close(cameraFd);
return 0;
}
编译方法:
vi ~/.bashrc
export PATH=<SDK Directory>/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin:$PATH
source ~/.bashrc
arm-rockchip830-linux-uclibcgnueabihf-gcc gpio.c -o gpio
放到开发板,执行后可以看到效果:
2、配置EC20
这里的配置仅仅提供一个参考,参考的博客:Quectel EC20在嵌入式平台的适配 - 大窟窿 - 博客园 (cnblogs.com)
进入文件夹下,路径:luckfox-pico/sysdrv/source/kernel/drivers/usb/serial
打开添加如下内容,保存
{ USB_DEVICE(0x05C6, 0x9215) }, /* Quectel EC20 */
注释掉冲突的vid以及pid设备,路径:luckfox-pico/sysdrv/source/kernel/drivers/usb/serial
修改路径:luckfox-pico/sysdrv/source/kernel/drivers/net/usb
添加零包处理(这个和usb 协议中的批量传输有关)For Linux Kernel Version newer than 2.6.34: 路径:luckfox-pico/sysdrv/source/kernel/drivers/usb/serial
.reset_resume = usb_wwan_resume,
修改内核配置:
编译内核 打包固件 下载固件 可以看见其设备节点ttyUSB0~3
下载ppp2.4.7源码 https://github.com/ppp-project/ppp.git
git clone -b ppp-2.4.7 https://github.com/ppp-project/ppp.git
交叉编译
./configure
make CC=/home/czm/luckfox-pico/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf-gcc
编译完成后会在当前目录下生成chat/chat、 pppd/pppd、 pppdump/pppdump 和pppstats/pppstats 这四个文件,把这四个文件拷贝到文件系统中的/usr/bin目录下
最后移植ppp拨号脚本(附件提供),放到/etc/目录下即可
使用 pppd -v :
移植完成后 使用 pppd call quectel-ppp & 拨号
使用iperf测速
- 2024-02-21
-
回复了主题帖:
【Luckfox幸狐 RV1106 Linux 开发板使用】opencv-mobile 使用
LitchiCheng 发表于 2024-2-21 09:16
这个opencv-mobile库精简到只能用rockchip isp的视频流,也就是只能插官方的摄像头
也可以这么玩,不去调他的读流接口就行,用原生的mpp接口读完视频流,转opencv 的mat型数据就好啦,这样编解码就都是自己能够控制的。也就是只用opencv的处理部分
- 2024-02-20
-
发表了主题帖:
【Luckfox幸狐 RV1106 Linux 开发板使用】opencv-mobile 使用
本帖最后由 0x4C 于 2024-2-20 14:05 编辑
看官方教程提供了opencv-mobile的使用,简单易用,浅尝一下
官方教程: opencv-mobile | LUCKFOX WIKI
1、基本测试
创建一个文件夹
mkdir opencvMobile
cd opencvMobile/
下载并解压包,放到创建的文件夹下面
在文件夹下创建新的文件 vi CMakeLists.txt 添加内容,将 <SDK Directory> 修改为自己的 SDK 路径,如 /home/luckfox/luckfox-pico/
project(opencv-mobile-test)
cmake_minimum_required(VERSION 3.5)
set(CMAKE_CXX_STANDARD 11)
SET(CMAKE_C_COMPILER "<SDK Directory>/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf-gcc")
SET(CMAKE_CXX_COMPILER "<SDK Directory>/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf-g++")
set(OpenCV_DIR "${CMAKE_CURRENT_SOURCE_DIR}/opencv-mobile-4.8.1-luckfox-pico/lib/cmake/opencv4")
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(opencv-mobile-test main.cpp)
target_link_libraries(opencv-mobile-test ${OpenCV_LIBS})
创建main vi main.cpp
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <unistd.h> // sleep()
int main()
{
cv::VideoCapture cap;
cap.set(cv::CAP_PROP_FRAME_WIDTH, 320);
cap.set(cv::CAP_PROP_FRAME_HEIGHT, 240);
cap.open(0);
const int w = cap.get(cv::CAP_PROP_FRAME_WIDTH);
const int h = cap.get(cv::CAP_PROP_FRAME_HEIGHT);
fprintf(stderr, "%d x %d\n", w, h);
cv::Mat bgr[9];
for (int i = 0; i < 9; i++)
{
cap >> bgr[i];
sleep(1);
}
cap.release();
// combine into big image
{
cv::Mat out(h * 3, w * 3, CV_8UC3);
bgr[0].copyTo(out(cv::Rect(0, 0, w, h)));
bgr[1].copyTo(out(cv::Rect(w, 0, w, h)));
bgr[2].copyTo(out(cv::Rect(w * 2, 0, w, h)));
bgr[3].copyTo(out(cv::Rect(0, h, w, h)));
bgr[4].copyTo(out(cv::Rect(w, h, w, h)));
bgr[5].copyTo(out(cv::Rect(w * 2, h, w, h)));
bgr[6].copyTo(out(cv::Rect(0, h * 2, w, h)));
bgr[7].copyTo(out(cv::Rect(w, h * 2, w, h)));
bgr[8].copyTo(out(cv::Rect(w * 2, h * 2, w, h)));
cv::imwrite("out.jpg", out);
}
return 0;
}
编译
mkdir build
cd build
cmake ..
make
文件夹结构:
在build下就生成了可执行程序
将整个文件夹复制到开发板的root路径下
执行 ./opencv-mobile-test
得到图像
2、opencv4.9支持
github上已经更新到opencv4.9了,浅尝一下区别 nihui/opencv-mobile: The minimal opencv for Android, iOS, ARM Linux, Windows, Linux, MacOS, WebAssembly (github.com)
下载对应的包
解压后也放到刚才的文件夹下,删除build文件夹
修改camkelists.txt
其余步骤相同
使用的做设备 luckfox-pico max + sc3336
4.8.1下的输出
# ./opencv-mobile-test
this device is not whitelisted for jpeg decoder cvi
this device is not whitelisted for jpeg decoder cvi
this device is not whitelisted for jpeg decoder cvi
[ 430.140795] stream_cif_mipi_id0: s_power 1, entity use_count 1
devpath = /dev/video11
driver = rkisp_v7
card = rkisp_mainpath
bus_info = platform:rkisp-vir0
version = 20000
capabilities = 84201000
device_caps = 4201000
fmt = UYVY 4:2:2 59565955
fmt = Y/CbCr 4:2:2 3631564e
fmt = Y/CrCb 4:2:2 3136564e
fmt = Y/CrCb 4:2:0 3132564e
size = 32 x 16 ~ 2304 x 1296 (+8 +8)
fmt = Y/CbCr 4:2:0 3231564e
fmt = Y/CrCb 4:2:0 (N-C) 31324d4e
fmt = Y/CbCr 4:2:0 (N-C) 32314d4e
rkaiq log level ff0
[ 430.324185] stream_cif_mipi_id0: open video, entity use_countt 2
[ 430.324391] stream_cif_mipi_id1: open video, entity use_countt 1
/dev/video11 does not support changing fps
rga_api version 1.9.1_[0]
[ 430.338940] rkisp rkisp-vir0: first params buf queue
[ 430.341360] rkisp_hw ffa00000.rkisp: set isp clk = 198000000Hz
[ 430.341486] rkcif-mipi-lvds: sditf_reinit_mode, mode->rdbk_mode 0, mode->name rkisp-vir0, link_mode 1
[ 430.343320] rkcif-mipi-lvds: stream320 x 240
[0] start streaming
[ 430.343452] rockchip-mipi-csi2 ffa20000.mipi-csi2: stream on, src_sd: baffe55e, sd_name:rockchip-csi2-dphy0
[ 430.343466] rockchip-mipi-csi2 ffa20000.mipi-csi2: stream ON
[ 430.343542] rockchip-csi2-dphy0: dphy0, data_rate_mbps 506
[ 430.343574] rockchip-csi2-dphy csi2-dphy0: csi2_dphy_s_stream stream on:1, dphy0
[ 430.343587] rockchip-csi2-dphy csi2-dphy0: csi2_dphy_s_stream stream on:1, dphy0
[ 439.456220] rkcif-mipi-lvds: stream[0] start stopping, total mode 0x2, cur 0x2
[ 439.478307] rockchip-mipi-csi2 ffa20000.mipi-csi2: stream off, src_sd: baffe55e, sd_name:rockchip-csi2-dphy0
[ 439.478359] rockchip-mipi-csi2 ffa20000.mMessageParser process loop exit!
ipi-csi2: stream OFF
[ 439.480935] rockchip-csi2-dphy csi2-dphy0: csi2_dphy_s_stream_stop stream stop, dphy0
[ 439.480973] rockchip-csi2-dphy csi2-dphy0: csi2_dphy_s_stream stream on:0, dpmpp[645]: mpp_buffer: mpi_buf_id = 136, dma_buf_fd = 5
mpp[645]: mpp: mClinetFd 7 open ok attr.chan_id 0
[ 439.481019] rockchip-csi2-dphy csi2-dphy0: csi2_dphy_s_stream stream on:0, dphy0
[ 439.481238] rkcif-mipi-lvds: stream[0] stopping finished, dma_en 0x0
[ 439.496563] stream_cif_mipi_id1: close video, entity use_count#
# 0
[ 439.496651] stream_cif_mipi_id0: close video, entity use_count 1
[ 439.497314] stream_cif_mipi_id0: s_power 0, entity use_count 0
[ 439.516121] mpp_vcodec: 44: num_chan = 0
[ 439.516219] mpp_vcodec: 103: chan_entry->handle 65722eb9, enc 65722eb9
[ 439.516826] 755: MPP_ENC_SET_CFG in
[ 439.516855] 524: MPP_ENC_SET_RC_CFG bps 0 [0 : 0] fps [1:1] gop 1
4.9.0的输出
# ./opencv-mobile-test
this device is not whitelisted for jpeg decoder cvi
this device is not whitelisted for jpeg decoder cvi
this device is not whitelisted for jpeg decoder cvi
this device is not whitelisted for capture cvi
this device is not whitelisted for capture cvi
this device is not whitelisted for capture cvi
this device is not whitelisted for capture cvi
this device is not whitelisted for capture cvi
this device is not whitelisted for capture cvi
this device is not whitelisted for capture cvi
this device is not whitelisted for capture v4l2 awispapi
[ 1681.086395] stream_cif_mipi_id0: s_power 1, entity use_count 1
devpath = /dev/video11
driver = rkisp_v7
card = rkisp_mainpath
bus_info = platform:rkisp-vir0
version = 20000
capabilities = 84201000
device_caps = 4201000
fmt = UYVY 4:2:2 59565955
fmt = Y/CbCr 4:2:2 3631564e
fmt = Y/CrCb 4:2:2 3136564e
fmt = Y/CrCb 4:2:0 3132564e
size = 32 x 16 ~ 2304 x 1296 (+8 +8)
fmt = Y/CbCr 4:2:0 3231564e
fmt = Y/CrCb 4:2:0 (N-C) 31324d4e
fmt = Y/CbCr 4:2:0 (N-C) 32314d4e
rkaiq log level ff0
[ 1681.269800] stream_cif_mipi_id0: open video, entity use_countt 2
[ 1681.270001] stream_cif_mipi_id1: open video, entity use_countt 1
/dev/video11 does not support changing fps
rga_api version 1.9.1_[0]
[ 1681.284710] rkisp rkisp-vir0: first params buf queue
[ 1681.287253] rkisp_hw ffa00000.rkisp: set isp clk = 198000000Hz
[ 1681.287302] rkcif-mipi-lvds: sditf_reinit_mode, mode->rdbk_mode 0, mode->name rkisp-vir0, link_mode 1
[ 1681.289425] rkcif-mipi-lvds: stream[0] start st320 x 240
reaming
[ 1681.289596] rockchip-mipi-csi2 ffa20000.mipi-csi2: stream on, src_sd: baffe55e, sd_name:rockchip-csi2-dphy0
[ 1681.289611] rockchip-mipi-csi2 ffa20000.mipi-csi2: stream ON
[ 1681.289661] rockchip-csi2-dphy0: dphy0, data_rate_mbps 506
[ 1681.289691] rockchip-csi2-dphy csi2-dphy0: csi2_dphy_s_stream stream on:1, dphy0
[ 1681.289703] rockchip-csi2-dphy csi2-dphy0: csi2_dphy_s_stream stream on:1, dphy0
[ 1690.398035] rkcif-mipi-lvds: stream[0] start stopping, total mode 0x2, cur 0x2
[ 1690.424739] rockchip-mipi-csi2 ffa20000.mipi-csi2: stream off, src_sd: baffe55e, sd_name:rockchip-csi2-dphy0
[ 1690.424791] rockchip-mipi-MessageParser process loop exit!
csi2 ffa20000.mipi-csi2: stream OFF
[ 1690.427185] rockchip-csi2-dphy csi2-dphy0: csi2_dphy_s_stream_stop stream stop, dphy0
[ 1690.427235] rockchip-csi2-dphy csi2-dphmpp[740]: mpp_buffer: mpi_buf_id = 136, dma_buf_fd = 5
ympp[740]: mpp: mClinetFd 7 open ok attr.chan_id 0
0: csi2_dphy_s_stream stream on:0, dphy0
[ 1690.427297] rockchip-csi2-dphy csi2-dphy0: csi2_dphy_s_stream stream on:0ioctl IOCTL_FREE_IOMMU_ADDR failed 9 Bad file descriptor
ioctl ION_IOC_FREE failed 9 Bad file descriptor
, dphy0
[ 1690.427546] rkcif# -mipi-lvds: stream[0] stopping finished, dma_en 0x0
[ 1690.439913] stream_cif_mipi_id1: close video, entity use_count 0
[ 1690.440016] stream_cif_mipi_id0: close video, entity use_count 1
[ 1690.440679] stream_cif_mipi_id0: s_power 0, entity use_count 0
[ 1690.459025] mpp_vcodec: 44: num_chan = 0
[ 1690.459126] mpp_vcodec: 103: chan_entry->handle 68c79227, enc 68c79227
[ 1690.459735] 755: MPP_ENC_SET_CFG in
[ 1690.459764] 524: MPP_ENC_SET_RC_CFG bps 0 [0 : 0] fps [1:1] gop 1
3、寻找最大色块
#include <iostream>
#include <vector> // 添加 vector 头文件
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main()
{
Mat image = imread("test.jpg"); // 替换为您的图像路径
Mat hsvImage;
cvtColor(image, hsvImage, COLOR_BGR2HSV);
// 定义红色范围
Scalar lowerRed = Scalar(0, 100, 100);
Scalar upperRed = Scalar(10, 255, 255);
// 提取红色物体
Mat redMask;
inRange(hsvImage, lowerRed, upperRed, redMask);
// 查找红色物体的轮廓
std::vector<std::vector<Point>> contours;
findContours(redMask, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
// 绘制红色物体的轮廓并计算中心坐标
for (const auto& contour : contours)
{
drawContours(image, std::vector<std::vector<Point>>{contour}, -1, Scalar(0, 0, 255), 2);
// 计算轮廓的中心坐标
Moments mu = moments(contour, false);
Point2f center = Point2f(mu.m10 / mu.m00, mu.m01 / mu.m00);
// 在图像上绘制中心坐标
circle(image, center, 5, Scalar(255, 255, 255), -1);
// 输出中心坐标
std::cout << "Red object center coordinates: (" << center.x << ", " << center.y << ")" << std::endl;
}
// 显示结果
imshow("Red Objects", image);
waitKey(0);
return 0;
}
将测试图片放到和程序同一路径下,执行 ./opencv-mobile-test
输出结果:
# ./opencv-mobile-test
this device is not whitelisted for jpeg decoder cvi
this device is not whitelisted for jpeg decoder cvi
this device is not whitelisted for jpeg decoder cvi
Red object center coordinates: (nan, nan)
Red object center coordinates: (nan, nan)
Red object center coordinates: (245.15, 156.34)
imshow save image to Red Objects.pngwaitKey stub#
-
回复了主题帖:
【Luckfox幸狐 RV1106 Linux 开发板使用】 SC3336拍摄
wangerxian 发表于 2024-2-20 17:39
专用的摄像头要插在板子的哪?
CSI Camera | LUCKFOX WIKI
-
回复了主题帖:
【Luckfox幸狐 RV1106 Linux 开发板使用】 SC3336拍摄
LitchiCheng 发表于 2024-2-20 09:37
看来都买了那个专用的摄像头,我还是白嫖用USB摄像头
主要是测试跑压缩这块要方便一点
-
回复了主题帖:
【Luckfox幸狐 RV1106 Linux 开发板使用】 SC3336拍摄
nmg 发表于 2024-2-20 09:09
实际的效果那里没有,是不是视频上传忘记点击名称,插入啦?
第一次用,不太懂 哈哈哈
重新添加了
-
发表了主题帖:
【Luckfox幸狐 RV1106 Linux 开发板使用】 SC3336拍摄
本帖最后由 0x4C 于 2024-2-20 11:39 编辑
Luckfox的这块RV1106开发板是对SC3336进行了支持的,同时RV1106有着强大硬编码能力
本篇主要是实现使用SC3336来拍图,同时将图像进行JPEG硬编码然后通过网络发送出去
1、基本JPEG压缩测试
源码路径:/luckfox-pico/media/samples/simple_venc_jpeg.c
测试时用串口调试,连接网线到路由器来传输文件
串口连接:
插上网线,ifconfig看下设备的IP地址
键盘WIN+E,输入设备的IP地址:192.168.110.90
用户名为 root,密码为 luckfox
连接后就可以看见板子的文件了
默认的SDK编译完成后,在/oem/usr/bin下已经有测试的例程程序了
运行前先关闭开机自启的IPC程序 killall rkipc
输入 ./simple_venc_jpeg -w 1920 -h 1080 运行程序
在命令行每回车一次就会拍一张图片,对应的图片会保存在 /tmp/*.jpeg 下
最后输入 quit 程序结束运行,然后将图片拷贝到电脑上查看
打开拍摄的图片我们会发现图片的颜色可能会偏色,显示不正常,我们需要修改程序如下(代码段的main(){}部分):
int main(int argc, char *argv[]) {
RK_S32 s32Ret = RK_FAILURE;
RK_U32 u32Width = 1920;
RK_U32 u32Height = 1080;
RK_CODEC_ID_E enCodecType = RK_VIDEO_ID_JPEG;
RK_CHAR *pCodecName = "JPEG";
RK_S32 s32chnlId = 0;
int c;
while ((c = getopt(argc, argv, optstr)) != -1) {
switch (c) {
case 'w':
u32Width = atoi(optarg);
break;
case 'h':
u32Height = atoi(optarg);
break;
case 'I':
s32chnlId = atoi(optarg);
break;
case '?':
default:
print_usage(argv[0]);
return 0;
}
}
printf("#CodecName:%s\n", pCodecName);
printf("#Resolution: %dx%d\n", u32Width, u32Height);
printf("#CameraIdx: %d\n\n", s32chnlId);
printf("#Frame Count to save: %d\n", g_s32FrameCnt);
char *iq_dir = "/etc/iqfiles";
if (iq_dir) {
#ifdef RKAIQ
printf("ISP IQ file path: %s\n\n", iq_dir);
SAMPLE_COMM_ISP_Init(0, RK_AIQ_WORKING_MODE_NORMAL, 0, iq_dir);
SAMPLE_COMM_ISP_Run(0);
printf("ISP RUN!\n");
#endif
}
signal(SIGINT, sigterm_handler);
if (RK_MPI_SYS_Init() != RK_SUCCESS) {
RK_LOGE("rk mpi sys init fail!");
goto __FAILED;
}
vi_dev_init();
vi_chn_init(s32chnlId, u32Width, u32Height);
// venc init
test_venc_init(0, u32Width, u32Height, enCodecType);
MPP_CHN_S stSrcChn, stDestChn;
// bind vi to venc
stSrcChn.enModId = RK_ID_VI;
stSrcChn.s32DevId = 0;
stSrcChn.s32ChnId = s32chnlId;
stDestChn.enModId = RK_ID_VENC;
stDestChn.s32DevId = 0;
stDestChn.s32ChnId = 0;
printf("====RK_MPI_SYS_Bind vi0 to venc0====\n");
s32Ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn);
if (s32Ret != RK_SUCCESS) {
RK_LOGE("bind 0 ch venc failed");
goto __FAILED;
}
VENC_RECV_PIC_PARAM_S stRecvParam;
pthread_t main_thread;
pthread_create(&main_thread, NULL, GetMediaBuffer0, NULL);
char cmd[64];
VENC_JPEG_PARAM_S stJpegParam;
stJpegParam.u32Qfactor = 77;
RK_MPI_VENC_SetJpegParam(0, &stJpegParam);
while (!quit) {
fgets(cmd, sizeof(cmd), stdin);
printf("#Input cmd:%s\n", cmd);
if (strstr(cmd, "quit")) {
printf("#Get 'quit' cmd!\n");
quit = true;
break;
}
memset(&stRecvParam, 0, sizeof(VENC_RECV_PIC_PARAM_S));
stRecvParam.s32RecvPicNum = 1;
s32Ret = RK_MPI_VENC_StartRecvFrame(0, &stRecvParam);
if (s32Ret) {
printf("RK_MPI_VENC_StartRecvFrame failed!\n");
break;
}
usleep(30000); // sleep 30 ms.
}
sleep(1);
pthread_join(&main_thread, NULL);
s32Ret = RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
if (s32Ret != RK_SUCCESS) {
RK_LOGE("RK_MPI_SYS_UnBind fail %x", s32Ret);
}
s32Ret = RK_MPI_VI_DisableChn(0, s32chnlId);
RK_LOGE("RK_MPI_VI_DisableChn %x", s32Ret);
s32Ret = RK_MPI_VENC_StopRecvFrame(0);
if (s32Ret != RK_SUCCESS) {
return s32Ret;
}
s32Ret = RK_MPI_VENC_DestroyChn(0);
if (s32Ret != RK_SUCCESS) {
RK_LOGE("RK_MPI_VDEC_DestroyChn fail %x", s32Ret);
}
s32Ret = RK_MPI_VI_DisableDev(0);
RK_LOGE("RK_MPI_VI_DisableDev %x", s32Ret);
__FAILED:
RK_LOGE("test running exit:%d", s32Ret);
RK_MPI_SYS_Exit();
#ifdef RKAIQ
SAMPLE_COMM_ISP_Stop(0);
#endif
return 0;
}
重新编译后下载到板子上,重新测试就可以看到正常的图片了
左修改前,右修改后 可以看见拍摄的差异还是很明显的
2、图像VI和JPEG压缩非绑定
例程中图像输入后就直接送入JPEG压缩了,但是我们不总是希望这样。我们希望还可以对输入的图像(例如这里输入的YUV图像)进行自己的处理,处理之后再进行压缩,这里提供一种我测试的方法。
新建一个文件用来测试代码 vi_jpeg.c
修改media下的Makefile文件,添加
vi_jpeg: vi_jpeg.c
@$(SAMPLE_CC) $^ -o $@ $(SAMPLE_CFLAGS) $(LD_FLAGS)
代码参考/luckfox-pico/media/samples/test/sample_camera_stresstest.c
/*
* Copyright 2021 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.
*
*/
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <time.h>
#include <unistd.h>
#include "sample_comm.h"
#define FILE_TEST
typedef struct _rkMpiCtx {
SAMPLE_VI_CTX_S vi;
SAMPLE_VPSS_CTX_S vpss;
SAMPLE_VENC_CTX_S venc;
} SAMPLE_MPI_CTX_S;
static int g_loopcount = 1;
static int g_framcount = 200;
static COMPRESS_MODE_E g_compressMode = COMPRESS_AFBC_16x16;
static SAMPLE_MPI_CTX_S *g_ctx;
static bool quit = false;
static void sigterm_handler(int sig) {
fprintf(stderr, "signal %d\n", sig);
g_loopcount = 0;
quit = true;
}
static RK_CHAR optstr[] = "?::n:l:c:f:e:";
static const struct option long_options[] = {
{"index", required_argument, NULL, 'n'},
{"loop_count", required_argument, NULL, 'l'},
{"frame_count", required_argument, NULL, 'c'},
{"pixel_format", optional_argument, NULL, 'f'},
{NULL, 0, NULL, 0},
};
uint8_t encodingType = 0; /* 选择编码类型 */
/******************************************************************************
* function : show usage
******************************************************************************/
static void print_usage(const RK_CHAR *name) {
printf("Usage : %s -n <index> -l <loop count> -c <frame count> -f <pixel format>\n",
name);
printf("index:\n");
printf("\t 0)isp stresstest(IqFileDir: /etc/iqfiles ~ /usr/share/iqfiles)\n");
printf("\t 1)venc stresstest(H264 ~ H265)\n");
printf("\t 2)venc stresstest(1x ~ 0.5x resolution)\n");
printf("\t 3)vi->vps->venc stresstest\n");
printf("pixel format:\n");
printf("\t nv12) no compress\n");
printf("\t afbc) compress\n");
}
/******************************************************************************
* function : vi thread
******************************************************************************/
static void *vi_get_stream(void *pArgs) {
SAMPLE_VI_CTX_S *ctx = (SAMPLE_VI_CTX_S *)(pArgs);
RK_S32 s32Ret = RK_FAILURE;
char name[256] = {0};
FILE *fp = RK_NULL;
void *pData = RK_NULL;
RK_S32 loopCount = 0;
if (ctx->dstFilePath) {
snprintf(name, sizeof(name), "/%s/vi_%d.bin", ctx->dstFilePath, ctx->s32DevId);
fp = fopen(name, "wb");
if (fp == RK_NULL) {
printf("chn %d can't open %s file !\n", ctx->s32DevId, ctx->dstFilePath);
quit = true;
return RK_NULL;
}
}
while (!quit) {
s32Ret = SAMPLE_COMM_VI_GetChnFrame(ctx, &pData);
if (s32Ret == RK_SUCCESS) {
if (ctx->stViFrame.stVFrame.u64PrivateData <= 0) {
// SAMPLE_COMM_VI_ReleaseChnFrame(ctx);
// continue;
}
// exit when complete
if (ctx->s32loopCount > 0) {
if (loopCount >= ctx->s32loopCount) {
SAMPLE_COMM_VI_ReleaseChnFrame(ctx);
quit = true;
break;
}
}
if (fp) {
fwrite(pData, 1, ctx->stViFrame.stVFrame.u64PrivateData, fp);
fflush(fp);
}
RK_LOGE(
"SAMPLE_COMM_VI_GetChnFrame DevId %d ok:data %p size:%llu loop:%d seq:%d "
"pts:%lld ms\n",
ctx->s32DevId, pData, ctx->stViFrame.stVFrame.u64PrivateData, loopCount,
ctx->stViFrame.stVFrame.u32TimeRef,
ctx->stViFrame.stVFrame.u64PTS / 1000);
SAMPLE_COMM_VI_ReleaseChnFrame(ctx);
loopCount++;
}
usleep(1000);
}
if (fp)
fclose(fp);
return RK_NULL;
}
/******************************************************************************
* function : vpss thread
******************************************************************************/
static RK_U8 data[2560 * 1520 * 2];
static RK_U8 data0[2560 * 1520 * 2];
static RK_U8 data1[2560 * 1520 * 2];
static void *vpss_get_stream(void *pArgs) {
SAMPLE_VPSS_CTX_S *ctx = (SAMPLE_VPSS_CTX_S *)(pArgs);
RK_S32 s32Ret = RK_FAILURE;
char name[256] = {0};
FILE *fp = RK_NULL;
FILE *fbc0 = RK_NULL;
FILE *fbc1 = RK_NULL;
void *pData = RK_NULL;
RK_S32 loopCount = 0;
VIDEO_FRAME_INFO_S stChnFrameInfos;
if (ctx->dstFilePath) {
snprintf(name, sizeof(name), "/%s/vpss_%d.yuv", ctx->dstFilePath, ctx->s32ChnId);
fp = fopen(name, "wb");
if (fp == RK_NULL) {
printf("chn %d can't open %s file !\n", ctx->s32ChnId, ctx->dstFilePath);
quit = true;
return RK_NULL;
}
}
#if 0
fbc0 = fopen("/data/vpss_1280_760_fbc.bin", "r");
if (fbc0 == RK_NULL) {
printf("can't open /data/vpss_1280_760_fbc.bin file !\n");
quit = true;
return RK_NULL;
}
fbc1 = fopen("/data/vpss_2560_1520_fbc.bin", "r");
if (fbc1 == RK_NULL) {
printf("can't open /data/vpss_2560_1520_fbc.bin file !\n");
quit = true;
return RK_NULL;
}
fread(data0, 1, 1552384, fbc0);
fread(data1, 1, 6164480, fbc1);
#endif
while (!quit) {
s32Ret = SAMPLE_COMM_VPSS_GetChnFrame(ctx, &pData);
if (s32Ret == RK_SUCCESS) {
if (ctx->stChnFrameInfos.stVFrame.u64PrivateData <= 0) {
continue;
}
#if 0
// exit when complete
if (ctx->s32loopCount > 0) {
if (loopCount >= ctx->s32loopCount) {
SAMPLE_COMM_VPSS_ReleaseChnFrame(ctx);
quit = true;
break;
}
}
#endif
// if (fp) {
// fwrite(pData, 1, ctx->stChnFrameInfos.stVFrame.u64PrivateData, fp);
// fflush(fp);
// }
#if 1
// SAMPLE_COMM_VENC_SendStream(
// &g_ctx->venc, pData, ctx->stChnFrameInfos.stVFrame.u32Width,
// ctx->stChnFrameInfos.stVFrame.u32Height,
// ctx->stChnFrameInfos.stVFrame.u64PrivateData, g_compressMode);
s32Ret = RK_MPI_VENC_SendFrame(g_ctx->venc.s32ChnId,
&ctx->stChnFrameInfos.stVFrame, -1);
if (s32Ret != RK_SUCCESS) {
RK_LOGE("RK_MPI_VENC_SendFrame fail %x", s32Ret);
}
#else
if (ctx->stChnFrameInfos.stVFrame.u32Width == 1280) {
SAMPLE_COMM_VENC_SendStream(
&g_ctx->venc, data0, ctx->stChnFrameInfos.stVFrame.u32Width,
ctx->stChnFrameInfos.stVFrame.u32Height, 1552384, g_compressMode);
} else if (ctx->stChnFrameInfos.stVFrame.u32Width == 2560) {
SAMPLE_COMM_VENC_SendStream(
&g_ctx->venc, data1, ctx->stChnFrameInfos.stVFrame.u32Width,
ctx->stChnFrameInfos.stVFrame.u32Height, 6164480, g_compressMode);
}
#endif
printf("SAMPLE_COMM_VPSS_GetChnFrame DevId %d ok:data %p size:%llu loop:%d "
"seq:%d "
"pts:%lld ms\n",
ctx->s32GrpId, pData, ctx->stChnFrameInfos.stVFrame.u64PrivateData,
loopCount, ctx->stChnFrameInfos.stVFrame.u32TimeRef,
ctx->stChnFrameInfos.stVFrame.u64PTS / 1000);
SAMPLE_COMM_VPSS_ReleaseChnFrame(ctx);
loopCount++;
}
usleep(1000);
}
if (fp)
fclose(fp);
return RK_NULL;
}
static void *vpss_send_stream(void *pArgs) {
SAMPLE_VPSS_CTX_S *ctx = (SAMPLE_VPSS_CTX_S *)(pArgs);
RK_S32 s32Ret = RK_FAILURE;
FILE *fbc = RK_NULL;
void *pData = RK_NULL;
RK_S32 loopCount = 0;
fbc = fopen("/data/vpss_2560_1520_fbc.bin", "r");
if (fbc == RK_NULL) {
printf("can't open /data/vpss_2560_1520_fbc.bin file !\n");
quit = true;
return RK_NULL;
}
fread(data, 1, 6164480, fbc);
while (!quit) {
// exit when complete
if (ctx->s32loopCount > 0) {
if (loopCount >= ctx->s32loopCount) {
quit = true;
break;
}
}
SAMPLE_COMM_VPSS_SendStream(&g_ctx->vpss, data, 2560, 1520, 6164480,
g_compressMode);
loopCount++;
usleep(20000);
}
if (fbc)
fclose(fbc);
return RK_NULL;
}
/******************************************************************************
* function : venc thread
******************************************************************************/
static void *venc_get_stream(void *pArgs) {
SAMPLE_VENC_CTX_S *ctx = (SAMPLE_VENC_CTX_S *)(pArgs);
RK_S32 s32Ret = RK_FAILURE;
char name[256] = {0};
FILE *fp = RK_NULL;
void *pData = RK_NULL;
RK_S32 loopCount = 0;
if (ctx->dstFilePath) {
if(3 != encodingType)
{
snprintf(name, sizeof(name), "/%s/venc_%d.bin", ctx->dstFilePath, ctx->s32ChnId);
fp = fopen(name, "wb");
if (fp == RK_NULL) {
printf("chn %d can't open %s file !\n", ctx->s32ChnId, ctx->dstFilePath);
quit = true;
return RK_NULL;
}
}
}
while (!quit) {
s32Ret = SAMPLE_COMM_VENC_GetStream(ctx, &pData);
if (s32Ret == RK_SUCCESS) {
// exit when complete
if (ctx->s32loopCount > 0) {
if (loopCount >= ctx->s32loopCount) {
SAMPLE_COMM_VENC_ReleaseStream(ctx);
quit = true;
break;
}
// if (fp)
// {
// fwrite(pData, 1, ctx->stFrame.pstPack->u32Len, fp);
// fflush(fp);
// }
if(3 != encodingType)
{
fwrite(pData, 1, ctx->stFrame.pstPack->u32Len, fp);
fflush(fp);
}
else
{
static uint16_t pictureIndex = 0;
snprintf(name, sizeof(name), "/%s/venc_%d.jpeg", ctx->dstFilePath, pictureIndex);
fp = fopen(name, "wb");
if (fp == RK_NULL) {
printf("chn %d can't open %s file !\n", ctx->s32ChnId, ctx->dstFilePath);
quit = true;
return RK_NULL;
}
fwrite(pData, 1, ctx->stFrame.pstPack->u32Len, fp);
fflush(fp);
pictureIndex++;
printf("pictureIndex = %d",pictureIndex);
}
}
PrintStreamDetails(ctx->s32ChnId, ctx->stFrame.pstPack->u32Len);
RK_LOGD("chn:%d, loopCount:%d wd:%d\n", ctx->s32ChnId, loopCount,
ctx->stFrame.pstPack->u32Len);
SAMPLE_COMM_VENC_ReleaseStream(ctx);
loopCount++;
}
usleep(1000);
}
if (fp)
fclose(fp);
return RK_NULL;
}
int SAMPLE_CAMERA_VENC_Stresstest(SAMPLE_MPI_CTX_S *ctx, RK_S32 mode) {
RK_S32 s32Ret = RK_FAILURE;
int video_width = 2560;
int video_height = 1520;
int venc_width = 2560;
int venc_height = 1520;
RK_CHAR *pOutPathVenc = NULL;
RK_CHAR *iq_file_dir = "/etc/iqfiles";
RK_CHAR *pCodecName = "H264";
CODEC_TYPE_E enCodecType = RK_CODEC_TYPE_H264;
VENC_RC_MODE_E enRcMode = VENC_RC_MODE_H264CBR;
RK_S32 s32BitRate = 10 * 1024;
RK_S32 s32CamId = 0;
MPP_CHN_S stSrcChn, stDestChn;
RK_S32 s32loopCnt = g_framcount;
RK_S32 i;
RK_BOOL bMultictx = RK_FALSE;
quit = false;
pthread_t vpss_thread_id[2];
if (mode == 1) {
s32loopCnt = -1;
}
pOutPathVenc ="tmp";
printf("#CameraIdx: %d\n", s32CamId);
printf("#CodecName:%s\n", pCodecName);
printf("#Output Path: %s\n", pOutPathVenc);
if (iq_file_dir) {
#ifdef RKAIQ
printf("#Rkaiq XML DirPath: %s\n", iq_file_dir);
printf("#bMultictx: %d\n\n", bMultictx);
rk_aiq_working_mode_t hdr_mode = RK_AIQ_WORKING_MODE_NORMAL;
SAMPLE_COMM_ISP_Init(s32CamId, hdr_mode, bMultictx, iq_file_dir);
SAMPLE_COMM_ISP_Run(s32CamId);
#endif
}
if (RK_MPI_SYS_Init() != RK_SUCCESS) {
goto __FAILED;
}
MB_POOL pool = MB_INVALID_POOLID;
MB_POOL_CONFIG_S stMbPoolCfg;
memset(&stMbPoolCfg, 0, sizeof(MB_POOL_CONFIG_S));
stMbPoolCfg.u64MBSize = video_width * video_height * 2;
stMbPoolCfg.u32MBCnt = 10;
stMbPoolCfg.enAllocType = MB_ALLOC_TYPE_DMA;
pool = RK_MPI_MB_CreatePool(&stMbPoolCfg);
ctx->vpss.pool = ctx->venc.pool = pool;
// Init VI[0]
ctx->vi.u32Width = video_width;
ctx->vi.u32Height = video_height;
ctx->vi.s32DevId = s32CamId;
ctx->vi.u32PipeId = ctx->vi.s32DevId;
ctx->vi.s32ChnId = 2; // rk3588 mainpath:0 selfpath:1 fbcpath:2
ctx->vi.stChnAttr.stIspOpt.u32BufCount = 4;
ctx->vi.stChnAttr.stIspOpt.enMemoryType = VI_V4L2_MEMORY_TYPE_DMABUF;
ctx->vi.stChnAttr.u32Depth = 1;
ctx->vi.stChnAttr.enPixelFormat = RK_FMT_YUV420SP;
ctx->vi.stChnAttr.enCompressMode = g_compressMode;
ctx->vi.stChnAttr.stFrameRate.s32SrcFrameRate = -1;
ctx->vi.stChnAttr.stFrameRate.s32DstFrameRate = -1;
if (g_compressMode == COMPRESS_MODE_NONE) {
ctx->vi.s32ChnId = 0;
}
SAMPLE_COMM_VI_CreateChn(&ctx->vi);
// Init VPSS[0]
ctx->vpss.s32GrpId = 0;
ctx->vpss.s32ChnId = 0;
// RGA_device: VIDEO_PROC_DEV_RGA GPU_device: VIDEO_PROC_DEV_GPU
ctx->vpss.enVProcDevType = VIDEO_PROC_DEV_RGA;
// ctx->vpss.enVProcDevType = VIDEO_PROC_DEV_GPU;
ctx->vpss.s32loopCount = s32loopCnt;
ctx->vpss.stGrpVpssAttr.enPixelFormat = RK_FMT_YUV420SP;
ctx->vpss.stGrpVpssAttr.enCompressMode = g_compressMode;
ctx->vpss.stCropInfo.bEnable = RK_FALSE;
ctx->vpss.stCropInfo.enCropCoordinate = VPSS_CROP_RATIO_COOR;
ctx->vpss.stCropInfo.stCropRect.s32X = 0;
ctx->vpss.stCropInfo.stCropRect.s32Y = 0;
ctx->vpss.stCropInfo.stCropRect.u32Width = video_width;
ctx->vpss.stCropInfo.stCropRect.u32Height = video_height;
ctx->vpss.stChnCropInfo[0].bEnable = RK_TRUE;
ctx->vpss.stChnCropInfo[0].enCropCoordinate = VPSS_CROP_RATIO_COOR;
ctx->vpss.stChnCropInfo[0].stCropRect.s32X = 0;
ctx->vpss.stChnCropInfo[0].stCropRect.s32Y = 0;
ctx->vpss.stChnCropInfo[0].stCropRect.u32Width = venc_width * 1000 / video_width;
ctx->vpss.stChnCropInfo[0].stCropRect.u32Height = venc_height * 1000 / video_height;
ctx->vpss.s32ChnRotation[0] = ROTATION_0;
ctx->vpss.stRotationEx[0].bEnable = RK_FALSE;
ctx->vpss.stRotationEx[0].stRotationEx.u32Angle = 60;
ctx->vpss.stVpssChnAttr[0].enChnMode = VPSS_CHN_MODE_USER;
ctx->vpss.stVpssChnAttr[0].enDynamicRange = DYNAMIC_RANGE_SDR8;
ctx->vpss.stVpssChnAttr[0].enPixelFormat = RK_FMT_YUV420SP;
ctx->vpss.stVpssChnAttr[0].enCompressMode = g_compressMode;
ctx->vpss.stVpssChnAttr[0].stFrameRate.s32SrcFrameRate = -1;
ctx->vpss.stVpssChnAttr[0].stFrameRate.s32DstFrameRate = -1;
ctx->vpss.stVpssChnAttr[0].u32Width = venc_width;
ctx->vpss.stVpssChnAttr[0].u32Height = venc_height;
ctx->vpss.stVpssChnAttr[0].u32Depth = 2;
ctx->vpss.dstFilePath = pOutPathVenc;
SAMPLE_COMM_VPSS_CreateChn(&ctx->vpss);
#if defined(FILE_TEST)
pthread_create(&vpss_thread_id[0], 0, vpss_get_stream, (void *)(&ctx->vpss));
// pthread_create(&vpss_thread_id[1], 0, vpss_send_stream, (void *)(&ctx->vpss));
#endif
// Init VENC[0]
ctx->venc.s32ChnId = 0;
ctx->venc.u32Width = venc_width;
ctx->venc.u32Height = venc_height;
ctx->venc.u32Fps = 30;
ctx->venc.u32Gop = 50;
ctx->venc.u32BitRate = s32BitRate;
switch (encodingType)
{
case 1:
ctx->venc.enCodecType = RK_CODEC_TYPE_H265;
ctx->venc.enRcMode = VENC_RC_MODE_H265CBR;
// H264 66:Baseline 77:Main Profile 100:High Profile
// H265 0:Main Profile 1:Main 10 Profile
// MJPEG 0:Baseline
ctx->venc.stChnAttr.stVencAttr.u32Profile = 100;
break;
case 2:
ctx->venc.enCodecType = RK_CODEC_TYPE_H264;
ctx->venc.enRcMode = VENC_RC_MODE_H264CBR;
ctx->venc.stChnAttr.stVencAttr.u32Profile = 100;
break;
case 3:
ctx->venc.enCodecType = RK_CODEC_TYPE_JPEG;
break;
default:
break;
}
ctx->venc.getStreamCbFunc = venc_get_stream;
ctx->venc.s32loopCount = s32loopCnt;
ctx->venc.dstFilePath = pOutPathVenc;
ctx->venc.stChnAttr.stGopAttr.enGopMode = VENC_GOPMODE_NORMALP; // VENC_GOPMODE_SMARTP
SAMPLE_COMM_VENC_CreateChn(&ctx->venc);
// Bind VI[0] and VPSS[0]
stSrcChn.enModId = RK_ID_VI;
stSrcChn.s32DevId = ctx->vi.s32DevId;
stSrcChn.s32ChnId = ctx->vi.s32ChnId;
stDestChn.enModId = RK_ID_VPSS;
stDestChn.s32DevId = ctx->vpss.s32GrpId;
stDestChn.s32ChnId = ctx->vpss.s32ChnId;
SAMPLE_COMM_Bind(&stSrcChn, &stDestChn);
#if !defined(FILE_TEST)
// Bind VPSS[0] and VENC[0]
stSrcChn.enModId = RK_ID_VPSS;
stSrcChn.s32DevId = ctx->vpss.s32GrpId;
stSrcChn.s32ChnId = ctx->vpss.s32ChnId;
stDestChn.enModId = RK_ID_VENC;
stDestChn.s32DevId = 0;
stDestChn.s32ChnId = ctx->venc.s32ChnId;
SAMPLE_COMM_Bind(&stSrcChn, &stDestChn);
#endif
printf("%s initial finish\n", __func__);
if (mode == 0) {
while (!quit) {
sleep(1);
}
if (ctx->venc.getStreamCbFunc) {
pthread_join(ctx->venc.getStreamThread, NULL);
}
if (g_loopcount > 0) {
g_loopcount--;
printf("sample_camera_stresstest: g_loopcount(%d)\n", g_loopcount);
}
}
printf("%s exit!\n", __func__);
if (mode == 1) {
quit = true;
if (ctx->venc.getStreamCbFunc) {
pthread_join(ctx->venc.getStreamThread, NULL);
}
pthread_join(vpss_thread_id[0], NULL);
pthread_join(vpss_thread_id[1], NULL);
}
RK_MPI_MB_DestroyPool(pool);
#if !defined(FILE_TEST)
// UnBind VPSS[0] and VENC[0]
stSrcChn.enModId = RK_ID_VPSS;
stSrcChn.s32DevId = ctx->vpss.s32GrpId;
stSrcChn.s32ChnId = ctx->vpss.s32ChnId;
stDestChn.enModId = RK_ID_VENC;
stDestChn.s32DevId = 0;
stDestChn.s32ChnId = ctx->venc.s32ChnId;
SAMPLE_COMM_UnBind(&stSrcChn, &stDestChn);
printf("%s Unbind VPSS[0] - VENC[0]!\n", __func__);
// Bind VI[0] and VPSS[0]
stSrcChn.enModId = RK_ID_VI;
stSrcChn.s32DevId = ctx->vi.s32DevId;
stSrcChn.s32ChnId = ctx->vi.s32ChnId;
stDestChn.enModId = RK_ID_VPSS;
stDestChn.s32DevId = ctx->vpss.s32GrpId;
stDestChn.s32ChnId = ctx->vpss.s32ChnId;
SAMPLE_COMM_UnBind(&stSrcChn, &stDestChn);
printf("%s Unbind VI[0] - VPSS[0]!\n", __func__);
#endif
// Destroy VENC[0]
SAMPLE_COMM_VENC_DestroyChn(&ctx->venc);
// Destroy VPSS[0]
SAMPLE_COMM_VPSS_DestroyChn(&ctx->vpss);
// Destroy VI[0]
SAMPLE_COMM_VI_DestroyChn(&ctx->vi);
__FAILED:
RK_MPI_SYS_Exit();
if (iq_file_dir) {
#ifdef RKAIQ
SAMPLE_COMM_ISP_Stop(s32CamId);
#endif
}
return 0;
}
/******************************************************************************
* function : main()
* Description : main
******************************************************************************/
int main(int argc, char *argv[]) {
RK_S32 s32Ret = RK_FAILURE;
RK_S32 s32Index;
struct sigaction sa;
RK_CHAR *iq_file_dir = "/etc/iqfiles";
RK_BOOL bMultictx = RK_FALSE;
RK_S32 s32CamId = 0;
SAMPLE_MPI_CTX_S ctx;
if (argc < 2) {
print_usage(argv[0]);
return 0;
}
signal(SIGINT, sigterm_handler);
int c;
while ((c = getopt_long(argc, argv, optstr, long_options, NULL)) != -1) {
const char *tmp_optarg = optarg;
switch (c) {
case 'n':
s32Index = atoi(optarg);
break;
case 'l':
g_loopcount = atoi(optarg);
break;
case 'c':
g_framcount = atoi(optarg);
break;
case 'f':
if (!strcmp(optarg, "nv12")) {
g_compressMode = COMPRESS_MODE_NONE;
} else if (!strcmp(optarg, "afbc")) {
g_compressMode = COMPRESS_AFBC_16x16;
}
break;
case 'e':
if (!strcmp(optarg, "h265"))
{
encodingType = 1;
}
else if (!strcmp(optarg, "h264"))
{
encodingType = 2;
}
else if (!strcmp(optarg, "jpeg"))
{
encodingType = 3;
}
break;
case '?':
default:
print_usage(argv[0]);
return 0;
}
}
memset(&ctx, 0, sizeof(SAMPLE_MPI_CTX_S));
g_ctx = &ctx;
s32Ret = SAMPLE_CAMERA_VENC_Stresstest(&ctx, 0);
printf("%s finish!\n", __func__);
return 0;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
编译下载到板子后执行 ./vi_jpeg -n 1 -l 1 -c 10 -f nv12 -e jpeg,-c 表示测试的图片数量 -e 表示编码类型 (h264,h265,jpeg)
程序结束后在/tmp/路径下生成相应的文件,测试jpeg编码生成.jpeg文件,264/265 生成.bin文件
.bin的文件可以使用YUV VIEVER 查看
3、UDP发送JPEG图片
编译下载到板子后执行 ./vi_jpeg -n 1 -l 1 -c 1000 -f nv12 -e jpeg -i 192.168.110.36 -p 8000,代表拍图1000张 jpeg编码 udp服务器地址为192.168.110.36 端口为 8000
/*
* Copyright 2021 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.
*
*/
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <time.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include "sample_comm.h"
#define FILE_TEST
typedef struct _rkMpiCtx {
SAMPLE_VI_CTX_S vi;
SAMPLE_VPSS_CTX_S vpss;
SAMPLE_VENC_CTX_S venc;
} SAMPLE_MPI_CTX_S;
static int g_loopcount = 1;
static int g_framcount = 200;
static COMPRESS_MODE_E g_compressMode = COMPRESS_AFBC_16x16;
static SAMPLE_MPI_CTX_S *g_ctx;
static bool quit = false;
static void sigterm_handler(int sig) {
fprintf(stderr, "signal %d\n", sig);
g_loopcount = 0;
quit = true;
pthread_cancel(pthread_self());
}
static RK_CHAR optstr[] = "?::n:l:c:f:e:i:p:";
static const struct option long_options[] = {
{"index", required_argument, NULL, 'n'},
{"loop_count", required_argument, NULL, 'l'},
{"frame_count", required_argument, NULL, 'c'},
{"pixel_format", optional_argument, NULL, 'f'},
{NULL, 0, NULL, 0},
};
uint8_t encodingType = 0; /* 选择编码类型 */
int sockfd;
char *udpServerIp = NULL;
int udpServerPort = 0;
#define UDP_SEND_MAX_LEN ( 60 * 1024 ) /* 设置UDP一包发送的最大数量 */
/******************************************************************************
* function : show usage
******************************************************************************/
static void print_usage(const RK_CHAR *name) {
printf("Usage : %s -n <index> -l <loop count> -c <frame count> -f <pixel format>\n",
name);
printf("index:\n");
printf("\t 0)isp stresstest(IqFileDir: /etc/iqfiles ~ /usr/share/iqfiles)\n");
printf("\t 1)venc stresstest(H264 ~ H265)\n");
printf("\t 2)venc stresstest(1x ~ 0.5x resolution)\n");
printf("\t 3)vi->vps->venc stresstest\n");
printf("pixel format:\n");
printf("\t nv12) no compress\n");
printf("\t afbc) compress\n");
}
void *recv_thread(void *arg)
{
int socket_fd = *(int *)arg;
struct sockaddr_in recv_addr;
socklen_t addrlen = sizeof(recv_addr);
char recvbuf[1024] = {0};
while(1)
{
if(recvfrom(socket_fd, recvbuf, 1024, 0,(struct sockaddr*)&recv_addr,&addrlen) < 0) //1024表示本次接收的最大字节数
printf("rec error!\n");
printf("[recv from %s:%d]%s \n",inet_ntoa(*(struct in_addr*)&recv_addr.sin_addr.s_addr),ntohs(recv_addr.sin_port),recvbuf);
}
printf("%s------------------------------------------------------------------------------------------------exit\n", __func__);
pthread_exit(NULL);
}
/******************************************************************************
* function : vi thread
******************************************************************************/
static void *vi_get_stream(void *pArgs) {
SAMPLE_VI_CTX_S *ctx = (SAMPLE_VI_CTX_S *)(pArgs);
RK_S32 s32Ret = RK_FAILURE;
char name[256] = {0};
FILE *fp = RK_NULL;
void *pData = RK_NULL;
RK_S32 loopCount = 0;
if (ctx->dstFilePath) {
snprintf(name, sizeof(name), "/%s/vi_%d.bin", ctx->dstFilePath, ctx->s32DevId);
fp = fopen(name, "wb");
if (fp == RK_NULL) {
printf("chn %d can't open %s file !\n", ctx->s32DevId, ctx->dstFilePath);
quit = true;
return RK_NULL;
}
}
while (!quit) {
s32Ret = SAMPLE_COMM_VI_GetChnFrame(ctx, &pData);
if (s32Ret == RK_SUCCESS) {
if (ctx->stViFrame.stVFrame.u64PrivateData <= 0) {
// SAMPLE_COMM_VI_ReleaseChnFrame(ctx);
// continue;
}
// exit when complete
if (ctx->s32loopCount > 0) {
if (loopCount >= ctx->s32loopCount) {
SAMPLE_COMM_VI_ReleaseChnFrame(ctx);
quit = true;
break;
}
}
if (fp) {
fwrite(pData, 1, ctx->stViFrame.stVFrame.u64PrivateData, fp);
fflush(fp);
}
RK_LOGE(
"SAMPLE_COMM_VI_GetChnFrame DevId %d ok:data %p size:%llu loop:%d seq:%d "
"pts:%lld ms\n",
ctx->s32DevId, pData, ctx->stViFrame.stVFrame.u64PrivateData, loopCount,
ctx->stViFrame.stVFrame.u32TimeRef,
ctx->stViFrame.stVFrame.u64PTS / 1000);
SAMPLE_COMM_VI_ReleaseChnFrame(ctx);
loopCount++;
}
usleep(1000);
}
if (fp)
fclose(fp);
return RK_NULL;
}
/******************************************************************************
* function : vpss thread
******************************************************************************/
static RK_U8 data[2560 * 1520 * 2];
static RK_U8 data0[2560 * 1520 * 2];
static RK_U8 data1[2560 * 1520 * 2];
static void *vpss_get_stream(void *pArgs) {
SAMPLE_VPSS_CTX_S *ctx = (SAMPLE_VPSS_CTX_S *)(pArgs);
RK_S32 s32Ret = RK_FAILURE;
char name[256] = {0};
FILE *fp = RK_NULL;
FILE *fbc0 = RK_NULL;
FILE *fbc1 = RK_NULL;
void *pData = RK_NULL;
RK_S32 loopCount = 0;
VIDEO_FRAME_INFO_S stChnFrameInfos;
if (ctx->dstFilePath) {
snprintf(name, sizeof(name), "/%s/vpss_%d.yuv", ctx->dstFilePath, ctx->s32ChnId);
fp = fopen(name, "wb");
if (fp == RK_NULL) {
printf("chn %d can't open %s file !\n", ctx->s32ChnId, ctx->dstFilePath);
quit = true;
return RK_NULL;
}
}
#if 0
fbc0 = fopen("/data/vpss_1280_760_fbc.bin", "r");
if (fbc0 == RK_NULL) {
printf("can't open /data/vpss_1280_760_fbc.bin file !\n");
quit = true;
return RK_NULL;
}
fbc1 = fopen("/data/vpss_2560_1520_fbc.bin", "r");
if (fbc1 == RK_NULL) {
printf("can't open /data/vpss_2560_1520_fbc.bin file !\n");
quit = true;
return RK_NULL;
}
fread(data0, 1, 1552384, fbc0);
fread(data1, 1, 6164480, fbc1);
#endif
while (!quit) {
s32Ret = SAMPLE_COMM_VPSS_GetChnFrame(ctx, &pData);
if (s32Ret == RK_SUCCESS) {
if (ctx->stChnFrameInfos.stVFrame.u64PrivateData <= 0) {
continue;
}
#if 0
// exit when complete
if (ctx->s32loopCount > 0) {
if (loopCount >= ctx->s32loopCount) {
SAMPLE_COMM_VPSS_ReleaseChnFrame(ctx);
quit = true;
break;
}
}
#endif
// if (fp) {
// fwrite(pData, 1, ctx->stChnFrameInfos.stVFrame.u64PrivateData, fp);
// fflush(fp);
// }
#if 1
// SAMPLE_COMM_VENC_SendStream(
// &g_ctx->venc, pData, ctx->stChnFrameInfos.stVFrame.u32Width,
// ctx->stChnFrameInfos.stVFrame.u32Height,
// ctx->stChnFrameInfos.stVFrame.u64PrivateData, g_compressMode);
s32Ret = RK_MPI_VENC_SendFrame(g_ctx->venc.s32ChnId,
&ctx->stChnFrameInfos.stVFrame, -1);
if (s32Ret != RK_SUCCESS) {
RK_LOGE("RK_MPI_VENC_SendFrame fail %x", s32Ret);
}
#else
if (ctx->stChnFrameInfos.stVFrame.u32Width == 1280) {
SAMPLE_COMM_VENC_SendStream(
&g_ctx->venc, data0, ctx->stChnFrameInfos.stVFrame.u32Width,
ctx->stChnFrameInfos.stVFrame.u32Height, 1552384, g_compressMode);
} else if (ctx->stChnFrameInfos.stVFrame.u32Width == 2560) {
SAMPLE_COMM_VENC_SendStream(
&g_ctx->venc, data1, ctx->stChnFrameInfos.stVFrame.u32Width,
ctx->stChnFrameInfos.stVFrame.u32Height, 6164480, g_compressMode);
}
#endif
printf("SAMPLE_COMM_VPSS_GetChnFrame DevId %d ok:data %p size:%llu loop:%d "
"seq:%d "
"pts:%lld ms\n",
ctx->s32GrpId, pData, ctx->stChnFrameInfos.stVFrame.u64PrivateData,
loopCount, ctx->stChnFrameInfos.stVFrame.u32TimeRef,
ctx->stChnFrameInfos.stVFrame.u64PTS / 1000);
SAMPLE_COMM_VPSS_ReleaseChnFrame(ctx);
loopCount++;
}
usleep(1000);
}
if (fp)
fclose(fp);
return RK_NULL;
}
static void *vpss_send_stream(void *pArgs) {
SAMPLE_VPSS_CTX_S *ctx = (SAMPLE_VPSS_CTX_S *)(pArgs);
RK_S32 s32Ret = RK_FAILURE;
FILE *fbc = RK_NULL;
void *pData = RK_NULL;
RK_S32 loopCount = 0;
fbc = fopen("/data/vpss_2560_1520_fbc.bin", "r");
if (fbc == RK_NULL) {
printf("can't open /data/vpss_2560_1520_fbc.bin file !\n");
quit = true;
return RK_NULL;
}
fread(data, 1, 6164480, fbc);
while (!quit) {
// exit when complete
if (ctx->s32loopCount > 0) {
if (loopCount >= ctx->s32loopCount) {
quit = true;
break;
}
}
SAMPLE_COMM_VPSS_SendStream(&g_ctx->vpss, data, 2560, 1520, 6164480,
g_compressMode);
loopCount++;
usleep(20000);
}
if (fbc)
fclose(fbc);
return RK_NULL;
}
/******************************************************************************
* function : venc thread
******************************************************************************/
static void *venc_get_stream(void *pArgs) {
SAMPLE_VENC_CTX_S *ctx = (SAMPLE_VENC_CTX_S *)(pArgs);
RK_S32 s32Ret = RK_FAILURE;
char name[256] = {0};
FILE *fp = RK_NULL;
void *pData = RK_NULL;
RK_S32 loopCount = 0;
if (ctx->dstFilePath) {
if(3 != encodingType)
{
snprintf(name, sizeof(name), "/%s/venc_%d.bin", ctx->dstFilePath, ctx->s32ChnId);
fp = fopen(name, "wb");
if (fp == RK_NULL) {
printf("chn %d can't open %s file !\n", ctx->s32ChnId, ctx->dstFilePath);
quit = true;
return RK_NULL;
}
}
}
while (!quit) {
s32Ret = SAMPLE_COMM_VENC_GetStream(ctx, &pData);
if (s32Ret == RK_SUCCESS) {
// exit when complete
if (ctx->s32loopCount > 0) {
if (loopCount >= ctx->s32loopCount) {
SAMPLE_COMM_VENC_ReleaseStream(ctx);
quit = true;
break;
}
// if (fp)
// {
// fwrite(pData, 1, ctx->stFrame.pstPack->u32Len, fp);
// fflush(fp);
// }
if(3 != encodingType)
{
fwrite(pData, 1, ctx->stFrame.pstPack->u32Len, fp);
fflush(fp);
}
else
{
static uint16_t pictureIndex = 0;
snprintf(name, sizeof(name), "/%s/venc_%d.jpeg", ctx->dstFilePath, pictureIndex);
fp = fopen(name, "wb");
if (fp == RK_NULL) {
printf("chn %d can't open %s file !\n", ctx->s32ChnId, ctx->dstFilePath);
quit = true;
return RK_NULL;
}
// fwrite(pData, 1, ctx->stFrame.pstPack->u32Len, fp);
// fflush(fp);
pictureIndex++;
printf("pictureIndex = %d",pictureIndex);
}
char picInfo[100];
unsigned int preSendPicLen = ctx->stFrame.pstPack->u32Len;
int sendCnt = 0;
unsigned char * startPalce = pData;
struct sockaddr_in sock_addr = {0};
sock_addr.sin_family = AF_INET; // 设置地址族为IPv4
sock_addr.sin_port = htons(udpServerPort); // 设置地址的端口号信息
sock_addr.sin_addr.s_addr = inet_addr(udpServerIp); // 设置IP地址
sprintf(picInfo,"%s,%d,%ld,%s","frameData",ctx->stFrame.pstPack->u32Len,0,"123");
sendto(sockfd,picInfo,strlen(picInfo), 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr));/* 发送图片大小数据包 */
/* 发送图片数据包 */
if(preSendPicLen > UDP_SEND_MAX_LEN) /* 如果图片的大小大于设定的最大值,分包发送 */
{
// ESP_LOGI(camera,"preSendPicLen = %d \r\n",preSendPicLen);
while(UDP_SEND_MAX_LEN * (sendCnt + 1) < preSendPicLen)
{
sendto(sockfd,startPalce + (UDP_SEND_MAX_LEN * sendCnt),UDP_SEND_MAX_LEN, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
sendCnt++;
}
sendto(sockfd,startPalce + (UDP_SEND_MAX_LEN * sendCnt),preSendPicLen % UDP_SEND_MAX_LEN, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
sendCnt = 0;
}
else /* 如果图片的大小没有大于设定的最大值,直接发送 */
{
sendto(sockfd,startPalce,preSendPicLen, 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
}
}
PrintStreamDetails(ctx->s32ChnId, ctx->stFrame.pstPack->u32Len);
RK_LOGD("chn:%d, loopCount:%d wd:%d\n", ctx->s32ChnId, loopCount,
ctx->stFrame.pstPack->u32Len);
SAMPLE_COMM_VENC_ReleaseStream(ctx);
loopCount++;
}
usleep(1000);
}
if (fp)
fclose(fp);
return RK_NULL;
}
int SAMPLE_CAMERA_VENC_Stresstest(SAMPLE_MPI_CTX_S *ctx, RK_S32 mode) {
RK_S32 s32Ret = RK_FAILURE;
int video_width = 2560;
int video_height = 1520;
int venc_width = 2560;
int venc_height = 1520;
RK_CHAR *pOutPathVenc = NULL;
RK_CHAR *iq_file_dir = "/etc/iqfiles";
RK_CHAR *pCodecName = "H264";
CODEC_TYPE_E enCodecType = RK_CODEC_TYPE_H264;
VENC_RC_MODE_E enRcMode = VENC_RC_MODE_H264CBR;
RK_S32 s32BitRate = 10 * 1024;
RK_S32 s32CamId = 0;
MPP_CHN_S stSrcChn, stDestChn;
RK_S32 s32loopCnt = g_framcount;
RK_S32 i;
RK_BOOL bMultictx = RK_FALSE;
quit = false;
pthread_t vpss_thread_id[2];
if (mode == 1) {
s32loopCnt = -1;
}
pOutPathVenc ="tmp";
printf("#CameraIdx: %d\n", s32CamId);
printf("#CodecName:%s\n", pCodecName);
printf("#Output Path: %s\n", pOutPathVenc);
if (iq_file_dir) {
#ifdef RKAIQ
printf("#Rkaiq XML DirPath: %s\n", iq_file_dir);
printf("#bMultictx: %d\n\n", bMultictx);
rk_aiq_working_mode_t hdr_mode = RK_AIQ_WORKING_MODE_NORMAL;
SAMPLE_COMM_ISP_Init(s32CamId, hdr_mode, bMultictx, iq_file_dir);
SAMPLE_COMM_ISP_Run(s32CamId);
#endif
}
if (RK_MPI_SYS_Init() != RK_SUCCESS) {
goto __FAILED;
}
MB_POOL pool = MB_INVALID_POOLID;
MB_POOL_CONFIG_S stMbPoolCfg;
memset(&stMbPoolCfg, 0, sizeof(MB_POOL_CONFIG_S));
stMbPoolCfg.u64MBSize = video_width * video_height * 2;
stMbPoolCfg.u32MBCnt = 10;
stMbPoolCfg.enAllocType = MB_ALLOC_TYPE_DMA;
pool = RK_MPI_MB_CreatePool(&stMbPoolCfg);
ctx->vpss.pool = ctx->venc.pool = pool;
// Init VI[0]
ctx->vi.u32Width = video_width;
ctx->vi.u32Height = video_height;
ctx->vi.s32DevId = s32CamId;
ctx->vi.u32PipeId = ctx->vi.s32DevId;
ctx->vi.s32ChnId = 2; // rk3588 mainpath:0 selfpath:1 fbcpath:2
ctx->vi.stChnAttr.stIspOpt.u32BufCount = 4;
ctx->vi.stChnAttr.stIspOpt.enMemoryType = VI_V4L2_MEMORY_TYPE_DMABUF;
ctx->vi.stChnAttr.u32Depth = 1;
ctx->vi.stChnAttr.enPixelFormat = RK_FMT_YUV420SP;
ctx->vi.stChnAttr.enCompressMode = g_compressMode;
ctx->vi.stChnAttr.stFrameRate.s32SrcFrameRate = -1;
ctx->vi.stChnAttr.stFrameRate.s32DstFrameRate = -1;
if (g_compressMode == COMPRESS_MODE_NONE) {
ctx->vi.s32ChnId = 0;
}
SAMPLE_COMM_VI_CreateChn(&ctx->vi);
// Init VPSS[0]
ctx->vpss.s32GrpId = 0;
ctx->vpss.s32ChnId = 0;
// RGA_device: VIDEO_PROC_DEV_RGA GPU_device: VIDEO_PROC_DEV_GPU
ctx->vpss.enVProcDevType = VIDEO_PROC_DEV_RGA;
// ctx->vpss.enVProcDevType = VIDEO_PROC_DEV_GPU;
ctx->vpss.s32loopCount = s32loopCnt;
ctx->vpss.stGrpVpssAttr.enPixelFormat = RK_FMT_YUV420SP;
ctx->vpss.stGrpVpssAttr.enCompressMode = g_compressMode;
ctx->vpss.stCropInfo.bEnable = RK_FALSE;
ctx->vpss.stCropInfo.enCropCoordinate = VPSS_CROP_RATIO_COOR;
ctx->vpss.stCropInfo.stCropRect.s32X = 0;
ctx->vpss.stCropInfo.stCropRect.s32Y = 0;
ctx->vpss.stCropInfo.stCropRect.u32Width = video_width;
ctx->vpss.stCropInfo.stCropRect.u32Height = video_height;
ctx->vpss.stChnCropInfo[0].bEnable = RK_TRUE;
ctx->vpss.stChnCropInfo[0].enCropCoordinate = VPSS_CROP_RATIO_COOR;
ctx->vpss.stChnCropInfo[0].stCropRect.s32X = 0;
ctx->vpss.stChnCropInfo[0].stCropRect.s32Y = 0;
ctx->vpss.stChnCropInfo[0].stCropRect.u32Width = venc_width * 1000 / video_width;
ctx->vpss.stChnCropInfo[0].stCropRect.u32Height = venc_height * 1000 / video_height;
ctx->vpss.s32ChnRotation[0] = ROTATION_0;
ctx->vpss.stRotationEx[0].bEnable = RK_FALSE;
ctx->vpss.stRotationEx[0].stRotationEx.u32Angle = 60;
ctx->vpss.stVpssChnAttr[0].enChnMode = VPSS_CHN_MODE_USER;
ctx->vpss.stVpssChnAttr[0].enDynamicRange = DYNAMIC_RANGE_SDR8;
ctx->vpss.stVpssChnAttr[0].enPixelFormat = RK_FMT_YUV420SP;
ctx->vpss.stVpssChnAttr[0].enCompressMode = g_compressMode;
ctx->vpss.stVpssChnAttr[0].stFrameRate.s32SrcFrameRate = -1;
ctx->vpss.stVpssChnAttr[0].stFrameRate.s32DstFrameRate = -1;
ctx->vpss.stVpssChnAttr[0].u32Width = venc_width;
ctx->vpss.stVpssChnAttr[0].u32Height = venc_height;
ctx->vpss.stVpssChnAttr[0].u32Depth = 2;
ctx->vpss.dstFilePath = pOutPathVenc;
SAMPLE_COMM_VPSS_CreateChn(&ctx->vpss);
#if defined(FILE_TEST)
pthread_create(&vpss_thread_id[0], 0, vpss_get_stream, (void *)(&ctx->vpss));
// pthread_create(&vpss_thread_id[1], 0, vpss_send_stream, (void *)(&ctx->vpss));
#endif
// Init VENC[0]
ctx->venc.s32ChnId = 0;
ctx->venc.u32Width = venc_width;
ctx->venc.u32Height = venc_height;
ctx->venc.u32Fps = 30;
ctx->venc.u32Gop = 50;
ctx->venc.u32BitRate = s32BitRate;
switch (encodingType)
{
case 1:
ctx->venc.enCodecType = RK_CODEC_TYPE_H265;
ctx->venc.enRcMode = VENC_RC_MODE_H265CBR;
// H264 66:Baseline 77:Main Profile 100:High Profile
// H265 0:Main Profile 1:Main 10 Profile
// MJPEG 0:Baseline
ctx->venc.stChnAttr.stVencAttr.u32Profile = 100;
break;
case 2:
ctx->venc.enCodecType = RK_CODEC_TYPE_H264;
ctx->venc.enRcMode = VENC_RC_MODE_H264CBR;
ctx->venc.stChnAttr.stVencAttr.u32Profile = 100;
break;
case 3:
ctx->venc.enCodecType = RK_CODEC_TYPE_JPEG;
break;
default:
break;
}
ctx->venc.getStreamCbFunc = venc_get_stream;
ctx->venc.s32loopCount = s32loopCnt;
ctx->venc.dstFilePath = pOutPathVenc;
ctx->venc.stChnAttr.stGopAttr.enGopMode = VENC_GOPMODE_NORMALP; // VENC_GOPMODE_SMARTP
SAMPLE_COMM_VENC_CreateChn(&ctx->venc);
// Bind VI[0] and VPSS[0]
stSrcChn.enModId = RK_ID_VI;
stSrcChn.s32DevId = ctx->vi.s32DevId;
stSrcChn.s32ChnId = ctx->vi.s32ChnId;
stDestChn.enModId = RK_ID_VPSS;
stDestChn.s32DevId = ctx->vpss.s32GrpId;
stDestChn.s32ChnId = ctx->vpss.s32ChnId;
SAMPLE_COMM_Bind(&stSrcChn, &stDestChn);
#if !defined(FILE_TEST)
// Bind VPSS[0] and VENC[0]
stSrcChn.enModId = RK_ID_VPSS;
stSrcChn.s32DevId = ctx->vpss.s32GrpId;
stSrcChn.s32ChnId = ctx->vpss.s32ChnId;
stDestChn.enModId = RK_ID_VENC;
stDestChn.s32DevId = 0;
stDestChn.s32ChnId = ctx->venc.s32ChnId;
SAMPLE_COMM_Bind(&stSrcChn, &stDestChn);
#endif
printf("%s initial finish\n", __func__);
if (mode == 0) {
while (!quit) {
sleep(1);
}
if (ctx->venc.getStreamCbFunc) {
pthread_join(ctx->venc.getStreamThread, NULL);
}
if (g_loopcount > 0) {
g_loopcount--;
printf("sample_camera_stresstest: g_loopcount(%d)\n", g_loopcount);
}
}
printf("%s exit!\n", __func__);
if (mode == 1) {
quit = true;
if (ctx->venc.getStreamCbFunc) {
pthread_join(ctx->venc.getStreamThread, NULL);
}
pthread_join(vpss_thread_id[0], NULL);
pthread_join(vpss_thread_id[1], NULL);
}
RK_MPI_MB_DestroyPool(pool);
#if !defined(FILE_TEST)
// UnBind VPSS[0] and VENC[0]
stSrcChn.enModId = RK_ID_VPSS;
stSrcChn.s32DevId = ctx->vpss.s32GrpId;
stSrcChn.s32ChnId = ctx->vpss.s32ChnId;
stDestChn.enModId = RK_ID_VENC;
stDestChn.s32DevId = 0;
stDestChn.s32ChnId = ctx->venc.s32ChnId;
SAMPLE_COMM_UnBind(&stSrcChn, &stDestChn);
printf("%s Unbind VPSS[0] - VENC[0]!\n", __func__);
// Bind VI[0] and VPSS[0]
stSrcChn.enModId = RK_ID_VI;
stSrcChn.s32DevId = ctx->vi.s32DevId;
stSrcChn.s32ChnId = ctx->vi.s32ChnId;
stDestChn.enModId = RK_ID_VPSS;
stDestChn.s32DevId = ctx->vpss.s32GrpId;
stDestChn.s32ChnId = ctx->vpss.s32ChnId;
SAMPLE_COMM_UnBind(&stSrcChn, &stDestChn);
printf("%s Unbind VI[0] - VPSS[0]!\n", __func__);
#endif
// Destroy VENC[0]
SAMPLE_COMM_VENC_DestroyChn(&ctx->venc);
// Destroy VPSS[0]
SAMPLE_COMM_VPSS_DestroyChn(&ctx->vpss);
// Destroy VI[0]
SAMPLE_COMM_VI_DestroyChn(&ctx->vi);
__FAILED:
RK_MPI_SYS_Exit();
if (iq_file_dir) {
#ifdef RKAIQ
SAMPLE_COMM_ISP_Stop(s32CamId);
#endif
}
return 0;
}
/******************************************************************************
* function : main()
* Description : main
******************************************************************************/
int main(int argc, char *argv[]) {
RK_S32 s32Ret = RK_FAILURE;
RK_S32 s32Index;
struct sigaction sa;
RK_CHAR *iq_file_dir = "/etc/iqfiles";
RK_BOOL bMultictx = RK_FALSE;
RK_S32 s32CamId = 0;
SAMPLE_MPI_CTX_S ctx;
if (argc < 2) {
print_usage(argv[0]);
return 0;
}
signal(SIGINT, sigterm_handler);
int c;
while ((c = getopt_long(argc, argv, optstr, long_options, NULL)) != -1) {
const char *tmp_optarg = optarg;
switch (c) {
case 'n':
s32Index = atoi(optarg);
break;
case 'l':
g_loopcount = atoi(optarg);
break;
case 'c':
g_framcount = atoi(optarg);
break;
case 'f':
if (!strcmp(optarg, "nv12")) {
g_compressMode = COMPRESS_MODE_NONE;
} else if (!strcmp(optarg, "afbc")) {
g_compressMode = COMPRESS_AFBC_16x16;
}
break;
case 'e':
if (!strcmp(optarg, "h265"))
{
encodingType = 1;
}
else if (!strcmp(optarg, "h264"))
{
encodingType = 2;
}
else if (!strcmp(optarg, "jpeg"))
{
encodingType = 3;
}
break;
case 'i':
udpServerIp = optarg;
break;
case 'p':
udpServerPort = atoi(optarg);
break;
case '?':
default:
print_usage(argv[0]);
return 0;
}
}
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (-1 == sockfd)
{
printf("socket open err.");
return -1;
}
// 2、绑定本地的相关信息,如果不绑定,则系统会随机分配一个端口号
struct sockaddr_in local_addr = {0};
local_addr.sin_family = AF_INET; //使用IPv4地址
local_addr.sin_addr.s_addr = inet_addr(udpServerIp); //本机IP地址
local_addr.sin_port = htons(udpServerPort); //端口
// local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//将套接字和IP、端口绑定
if (bind(sockfd, (struct sockaddr*)&local_addr, sizeof(local_addr)) < 0)
printf("bind error");
// 3、打印本机ip地址和端口号
printf("IP地址: %s\n", udpServerIp);
printf("端口号: %d\n", udpServerPort);
pthread_t udpRecThread = -1;
// 4、创建一个线程,用来接收数据
pthread_create(&udpRecThread, NULL, recv_thread, &sockfd);
// // 5、等待输入数据,然后发送出去,直到输入的数据为'quit','192.168.0.107'表示目的ip地址,8266表示目的端口号
// struct sockaddr_in sock_addr = {0};
// sock_addr.sin_family = AF_INET; // 设置地址族为IPv4
// sock_addr.sin_port = htons(8266); // 设置地址的端口号信息
// sock_addr.sin_addr.s_addr = inet_addr(udpServerIp); // 设置IP地址
// char sendbuf[1024]={"hello world, I am a UDP socket."};
// int cnt = 10;
// while(cnt--)
// {
// printf("please input a string.input 'quit' to quit.\n");
// scanf("%s",sendbuf);
// if(strcmp(sendbuf,"quit") == 0)
// break;
// sendto(sockfd, sendbuf, strlen(sendbuf), 0, (struct sockaddr*)&sock_addr, sizeof(sock_addr));
// }
memset(&ctx, 0, sizeof(SAMPLE_MPI_CTX_S));
g_ctx = &ctx;
s32Ret = SAMPLE_CAMERA_VENC_Stresstest(&ctx, 0);
printf("%s finish!\n", __func__);
// 等待线程退出
pthread_join(recv_thread, NULL);
close(sockfd);
return 0;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
这里拿了之前自己做的UDP收图的程序
实际的效果:
[localvideo]ca1746bb589066034be771abefc2b30b[/localvideo]