1 /*
2 * Copyright 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #ifndef HDR_PLUS_TYPES_H
17 #define HDR_PLUS_TYPES_H
18
19 #include <array>
20 #include <stdint.h>
21 #include <string>
22 #include <vector>
23
24 namespace pbcamera {
25
26 // This file defines the common types used in HDR+ client and HDR+ service API.
27
28 typedef int32_t status_t;
29
30 /*
31 * ImageConfiguration and PlaneConfiguration define the layout of a buffer.
32 * The following is an example of a NV21 buffer.
33 *
34 * <-------Y stride (in bytes)------->
35 * <----width (in pixels)---->
36 * Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^
37 * Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
38 * Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
39 * Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . height Y scanline
40 * Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . (in lines) (in lines)
41 * Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
42 * Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
43 * Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
44 * Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . | |
45 * Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . v |
46 * . . . . . . . . . . . . . . . . . . |
47 * . . . . . . . . . . . . . . . . . . v
48 * <------V/U stride (in bytes)------>
49 * V U V U V U V U V U V U V U . . . . ^
50 * V U V U V U V U V U V U V U . . . . |
51 * V U V U V U V U V U V U V U . . . . |
52 * V U V U V U V U V U V U V U . . . . V/U scanline
53 * V U V U V U V U V U V U V U . . . . (in lines)
54 * . . . . . . . . . . . . . . . . . . |
55 * . . . . . . . . . . . . . . . . . . v
56 * . . . . . . . . . . . . . . . . . . -> Image padding.
57 */
58
59 // PlaneConfiguration defines an image planes configuration.
60 struct PlaneConfiguration {
61 // Number of bytes in each line including padding.
62 uint32_t stride;
63 // Number of lines vertically including padding.
64 uint32_t scanline;
65
PlaneConfigurationPlaneConfiguration66 PlaneConfiguration() : stride(0), scanline(0) {};
67
68 bool operator==(const PlaneConfiguration &other) const {
69 return stride == other.stride &&
70 scanline == other.scanline;
71 }
72
73 bool operator!=(const PlaneConfiguration &other) const {
74 return !(*this == other);
75 }
76 };
77
78 // ImageConfiguration defines an image configuration.
79 struct ImageConfiguration {
80 // Image width.
81 uint32_t width;
82 // Image height;
83 uint32_t height;
84 // Image format;
85 int format;
86 // Configuration for each planes.
87 std::vector<PlaneConfiguration> planes;
88 // Number of padded bytes after the last plane.
89 uint32_t padding;
90
ImageConfigurationImageConfiguration91 ImageConfiguration() : width(0), height(0), format(0), padding(0) {};
92
93 bool operator==(const ImageConfiguration &other) const {
94 return width == other.width &&
95 height == other.height &&
96 format == other.format &&
97 planes == other.planes &&
98 padding == other.padding;
99 }
100
101 bool operator!=(const ImageConfiguration &other) const {
102 return !(*this == other);
103 }
104 };
105
106 /*
107 * StreamConfiguration defines a stream's configuration, such as its image buffer resolution, used
108 * during stream configuration.
109 */
110 struct StreamConfiguration {
111 /*
112 * Unique ID of the stream. Each stream must have an unique ID so it can be used to identify
113 * the output streams of a StreamBuffer in CaptureRequest.
114 */
115 uint32_t id;
116
117 // Image configuration.
118 ImageConfiguration image;
119
120 bool operator==(const StreamConfiguration &other) const {
121 return id == other.id &&
122 image == other.image;
123 }
124
125 bool operator!=(const StreamConfiguration &other) const {
126 return !(*this == other);
127 }
128 };
129
130 /*
131 * SensorMode contains the sensor mode information.
132 */
133 struct SensorMode {
134 // Usually 0 is back camera and 1 is front camera.
135 uint32_t cameraId;
136
137 // Pixel array resolution.
138 uint32_t pixelArrayWidth;
139 uint32_t pixelArrayHeight;
140
141 // Active array resolution.
142 uint32_t activeArrayWidth;
143 uint32_t activeArrayHeight;
144
145 // Sensor output pixel clock.
146 uint32_t outputPixelClkHz;
147
148 // Sensor timestamp offset due to gyro calibration. When comparing timestamps between AP and
149 // Easel, this offset should be subtracted from AP timestamp.
150 int64_t timestampOffsetNs;
151
152 // Sensor timestamp offset due to sensor cropping. When comparing timestamps between AP and
153 // Easel, this offset should be subtracted from AP timestamp.
154 int64_t timestampCropOffsetNs;
155
156 // Sensor output format as defined in android_pixel_format.
157 int format;
158
SensorModeSensorMode159 SensorMode() : cameraId(0), pixelArrayWidth(0), pixelArrayHeight(0), activeArrayWidth(0),
160 activeArrayHeight(0), outputPixelClkHz(0) {};
161 };
162
163 /*
164 * InputConfiguration defines the input configuration for HDR+ service.
165 */
166 struct InputConfiguration {
167 // Whether the input frames come from sensor MIPI or AP. If true, HDR+ service will get input
168 // frames from sensor and sensorMode contains the sensor mode information. If false, HDR+
169 // service will get input frames from AP and streamConfig contains the input stream
170 // configuration.
171 bool isSensorInput;
172 // Sensor mode if isSensorInput is true.
173 SensorMode sensorMode;
174 // Input stream configuration if isSensorInput is false.
175 StreamConfiguration streamConfig;
176
InputConfigurationInputConfiguration177 InputConfiguration() : isSensorInput(false) {};
178 };
179
180 /*
181 * StreamBuffer defines a buffer in a stream.
182 */
183 struct StreamBuffer {
184 // ID of the stream that this buffer belongs to.
185 uint32_t streamId;
186 // DMA buffer fd for this buffer if it's an ION buffer.
187 int32_t dmaBufFd;
188 // Pointer to the data of this buffer.
189 void* data;
190 // Size of the allocated data.
191 uint32_t dataSize;
192 };
193
194 /*
195 * CaptureRequest defines a capture request that HDR+ client sends to HDR+ service.
196 */
197 struct CaptureRequest {
198 /*
199 * ID of the capture request. Each capture request must have an unique ID. When HDR+ service
200 * sends a CaptureResult to HDR+ client for this request, CaptureResult.requestId will be
201 * assigned to this ID.
202 */
203 uint32_t id;
204 /*
205 * Output buffers of the request. The buffers will be filled with captured image when HDR+
206 * service sends the output buffers in CaptureResult.
207 */
208 std::vector<StreamBuffer> outputBuffers;
209 };
210
211 // Util functions used in StaticMetadata and FrameMetadata.
212 namespace metadatautils {
213 template<typename T>
214 void appendValueToString(std::string *strOut, const char* key, T value);
215
216 template<typename T>
217 void appendVectorOrArrayToString(std::string *strOut, T values);
218
219 template<typename T>
220 void appendVectorOrArrayToString(std::string *strOut, const char* key, T values);
221
222 template<typename T, size_t SIZE>
223 void appendVectorArrayToString(std::string *strOut, const char* key,
224 std::vector<std::array<T, SIZE>> values);
225
226 template<typename T, size_t SIZE>
227 void appendArrayArrayToString(std::string *strOut, const char* key,
228 std::array<T, SIZE> values);
229 } // namespace metadatautils
230
231 static const uint32_t DEBUG_PARAM_NONE = 0u;
232 static const uint32_t DEBUG_PARAM_SAVE_GCAME_INPUT_METERING = (1u);
233 static const uint32_t DEBUG_PARAM_SAVE_GCAME_INPUT_PAYLOAD = (1u << 1);
234 static const uint32_t DEBUG_PARAM_SAVE_GCAME_TEXT = (1u << 2);
235 static const uint32_t DEBUG_PARAM_SAVE_PROFILE = (1u << 3);
236 static const uint32_t DEBUG_PARAM_SAVE_GCAME_IPU_WATERMARK = (1u << 4);
237
238 /*
239 * StaticMetadata defines a camera device's characteristics.
240 *
241 * If this structure is changed, serialization in MessengerToHdrPlusService and deserialization in
242 * MessengerListenerFromHdrPlusClient should also be updated.
243 */
244 struct StaticMetadata {
245 // The following are from Android Camera Metadata
246 uint8_t flashInfoAvailable; // android.flash.info.available
247 std::array<int32_t, 2> sensitivityRange; // android.sensor.info.sensitivityRange
248 int32_t maxAnalogSensitivity; // android.sensor.maxAnalogSensitivity
249 std::array<int32_t, 2> pixelArraySize; // android.sensor.info.pixelArraySize
250 std::array<int32_t, 4> activeArraySize; // android.sensor.info.activeArraySize
251 std::vector<std::array<int32_t, 4>> opticalBlackRegions; // android.sensor.opticalBlackRegions
252 // android.scaler.availableStreamConfigurations
253 std::vector<std::array<int32_t, 4>> availableStreamConfigurations;
254 uint8_t referenceIlluminant1; // android.sensor.referenceIlluminant1
255 uint8_t referenceIlluminant2; // android.sensor.referenceIlluminant2
256 std::array<float, 9> calibrationTransform1; // android.sensor.calibrationTransform1
257 std::array<float, 9> calibrationTransform2; // android.sensor.calibrationTransform2
258 std::array<float, 9> colorTransform1; // android.sensor.colorTransform1
259 std::array<float, 9> colorTransform2; // android.sensor.colorTransform2
260 int32_t whiteLevel; // android.sensor.info.whiteLevel
261 uint8_t colorFilterArrangement; // android.sensor.info.colorFilterArrangement
262 std::vector<float> availableApertures; // android.lens.info.availableApertures
263 std::vector<float> availableFocalLengths; // android.lens.info.availableFocalLengths
264 std::array<int32_t, 2> shadingMapSize; // android.lens.info.shadingMapSize
265 uint8_t focusDistanceCalibration; // android.lens.info.focusDistanceCalibration
266 std::array<int32_t, 2> aeCompensationRange; // android.control.aeCompensationRange
267 float aeCompensationStep; // android.control.aeCompensationStep
268
269 uint32_t debugParams; // Use HDRPLUS_DEBUG_PARAM_*
270
271 // Convert this static metadata to a string and append it to the specified string.
appendToStringStaticMetadata272 void appendToString(std::string *strOut) const {
273 if (strOut == nullptr) return;
274
275 metadatautils::appendValueToString(strOut, "flashInfoAvailable", flashInfoAvailable);
276 metadatautils::appendVectorOrArrayToString(strOut, "sensitivityRange", sensitivityRange);
277 metadatautils::appendValueToString(strOut, "maxAnalogSensitivity", maxAnalogSensitivity);
278 metadatautils::appendVectorOrArrayToString(strOut, "pixelArraySize", pixelArraySize);
279 metadatautils::appendVectorOrArrayToString(strOut, "activeArraySize", activeArraySize);
280 metadatautils::appendVectorArrayToString(strOut, "opticalBlackRegions",
281 opticalBlackRegions);
282 metadatautils::appendVectorArrayToString(strOut, "availableStreamConfigurations",
283 availableStreamConfigurations);
284 metadatautils::appendValueToString(strOut, "referenceIlluminant1", referenceIlluminant1);
285 metadatautils::appendValueToString(strOut, "referenceIlluminant2", referenceIlluminant2);
286 metadatautils::appendVectorOrArrayToString(strOut, "calibrationTransform1",
287 calibrationTransform1);
288 metadatautils::appendVectorOrArrayToString(strOut, "calibrationTransform2",
289 calibrationTransform2);
290 metadatautils::appendVectorOrArrayToString(strOut, "colorTransform1", colorTransform1);
291 metadatautils::appendVectorOrArrayToString(strOut, "colorTransform2", colorTransform2);
292 metadatautils::appendValueToString(strOut, "whiteLevel", whiteLevel);
293 metadatautils::appendValueToString(strOut, "colorFilterArrangement",
294 colorFilterArrangement);
295 metadatautils::appendVectorOrArrayToString(strOut, "availableApertures",
296 availableApertures);
297 metadatautils::appendVectorOrArrayToString(strOut, "availableFocalLengths",
298 availableFocalLengths);
299 metadatautils::appendVectorOrArrayToString(strOut, "shadingMapSize", shadingMapSize);
300 metadatautils::appendValueToString(strOut, "focusDistanceCalibration",
301 focusDistanceCalibration);
302 metadatautils::appendVectorOrArrayToString(strOut, "aeCompensationRange",
303 aeCompensationRange);
304 metadatautils::appendValueToString(strOut, "aeCompensationStep",
305 aeCompensationStep);
306 metadatautils::appendValueToString(strOut, "debugParams", debugParams);
307 }
308 };
309
310 /*
311 * FrameMetadata defines properties of a frame captured on AP.
312 *
313 * If this structure is changed, serialization in MessengerToHdrPlusService and deserialization in
314 * MessengerListenerFromHdrPlusClient should also be updated.
315 */
316 struct FrameMetadata {
317 int64_t easelTimestamp; // Easel timestamp
318
319 // The following are from Android Camera Metadata
320 int64_t exposureTime; // android.sensor.exposureTime
321 int32_t sensitivity; // android.sensor.sensitivity
322 int32_t postRawSensitivityBoost; // android.control.postRawSensitivityBoost
323 uint8_t flashMode; // android.flash.mode
324 std::array<float, 4> colorCorrectionGains; // android.colorCorrection.gains
325 std::array<float, 9> colorCorrectionTransform; // android.colorCorrection.transform
326 std::array<float, 3> neutralColorPoint; // android.sensor.neutralColorPoint
327 int64_t timestamp; // android.sensor.timestamp
328 uint8_t blackLevelLock; // android.blackLevel.lock
329 uint8_t faceDetectMode; // android.statistics.faceDetectMode
330 std::vector<int32_t> faceIds; // android.statistics.faceIds
331 std::vector<std::array<int32_t, 6>> faceLandmarks; // android.statistics.faceLandmarks
332 std::vector<std::array<int32_t, 4>> faceRectangles; // android.statistics.faceRectangles
333 std::vector<uint8_t> faceScores; // android.statistics.faceScores
334 uint8_t sceneFlicker; // android.statistics.sceneFlicker
335 std::array<std::array<double, 2>, 4> noiseProfile; // android.sensor.noiseProfile
336 std::array<float, 4> dynamicBlackLevel; // android.sensor.dynamicBlackLevel
337 std::vector<float> lensShadingMap; // android.statistics.lensShadingMap
338 float focusDistance; // android.lens.focusDistance
339 int32_t aeExposureCompensation; // android.control.aeExposureCompensation
340 uint8_t aeMode; // android.control.aeMode
341 uint8_t aeLock; // android.control.aeLock
342 uint8_t aeState; // android.control.aeState
343 uint8_t aePrecaptureTrigger; // android.control.aePrecaptureTrigger
344 std::vector<std::array<int32_t, 5>> aeRegions; // android.control.aeRegions
345
346 // Convert this static metadata to a string and append it to the specified string.
appendToStringFrameMetadata347 void appendToString(std::string *strOut) const {
348 if (strOut == nullptr) return;
349
350 metadatautils::appendValueToString(strOut, "easelTimestamp", easelTimestamp);
351 metadatautils::appendValueToString(strOut, "exposureTime", exposureTime);
352 metadatautils::appendValueToString(strOut, "sensitivity", sensitivity);
353 metadatautils::appendValueToString(strOut, "postRawSensitivityBoost",
354 postRawSensitivityBoost);
355 metadatautils::appendValueToString(strOut, "flashMode", flashMode);
356 metadatautils::appendVectorOrArrayToString(strOut, "colorCorrectionGains",
357 colorCorrectionGains);
358 metadatautils::appendVectorOrArrayToString(strOut, "colorCorrectionTransform",
359 colorCorrectionTransform);
360 metadatautils::appendVectorOrArrayToString(strOut, "neutralColorPoint", neutralColorPoint);
361 metadatautils::appendValueToString(strOut, "timestamp", timestamp);
362 metadatautils::appendValueToString(strOut, "blackLevelLock", blackLevelLock);
363 metadatautils::appendValueToString(strOut, "faceDetectMode", faceDetectMode);
364 metadatautils::appendVectorOrArrayToString(strOut, "faceIds", faceIds);
365 metadatautils::appendVectorArrayToString(strOut, "faceLandmarks", faceLandmarks);
366 metadatautils::appendVectorArrayToString(strOut, "faceRectangles", faceRectangles);
367 metadatautils::appendVectorOrArrayToString(strOut, "faceScores", faceScores);
368 metadatautils::appendArrayArrayToString(strOut, "noiseProfile", noiseProfile);
369 metadatautils::appendValueToString(strOut, "sceneFlicker", sceneFlicker);
370 metadatautils::appendVectorOrArrayToString(strOut, "dynamicBlackLevel", dynamicBlackLevel);
371 metadatautils::appendVectorOrArrayToString(strOut, "lensShadingMap", lensShadingMap);
372 metadatautils::appendValueToString(strOut, "focusDistance", focusDistance);
373 metadatautils::appendValueToString(strOut, "aeExposureCompensation", aeExposureCompensation);
374 metadatautils::appendValueToString(strOut, "aeMode", aeMode);
375 metadatautils::appendValueToString(strOut, "aeLock", aeLock);
376 metadatautils::appendValueToString(strOut, "aeState", aeState);
377 metadatautils::appendValueToString(strOut, "aePrecaptureTrigger", aePrecaptureTrigger);
378 metadatautils::appendVectorArrayToString(strOut, "aeRegions", aeRegions);
379 }
380 };
381
382 /*
383 * RequestMetadata defines the properties for a capture request.
384 *
385 * If this structure is changed, serialization in MessengerToHdrPlusClient and deserialization in
386 * MessengerListenerFromHdrPlusService should also be updated.
387 */
388 struct RequestMetadata {
389 std::array<int32_t, 4> cropRegion; // android.scaler.cropRegion (x_min, y_min, width, height)
390 int32_t aeExposureCompensation; // android.control.aeExposureCompensation
391
392 bool postviewEnable; // com.google.nexus.experimental2017.stats.postview_enable
393 bool continuousCapturing; // Whether to capture RAW while HDR+ processing.
394
395 // Convert this static metadata to a string and append it to the specified string.
appendToStringRequestMetadata396 void appendToString(std::string *strOut) const {
397 if (strOut == nullptr) return;
398 metadatautils::appendVectorOrArrayToString(strOut, "cropRegion", cropRegion);
399 metadatautils::appendValueToString(strOut, "aeExposureCompensation", aeExposureCompensation);
400 metadatautils::appendValueToString(strOut, "postviewEnable", postviewEnable);
401 metadatautils::appendValueToString(strOut, "continuousCapturing", continuousCapturing);
402 }
403 };
404
405 /*
406 * ResultMetadata defines a process frame's properties that have been modified due to processing.
407 *
408 * If this structure is changed, serialization in MessengerToHdrPlusClient and deserialization in
409 * MessengerListenerFromHdrPlusService should also be updated.
410 */
411 struct ResultMetadata {
412 int64_t easelTimestamp; // Easel timestamp of SOF of the base frame.
413 int64_t timestamp; // android.sensor.timestamp. AP timestamp of exposure start of the base
414 // frame.
415 std::string makernote; // Obfuscated capture information.
416
417 // Convert this static metadata to a string and append it to the specified string.
appendToStringResultMetadata418 void appendToString(std::string *strOut) const {
419 if (strOut == nullptr) return;
420 metadatautils::appendValueToString(strOut, "easelTimestamp", easelTimestamp);
421 metadatautils::appendValueToString(strOut, "timestamp", timestamp);
422 metadatautils::appendValueToString(strOut, "makernote", makernote.size());
423 }
424 };
425
426 /*
427 * CaptureResult defines a capture result that HDR+ service returns to HDR+ client.
428 */
429 struct CaptureResult {
430 /*
431 * ID of the CaptureRequest that this capture result corresponds to. It can be used to match
432 * the original CaptureRequest when the HDR+ client receives this result.
433 */
434 uint32_t requestId;
435 /*
436 * Output buffers filled with processed frame by HDR+ service.
437 */
438 std::vector<StreamBuffer> outputBuffers;
439
440 /*
441 * Result metadata including modified properties due to processing.
442 */
443 ResultMetadata metadata;
444 };
445
446 // Util functions used in StaticMetadata and FrameMetadata.
447 namespace metadatautils {
448
449 /*
450 * Append a key and a value to a string.
451 *
452 * strOut is the string to append a key and a value to.
453 * key is the name of the data.
454 * value is the value of the data.
455 */
456 template<typename T>
appendValueToString(std::string * strOut,const char * key,T value)457 void appendValueToString(std::string *strOut, const char* key, T value) {
458 if (strOut == nullptr) return;
459 (*strOut) += std::string(key) + ": " + std::to_string(value) + "\n";
460 }
461
462 /*
463 * Append a vector or an array of values to a string.
464 *
465 * strOut is the string to append a key and values to.
466 * values is a vector or an array containing values to append to the string.
467 */
468 template<typename T>
appendVectorOrArrayToString(std::string * strOut,T values)469 void appendVectorOrArrayToString(std::string *strOut, T values) {
470 if (strOut == nullptr) return;
471 for (size_t i = 0; i < values.size(); i++) {
472 (*strOut) += std::to_string(values[i]);
473 if (i != values.size() - 1) {
474 (*strOut) +=", ";
475 }
476 }
477 }
478
479 /*
480 * Append a key and a vector or an array of values to a string.
481 *
482 * strOut is the string to append a key and values to.
483 * key is the name of the data.
484 * values is a vector or an array containing values to append to the string.
485 */
486 template<typename T>
appendVectorOrArrayToString(std::string * strOut,const char * key,T values)487 void appendVectorOrArrayToString(std::string *strOut, const char* key, T values) {
488 if (strOut == nullptr) return;
489 (*strOut) += std::string(key) + ": ";
490 appendVectorOrArrayToString(strOut, values);
491 (*strOut) += "\n";
492 }
493
494 /*
495 * Append a key and a vector of arrays to a string.
496 *
497 * strOut is the string to append a key and values to.
498 * key is the name of the data.
499 * values is a vector of arrays containing values to append to the string.
500 */
501 template<typename T, size_t SIZE>
appendVectorArrayToString(std::string * strOut,const char * key,std::vector<std::array<T,SIZE>> values)502 void appendVectorArrayToString(std::string *strOut, const char* key,
503 std::vector<std::array<T, SIZE>> values) {
504 if (strOut == nullptr) return;
505 (*strOut) += std::string(key) + ": ";
506 for (size_t i = 0; i < values.size(); i++) {
507 appendVectorOrArrayToString(strOut, values[i]);
508 if (i != values.size() - 1) {
509 (*strOut) +=", ";
510 }
511 }
512 (*strOut) += "\n";
513 }
514
515 /*
516 * Append a key and an array of arrays to a string.
517 *
518 * strOut is the string to append a key and values to.
519 * key is the name of the data.
520 * values is an array of arrays containing values to append to the string.
521 */
522 template<typename T, size_t SIZE>
appendArrayArrayToString(std::string * strOut,const char * key,std::array<T,SIZE> values)523 void appendArrayArrayToString(std::string *strOut, const char* key,
524 std::array<T, SIZE> values) {
525 if (strOut == nullptr) return;
526 (*strOut) += std::string(key) + ": ";
527 for (size_t i = 0; i < values.size(); i++) {
528 appendVectorOrArrayToString(strOut, values[i]);
529 if (i != values.size() - 1) {
530 (*strOut) +=", ";
531 }
532 }
533 (*strOut) += "\n";
534 }
535
536 } // namespace metadatautils
537
538 } // namespace pbcamera
539
540 #endif // HDR_PLUS_TYPES_H
541