ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Firefly1126中RKMedia中摄像头录制程序编写

2022-07-01 20:00:11  阅读:214  来源: 互联网

标签:attr vi chn Firefly1126 RKMedia venc printf 摄像头 RK


Firefly1126中RKMedia中摄像头录制程序编写

1,录制视频主要流程

主要流程可分为开启录制,从摄像头获取码流,码流编码,编码保存,本录制程序中使用芯片为RV1126,摄像头为USB摄像头,分辨率为640*480,生图格式为YUYV422。

2,参考代码

主要参考代码有原厂中rkmedia_vi_venc_test.c与rkmedia_venc_local_file_test.c两个文件,新文件命名为rkmedia_vi_venc_local_file_test.c

3,添加编译信息

在同原厂SDK同一目录下sdk//external/rkmedia/examples中的CMakeList.txt中添加编译信息如下:

#--------------------------
# rkmedia_vi_venc_local_file_test
#--------------------------
add_executable(rkmedia_vi_venc_local_file_test rkmedia_vi_venc_local_file_test.c ${COMMON_SRC})
add_dependencies(rkmedia_vi_venc_local_file_test easymedia)
target_link_libraries(rkmedia_vi_venc_local_file_test easymedia)
target_include_directories(rkmedia_vi_venc_local_file_test PRIVATE ${CMAKE_SOURCE_DIR}/include)
install(TARGETS rkmedia_vi_venc_local_file_test RUNTIME DESTINATION "bin")
4,编写代码,

主要与rkmedia_vi_venc_test.c与rkmedia_venc_local_file_test.c文件中不同的地方有,

去除帧打包命令:video_packet_cb,并去除rkmedia_venc_local_file_test.c中相关读取文件相关代码,同时以开辟新线程的方式获取venc中编码码流代替vi_venc_test.c中回调函数方式,代码更清晰简洁。

相关代码如下:

// Copyright 2020 Fuzhou Rockchip Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// rkmedia_vi_venc_local_file_test.c

#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>

#include "common/sample_common.h"
#include "rkmedia_api.h"
#include "rkmedia_venc.h"

static bool quit = false;
// static FILE *g_output_file;
static RK_S32 g_s32FrameCnt = -1;

//退出信号
static void sigterm_handler(int sig) {
  fprintf(stderr, "signal %d\n", sig);
  quit = true;
}

//捕获视频数据保存线程
static void *GetMediaBuffer(void *arg) {
  char *ot_path = (char *)arg;
  printf("#Start %s thread, arg:%p, out path: %s\n", __func__, arg, ot_path);
  FILE *save_file = fopen(ot_path, "w");
  if (!save_file)
    printf("ERROR: Open %s failed!\n", ot_path);

  MEDIA_BUFFER mb = NULL;
  while (!quit) {
    //从VENC通道0中阻塞获取数据
    mb = RK_MPI_SYS_GetMediaBuffer(RK_ID_VENC, 0, -1);
    if (!mb) {
      printf("RK_MPI_SYS_GetMediaBuffer get null buffer!\n");
      break;
    }

    printf("Get packet:ptr:%p, fd:%d, size:%zu, mode:%d, channel:%d, "
           "timestamp:%lld\n",
           RK_MPI_MB_GetPtr(mb), RK_MPI_MB_GetFD(mb), RK_MPI_MB_GetSize(mb),
           RK_MPI_MB_GetModeID(mb), RK_MPI_MB_GetChannelID(mb),
           RK_MPI_MB_GetTimestamp(mb));

    if (save_file)
      fwrite(RK_MPI_MB_GetPtr(mb), 1, RK_MPI_MB_GetSize(mb), save_file);
    RK_MPI_MB_ReleaseBuffer(mb);
  }

  if (save_file)
    fclose(save_file);

  return NULL;
}

static RK_CHAR optstr[] = "?::a::w:h:c:o:e:d:I:M:";
static const struct option long_options[] = {
    {"aiq", optional_argument, NULL, 'a'},
    {"device_name", required_argument, NULL, 'd'},
    {"width", required_argument, NULL, 'w'},
    {"height", required_argument, NULL, 'h'},
    {"frame_cnt", required_argument, NULL, 'c'},
    {"output_path", required_argument, NULL, 'o'},
    {"encode", required_argument, NULL, 'e'},
    {"camid", required_argument, NULL, 'I'},
    {"multictx", required_argument, NULL, 'M'},
    {"fps", required_argument, NULL, 'f'},
    {"hdr_mode", required_argument, NULL, 'h' + 'm'},
    {"vi_buf_cnt", required_argument, NULL, 'b' + 'c'},
    {"help", optional_argument, NULL, '?'},
    {NULL, 0, NULL, 0},
};

static void print_usage(const RK_CHAR *name) {
  printf("usage example:\n");
#ifdef RKAIQ
  printf("\t%s [-a [iqfiles_dir]] [-w 1920] "
         "[-h 1080]"
         "[-c 150] "
         "[-d rkispp_scale0] "
         "[-e 0] "
         "[-I 0] "
         "[-M 0] "
         "[-o output.h264] \n",
         name);
  printf("\t-a | --aiq: enable aiq with dirpath provided, eg:-a "
         "/oem/etc/iqfiles/, "
         "set dirpath emtpty to using path by default, without this option aiq "
         "should run in other application\n");
  printf("\t-M | --multictx: switch of multictx in isp, set 0 to disable, set "
         "1 to enable. Default: 0\n");
  printf("\t--fps fps of vi.\n");
  printf("\t--hdr_mode [normal hdr2 hdr3].\n");
  printf("\t--vi_buf_cnt buffer count of vi.\n");
#else
  printf("\t%s [-w 1920] "
         "[-h 1080]"
         "[-c 150] "
         "[-I 0] "
         "[-d rkispp_scale0] "
         "[-e 0] "
         "[-o output.h264] \n",
         name);
#endif
  printf("\t-w | --width: VI width, Default:1920\n");
  printf("\t-h | --heght: VI height, Default:1080\n");
  printf("\t-c | --frame_cnt: frame number of output, Default:150\n");
  printf("\t-I | --camid: camera ctx id, Default 0\n");
  printf("\t-d | --device_name set pcDeviceName, Default:rkispp_scale0, "
         "Option:[rkispp_scale0, rkispp_scale1, rkispp_scale2]\n");
  printf(
      "\t-e | --encode: encode type, Default:h264, Value:h264, h265, mjpeg\n");
  printf("\t-o | --output_path: output path, Default:NULL\n");
}

int main(int argc, char *argv[]) {
  RK_U32 u32Width = 1920;
  RK_U32 u32Height = 1080;
  RK_CHAR *pDeviceName = "rkispp_scale0";
  RK_CHAR *pOutPath = NULL;
  RK_CHAR *pIqfilesPath = NULL;
  CODEC_TYPE_E enCodecType = RK_CODEC_TYPE_H264;
  RK_CHAR *pCodecName = "H264";
  RK_S32 s32CamId = 0;
  RK_U32 u32BufCnt = 3;

#ifdef RKAIQ
  RK_BOOL bMultictx = RK_FALSE;
  RK_U32 u32Fps = 30;
  rk_aiq_working_mode_t hdr_mode = RK_AIQ_WORKING_MODE_NORMAL;
#endif

  int c;
  int ret = 0;
  while ((c = getopt_long(argc, argv, optstr, long_options, NULL)) != -1) {
    const char *tmp_optarg = optarg;
    switch (c) {
    case 'a':
      if (!optarg && NULL != argv[optind] && '-' != argv[optind][0]) {
        tmp_optarg = argv[optind++];
      }
      if (tmp_optarg) {
        pIqfilesPath = (char *)tmp_optarg;
      } else {
        pIqfilesPath = "/oem/etc/iqfiles";
      }
      break;
    case 'w':
      u32Width = atoi(optarg);
      break;
    case 'h':
      u32Height = atoi(optarg);
      break;
    case 'c':
      g_s32FrameCnt = atoi(optarg);
      break;
    case 'o':
      pOutPath = optarg;
      break;
    case 'd':
      pDeviceName = optarg;
      break;
    case 'e':
      if (!strcmp(optarg, "h264")) {
        enCodecType = RK_CODEC_TYPE_H264;
        pCodecName = "H264";
      } else if (!strcmp(optarg, "h265")) {
        enCodecType = RK_CODEC_TYPE_H265;
        pCodecName = "H265";
      } else if (!strcmp(optarg, "mjpeg")) {
        enCodecType = RK_CODEC_TYPE_MJPEG;
        pCodecName = "MJPEG";
      } else {
        printf("ERROR: Invalid encoder type.\n");
        return 0;
      }
      break;
    case 'I':
      s32CamId = atoi(optarg);
      break;
#ifdef RKAIQ
    case 'M':
      if (atoi(optarg)) {
        bMultictx = RK_TRUE;
      }
      break;
    case 'f':
      u32Fps = atoi(optarg);
      printf("#u32Fps = %u.\n", u32Fps);
      break;
    case 'h' + 'm':
      if (strcmp(optarg, "normal") == 0) {
        hdr_mode = RK_AIQ_WORKING_MODE_NORMAL;
      } else if (strcmp(optarg, "hdr2") == 0) {
        hdr_mode = RK_AIQ_WORKING_MODE_ISP_HDR2;
      } else if (strcmp(optarg, "hdr3") == 0) {
        hdr_mode = RK_AIQ_WORKING_MODE_ISP_HDR3;
      } else {
        print_usage(argv[0]);
        return 0;
      }
      printf("#hdr_mode = %u.\n", hdr_mode);
      break;
#endif
    case 'b' + 'c':
      u32BufCnt = atoi(optarg);
      printf("#vi buffer conunt = %u.\n", u32BufCnt);
      break;
    case '?':
    default:
      print_usage(argv[0]);
      return 0;
    }
  }

  printf("#Device: %s\n", pDeviceName);
  printf("#CodecName:%s\n", pCodecName);
  printf("#Resolution: %dx%d\n", u32Width, u32Height);
  printf("#Frame Count to save: %d\n", g_s32FrameCnt);
  printf("#Output Path: %s\n", pOutPath);
  printf("#CameraIdx: %d\n\n", s32CamId);
#ifdef RKAIQ
  printf("#bMultictx: %d\n\n", bMultictx);
  printf("#Aiq xml dirpath: %s\n\n", pIqfilesPath);
#endif

  if (pIqfilesPath) {
#ifdef RKAIQ
    SAMPLE_COMM_ISP_Init(s32CamId, hdr_mode, bMultictx, pIqfilesPath);
    SAMPLE_COMM_ISP_Run(s32CamId);
    SAMPLE_COMM_ISP_SetFrameRate(s32CamId, u32Fps);
#endif
  }

  // if (pOutPath) {
  //   g_output_file = fopen(pOutPath, "w");
  //   if (!g_output_file) {
  //     printf("ERROR: open file: %s fail, exit\n", pOutPath);
  //     return 0;
  //   }
  // }

  RK_MPI_SYS_Init();
  VI_CHN_ATTR_S vi_chn_attr;
  vi_chn_attr.pcVideoNode = pDeviceName;
  vi_chn_attr.u32BufCnt = u32BufCnt;
  vi_chn_attr.u32Width = u32Width;
  vi_chn_attr.u32Height = u32Height;
  vi_chn_attr.enPixFmt = IMAGE_TYPE_YUYV422;
  vi_chn_attr.enBufType = VI_CHN_BUF_TYPE_MMAP;
  vi_chn_attr.enWorkMode = VI_WORK_MODE_NORMAL;
  ret = RK_MPI_VI_SetChnAttr(s32CamId, 0, &vi_chn_attr);
  ret |= RK_MPI_VI_EnableChn(s32CamId, 0);
  if (ret) {
    printf("ERROR: create VI[0] error! ret=%d\n", ret);
    return 0;
  }

  VENC_CHN_ATTR_S venc_chn_attr;
  memset(&venc_chn_attr, 0, sizeof(venc_chn_attr));
  switch (enCodecType) {
  case RK_CODEC_TYPE_H265:
    venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_H265;
    venc_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_H265CBR;
    venc_chn_attr.stRcAttr.stH265Cbr.u32Gop = 30;
    venc_chn_attr.stRcAttr.stH265Cbr.u32BitRate = u32Width * u32Height;
    // frame rate: in 30/1, out 30/1.
    venc_chn_attr.stRcAttr.stH265Cbr.fr32DstFrameRateDen = 1;
    venc_chn_attr.stRcAttr.stH265Cbr.fr32DstFrameRateNum = 30;
    venc_chn_attr.stRcAttr.stH265Cbr.u32SrcFrameRateDen = 1;
    venc_chn_attr.stRcAttr.stH265Cbr.u32SrcFrameRateNum = 30;
    break;
  case RK_CODEC_TYPE_MJPEG:
    venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_MJPEG;
    venc_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_MJPEGCBR;
    venc_chn_attr.stRcAttr.stMjpegCbr.fr32DstFrameRateDen = 1;
    venc_chn_attr.stRcAttr.stMjpegCbr.fr32DstFrameRateNum = 30;
    venc_chn_attr.stRcAttr.stMjpegCbr.u32SrcFrameRateDen = 1;
    venc_chn_attr.stRcAttr.stMjpegCbr.u32SrcFrameRateNum = 30;
    venc_chn_attr.stRcAttr.stMjpegCbr.u32BitRate = u32Width * u32Height * 8;
    break;
  case RK_CODEC_TYPE_H264:
  default:
    venc_chn_attr.stVencAttr.enType = RK_CODEC_TYPE_H264;
    venc_chn_attr.stRcAttr.enRcMode = VENC_RC_MODE_H264CBR;
    venc_chn_attr.stRcAttr.stH264Cbr.u32Gop = 30;
    venc_chn_attr.stRcAttr.stH264Cbr.u32BitRate = u32Width * u32Height;
    // frame rate: in 30/1, out 30/1.
    venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateDen = 1;
    venc_chn_attr.stRcAttr.stH264Cbr.fr32DstFrameRateNum = 30;
    venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateDen = 1;
    venc_chn_attr.stRcAttr.stH264Cbr.u32SrcFrameRateNum = 30;
    break;
  }
  venc_chn_attr.stVencAttr.imageType = IMAGE_TYPE_YUYV422;
  venc_chn_attr.stVencAttr.u32PicWidth = u32Width;
  venc_chn_attr.stVencAttr.u32PicHeight = u32Height;
  venc_chn_attr.stVencAttr.u32VirWidth = u32Width;
  venc_chn_attr.stVencAttr.u32VirHeight = u32Height;
  venc_chn_attr.stVencAttr.u32Profile = 77;
  ret = RK_MPI_VENC_CreateChn(0, &venc_chn_attr);
  if (ret) {
    printf("ERROR: create VENC[0] error! ret=%d\n", ret);
    return 0;
  }

  MPP_CHN_S stSrcChn;
  stSrcChn.enModId = RK_ID_VI;
  stSrcChn.s32DevId = 0;
  stSrcChn.s32ChnId = 0;
  MPP_CHN_S stDestChn;
  stDestChn.enModId = RK_ID_VENC;
  stDestChn.s32DevId = 0;
  stDestChn.s32ChnId = 0;
  ret = RK_MPI_SYS_Bind(&stSrcChn, &stDestChn);
  if (ret) {
    printf("ERROR: Bind VI[0] and VENC[0] error! ret=%d\n", ret);
    return 0;
  }

  printf("%s initial finish\n", __func__);
  signal(SIGINT, sigterm_handler);

  pthread_t read_thread;
  pthread_create(&read_thread, NULL, GetMediaBuffer, pOutPath);
                           IMAGE_TYPE_YUYV422};

  while (!quit) {
    usleep(500000);
  }

  // if (g_output_file)
  //   fclose(g_output_file);

  printf("%s exit!\n", __func__);
  // unbind first
  ret = RK_MPI_SYS_UnBind(&stSrcChn, &stDestChn);
  if (ret) {
    printf("ERROR: UnBind VI[0] and VENC[0] error! ret=%d\n", ret);
    return 0;
  }
  // destroy venc before vi
  ret = RK_MPI_VENC_DestroyChn(0);
  if (ret) {
    printf("ERROR: Destroy VENC[0] error! ret=%d\n", ret);
    return 0;
  }
  // destroy vi
  ret = RK_MPI_VI_DisableChn(s32CamId, 0);
  if (ret) {
    printf("ERROR: Destroy VI[0] error! ret=%d\n", ret);
    return 0;
  }

  if (pIqfilesPath) {
#ifdef RKAIQ
    SAMPLE_COMM_ISP_Stop(s32CamId);
#endif
  }
  return 0;
}

5,代码编译,

编写完成后,在/sdk目录下运行以下指令:

# SDK根目录,选择环境
source envsetup.sh firefly_rv1126_rv1109
# 重编rkmedia源码
make rkmedia-dirclean && make rkmedia

编译完成后,在SDK/buildroot/output/firefly_rv1126_rv1109/oem/usr/bin目录下找到rkmedia_vi_venc_local_file_test二进制可执行程序,移动到板子某一个目录下,再进行测试。

6,测试指令

在开发板存放可执行程序目标终端下输入以下指令:

./rkmedia_vi_venc_local_file_test -w 640 -h 480 -d /dev/video25 -c 30 -e h264 -o /mnt/nfs/output_test.h264

其中参数w为摄像头输入视频宽,h为摄像头输入视频高,d为摄像头设备号,c为输入视频帧率,e为编码格式,o为视频保存路径

标签:attr,vi,chn,Firefly1126,RKMedia,venc,printf,摄像头,RK
来源: https://www.cnblogs.com/kxqblog/p/16435824.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有