IMX8MP录像功能测试

IMX8MP录像功能测试

目录

1.开发环境搭建

2.编译hello world

3.录像功能测试

4.参考资料


1.开发环境搭建

1.1 开发工具链和源码


开发环境的搭建按照手册上的命令搭建即可,可以更换其中的安装目录,其中需要sdk的目录和工具链目录统一放置在/opt/imx8/目录下,交叉编译所需要的工具链所在目录/opt/imx8/sdk;另一个是/opt/imx8/source,该目录是工程的源码所在目录。

获取sdk和交叉工具链指令如下

#创建目录
mkdir -p /opt/imx8/sdk
cd /opt/imx8/sdk

#解压sdk,过程需要知道sdk目录
./fsl-imx-xwayland-glibc-x86_64-meta-toolchain-qt5-aarch64-\
imx8mpevk-toolchain-5.4-zeus.sh

#配置环境
source ./environment-setup-aarch64-poky-linux

#获取版本信息
aarch64-poky-linux-gcc -v

imx8mpsdktree

编译工具在/opt/imx8/sdk/sysroots/x86_64-pokysdk-linux/usr/bin/aarch64-poky-linux/
源码则解压到/opt/imx8/source目录下;

1.2编译源码
编译前需要先配置环境,使其生效

  • 编译内核
#配置环境
source ./environment-setup-aarch64-poky-linux
#查看环境变量是否设置生效
aarch64-poky-linux-gcc -v
#编译 编译完的文件在/opt/imx8/source/OK8MP-linux-sdk/images/kernel/
./build.sh kernel
#如果要清除内核,执行以下指令
./build.sh kernel_clean
  • 编译测试程序
#配置环境
source ./environment-setup-aarch64-poky-linux
#查看环境变量是否设置生效
aarch64-poky-linux-gcc -v
#编译 编译完的文件在/opt/imx8/source/OK8MP-linux-sdk/OK8MP-linux-fs/rootfs/usr/bin/
./build.sh apps
#如果要清除内核,执行以下指令
./build.sh clean_apps
  • 编译freertos
#配置环境
source ./environment-setup-aarch64-poky-linux
#查看环境变量是否设置生效
aarch64-poky-linux-gcc -v
#编译 编译完的文件在/opt/imx8/source/OK8MP-linux-sdk/OK8MP-linux-fs/rootfs/lib/firmware/
./build.sh freertos_demo
#如果要清除内核,执行以下指令
./build.sh clean_freertos_demo

2.编译hello world

先编译最简单的hello程序检查编译环境配置是否有问题,实际上是真的有问题,这个开发工具链有些bug,导致编译的时候会提示找不到一些最基本的头文件;
测试程序代码如下

#include <stdio.h>
int main()
{
   printf("Hello, World!\n");
   return 0;
}

编译指令

#配置环境
source /opt/imx8/sdk/environment-setup-aarch64-poky-linux
#编译程序
aarch64-poky-linux-gcc ./hello.c -o hello

会出现编译报错问题
02imx8helloerror

最简单的标准库头文件都没有找到,显然环境有问题,编译配置环境,最终定位到需要指定编译链的目录;

aarch64-poky-linux-gcc --sysroot=/opt/imx8/sdk/sysroots/aarch64-poky-linux ./hello.c -o hello #需要添加--sysroot指定编译链路径

3.录像功能测试
  • 3.1应用程序编译

这个文件夹不仅可以测试录像的功能,也能测试其他模块功能,文件夹的目录结构如下所示;

03imx8dirtree


CC = aarch64-poky-linux-gcc
CXX = aarch64-poky-linux-g++

export CURDIR = $(shell pwd)
export INSDIR = $(CURDIR)/output
export SDKDIR = /opt/imx8/sdk

TARGET = testRec

SRCS += $(CURDIR)/src/*
OBJS    := $(SRCS:%.c=%.o)
OBJS	+= $(SRCPPS:%.cpp=%.o)

export BUILD_SH			= $(CURDIR)/script/BUILD.sh

CFLAGS = 
CFLAGS += --sysroot=$(SDKDIR)/sysroots/aarch64-poky-linux
CFLAGS += -I$(CURDIR)/include
CFLAGS += -Wall -g

LD_FLAGS += -lpthread -lm 
LD_FLAGS += -L$(CURDIR)/lib

$(TARGET):$(OBJS)
	@/bin/echo "************ Compiling Start ***********"
	$(CC) $(CFLAGS) $(LD_FLAGS) $^ -o $@  
	@/bin/echo "************ Compiling Finish ***********"

$(OBJS):
ifneq ($(SRCS), )
	for x in $(SRCS);	\
	do			\
		$(CC) -MM -MT"$${x%.c}.o" $(CFLAGS) $$x >> $@;\
	done
endif
ifneq ($(SRCPPS), )
	for x in $(SRCPPS);	\
	do			\
		$(CXX) -MM -MT "$${x%.cpp}.o" $(CPPFLAGS) $$x >> $@;\
	done	
endif

clean:
	$(RM) *.o $(TARGET) -r

install:
	cp -rf $(TARGET) $(INSDIR)
	$(RM) $(CURDIR)/$(TARGET)

# vim:noet:sw=4:ts=4

直接执行指令,即可在安装目录下获取到测试的目标文件,将其拷贝到板端即可在板端运行;

make
make install
  • 3.2 测试源代码
#include <stdio.h>
#include <pthread.h>
#include <stdbool.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <malloc.h>
#include <time.h>
#include <sys/time.h>
#include <string.h>
#include <sys/types.h>


#define THREAD_NUM 3           /* 线程数量 */
#define WRITE_SIZE (256*1024)  /* 写入数据量 */

/* 获取当前时间(us) */
static long long int microtime(void)
{
    struct timeval time;
    gettimeofday(&time, NULL);
    long long int microsec = ((long long)time.tv_sec * 1000000) + time.tv_usec;
    return microsec;
}

/* 写文件线程 */
void *write_file_body(void *arg)
{
    int *pChn = (int *)arg;
    char szPath[64] = {0};
    char szCmd[128] = {0};
    long long s64CurTime = 0;
    long long s64LastTime = 0;
    char data[WRITE_SIZE] = {0};
    int ret = 0;
    int cnt = 0;
    sprintf(szPath, "/run/media/sda1/testRec/test%d",*pChn);//卡挂载目录,一般是udev挂载,也可以自己挂载
    sprintf(szCmd, "rm -rf %s",szPath);
    system(szCmd);
    FILE* fp = fopen(szPath, "ab+");
    if (NULL == fp)
    {
        printf("open file %s filed \n",szPath);
    }

    while(1)
    {
        s64LastTime = microtime();
        sprintf(data, "%d",cnt);
        if (cnt <= 1000)
        {
            ret = fwrite(data, WRITE_SIZE, 1,fp);
            if (0 == ret)
            {
                 printf("write failed\n");
            }
        }
	    else
        {
	        break;
        }
        
        if(cnt == 1000)
        {
            fclose(fp);
            printf("close file %d\n",*pChn);
        }
        
        cnt++;
	    s64CurTime = microtime();
        printf("chn[%d] %lld us\n",*pChn, (s64CurTime - s64LastTime));
    }
    return NULL;
}
/* 主线程 */
int main()
{
    pthread_t thread_id;
    static int num[3] = {0};
    int ret = 0;
    int i = 0;
    for(i=0; i<THREAD_NUM; i++)
    {
        num[i] = i;
        ret = pthread_create(&thread_id, NULL, write_file_body, &num[i]);
        if (0 != ret)
        {
            printf("pthread[%d] create failed! [err=%d]\n",i, ret);
            return ret;
        }        
    }
    while(1)
    {
         usleep(1000000);
         //sync();//定时回写
    }

    return 0;
}

​ (1)256k (2)128k (3)64k
256k 128k 64k

上图分别为256*1024 128*102464*1024字节写入卡内,显然,256k128k的三路同时写入耗时超过40ms,对于视频的帧率而言会导致丢帧的问题,而64k字节写入会出现写入不太稳定的问题,这个不稳定是快到尾部的时候写入同步数据到卡上引起的,另一方面,写入卡耗时还由于这张卡是通过USB Hub连接到读卡器上的sd卡,因此耗时也会比在设备端的sd卡耗时更长,具体的可以根据硬件设计完再测试。

  • 3.3 定时回写测试

在主循环中通过手动定时调用sync定时将数据回写,在128k的写入速度写测试,如果添加定时回写,在写1000帧快结束的时候,大部分情况会有耗时比不添加的要少一些,但这个不是绝对的,与系统当前的负载有关,但是大部分情况还是会比不添加手动同步的要耗时少,在64k的写入速度下效果不太明显。

(1) 256k定时手动同步 (2)128k定时手动同步 (3)64k定时手动同步
256k 128k64k

  • 3.4 同步时间间隔

既然同步在一定情况下可以平均负载,降低部分写数据的耗时,那是否可以不停的同步呢?经过测试发现,降低同步时间在一定范围内是可以降低写数据耗时,但是会降低系统处理其他操作的性能,同时当负载过大的情况下,不断的同步会增加操作系统的负担,不利于整体的性能,因此同步操作需要实际测试指定一个比较合适的时间范围;


4.参考资料
*** 不足之处,敬请指出,谢谢! ***
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值