【華爲Hicar倒車影像分流需求 六】- 共享內存方案最終代碼實現 一 之 數據接收端
本文接着《【華爲Hicar倒車影像分流需求 五】- 共享內存方案最終代碼實現 一 之 數據發送端》
二、共享內存接收端代碼實現
1. 頭文件 H264_Reverse.h
# nativecamerasdk/video/H264_Reverse.h
#ifndef __H264_REVERSE_H__
#define __H264_REVERSE_H__
#define DLS_CAMERA_PREVIEW_WIDTH 720 //raw camera output
#define DLS_CAMERA_PREVIEW_HEIGHT 480 //raw camera output
//YUV420-N21 YYYYYYYY UVUV
#define MAX_BUF_SIZE DLS_CAMERA_PREVIEW_WIDTH * DLS_CAMERA_PREVIEW_HEIGHT * 3/2 + 200
#define REVERSE_CAMERA_DUMP_LOCATION "/sdcard/reverse/"
// 進程鎖結構體
typedef struct MUTEX_SHAREDLOCK {
pthread_mutex_t lock;
pthread_mutexattr_t lock_attr;
} mutex_sharedLock_t;
class Camera_Shared_Memory_R
{
public:
static Camera_Shared_Memory_R* get_Read_Shared_Memory();
int attach_Read_Shared_Memory();
int open_Read_Shared_Memory(unsigned char *buffer);
int close_Read_Shared_Memory();
int shm_chn_attach();
unsigned char * shm_addr_buff;
// dump data
void Camera_Shared_Memory_Dump(unsigned char * buf, int size);
private:
//method declare
Camera_Shared_Memory_R();
~Camera_Shared_Memory_R();
static Camera_Shared_Memory_R* sInstance;
void* shm_addr;
int shm_id;
};
#endif // END __H264_REVERSE_H__
2. 源文件 H264_Reverse.cpp
# nativecamerasdk/video/H264_Reverse.cpp
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <malloc.h>
#include <cutils/log.h>
#include <cutils/properties.h>
#include <sys/stat.h>
#include "H264_Reverse.h"
static mutex_sharedLock_t *sharedLock_r;
Camera_Shared_Memory_R* Camera_Shared_Memory_R::sInstance = 0;
Camera_Shared_Memory_R::Camera_Shared_Memory_R():shm_addr(NULL),shm_id(0)
{
attach_Read_Shared_Memory();
// alloc buffer
shm_addr_buff = (unsigned char *)malloc(MAX_BUF_SIZE);
}
Camera_Shared_Memory_R::~Camera_Shared_Memory_R()
{
// release addr
close_Read_Shared_Memory();
// who create who destroy, so don't delete IPC memory here
//if(shmctl(shm_id, IPC_RMID, NULL) !=0 )
// ALOGI("[%s][%d] shmctl error!,shm_id=%d \n", __func__,__LINE__, shm_id);
// free buffer
free(shm_addr_buff);
shm_id = -1;
}
Camera_Shared_Memory_R* Camera_Shared_Memory_R::get_Read_Shared_Memory()
{
if(!Camera_Shared_Memory_R::sInstance)
{
Camera_Shared_Memory_R::sInstance = new Camera_Shared_Memory_R;
}
return Camera_Shared_Memory_R::sInstance;
}
int Camera_Shared_Memory_R::attach_Read_Shared_Memory()
{
return Camera_Shared_Memory_R::shm_chn_attach();
}
int Camera_Shared_Memory_R::shm_chn_attach()
{
shm_id = shmget((key_t)1225, 0, 0);
if(-1== shm_id)
{
ALOGI("[reverse_exe][%s][%d] share memory get error!\n",__func__, __LINE__);
goto err;
}
shm_addr= shmat(shm_id, 0, 0);
if((void *)-1== shm_addr)
{
ALOGI("[reverse_exe][%s][%d] share memory attach address error\n",__func__, __LINE__);
goto err;
}
sharedLock_r = (mutex_sharedLock_t *)shm_addr;
return 0;
err:
return -1;
}
int Camera_Shared_Memory_R::open_Read_Shared_Memory(unsigned char *buffer)
{
//pthread_mutex_lock( &(sharedLock_r->lock) );
if (0 == pthread_mutex_trylock( &(sharedLock_r->lock))) {
memcpy(buffer, ((pthread_mutex_t *)shm_addr)+1, MAX_BUF_SIZE);
ALOGI("[reverse_exe][%s][%d] buffer -- %x-%x-%x-%x - %x-%x-%x-%x - %x-%x-%x-%x",__func__,__LINE__,
buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6],
buffer[7],buffer[8],buffer[9],buffer[10],buffer[11]);
pthread_mutex_unlock( &(sharedLock_r->lock) );
}else{
ALOGI("[reverse_exe][%s][%d] lock is busy \n", __func__,__LINE__);
return -1;
}
return 0;
}
int Camera_Shared_Memory_R::close_Read_Shared_Memory()
{
ALOGI("[%s][%d] shm_id=%d, shm_addr=%p \n", __func__,__LINE__, shm_id, shm_addr);
// release shm_addr
if ((shm_addr != NULL) && shmdt(shm_addr) == -1)
{
ALOGI("[%s][%d] shmdt error!,shm_addr=%p \n", __func__,__LINE__, shm_addr);
return -1;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////
// save yuv file in /sdcard/reverse/Rear-Camera-720x480-0.yuv
static int index = 0;
void Camera_Shared_Memory_R::Camera_Shared_Memory_Dump(unsigned char * buf, int size)
{
char filename_buf[128];
if(index >= 200){
ALOGI("[reverse_exe][%s][%d] index=%d ,too big \n",__func__, __LINE__, index);
return;
}
if(access(REVERSE_CAMERA_DUMP_LOCATION,F_OK) != 0){
printf("create new path!\n");
mkdir(REVERSE_CAMERA_DUMP_LOCATION, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
}
snprintf(filename_buf, sizeof(filename_buf), "%sRear-Camera-720x480-%d.yuv", REVERSE_CAMERA_DUMP_LOCATION, index);
ALOGI("[reverse_exe][%s][%d] filename_buf=%s \n",__func__, __LINE__, filename_buf);
int file_fd = open(filename_buf, O_RDWR | O_CREAT, 0777);
ssize_t written_len = 0;
if (file_fd >= 0){
fchmod(file_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
write(file_fd, buf, MAX_BUF_SIZE);
close(file_fd);
index ++;
}else{
ALOGE("%s: fail t open file for image dumping", __func__);
}
}
3. 測試Daemon代碼 H264_Reverse.cpp
# nativecamerasdk/native_camera_impl.cpp
//[email protected] +++
#include "video/H264_Reverse.h"
DMSDPSendBackDataCB reverse_sendbackFrameFunc = nullptr;
static int reverse_capturing = 0;
// 註冊Camera 數據回調函數
int32_t CameraRegisterSendDataCallback(const char* id, uint32_t idLen, const DMSDPSendBackDataCB cb)
{
/* regist callback senddata */
ALOGI("CameraRegisterSendDataCallback");
// [email protected] +++
if( strcmp(id, "5") == 0 ) { // id = 5, reverse_camera
reverse_sendbackFrameFunc = cb;
}
return DMSDP_NO_ERROR;
}
// 數據採集線程
void * cap_reverse (void *arg)
{
ALOGI("[reverse_exe][%s][%d] Enter ... \n",__func__, __LINE__);
// 1. init
Camera_Shared_Memory_R * Camera_Shared_Memory_r = Camera_Shared_Memory_R::get_Read_Shared_Memory();
while(reverse_capturing)
{
memset(Camera_Shared_Memory_r->shm_addr_buff, 0, MAX_BUF_SIZE);
// 2. read shm data
Camera_Shared_Memory_r->open_Read_Shared_Memory(Camera_Shared_Memory_r->shm_addr_buff);
// 3. daemon ,save data with yuv file
Camera_Shared_Memory_r->Camera_Shared_Memory_Dump(Camera_Shared_Memory_r->shm_addr_buff , MAX_BUF_SIZE);
// here call callback send buff
//sendbackFrameFunc( id_s , sizeof(id_s), Camera_Shared_Memory_r->shm_addr_buff, MAX_BUF_SIZE, (int32_t)DMSDPCameraDataType::H264);
usleep(30000); //sleep 30ms
}
pthread_exit(NULL);
}
// 打開攝像頭,開始啓動數據採集線程
int32_t OpenCamera(const DMSDPCameraParam* param) {
if (param == nullptr) {
ALOGE("%s: open camera param is null", __FUNCTION__);
return DMSDP_ERR_INVALID_PARAMETER;
}
ALOGI("[reverse_exe][%s][%d] id=%s \n",__func__, __LINE__, param->id);
if( strcmp(param->id, "5") == 0 ) // id = 5, reverse_camera
{
// init share memory
Camera_Shared_Memory_R * Camera_Shared_Memory_r = Camera_Shared_Memory_R::get_Read_Shared_Memory();
reverse_capturing = 1;
// start pthread
pthread_t pthreadReverse;
if (pthread_create(&pthreadReverse, nullptr, cap_reverse, nullptr))
ALOGI("%s: Create cap_reverse error!", __FUNCTION__);
if (pthreadReverse != 0)
{
pthread_detach(pthreadReverse);
ALOGI("%s: capture h264 preview exit", __FUNCTION__);
}
}
ALOGI("%s: open camera success", __FUNCTION__);
return DMSDP_NO_ERROR;
}
// 關閉數據採集
int32_t CloseCamera(const char* id, uint32_t idLen)
{
if( strcmp(id, "5") == 0 ){
reverse_capturing = 0;
}
return DMSDP_NO_ERROR;
}
// Daemon 主函數,後續,該部分調用由華爲來實現
int main(void)
{
char id_test[] = "5";
const char *id_pt = id_test;
DMSDPCameraParam param_test;
param_test.id = id_pt;
// 1. register callback
// CameraRegisterSendDataCallback
// 2. open camera get data
OpenCamera(¶m_test);
while(1){
sleep(10);
}
return 0;
}
三、Daemon 實測
1. 發送端log 輸出
通過 PCAN ,往車機發送倒車命令後,進入倒車模式,開啓倒車攝像頭,
當有數據輸出時,會初始化共享內存,創建 共享 buffer ,開始發送數據
ciellee@sh:~/tamp$ adb logcat -b all | grep Shared_Memory
05-29 10:50:45.740 798 930 I : [create_Shared_Memory][46] shm_id : 0
05-29 10:50:45.741 798 930 I : [create_Shared_Memory][67] add shm_id=0, shm_addr=0xb2887000
2. 接收端log 輸出
執行可執行程序: msm8937_32go:/ # libdmsdpcamerahandler_exe
掛接共享內存後,開始讀取共享內存數據,並保存爲yuv 圖片。
05-29 10:51:12.932 7616 7616 I CamSDK_3rdCamera: [reverse_exe][OpenCamera][569] id=5
05-29 10:51:12.939 7616 7618 I CamSDK_3rdCamera: [reverse_exe][cap_reverse][543] Enter ...
05-29 10:51:12.957 7616 7618 I : [reverse_exe][open_Read_Shared_Memory][84] buffer -- d2-d2-d2-d2 - d2-d2-d2-d2 - d2-d2-d2-d2
05-29 10:51:12.967 7616 7618 I : [reverse_exe][Camera_Shared_Memory_Dump][132] filename_buf=/sdcard/reverse/Rear-Camera-720x480-0.yuv
05-29 10:51:13.004 7616 7618 I : [reverse_exe][open_Read_Shared_Memory][84] buffer -- d2-d2-d2-d2 - d2-d2-d2-d2 - d2-d2-d2-d2
05-29 10:51:13.004 7616 7618 I : [reverse_exe][Camera_Shared_Memory_Dump][132] filename_buf=/sdcard/reverse/Rear-Camera-720x480-1.yuv
05-29 10:51:13.041 7616 7618 I : [reverse_exe][open_Read_Shared_Memory][84] buffer -- d2-d2-d2-d2 - d2-d2-d2-d2 - d2-d2-d2-d2
05-29 10:51:13.041 7616 7618 I : [reverse_exe][Camera_Shared_Memory_Dump][132] filename_buf=/sdcard/reverse/Rear-Camera-720x480-2.yuv
05-29 10:51:13.083 7616 7618 I : [reverse_exe][open_Read_Shared_Memory][84] buffer -- d2-d2-d2-d2 - d2-d2-d2-d2 - d2-d2-d2-d2
3. 導出YUV 圖片
ciellee@sh:~/tamp$ adb pull /sdcard/reverse/ .
pull: building file list...
pull: /sdcard/reverse/Rear-Camera-720x480-47.yuv -> ./Rear-Camera-720x480-47.yuv
pull: /sdcard/reverse/Rear-Camera-720x480-46.yuv -> ./Rear-Camera-720x480-46.yuv
pull: /sdcard/reverse/Rear-Camera-720x480-45.yuv -> ./Rear-Camera-720x480-45.yuv
pull: /sdcard/reverse/Rear-Camera-720x480-44.yuv -> ./Rear-Camera-720x480-44.yuv
pull: /sdcard/reverse/Rear-Camera-720x480-43.yuv -> ./Rear-Camera-720x480-43.yuv
pull: /sdcard/reverse/Rear-Camera-720x480-42.yuv -> ./Rear-Camera-720x480-42.yuv
查看圖片:
ffplay -video_size 720x480 -pix_fmt nv21 -i Rear-Camera-720x480-40.yuv
如下是獲取的 pattern 圖:
四、下一步工作
現在共享內存 Deamon 寫好了,已經發郵件請華爲安排一位研發和我對接聯調。
所以接下來兩件事:
- 和華爲工程師聯調 Hicar 倒車影像功能
- 使用C++ ADIL 來代替 共享內存 ,實現進程間大數據傳輸
參考:《Linux進程間互斥鎖 (共享內存實現)》