[文章]使用AI Camera HarmonyOS开发板进行拍照和录像

阅读量0
0
0
一、前言
本文主要介绍如何使用鸿蒙官方camera示例代码,在AI Camera开发板(Hi3516DV300)上进行拍照和录像演示,目的为理解鸿蒙操作系统应用框架,熟悉鸿蒙开发板上应用调试流程,使得能够对HarmonyOS的摄像头控制有更深入的了解,后续可参考此官方示例进行“AI智能相机”等设备产品开发。
二、配置编译camera示例代码
1,HarmonyOS官方SDK的camera示例代码位于:applications/sample/camera/media/camera_sample.cpp。
      2,查看对应的BUILD.gn文件发现编译后的可执行文件输出路径为out/dev_tools目录;
cap.png

      如果想将camera_sample可执行程序生产到bin目录可修改为output_dir=  "$root_out_dir/"。
3,需要注意,开发板启动后默认会加载launcher应用,应用的图形界面默认显示在媒体图层上方,会影响camera_sample的演示结果,因此需要在编译或是打包时去掉launcher应用。
修改方法:将“applications/sample/camera/hap/BUILD.gn”中copy("copy_hap") {}中 "//applications/sample/camera/hap/launcher.hap",整行注释。
hap.png


三、拍照和录像核心代码分析
       拍照开发步骤
       1,实现设备状态回调的派生类,用户在设备状态发生变更(如新插入相机设备/相机掉线)时,自定义操作。
  1. class SampleCameraDeviceCallback : public CameraDeviceCallback {
  2.     void OnCameraStatus(std::string cameraId, int32_t status) override
  3.     {
  4.         //do something when camera is available/unavailable
  5.     }
  6. };
复制代码
      2,实现帧事件回调的派生类,这里在拿到帧数据以后将其转存为文件。
  1. static void SampleSaveCapture(const char *p, uint32_t size)
  2. {
  3.     cout << "Start saving picture" << endl;
  4.     struct timeval tv;
  5.     gettimeofday(&tv, NULL);
  6.     struct tm *ltm = localtime(&tv.tv_sec);
  7.     if (ltm != nullptr) {
  8.         ostringstream ss("Capture_");
  9.         ss << "Capture" << ltm->tm_hour << "-" << ltm->tm_min << "-" << ltm->tm_sec << ".jpg";


  10.         ofstream pic("/sdcard/" + ss.str(), ofstream::out | ofstream::trunc);
  11.         cout << "write " << size << " bytes" << endl;
  12.         pic.write(p, size);
  13.         cout << "Saving picture end" << endl;
  14.     }
  15. }


  16. class TestFrameStateCallback : public FrameStateCallback {
  17.     void OnFrameFinished(Camera &camera, FrameConfig &fc, FrameResult &result) override
  18.     {
  19.         cout << "Receive frame complete inform." << endl;
  20.         if (fc.GetFrameConfigType() == FRAME_CONFIG_CAPTURE) {
  21.             cout << "Capture frame received." << endl;
  22.             list<Surface *> surfaceList = fc.GetSurfaces();
  23.             for (Surface *surface : surfaceList) {
  24.                 SurfaceBuffer *buffer = surface->AcquireBuffer();
  25.                 if (buffer != nullptr) {
  26.                     char *virtAddr = static_cast<char *>(buffer->GetVirAddr());
  27.                     if (virtAddr != nullptr) {
  28.                         SampleSaveCapture(virtAddr, buffer->GetSize());
  29.                     }
  30.                     surface->ReleaseBuffer(buffer);
  31.                 }
  32.                 delete surface;
  33.             }
  34.             delete &fc;
  35.         }
  36.     }
  37. };
复制代码
        3,实现相机状态回调的派生类,当相机状态发生变化(配置成功/失败,创建成功/失败)时,自定义操作。
  1. class SampleCameraStateMng : public CameraStateCallback {
  2. public:
  3.     SampleCameraStateMng() = delete;
  4.     SampleCameraStateMng(EventHandler &eventHdlr) : eventHdlr_(eventHdlr) {}
  5.     ~SampleCameraStateMng()
  6.     {
  7.         if (recordFd_ != -1) {
  8.             close(recordFd_);
  9.         }
  10.     }
  11.     void OnCreated(Camera &c) override
  12.     {
  13.         cout << "Sample recv OnCreate camera." << endl;
  14.         auto config = CameraConfig::CreateCameraConfig();
  15.         config->SetFrameStateCallback(&fsCb_, &eventHdlr_);
  16.         c.Configure(*config);
  17.         cam_ = &c;
  18.     }
  19.     void OnCreateFailed(const std::string cameraId, int32_t errorCode) override {}
  20.     void OnReleased(Camera &c) override {}
  21. };
复制代码
       4,创建CameraKit,用于创建和获取camera信息。
  1. CameraKit *camKit = CameraKit::GetInstance();
  2. list<string> camList = camKit->GetCameraIds();
  3. string camId;
  4. for (auto &cam : camList) {
  5.     cout << "camera name:" << cam << endl;
  6.     const CameraAbility *ability = camKit->GetCameraAbility(cam);
  7.     /* find camera which fits user's ability */
  8.     list<CameraPicSize> sizeList = ability->GetSupportedSizes(0);
  9.     if (find(sizeList.begin(), sizeList.end(), CAM_PIC_1080P) != sizeList.end()) {
  10.         camId = cam;
  11.         break;
  12.     }
  13. }
复制代码
       5,创建Camera实例。
  1. EventHandler eventHdlr; // Create a thread to handle callback events
  2. SampleCameraStateMng CamStateMng(eventHdlr);


  3. camKit->CreateCamera(camId, CamStateMng, eventHdlr);
复制代码
     6,根据步骤1、步骤2、步骤3中的回调设计,camera实例创建成功后会进行配置操作,主流程中app需要设计同步机制。
  1. void OnCreated(Camera &c) override
  2. {
  3.     cout << "Sample recv OnCreate camera." << endl;
  4.     auto config = CameraConfig::CreateCameraConfig();
  5.     config->SetFrameStateCallback(&fsCb_, &eventHdlr_);
  6.     c.Configure(*config);
  7.     cam_ = &c;
  8. }


  9. void Capture()
  10. {
  11.     if (cam_ == nullptr) {
  12.         cout << "Camera is not ready." << endl;
  13.         return;
  14.     }
  15.     FrameConfig *fc = new FrameConfig(FRAME_CONFIG_CAPTURE);
  16.     Surface *surface = Surface::CreateSurface();
  17.     if (surface == nullptr) {
  18.         delete fc;
  19.     }
  20.     surface->SetWidthAndHeight(1920, 1080); /* 1920:width,1080:height */
  21.     fc->AddSurface(*surface);
  22.     cam_->TriggerSingleCapture(*fc);
  23. }
复制代码
录像步骤
       1,1-4步和拍照开发步骤相同。
       2,获取录像FrameConfig。
  1. /* 从recorder获取surface */
  2. Surface *surface = recorder_->GetSurface(0);
  3. surface->SetWidthAndHeight(1920, 1080);
  4. surface->SetQueueSize(3);
  5. surface->SetSize(1024 * 1024);
  6. /* 将surface配置到帧配置中 */
  7. FrameConfig *fc = new FrameConfig(FRAME_CONFIG_RECORD);
  8. fc->AddSurface(*surface);
复制代码
       3,开启和停止录像。
  1. stateCallback->camera_->TriggerLoopingCapture(*fc); // 开始录像
  2. stateCallback->camera_->StopLoopingCapture(); // 结束录像
复制代码


三、调试运行
       1,通过TF卡拷贝到开发板运行
       将可执行文件camera_sample拷贝到TF卡中,然后插入TF卡到开发板,如果先插TF到开发板再开机会自动挂载TF到/sdcard目录,如果是先开机再插入TF卡,则需要手动进行挂载TF卡,手动挂载TF卡方法如下:
mount.png

       2,如果没有TF卡或读卡器,可以将编译出来的camera_sample可执行文件,生产到rootfs.img中,然后烧录到开发板进行运行。需要修改applications/sample/camera/media/BUILD.gn文件

output_dir = "$root_out_dir/dev_ools"修改为output_dir = "$root_out_dir/"即可。
重新执行源码仓编译并烧写入单板后,可在单板bin目录下找到camera_sample文件。
        3,在开发板运行
run.png


如上图,运行示例程序后
按1进行拍照,拍照的文件格式为jpg,存储在/sdcard,文件名Capture*;
按2进行录像,录像的文件格式为mp4,存储在/sdcard,文件名Record*,按s键停止;
按q可退出程序。














回帖

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
链接复制成功,分享给好友