• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Deferred Photo Delivery (C/C++)
2<!--Kit: Camera Kit-->
3<!--Subsystem: Multimedia-->
4<!--Owner: @qano-->
5<!--SE: @leo_ysl-->
6<!--TSE: @xchaosioda-->
7
8As an important feature of the camera, deferred photo delivery enables the system, after receiving a photo capture task from an application, to report images of different quality levels in multiple phases.
9
10- In the first phase, the system promptly delivers an image that has undergone lightweight processing, offering a balance between reduced quality and swift image availability. The application receives a PhotoAsset object through the callback. Through this object, the application can call the media library APIs to read the image or flush the image to the disk.
11- In the second phase, the camera framework enhances the image to achieve full quality, either in response to the application's request for higher quality or when the system is not busy. The enhanced image is then sent back to the media library to replace the previously provided one.
12
13## How to Develop
14
15Read [Camera](../../reference/apis-camera-kit/capi-oh-camera.md) for the API reference.
16
171. Import the NDK, which provides camera-related attributes and methods.
18
19   ```c++
20   // Include the NDK header files.
21   #include <cstdint>
22   #include <cstdlib>
23   #include <cstring>
24   #include <string.h>
25   #include <memory>
26   #include "hilog/log.h"
27   #include "napi/native_api.h"
28   #include <ohcamera/camera.h>
29   #include <ohcamera/photo_output.h>
30   #include <ohcamera/camera_manager.h>
31   #include <multimedia/media_library/media_asset_manager_capi.h>
32   #include <multimedia/media_library/media_asset_change_request_capi.h>
33   #include <multimedia/media_library/media_access_helper_capi.h>
34   #include <multimedia/image_framework/image/image_packer_native.h>
35   ```
36
372. Link the dynamic libraries in the CMake script.
38
39   ```txt
40   target_link_libraries(entry PUBLIC
41       libace_napi.z.so
42       libhilog_ndk.z.so
43       libohcamera.so
44       libimage_source.so
45       libmedia_asset_manager.so
46       libimage_packer.so
47   )
48   ```
49
503. Initialize the camera and trigger photo capture. For details, see [Photo Capture (C/C++)](./native-camera-shooting.md).
51
524. Register a deferred photo delivery callback, which is defined as **PhotoAssetAvailable**. Compared with one-time photo capture, only the callback registered is different.
53
54   > **NOTE**
55   >
56   > If the **PhotoAssetAvailable** callback has been registered and the **PhotoAvailable** callback is registered after the session starts, the stream will be restarted. In this case, only the **PhotoAssetAvailable** callback takes effect.
57   >
58   > Therefore, you are not advised to register both **PhotoAssetAvailable** and **PhotoAvailable**.
59
60   Register **PhotoAssetAvailableCallback** to receive images delivered in both phases.
61
62   The development process is as follows:
63
64   - Register the callback before the session commits the configuration.
65   - Obtain a media asset through the callback.
66   - Through the media asset, either save the images or request images and after service processing, save them through a buffer or display them. For details, see step 5 in [Photo Capture (C/C++)](./native-camera-shooting.md).
67   - Unregister the callback when it is no longer required.
68
69   ```c++
70   // Method 1: Call the media library API to save the images.
71   void mediaLibSavePhoto(OH_MediaAsset* mediaAsset) {
72       if (mediaAsset == nullptr) {
73           OH_LOG_ERROR(LOG_APP, "mediaAsset is nullptr!");
74           return;
75       }
76       // Create a media asset change request object.
77       OH_MediaAssetChangeRequest* changeRequest = OH_MediaAssetChangeRequest_Create(mediaAsset);
78       if (changeRequest == nullptr) {
79           OH_LOG_ERROR(LOG_APP, "changeRequest is nullptr!");
80           return;
81       }
82       // Request to save the image.
83       MediaLibrary_ErrorCode errCode =
84           OH_MediaAssetChangeRequest_SaveCameraPhoto(changeRequest, MEDIA_LIBRARY_IMAGE_JPEG);
85       OH_LOG_INFO(LOG_APP, "SaveCameraPhoto get errCode:%{public}d", errCode);
86       // Initiate a request.
87       errCode = OH_MediaAccessHelper_ApplyChanges(changeRequest);
88       OH_LOG_INFO(LOG_APP, "ApplyChanges get errCode:%{public}d", errCode);
89   }
90
91   // Method 2: Call the media library API to request images.
92   // Called when the image source is ready.
93   OH_MediaAsset* g_mediaAsset_;
94   void OnImageDataPrepared(MediaLibrary_ErrorCode result, MediaLibrary_RequestId requestId,
95                            MediaLibrary_MediaQuality mediaQuality, MediaLibrary_MediaContentType type,
96                            OH_ImageSourceNative* imageSourceNative) {
97       if (imageSourceNative == nullptr) {
98           OH_LOG_ERROR(LOG_APP, "OnImageDataPrepared: imageSourceNative is nullptr!");
99           return;
100       }
101       if (mediaQuality == MediaLibrary_MediaQuality::MEDIA_LIBRARY_QUALITY_FAST) {
102           OH_LOG_INFO(LOG_APP, "OnImageDataPrepared: Using fast media quality.");
103       } else if (mediaQuality == MediaLibrary_MediaQuality::MEDIA_LIBRARY_QUALITY_FULL) {
104           OH_LOG_INFO(LOG_APP, "OnImageDataPrepared: Using full media quality.");
105       }
106       // Create OH_PixelmapNative through OH_ImageSourceNative.
107       OH_PixelmapNative* pixelmapNative = nullptr;
108       OH_DecodingOptions* decodingOptions = nullptr;
109       Image_ErrorCode imageErr = IMAGE_SUCCESS;
110       imageErr = OH_ImageSourceNative_CreatePixelmap(imageSourceNative, decodingOptions, &pixelmapNative);
111       if (imageErr != IMAGE_SUCCESS) {
112           OH_LOG_ERROR(LOG_APP, "OnImageDataPrepared: CreatePixelmap failed.");
113           return;
114       }
115       // Create an image packer and set packing options.
116       OH_ImagePackerNative* imagePacker;
117       OH_ImagePackerNative_Create(&imagePacker);
118       OH_PackingOptions* options;
119       OH_PackingOptions_Create(&options);
120       char format[] = "image/jpeg";
121       Image_MimeType image_MimeType = {format, strlen(format)};
122       OH_PackingOptions_SetMimeType(options, &image_MimeType);
123       OH_PackingOptions_SetQuality (options, 100); // Highest quality: 100
124       size_t bufferSize = 3072 * 4096; // If a value greater than the size after encoding is passed, a new value will be assigned after encoding.
125       // Parse the image buffer.
126       auto buffer = std::make_unique<uint8_t[]>(bufferSize);
127       imageErr = OH_ImagePackerNative_PackToDataFromPixelmap(imagePacker, options, pixelmapNative, buffer.get(), &bufferSize);
128       OH_LOG_INFO(LOG_APP, "OnImageDataPrepared: packToData ret code:%{public}u outsize:%{public}zu", imageErr, bufferSize);
129       if (g_mediaAsset_ == nullptr) {
130           OH_LOG_ERROR(LOG_APP,  "OnImageDataPrepared: get current mediaAsset failed!");
131           return;
132       }
133       // Call the media library API to save images in the buffer.
134       OH_MediaAssetChangeRequest* changeRequest = OH_MediaAssetChangeRequest_Create(g_mediaAsset_);
135       MediaLibrary_ErrorCode mediaErr = OH_MediaAssetChangeRequest_AddResourceWithBuffer(changeRequest,
136           MEDIA_LIBRARY_IMAGE_RESOURCE, buffer.get(), bufferSize);
137       OH_LOG_INFO(LOG_APP,  "OnImageDataPrepared: AddResourceWithBuffer get errCode:%{public}d", mediaErr);
138       mediaErr = OH_MediaAssetChangeRequest_SaveCameraPhoto(changeRequest, MEDIA_LIBRARY_IMAGE_JPEG);
139       OH_LOG_INFO(LOG_APP,  "OnImageDataPrepared: SaveCameraPhoto get errCode:%{public}d", mediaErr);
140       mediaErr = OH_MediaAccessHelper_ApplyChanges(changeRequest);
141       OH_LOG_INFO(LOG_APP,  "OnImageDataPrepared: ApplyChanges get errCode:%{public}d", mediaErr);
142   }
143
144   void mediaLibRequestBuffer(OH_MediaAsset* mediaAsset) {
145       if (mediaAsset == nullptr) {
146           OH_LOG_ERROR(LOG_APP, "mediaAsset is nullptr!");
147           return;
148       }
149       // Create a media asset manager.
150       OH_MediaAssetManager* mediaAssetManager = OH_MediaAssetManager_Create();
151       if (mediaAssetManager == nullptr) {
152           OH_LOG_ERROR(LOG_APP, "mediaAssetManager is nullptr!");
153           return;
154       }
155       // Set the parameters for requesting images.
156       MediaLibrary_RequestOptions requestOptions;
157       // Configure the policy mode based on service requirements to request image assets.
158       // MEDIA_LIBRARY_FAST_MODE: callback for receiving the first-phase image.
159       // MEDIA_LIBRARY_HIGH_QUALITY_MODE: callback for receiving the second-phase image.
160       // MEDIA_LIBRARY_BALANCED_MODE: callback for receiving both images.
161       requestOptions.deliveryMode = MEDIA_LIBRARY_FAST_MODE;
162       MediaLibrary_RequestId requestId;
163       // Request the image asset. Call onImageDataPrepared when it is ready.
164       MediaLibrary_ErrorCode result = OH_MediaAssetManager_RequestImage(mediaAssetManager, mediaAsset, requestOptions, &requestId, OnImageDataPrepared);
165       if (result != MEDIA_LIBRARY_OK) {
166           OH_LOG_ERROR(LOG_APP, "OH_MediaAssetManager_RequestImage failed.");
167       }
168   }
169
170   // Deferred phot delivery callback.
171   void OnPhotoAssetAvailable(Camera_PhotoOutput* photoOutput, OH_MediaAsset* mediaAsset) {
172       OH_LOG_INFO(LOG_APP, "OnPhotoAssetAvailable start!");
173       if (mediaAsset == nullptr) {
174           OH_LOG_ERROR(LOG_APP, "OnPhotoAssetAvailable mediaAsset nullptr!");
175           return;
176       }
177       // Processing method 1: Call the media library API to save the image in the first phase. After the image in the second phase is ready, the media library proactively replaces the image flushed.
178       // mediaLibSavePhoto(mediaAsset);
179       // Processing method 2: Call the media library API to request an image asset, obtain the buffer of the first-phase or second-phase image, and save the image in the buffer after service processing.
180       g_mediaAsset_ = mediaAsset;
181       mediaLibRequestBuffer(mediaAsset);
182   }
183
184   // Register the PhotoAssetAvailableCallback callback.
185   Camera_ErrorCode PhotoOutputRegisterPhotoAssetAvailableCallback(Camera_PhotoOutput* photoOutput) {
186       Camera_ErrorCode ret = OH_PhotoOutput_RegisterPhotoAssetAvailableCallback(photoOutput, OnPhotoAssetAvailable);
187       if (ret != CAMERA_OK) {
188           OH_LOG_ERROR(LOG_APP, "OH_PhotoOutput_RegisterPhotoAssetAvailableCallback failed.");
189       }
190       return ret;
191   }
192   ```
193