> 文档中心 > 鸿蒙OpenHarmony hi3516开发板,标准系统响应按钮拍照

鸿蒙OpenHarmony hi3516开发板,标准系统响应按钮拍照

自从搞懂了标准系统GPIO的操作后,即鸿蒙OpenHarmony hi3516开发板,标准系统按钮开关灯,下一步使用按钮拍照也很快的搞定了,先做个暂时的记录吧。下一步,研究如何http调用云服务AI识图

整体开发方式跟上次一样,就不再追溯了,仅仅修改了applications/standard/app/hello.c

重点参考了OpenHarmony的文档和一个test源代码,文档中写了主要的步骤,另外我在代码中把每个步骤都写了注释:

参考文档:multimedia_camera_standard: Implementation of camera device management and camera capture functions | 相机设备和相机采集功能实现

参考源代码:interfaces/innerkits/native/test/camera_capture.cpp · OpenHarmony/multimedia_camera_standard - Gitee.com

使用的代码版本是OH2021-12-25的master源代码,等最近出了新版本tag后,我再验证下这个最新版本是否也OK。

#include#include#include#include#include#include#include "input/camera_input.h"#include "input/camera_manager.h"#include "surface.h"#include #include #include #include #include #include #include #include #include using namespace std;using namespace OHOS;using namespace OHOS::CameraStandard;#define MSG(args...) printf(args)  //函数声明static int gpio_export(int pin);static int gpio_unexport(int pin);static int gpio_direction(int pin, int dir);static int gpio_write(int pin, int value);static int gpio_read(int pin);static int gpio_edge(int pin, int edge);static int gpio_export(int pin)  {      char buffer[64];      int len;      int fd; fd = open("/sys/class/gpio/export", O_WRONLY);      if (fd < 0)     {   MSG("Failed to open export for writing!\n");   return(-1);      } len = snprintf(buffer, sizeof(buffer), "%d", pin);      printf("%s,%d,%d\n",buffer,sizeof(buffer),len);    if (write(fd, buffer, len) < 0)     {   MSG("Failed to export gpio!");   return -1;      }    close(fd);      return 0;  }  static int gpio_unexport(int pin)  {      char buffer[64];      int len;      int fd; fd = open("/sys/class/gpio/unexport", O_WRONLY);      if (fd < 0)     {   MSG("Failed to open unexport for writing!\n");   return -1;      } len = snprintf(buffer, sizeof(buffer), "%d", pin);      if (write(fd, buffer, len) IN, 1-->OUTstatic int gpio_direction(int pin, int dir)  {      static const char dir_str[] = "in\0out";      char path[64];      int fd; snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", pin);      fd = open(path, O_WRONLY);      if (fd < 0)     {   MSG("Failed to open gpio direction for writing!\n");   return -1;      } if (write(fd, &dir_str[dir == 0 ? 0 : 3], dir == 0 ? 2 : 3) LOW, 1-->HIGHstatic int gpio_write(int pin, int value)  {      static const char values_str[] = "01";      char path[64];      int fd; snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);      fd = open(path, O_WRONLY);      if (fd < 0)     {   MSG("Failed to open gpio value for writing!\n");   return -1;      } if (write(fd, &values_str[value == 0 ? 0 : 1], 1) < 0)     {   MSG("Failed to write value!\n");   return -1;      } close(fd);      return 0;  }static int gpio_read(int pin)  {      char path[64];      char value_str[3];      int fd; snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);      fd = open(path, O_RDONLY);      if (fd < 0)     {   MSG("Failed to open gpio value for reading!\n");   return -1;      } if (read(fd, value_str, 3) none, 1-->rising, 2-->falling, 3-->bothstatic int gpio_edge(int pin, int edge){const char dir_str[] = "none\0rising\0falling\0both"; int ptr;char path[64];      int fd; switch(edge){    case 0: ptr = 0; break;    case 1: ptr = 5; break;    case 2: ptr = 12; break;    case 3: ptr = 20; break;    default: ptr = 0;}snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/edge", pin);      fd = open(path, O_WRONLY);      if (fd < 0)     {   MSG("Failed to open gpio edge for writing!\n");   return -1;      } if (write(fd, &dir_str[ptr], strlen(&dir_str[ptr])) < 0)     {   MSG("Failed to set edge!\n");   return -1;      } close(fd);      return 0;  }enum class mode_ {    MODE_PREVIEW = 0,    MODE_PHOTO};// 获取当前时间static uint64_t GetCurrentLocalTimeStamp(){    std::chrono::time_point tp = std::chrono::time_point_cast(std::chrono::system_clock::now());    auto tmp = std::chrono::duration_cast(tp.time_since_epoch());    return tmp.count();}// 保存图片static int32_t SaveYUV(mode_ mode, const char *buffer, int32_t size){    static const std::int32_t FILE_PERMISSION_FLAG = 00766;    char path[PATH_MAX] = {0};    int32_t retVal;    if (mode == mode_::MODE_PREVIEW) { system("mkdir -p /data/preview"); retVal = sprintf_s(path, sizeof(path) / sizeof(path[0]), "/data/preview/%s_%lld.yuv", "preview",     GetCurrentLocalTimeStamp());    } else { system("mkdir -p /data/capture"); retVal = sprintf_s(path, sizeof(path) / sizeof(path[0]), "/data/capture/%s_%lld.jpg", "photo",     GetCurrentLocalTimeStamp());    }    if (retVal < 0) { printf("Path Assignment failed"); return -1;    }    printf("%s, saving file to %s", __FUNCTION__, path);    int imgFd = open(path, O_RDWR | O_CREAT, FILE_PERMISSION_FLAG);    if (imgFd == -1) { printf("%s, open file failed, errno = %s.", __FUNCTION__, strerror(errno)); return -1;    }    int ret = write(imgFd, buffer, size);    if (ret == -1) { printf("%s, write file failed, error = %s.", __FUNCTION__, strerror(errno)); close(imgFd); return -1;    }    close(imgFd);    return 0;}// 1.创建缓冲区消费者端监听器(CaptureSurfaceListener)以保存图像。class CaptureSurfaceListener : public IBufferConsumerListener {public:    mode_ mode;    sptr surface_;    void OnBufferAvailable() override    { int32_t flushFence = 0; int64_t timestamp = 0; OHOS::Rect damage; // initialize the damage OHOS::sptr buffer = nullptr; surface_->AcquireBuffer(buffer, flushFence, timestamp, damage); if (buffer != nullptr) {     char *addr = static_cast(buffer->GetVirAddr());     int32_t size = buffer->GetSize();     // Save the buffer(addr) to a file.     SaveYUV(mode, addr, size);     surface_->ReleaseBuffer(buffer, -1); }    }};int main()  {      int gpio_fd, ret;    struct pollfd fds[1];    char buff[10];    //41为红灯, 1为1号按键     gpio_unexport(41);    gpio_unexport(1);  //41红灯亮起    gpio_export(41);    gpio_direction(41, 1);//output out    gpio_write(41, 1); //1按钮初始化    gpio_export(1);    gpio_direction(1, 0);//input in    gpio_edge(1,2);    gpio_fd = open("/sys/class/gpio/gpio1/value",O_RDONLY);    if(gpio_fd < 0)    { MSG("Failed to open value!\n");   return -1;      }    fds[0].fd = gpio_fd;    fds[0].events  = POLLPRI;    // 参考Camera组件拍摄 https://gitee.com/openharmony/multimedia_camera_standard    // 样例:foundation/multimedia/camera_standard/interfaces/innerkits/native/test/camera_capture.cpp    // 2.获取相机管理器实例并获取相机对象列表。    int32_t intResult = -1;    sptr camManagerObj = CameraManager::GetInstance();    std::vector<sptr> cameraObjList = camManagerObj->GetCameras();    if (cameraObjList.size() GetID().c_str());    }    //3. 创建采集会话。    sptr captureSession = camManagerObj->CreateCaptureSession();    if (captureSession == nullptr) { printf("Failed to create capture session"); return -1;    }    //4. 开始配置采集会话。    captureSession->BeginConfig();    //5. 使用相机对象创建相机输入。    sptr photoOutput;    sptr cameraInput = camManagerObj->CreateCameraInput(cameraObjList[0]);    if (cameraInput != nullptr) { //6.将相机输入添加到采集会话。 intResult = captureSession->AddInput(cameraInput); if (intResult == 0) {     //7.创建消费者Surface并注册监听器以监听缓冲区更新。拍照的宽和高可以配置为所支持的 1280x960 分辨率。     sptr photoSurface = Surface::CreateSurfaceAsConsumer();     photoSurface->SetDefaultWidthAndHeight(1280, 960);     sptr capturelistener = new CaptureSurfaceListener();     capturelistener->mode = mode_::MODE_PHOTO;     capturelistener->surface_ = photoSurface;     photoSurface->RegisterConsumerListener((sptr &)capturelistener);     //8.使用上面创建的 Surface 创建拍照输出。     photoOutput = camManagerObj->CreatePhotoOutput(photoSurface);     if (photoOutput == nullptr) {  printf("Failed to create PhotoOutput");  return -1;     }     //9.将拍照输出添加到采集会话。     intResult = captureSession->AddOutput(photoOutput);     if (intResult != 0) {  printf("Failed to Add output to session, intResult: %d", intResult);  return -1;     }     //10. 将配置提交到采集会话。     intResult = captureSession->CommitConfig();     if (intResult != 0) {  printf("Failed to Commit config, intResult: %d", intResult);  return -1;     } }    } while(1)    { ret = poll(fds,1,5000); if( ret == -1 ) MSG("poll\n"); if( fds[0].revents & POLLPRI) {     ret = lseek(gpio_fd,0,SEEK_SET);     if( ret == -1 )     MSG("lseek\n");      ret = read(gpio_fd,buff,10);//读取按钮值,但这里没使用     if( ret == -1 )     MSG("read\n");     //切换红灯     int status = gpio_read(41);     printf("41 = %d\n",status);     gpio_write(41, 1 - status);     //11.拍摄照片。     intResult = ((sptr &)photoOutput)->Capture();     if (intResult != 0) {  printf("Failed to capture, intResult: %d", intResult);  return -1;     }else{  printf("Success to capture, intResult: %d", intResult);     }   //gpio_write(44, cnt++%2);     printf("**********************************\n"); } printf("one loop\n"); //usleep(5);    }    //12. 释放采集会话资源。    captureSession->Release();    return 0;}

Build.gn 引入camera子系统的头文件及模块

import("//build/ohos.gni")import("//drivers/adapter/uhdf2/uhdf.gni")ohos_executable("madixin") {  sources = [    "madixin.cpp"  ]  subsystem_name = "applications"  part_name = "prebuilt_hap"  include_dirs = [    "//foundation/multimedia/camera_standard/interfaces/innerkits/native/camera/include",    "//foundation/multimedia/camera_standard/interfaces/innerkits/native/test",    "//foundation/multimedia/camera_standard/services/camera_service/include",    "//foundation/multimedia/camera_standard/services/camera_service/binder/base/include",    "//foundation/multimedia/camera_standard/services/camera_service/binder/client/include",    "//foundation/multimedia/camera_standard/services/camera_service/binder/server/include",    "//foundation/graphic/standard/frameworks/surface/include",    "//foundation/multimedia/camera_standard/frameworks/innerkitsimpl/metadata/include",    "//utils/system/safwk/native/include",    "//drivers/framework/include/utils",    "//drivers/adapter/uhdf2/osal/include",    "//drivers/adapter/uhdf2/include/hdi",    "//drivers/peripheral/display/interfaces/include",    "//drivers/peripheral/camera/interfaces/include",    "//drivers/peripheral/camera/interfaces/hdi_ipc",    "//drivers/peripheral/camera/interfaces/hdi_ipc/server",    "//drivers/peripheral/camera/interfaces/hdi_ipc/callback/device",    "//drivers/peripheral/camera/interfaces/hdi_ipc/callback/operator",    "//drivers/peripheral/camera/interfaces/hdi_ipc/callback/host",  ] deps = [    "//foundation/graphic/standard:libsurface",    "//foundation/multimedia/camera_standard/frameworks/innerkitsimpl/camera:camera_framework",    "//foundation/multimedia/camera_standard/frameworks/innerkitsimpl/metadata:metadata",    "//utils/native/base:utils",  ]}

因为在CaptureSurfaceListener定义了照片保存路径,即/data/capture目录,因此点击按钮拍照后,串口中会输出信息,照片也保存在了/data/capture目录下。

使用命令把照片发到本机就可以浏览拉:

hdc_std file recv /data/capture/photo_4942243.jpg D:\madixin\test\images\

源代码

MyOpenHarmonySample: 我的OpenHarmonySample代码 - Gitee.com

驱动天空下载