[原创] 【Luckfox幸狐 RV1106 Linux 开发板使用】 SC3336拍摄

0x4C   2024-2-20 05:17 楼主

Luckfox的这块RV1106开发板是对SC3336进行了支持的,同时RV1106有着强大硬编码能力

本篇主要是实现使用SC3336来拍图,同时将图像进行JPEG硬编码然后通过网络发送出去

image.png  

1、基本JPEG压缩测试

    源码路径:/luckfox-pico/media/samples/simple_venc_jpeg.c

    测试时用串口调试,连接网线到路由器来传输文件

    串口连接:

     image.png  

    插上网线,ifconfig看下设备的IP地址

image.png  

    键盘WIN+E,输入设备的IP地址:192.168.110.90

    用户名为 root,密码为 luckfox

image.png  

    连接后就可以看见板子的文件了

image.png  

    默认的SDK编译完成后,在/oem/usr/bin下已经有测试的例程程序了

     image.png  

    运行前先关闭开机自启的IPC程序 killall rkipc

    输入  ./simple_venc_jpeg -w 1920 -h 1080 运行程序

    在命令行每回车一次就会拍一张图片,对应的图片会保存在 /tmp/*.jpeg 

     image.png  

    最后输入 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;
}

    重新编译后下载到板子上,重新测试就可以看到正常的图片了

image.png      

    左修改前,右修改后  可以看见拍摄的差异还是很明显的

2、图像VI和JPEG压缩非绑定

    例程中图像输入后就直接送入JPEG压缩了,但是我们不总是希望这样。我们希望还可以对输入的图像(例如这里输入的YUV图像)进行自己的处理,处理之后再进行压缩,这里提供一种我测试的方法。

    新建一个文件用来测试代码 vi_jpeg.c

    修改media下的Makefile文件,添加

vi_jpeg: vi_jpeg.c
	@$(SAMPLE_CC) $^ -o $@ $(SAMPLE_CFLAGS) $(LD_FLAGS)

     屏幕截图 2024-02-19 041755.png  

    代码参考/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文件

     image.png  

    .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收图的程序

    实际的效果:

jpeg的udp方式推视频流

 

本帖最后由 0x4C 于 2024-2-20 11:39 编辑

回复评论 (12)

实际的效果那里没有,是不是视频上传忘记点击名称,插入啦?

点赞  2024-2-20 09:09

看来都买了那个专用的摄像头,我还是白嫖用USB摄像头

点赞  2024-2-20 09:37
引用: nmg 发表于 2024-2-20 09:09 实际的效果那里没有,是不是视频上传忘记点击名称,插入啦?

第一次用,不太懂 哈哈哈

重新添加了

点赞  2024-2-20 11:42
引用: LitchiCheng 发表于 2024-2-20 09:37 看来都买了那个专用的摄像头,我还是白嫖用USB摄像头

主要是测试跑压缩这块要方便一点

点赞  2024-2-20 11:45

专用的摄像头要插在板子的哪?

点赞  2024-2-20 17:39
引用: wangerxian 发表于 2024-2-20 17:39 专用的摄像头要插在板子的哪?

CSI Camera | LUCKFOX WIKI

点赞  2024-2-20 19:29
引用: 0x4C 发表于 2024-2-20 19:29 CSI Camera | LUCKFOX WIKI

四十多米倒还行。有摄像头后续还可以跑一些实时图像识别~

点赞  2024-2-21 09:35
引用: LitchiCheng 发表于 2024-2-20 09:37 看来都买了那个专用的摄像头,我还是白嫖用USB摄像头

USB摄像头接板子的哪哦?

点赞  2024-2-21 09:35

你好,新手不太懂,求教一下。我SDK编译好了,按你的教程,偏绿的图片也拍出来了,那个simple_venc_jpeg文件更改后放在哪个位置,需要用什么命令和参数编译,谢谢!

点赞  2024-3-27 17:44
引用: LOI-T_T-o 发表于 2024-3-27 17:44 你好,新手不太懂,求教一下。我SDK编译好了,按你的教程,偏绿的图片也拍出来了,那个simple_venc_jpeg文 ...

这个就是SDK下的例程代码,直接修改就行,然后编译SDK就好了,编译完成后在对应的输出路径下就有最后的程序了

在你设置好SDK的编译环境之后进入/luckfox-pico/media/samples路径下执行make

然后同级目录下的out/bin里就有对应的输出程序

点赞  2024-3-28 20:37
引用: 0x4C 发表于 2024-3-28 20:37 这个就是SDK下的例程代码,直接修改就行,然后编译SDK就好了,编译完成后在对应的输出路径下就有最后的程 ...

好的,我试一下,谢谢!

点赞  2024-3-29 22:10

UDP 收图的程序操作方法能share下么,需要先在板子上开启UDP服务吗?

板子作为server,Windows机器作为client这样?

 谢谢!!!

本帖最后由 八月长安ii 于 2024-6-4 17:29 编辑
点赞 (1) 2024-6-4 13:53
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复