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收图的程序
实际的效果:
查看h264/265视频
用到的文件
看来都买了那个专用的摄像头,我还是白嫖用USB摄像头
引用: LitchiCheng 发表于 2024-2-20 09:37 看来都买了那个专用的摄像头,我还是白嫖用USB摄像头
主要是测试跑压缩这块要方便一点
专用的摄像头要插在板子的哪?
引用: wangerxian 发表于 2024-2-20 17:39 专用的摄像头要插在板子的哪?
引用: 0x4C 发表于 2024-2-20 19:29 CSI Camera | LUCKFOX WIKI
四十多米倒还行。有摄像头后续还可以跑一些实时图像识别~
引用: LitchiCheng 发表于 2024-2-20 09:37 看来都买了那个专用的摄像头,我还是白嫖用USB摄像头
USB摄像头接板子的哪哦?
你好,新手不太懂,求教一下。我SDK编译好了,按你的教程,偏绿的图片也拍出来了,那个simple_venc_jpeg文件更改后放在哪个位置,需要用什么命令和参数编译,谢谢!
引用: LOI-T_T-o 发表于 2024-3-27 17:44 你好,新手不太懂,求教一下。我SDK编译好了,按你的教程,偏绿的图片也拍出来了,那个simple_venc_jpeg文 ...
这个就是SDK下的例程代码,直接修改就行,然后编译SDK就好了,编译完成后在对应的输出路径下就有最后的程序了
在你设置好SDK的编译环境之后进入/luckfox-pico/media/samples路径下执行make
然后同级目录下的out/bin里就有对应的输出程序
引用: 0x4C 发表于 2024-3-28 20:37 这个就是SDK下的例程代码,直接修改就行,然后编译SDK就好了,编译完成后在对应的输出路径下就有最后的程 ...
好的,我试一下,谢谢!
UDP 收图的程序操作方法能share下么,需要先在板子上开启UDP服务吗?
板子作为server,Windows机器作为client这样?
谢谢!!!
本帖最后由 八月长安ii 于 2024-6-4 17:29 编辑