• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "hdecoder.h"
17 #include <cassert>
18 #include <sys/ioctl.h>
19 #include <linux/dma-buf.h>
20 #include "utils/hdf_base.h"
21 #include "codec_omx_ext.h"
22 #include "media_description.h"  // foundation/multimedia/av_codec/interfaces/inner_api/native/
23 #include "sync_fence.h"  // foundation/graphic/graphic_2d/utils/sync_fence/export/
24 #include "OMX_VideoExt.h"
25 #include "hcodec_log.h"
26 #include "hcodec_dfx.h"
27 #include "type_converter.h"
28 #include "surface_buffer.h"
29 #include "buffer_extra_data_impl.h"  // foundation/graphic/graphic_surface/surface/include/
30 
31 namespace OHOS::MediaAVCodec {
32 using namespace std;
33 using namespace CodecHDI;
34 
~HDecoder()35 HDecoder::~HDecoder()
36 {
37     MsgHandleLoop::Stop();
38 }
39 
OnConfigure(const Format & format)40 int32_t HDecoder::OnConfigure(const Format &format)
41 {
42     configFormat_ = make_shared<Format>(format);
43 
44     int32_t ret = SetLowLatency(format);
45     if (ret != AVCS_ERR_OK) {
46         return ret;
47     }
48     SaveTransform(format);
49     SaveScaleMode(format);
50     (void)SetProcessName();
51     (void)SetFrameRateAdaptiveMode(format);
52     return SetupPort(format);
53 }
54 
SetupPort(const Format & format)55 int32_t HDecoder::SetupPort(const Format &format)
56 {
57     int32_t width;
58     if (!format.GetIntValue(MediaDescriptionKey::MD_KEY_WIDTH, width) || width <= 0) {
59         HLOGE("format should contain width");
60         return AVCS_ERR_INVALID_VAL;
61     }
62     int32_t height;
63     if (!format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height) || height <= 0) {
64         HLOGE("format should contain height");
65         return AVCS_ERR_INVALID_VAL;
66     }
67     HLOGI("user set width %d, height %d", width, height);
68     if (!GetPixelFmtFromUser(format)) {
69         return AVCS_ERR_INVALID_VAL;
70     }
71 
72     optional<double> frameRate = GetFrameRateFromUser(format);
73     if (frameRate.has_value()) {
74         codecRate_ = frameRate.value();
75     } else {
76         HLOGI("user don't set valid frame rate, use default 60.0");
77         frameRate = 60.0;  // default frame rate 60.0
78     }
79 
80     PortInfo inputPortInfo {static_cast<uint32_t>(width), static_cast<uint32_t>(height),
81                             codingType_, std::nullopt, frameRate.value()};
82     int32_t maxInputSize = 0;
83     if (format.GetIntValue(MediaDescriptionKey::MD_KEY_MAX_INPUT_SIZE, maxInputSize)) {
84         if (maxInputSize > 0) {
85             inputPortInfo.inputBufSize = static_cast<uint32_t>(maxInputSize);
86         } else {
87             HLOGW("user don't set valid input buffer size");
88         }
89     }
90 
91     int32_t ret = SetVideoPortInfo(OMX_DirInput, inputPortInfo);
92     if (ret != AVCS_ERR_OK) {
93         return ret;
94     }
95 
96     PortInfo outputPortInfo = {static_cast<uint32_t>(width), static_cast<uint32_t>(height),
97                                OMX_VIDEO_CodingUnused, configuredFmt_, frameRate.value()};
98     ret = SetVideoPortInfo(OMX_DirOutput, outputPortInfo);
99     if (ret != AVCS_ERR_OK) {
100         return ret;
101     }
102 
103     return AVCS_ERR_OK;
104 }
105 
UpdateInPortFormat()106 int32_t HDecoder::UpdateInPortFormat()
107 {
108     OMX_PARAM_PORTDEFINITIONTYPE def;
109     InitOMXParam(def);
110     def.nPortIndex = OMX_DirInput;
111     if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
112         HLOGE("get input port definition failed");
113         return AVCS_ERR_UNKNOWN;
114     }
115     PrintPortDefinition(def);
116     if (inputFormat_ == nullptr) {
117         inputFormat_ = make_shared<Format>();
118     }
119     inputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, def.format.video.nFrameWidth);
120     inputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, def.format.video.nFrameHeight);
121     return AVCS_ERR_OK;
122 }
123 
UpdateConfiguredFmt(OMX_COLOR_FORMATTYPE portFmt)124 bool HDecoder::UpdateConfiguredFmt(OMX_COLOR_FORMATTYPE portFmt)
125 {
126     auto graphicFmt = static_cast<GraphicPixelFormat>(portFmt);
127     if (graphicFmt != configuredFmt_.graphicFmt) {
128         optional<PixelFmt> fmt = TypeConverter::GraphicFmtToFmt(graphicFmt);
129         if (!fmt.has_value()) {
130             return false;
131         }
132         HLOGI("GraphicPixelFormat need update: configured(%s) -> portdefinition(%s)",
133             configuredFmt_.strFmt.c_str(), fmt->strFmt.c_str());
134         configuredFmt_ = fmt.value();
135     }
136     return true;
137 }
138 
UpdateOutPortFormat()139 int32_t HDecoder::UpdateOutPortFormat()
140 {
141     OMX_PARAM_PORTDEFINITIONTYPE def;
142     InitOMXParam(def);
143     def.nPortIndex = OMX_DirOutput;
144     if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
145         HLOGE("get output port definition failed");
146         return AVCS_ERR_UNKNOWN;
147     }
148     PrintPortDefinition(def);
149     if (def.nBufferCountActual == 0) {
150         HLOGE("invalid bufferCount");
151         return AVCS_ERR_UNKNOWN;
152     }
153     (void)UpdateConfiguredFmt(def.format.video.eColorFormat);
154 
155     uint32_t w = def.format.video.nFrameWidth;
156     uint32_t h = def.format.video.nFrameHeight;
157 
158     // save into member variable
159     OHOS::Rect damage{};
160     GetCropFromOmx(w, h, damage);
161     outBufferCnt_ = def.nBufferCountActual;
162     requestCfg_.timeout = 0;
163     requestCfg_.width = damage.w;
164     requestCfg_.height = damage.h;
165     requestCfg_.strideAlignment = STRIDE_ALIGNMENT;
166     requestCfg_.format = configuredFmt_.graphicFmt;
167     requestCfg_.usage = GetProducerUsage();
168 
169     // save into format
170     if (outputFormat_ == nullptr) {
171         outputFormat_ = make_shared<Format>();
172     }
173     if (!outputFormat_->ContainKey(MediaDescriptionKey::MD_KEY_WIDTH)) {
174         outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, w); // deprecated
175     }
176     if (!outputFormat_->ContainKey(MediaDescriptionKey::MD_KEY_HEIGHT)) {
177         outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, h); // deprecated
178     }
179     outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_DISPLAY_WIDTH, damage.w);
180     outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_DISPLAY_HEIGHT, damage.h);
181     outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_PIC_WIDTH, damage.w);
182     outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_PIC_HEIGHT, damage.h);
183     outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT,
184         static_cast<int32_t>(configuredFmt_.innerFmt));
185     HLOGI("output format: %s", outputFormat_->Stringify().c_str());
186     return AVCS_ERR_OK;
187 }
188 
UpdateColorAspects()189 void HDecoder::UpdateColorAspects()
190 {
191     CodecVideoColorspace param;
192     InitOMXParamExt(param);
193     param.portIndex = OMX_DirOutput;
194     if (!GetParameter(OMX_IndexColorAspects, param, true)) {
195         return;
196     }
197     HLOGI("isFullRange %d, primary %u, transfer %u, matrix %u",
198         param.aspects.range, param.aspects.primaries, param.aspects.transfer, param.aspects.matrixCoeffs);
199     if (outputFormat_) {
200         outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_RANGE_FLAG, param.aspects.range);
201         outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_COLOR_PRIMARIES, param.aspects.primaries);
202         outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_TRANSFER_CHARACTERISTICS, param.aspects.transfer);
203         outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_MATRIX_COEFFICIENTS, param.aspects.matrixCoeffs);
204         HLOGI("output format changed: %s", outputFormat_->Stringify().c_str());
205         callback_->OnOutputFormatChanged(*(outputFormat_.get()));
206     }
207 }
208 
GetCropFromOmx(uint32_t w,uint32_t h,OHOS::Rect & damage)209 void HDecoder::GetCropFromOmx(uint32_t w, uint32_t h, OHOS::Rect& damage)
210 {
211     damage.x = 0;
212     damage.y = 0;
213     damage.w = static_cast<int32_t>(w);
214     damage.h = static_cast<int32_t>(h);
215 
216     OMX_CONFIG_RECTTYPE rect;
217     InitOMXParam(rect);
218     rect.nPortIndex = OMX_DirOutput;
219     if (!GetParameter(OMX_IndexConfigCommonOutputCrop, rect, true)) {
220         HLOGW("get crop failed, use default");
221         return;
222     }
223     if (rect.nLeft < 0 || rect.nTop < 0 ||
224         rect.nWidth == 0 || rect.nHeight == 0 ||
225         rect.nLeft + static_cast<int32_t>(rect.nWidth) > static_cast<int32_t>(w) ||
226         rect.nTop + static_cast<int32_t>(rect.nHeight) > static_cast<int32_t>(h)) {
227         HLOGW("wrong crop rect (%d, %d, %u, %u) vs. frame (%u," \
228               "%u), use default", rect.nLeft, rect.nTop, rect.nWidth, rect.nHeight, w, h);
229         return;
230     }
231     HLOGI("crop rect (%d, %d, %u, %u)",
232           rect.nLeft, rect.nTop, rect.nWidth, rect.nHeight);
233     damage.x = rect.nLeft;
234     damage.y = rect.nTop;
235     damage.w = static_cast<int32_t>(rect.nWidth);
236     damage.h = static_cast<int32_t>(rect.nHeight);
237     if (outputFormat_) {
238         outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_CROP_LEFT, rect.nLeft);
239         outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_CROP_TOP, rect.nTop);
240         outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_CROP_RIGHT,
241             static_cast<int32_t>(rect.nLeft + rect.nWidth) - 1);
242         outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_CROP_BOTTOM,
243             static_cast<int32_t>(rect.nTop + rect.nHeight) - 1);
244     }
245 }
246 
OnSetOutputSurface(const sptr<Surface> & surface,bool cfg)247 int32_t HDecoder::OnSetOutputSurface(const sptr<Surface> &surface, bool cfg)
248 {
249     return cfg ? OnSetOutputSurfaceWhenCfg(surface) : OnSetOutputSurfaceWhenRunning(surface);
250 }
251 
OnSetOutputSurfaceWhenCfg(const sptr<Surface> & surface)252 int32_t HDecoder::OnSetOutputSurfaceWhenCfg(const sptr<Surface> &surface)
253 {
254     SCOPED_TRACE();
255     HLOGI(">>");
256     if (surface == nullptr) {
257         HLOGE("surface is null");
258         return AVCS_ERR_INVALID_VAL;
259     }
260     if (surface->IsConsumer()) {
261         HLOGE("expect a producer surface but got a consumer surface");
262         return AVCS_ERR_INVALID_VAL;
263     }
264     int32_t ret = RegisterListenerToSurface(surface);
265     if (ret != AVCS_ERR_OK) {
266         return ret;
267     }
268     currSurface_ = SurfaceItem(surface);
269     HLOGI("set surface(%" PRIu64 ")(%s) succ", surface->GetUniqueId(), surface->GetName().c_str());
270     return AVCS_ERR_OK;
271 }
272 
OnSetParameters(const Format & format)273 int32_t HDecoder::OnSetParameters(const Format &format)
274 {
275     int32_t ret = SaveTransform(format, true);
276     if (ret != AVCS_ERR_OK) {
277         return ret;
278     }
279     ret = SaveScaleMode(format, true);
280     if (ret != AVCS_ERR_OK) {
281         return ret;
282     }
283     optional<double> frameRate = GetFrameRateFromUser(format);
284     if (frameRate.has_value()) {
285         OMX_PARAM_U32TYPE framerateCfgType;
286         InitOMXParam(framerateCfgType);
287         framerateCfgType.nPortIndex = OMX_DirInput;
288         framerateCfgType.nU32 = frameRate.value() * FRAME_RATE_COEFFICIENT;
289         if (SetParameter(OMX_IndexCodecExtConfigOperatingRate, framerateCfgType, true)) {
290             HLOGI("succ to set frameRate %.f", frameRate.value());
291         } else {
292             HLOGW("succ to set frameRate %.f", frameRate.value());
293         }
294         codecRate_ = frameRate.value();
295     }
296     return AVCS_ERR_OK;
297 }
298 
SaveTransform(const Format & format,bool set)299 int32_t HDecoder::SaveTransform(const Format &format, bool set)
300 {
301     int32_t orientation = 0;
302     if (format.GetIntValue(OHOS::Media::Tag::VIDEO_ORIENTATION_TYPE, orientation)) {
303         HLOGI("GraphicTransformType = %d", orientation);
304         transform_ = static_cast<GraphicTransformType>(orientation);
305         if (set) {
306             return SetTransform();
307         }
308         return AVCS_ERR_OK;
309     }
310     int32_t rotate;
311     if (!format.GetIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, rotate)) {
312         return AVCS_ERR_OK;
313     }
314     optional<GraphicTransformType> transform = TypeConverter::InnerRotateToDisplayRotate(
315         static_cast<VideoRotation>(rotate));
316     if (!transform.has_value()) {
317         return AVCS_ERR_INVALID_VAL;
318     }
319     HLOGI("VideoRotation = %d, GraphicTransformType = %d", rotate, transform.value());
320     transform_ = transform.value();
321     if (set) {
322         return SetTransform();
323     }
324     return AVCS_ERR_OK;
325 }
326 
SetTransform()327 int32_t HDecoder::SetTransform()
328 {
329     if (currSurface_.surface_ == nullptr) {
330         return AVCS_ERR_INVALID_VAL;
331     }
332     GSError err = currSurface_.surface_->SetTransform(transform_);
333     if (err != GSERROR_OK) {
334         HLOGW("set GraphicTransformType %d to surface failed", transform_);
335         return AVCS_ERR_UNKNOWN;
336     }
337     HLOGI("set GraphicTransformType %d to surface succ", transform_);
338     return AVCS_ERR_OK;
339 }
340 
SaveScaleMode(const Format & format,bool set)341 int32_t HDecoder::SaveScaleMode(const Format &format, bool set)
342 {
343     int scaleType;
344     if (!format.GetIntValue(MediaDescriptionKey::MD_KEY_SCALE_TYPE, scaleType)) {
345         return AVCS_ERR_OK;
346     }
347     auto scaleMode = static_cast<ScalingMode>(scaleType);
348     if (scaleMode != SCALING_MODE_SCALE_TO_WINDOW && scaleMode != SCALING_MODE_SCALE_CROP) {
349         HLOGW("user set invalid scale mode %d", scaleType);
350         return AVCS_ERR_INVALID_VAL;
351     }
352     HLOGI("user set ScalingType = %d", scaleType);
353     scaleMode_ = scaleMode;
354     if (set) {
355         return SetScaleMode();
356     }
357     return AVCS_ERR_OK;
358 }
359 
SetScaleMode()360 int32_t HDecoder::SetScaleMode()
361 {
362     if (currSurface_.surface_ == nullptr || !scaleMode_.has_value()) {
363         return AVCS_ERR_INVALID_VAL;
364     }
365     GSError err = currSurface_.surface_->SetScalingMode(scaleMode_.value());
366     if (err != GSERROR_OK) {
367         HLOGW("set ScalingMode %d to surface failed", scaleMode_.value());
368         return AVCS_ERR_UNKNOWN;
369     }
370     HLOGI("set ScalingMode %d to surface succ", scaleMode_.value());
371     return AVCS_ERR_OK;
372 }
373 
SubmitOutputBuffersToOmxNode()374 int32_t HDecoder::SubmitOutputBuffersToOmxNode()
375 {
376     for (BufferInfo& info : outputBufferPool_) {
377         if (info.owner != BufferOwner::OWNED_BY_US) {
378             continue;
379         }
380         if (info.surfaceBuffer != nullptr) {
381             int32_t ret = NotifyOmxToFillThisOutBuffer(info);
382             if (ret != AVCS_ERR_OK) {
383                 return ret;
384             }
385         }
386     }
387     auto inCnt = std::count_if(inputBufferPool_.begin(), inputBufferPool_.end(), [](const BufferInfo& info) {
388         return info.owner == BufferOwner::OWNED_BY_OMX;
389     });
390     inCnt++; // at least submit one out buffer to omx
391     while (inCnt > 0) {
392         SubmitDynamicBufferIfPossible();
393         inCnt--;
394     }
395     return AVCS_ERR_OK;
396 }
397 
UseHandleOnOutputPort(bool isDynamic)398 bool HDecoder::UseHandleOnOutputPort(bool isDynamic)
399 {
400     UseBufferType useBufferTypes;
401     InitOMXParamExt(useBufferTypes);
402     useBufferTypes.portIndex = OMX_DirOutput;
403     useBufferTypes.bufferType = (isDynamic ? CODEC_BUFFER_TYPE_DYNAMIC_HANDLE : CODEC_BUFFER_TYPE_HANDLE);
404     return SetParameter(OMX_IndexParamUseBufferType, useBufferTypes);
405 }
406 
ReadyToStart()407 bool HDecoder::ReadyToStart()
408 {
409     if (callback_ == nullptr || outputFormat_ == nullptr || inputFormat_ == nullptr) {
410         return false;
411     }
412     if (currSurface_.surface_ == nullptr) {
413         if (!UseHandleOnOutputPort(false)) {
414             HLOGE("invalid output buffer type");
415             return false;
416         }
417         HLOGI("buffer mode");
418         return true;
419     }
420     // has surface
421     SupportBufferType type;
422     InitOMXParamExt(type);
423     type.portIndex = OMX_DirOutput;
424     if (GetParameter(OMX_IndexParamSupportBufferType, type) &&
425         (type.bufferTypes & CODEC_BUFFER_TYPE_DYNAMIC_HANDLE) &&
426         UseHandleOnOutputPort(true)) {
427         HLOGI("surface dynamic mode");
428         isDynamic_ = true;
429     } else if (UseHandleOnOutputPort(false)) {
430         HLOGI("surface normal mode");
431         isDynamic_ = false;
432     } else {
433         HLOGE("invalid output buffer type");
434         return false;
435     }
436     SetTransform();
437     SetScaleMode();
438     return true;
439 }
440 
AllocateBuffersOnPort(OMX_DIRTYPE portIndex)441 int32_t HDecoder::AllocateBuffersOnPort(OMX_DIRTYPE portIndex)
442 {
443     if (portIndex == OMX_DirInput) {
444         return AllocateAvLinearBuffers(portIndex);
445     }
446     int32_t ret;
447     if (currSurface_.surface_) {
448         ret = isDynamic_ ? AllocOutDynamicSurfaceBuf() : AllocateOutputBuffersFromSurface();
449     } else {
450         ret = AllocateAvSurfaceBuffers(portIndex);
451     }
452     if (ret == AVCS_ERR_OK) {
453         UpdateFormatFromSurfaceBuffer();
454     }
455     return ret;
456 }
457 
SetCallerToBuffer(int fd)458 void HDecoder::SetCallerToBuffer(int fd)
459 {
460     if (currSurface_.surface_ == nullptr) {
461         return; // only set on surface mode
462     }
463     string pid = std::to_string(calledByAvcodec_ ? avcodecCaller_.pid : playerCaller_.pid);
464     int ret = ioctl(fd, DMA_BUF_SET_NAME_A, pid.c_str());
465     if (ret != 0) {
466         HLOGW("set pid %s to fd %d failed", pid.c_str(), fd);
467         return;
468     }
469     HLOGI("set pid %s to fd %d succ", pid.c_str(), fd);
470 }
471 
UpdateFormatFromSurfaceBuffer()472 void HDecoder::UpdateFormatFromSurfaceBuffer()
473 {
474     if (outputBufferPool_.empty()) {
475         return;
476     }
477     sptr<SurfaceBuffer> surfaceBuffer = outputBufferPool_.front().surfaceBuffer;
478     if (surfaceBuffer == nullptr) {
479         return;
480     }
481     HLOGI(">>");
482     outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_DISPLAY_WIDTH, surfaceBuffer->GetWidth());
483     outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_DISPLAY_HEIGHT, surfaceBuffer->GetHeight());
484     outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_PIC_WIDTH, surfaceBuffer->GetWidth());
485     outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_PIC_HEIGHT, surfaceBuffer->GetHeight());
486     int32_t stride = surfaceBuffer->GetStride();
487     if (stride <= 0) {
488         HLOGW("invalid stride %d", stride);
489         return;
490     }
491     outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_STRIDE, stride);
492     outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, stride); // deprecated
493 
494     OH_NativeBuffer_Planes *planes = nullptr;
495     GSError err = surfaceBuffer->GetPlanesInfo(reinterpret_cast<void**>(&planes));
496     if (err != GSERROR_OK || planes == nullptr) {
497         HLOGW("get plane info failed, GSError=%d", err);
498         return;
499     }
500     for (uint32_t i = 0; i < planes->planeCount; i++) {
501         HLOGI("plane[%u]: offset=%" PRIu64 ", rowStride=%u, columnStride=%u",
502               i, planes->planes[i].offset, planes->planes[i].rowStride, planes->planes[i].columnStride);
503     }
504     int32_t sliceHeight = static_cast<int32_t>(static_cast<int64_t>(planes->planes[1].offset) / stride);
505     HLOGI("[%dx%d][%dx%d]", surfaceBuffer->GetWidth(), surfaceBuffer->GetHeight(), stride, sliceHeight);
506     outputFormat_->PutIntValue(OHOS::Media::Tag::VIDEO_SLICE_HEIGHT, sliceHeight);
507     outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, sliceHeight);
508 }
509 
SubmitAllBuffersOwnedByUs()510 int32_t HDecoder::SubmitAllBuffersOwnedByUs()
511 {
512     HLOGI(">>");
513     if (isBufferCirculating_) {
514         HLOGI("buffer is already circulating, no need to do again");
515         return AVCS_ERR_OK;
516     }
517     int32_t ret = SubmitOutputBuffersToOmxNode();
518     if (ret != AVCS_ERR_OK) {
519         return ret;
520     }
521     for (BufferInfo& info : inputBufferPool_) {
522         if (info.owner == BufferOwner::OWNED_BY_US) {
523             NotifyUserToFillThisInBuffer(info);
524         }
525     }
526     isBufferCirculating_ = true;
527     return AVCS_ERR_OK;
528 }
529 
EraseBufferFromPool(OMX_DIRTYPE portIndex,size_t i)530 void HDecoder::EraseBufferFromPool(OMX_DIRTYPE portIndex, size_t i)
531 {
532     vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
533     if (i >= pool.size()) {
534         return;
535     }
536     BufferInfo& info = pool[i];
537     if (portIndex == OMX_DirOutput && info.owner != BufferOwner::OWNED_BY_SURFACE) {
538         CancelBufferToSurface(info);
539     }
540     FreeOmxBuffer(portIndex, info);
541     ReduceOwner((portIndex == OMX_DirInput), info.owner);
542     pool.erase(pool.begin() + i);
543 }
544 
OnClearBufferPool(OMX_DIRTYPE portIndex)545 void HDecoder::OnClearBufferPool(OMX_DIRTYPE portIndex)
546 {
547     if ((portIndex == OMX_DirOutput) && currSurface_.surface_) {
548         GSError err = currSurface_.surface_->CleanCache();
549         if (err != GSERROR_OK) {
550             HLOGW("clean cache failed, GSError=%d", err);
551         }
552     }
553 }
554 
GetProducerUsage()555 uint64_t HDecoder::GetProducerUsage()
556 {
557     uint64_t producerUsage = currSurface_.surface_ ? SURFACE_MODE_PRODUCER_USAGE : BUFFER_MODE_REQUEST_USAGE;
558 
559     GetBufferHandleUsageParams vendorUsage;
560     InitOMXParamExt(vendorUsage);
561     vendorUsage.portIndex = static_cast<uint32_t>(OMX_DirOutput);
562     if (GetParameter(OMX_IndexParamGetBufferHandleUsage, vendorUsage)) {
563         HLOGI("vendor producer usage = 0x%" PRIx64 "", vendorUsage.usage);
564         producerUsage |= vendorUsage.usage;
565     } else {
566         HLOGW("get vendor producer usage failed, add CPU_READ");
567         producerUsage |= BUFFER_USAGE_CPU_READ;
568     }
569     HLOGI("decoder producer usage = 0x%" PRIx64 "", producerUsage);
570     return producerUsage;
571 }
572 
CombineConsumerUsage()573 void HDecoder::CombineConsumerUsage()
574 {
575     uint32_t consumerUsage = currSurface_.surface_->GetDefaultUsage();
576     uint64_t finalUsage = requestCfg_.usage | consumerUsage;
577     HLOGI("producer usage 0x%" PRIx64 " | consumer usage 0x%x -> 0x%" PRIx64 "",
578         requestCfg_.usage, consumerUsage, finalUsage);
579     requestCfg_.usage = finalUsage;
580 }
581 
SetQueueSize(const sptr<Surface> & surface,uint32_t targetSize)582 int32_t HDecoder::SetQueueSize(const sptr<Surface> &surface, uint32_t targetSize)
583 {
584     GSError err = surface->SetQueueSize(targetSize);
585     if (err != GSERROR_OK) {
586         HLOGE("surface(%" PRIu64 "), SetQueueSize to %u failed, GSError=%d",
587               surface->GetUniqueId(), targetSize, err);
588         return AVCS_ERR_UNKNOWN;
589     }
590     HLOGI("surface(%" PRIu64 "), SetQueueSize to %u succ", surface->GetUniqueId(), targetSize);
591     return AVCS_ERR_OK;
592 }
593 
AllocOutDynamicSurfaceBuf()594 int32_t HDecoder::AllocOutDynamicSurfaceBuf()
595 {
596     SCOPED_TRACE();
597     currSurface_.surface_->CleanCache();
598     int32_t ret = SetQueueSize(currSurface_.surface_, outBufferCnt_);
599     if (ret != AVCS_ERR_OK) {
600         return ret;
601     }
602     outputBufferPool_.clear();
603 
604     for (uint32_t i = 0; i < outBufferCnt_; ++i) {
605         shared_ptr<OmxCodecBuffer> omxBuffer = DynamicSurfaceBufferToOmxBuffer();
606         shared_ptr<OmxCodecBuffer> outBuffer = make_shared<OmxCodecBuffer>();
607         ret = compNode_->UseBuffer(OMX_DirOutput, *omxBuffer, *outBuffer);
608         if (ret != HDF_SUCCESS) {
609             HLOGE("Failed to UseBuffer on input port");
610             return AVCS_ERR_UNKNOWN;
611         }
612         BufferInfo info {};
613         info.isInput = false;
614         info.owner = BufferOwner::OWNED_BY_US;
615         info.surfaceBuffer = nullptr;
616         info.avBuffer = AVBuffer::CreateAVBuffer();
617         info.omxBuffer = outBuffer;
618         info.bufferId = outBuffer->bufferId;
619         outputBufferPool_.push_back(info);
620     }
621     HLOGI("succ");
622     return AVCS_ERR_OK;
623 }
624 
AllocateOutputBuffersFromSurface()625 int32_t HDecoder::AllocateOutputBuffersFromSurface()
626 {
627     SCOPED_TRACE();
628     currSurface_.surface_->CleanCache();
629     int32_t ret = SetQueueSize(currSurface_.surface_, outBufferCnt_);
630     if (ret != AVCS_ERR_OK) {
631         return ret;
632     }
633     outputBufferPool_.clear();
634     CombineConsumerUsage();
635     for (uint32_t i = 0; i < outBufferCnt_; ++i) {
636         sptr<SurfaceBuffer> surfaceBuffer;
637         sptr<SyncFence> fence;
638         GSError err = currSurface_.surface_->RequestBuffer(surfaceBuffer, fence, requestCfg_);
639         if (err != GSERROR_OK || surfaceBuffer == nullptr) {
640             HLOGE("RequestBuffer %u failed, GSError=%d", i, err);
641             return AVCS_ERR_UNKNOWN;
642         }
643         shared_ptr<OmxCodecBuffer> omxBuffer = SurfaceBufferToOmxBuffer(surfaceBuffer);
644         if (omxBuffer == nullptr) {
645             currSurface_.surface_->CancelBuffer(surfaceBuffer);
646             return AVCS_ERR_UNKNOWN;
647         }
648         shared_ptr<OmxCodecBuffer> outBuffer = make_shared<OmxCodecBuffer>();
649         int32_t hdfRet = compNode_->UseBuffer(OMX_DirOutput, *omxBuffer, *outBuffer);
650         if (hdfRet != HDF_SUCCESS) {
651             currSurface_.surface_->CancelBuffer(surfaceBuffer);
652             HLOGE("Failed to UseBuffer with output port");
653             return AVCS_ERR_NO_MEMORY;
654         }
655         SetCallerToBuffer(surfaceBuffer->GetFileDescriptor());
656         outBuffer->fenceFd = -1;
657         BufferInfo info {};
658         info.isInput = false;
659         info.owner = BufferOwner::OWNED_BY_US;
660         info.surfaceBuffer = surfaceBuffer;
661         info.avBuffer = AVBuffer::CreateAVBuffer();
662         info.omxBuffer = outBuffer;
663         info.bufferId = outBuffer->bufferId;
664         outputBufferPool_.push_back(info);
665         HLOGI("bufferId=%u, seq=%u", info.bufferId, surfaceBuffer->GetSeqNum());
666     }
667     return AVCS_ERR_OK;
668 }
669 
CancelBufferToSurface(BufferInfo & info)670 void HDecoder::CancelBufferToSurface(BufferInfo& info)
671 {
672     if (currSurface_.surface_ && info.surfaceBuffer) {
673         GSError err = currSurface_.surface_->CancelBuffer(info.surfaceBuffer);
674         if (err != GSERROR_OK) {
675             HLOGW("surface(%" PRIu64 "), CancelBuffer(seq=%u) failed, GSError=%d",
676                   currSurface_.surface_->GetUniqueId(), info.surfaceBuffer->GetSeqNum(), err);
677         } else {
678             HLOGI("surface(%" PRIu64 "), CancelBuffer(seq=%u) succ",
679                   currSurface_.surface_->GetUniqueId(), info.surfaceBuffer->GetSeqNum());
680         }
681     }
682     ChangeOwner(info, BufferOwner::OWNED_BY_SURFACE); // change owner even if cancel failed
683 }
684 
RegisterListenerToSurface(const sptr<Surface> & surface)685 int32_t HDecoder::RegisterListenerToSurface(const sptr<Surface> &surface)
686 {
687     uint64_t surfaceId = surface->GetUniqueId();
688     std::weak_ptr<HCodec> weakThis = weak_from_this();
689     GSError err = surface->RegisterReleaseListener([weakThis, surfaceId](sptr<SurfaceBuffer>&) {
690         std::shared_ptr<HCodec> codec = weakThis.lock();
691         if (codec == nullptr) {
692             LOGD("decoder is gone");
693             return GSERROR_OK;
694         }
695         return codec->OnBufferReleasedByConsumer(surfaceId);
696     });
697     if (err != GSERROR_OK) {
698         HLOGE("surface(%" PRIu64 "), RegisterReleaseListener failed, GSError=%d", surfaceId, err);
699         return AVCS_ERR_UNKNOWN;
700     }
701     return AVCS_ERR_OK;
702 }
703 
OnBufferReleasedByConsumer(uint64_t surfaceId)704 GSError HDecoder::OnBufferReleasedByConsumer(uint64_t surfaceId)
705 {
706     ParamSP param = make_shared<ParamBundle>();
707     param->SetValue("surfaceId", surfaceId);
708     SendAsyncMsg(MsgWhat::GET_BUFFER_FROM_SURFACE, param);
709     return GSERROR_OK;
710 }
711 
RequestAndFindBelongTo(sptr<SurfaceBuffer> & buffer,sptr<SyncFence> & fence,std::vector<BufferInfo>::iterator & iter)712 bool HDecoder::RequestAndFindBelongTo(
713     sptr<SurfaceBuffer>& buffer, sptr<SyncFence>& fence, std::vector<BufferInfo>::iterator& iter)
714 {
715     SCOPED_TRACE();
716     GSError err = currSurface_.surface_->RequestBuffer(buffer, fence, requestCfg_);
717     if (err != GSERROR_OK || buffer == nullptr || buffer->GetBufferHandle() == nullptr) {
718         HLOGW("GSError=%d", err);
719         return false;
720     }
721     BufferHandle* handle = buffer->GetBufferHandle();
722     iter = std::find_if(outputBufferPool_.begin(), outputBufferPool_.end(), [handle](const BufferInfo& info) {
723         return (info.owner == BufferOwner::OWNED_BY_SURFACE) &&
724                info.surfaceBuffer && (info.surfaceBuffer->GetBufferHandle() == handle);
725     });
726     return true;
727 }
728 
OnGetBufferFromSurface(const ParamSP & param)729 void HDecoder::OnGetBufferFromSurface(const ParamSP& param)
730 {
731     uint64_t surfaceId = 0;
732     param->GetValue("surfaceId", surfaceId);
733     if (!currSurface_.surface_ || currSurface_.surface_->GetUniqueId() != surfaceId) {
734         return;
735     }
736     sptr<SurfaceBuffer> buffer;
737     sptr<SyncFence> fence;
738     auto iter = outputBufferPool_.end();
739     if (!RequestAndFindBelongTo(buffer, fence, iter)) {
740         return;
741     }
742     if (iter == outputBufferPool_.end()) {
743         HLOGI("seq=%u dont belong to output set, cancel it", buffer->GetSeqNum());
744         currSurface_.surface_->CancelBuffer(buffer);
745         return;
746     }
747     WaitFence(fence);
748     ChangeOwner(*iter, BufferOwner::OWNED_BY_US);
749     NotifyOmxToFillThisOutBuffer(*iter);
750 }
751 
SubmitDynamicBufferIfPossible()752 void HDecoder::SubmitDynamicBufferIfPossible()
753 {
754     if (!currSurface_.surface_ || !isDynamic_) {
755         return;
756     }
757     auto idleIter = std::find_if(outputBufferPool_.begin(), outputBufferPool_.end(), [](const BufferInfo& info) {
758         return info.surfaceBuffer == nullptr;
759     });
760     if (idleIter == outputBufferPool_.end()) {
761         return;
762     }
763     for (size_t i = 0; i < outputBufferPool_.size(); i++) {
764         sptr<SurfaceBuffer> buffer;
765         sptr<SyncFence> fence;
766         auto iter = outputBufferPool_.end();
767         if (!RequestAndFindBelongTo(buffer, fence, iter)) {
768             return;
769         }
770         WaitFence(fence);
771         if (iter != outputBufferPool_.end()) {
772             ChangeOwner(*iter, BufferOwner::OWNED_BY_US);
773             NotifyOmxToFillThisOutBuffer(*iter);
774             continue; // keep request until we got a new surfacebuffer
775         }
776         SetCallerToBuffer(buffer->GetFileDescriptor());
777         HLOGI("bufferId=%u, seq=%u", idleIter->bufferId, buffer->GetSeqNum());
778         WrapSurfaceBufferToSlot(*idleIter, buffer, 0, 0);
779         if (idleIter == outputBufferPool_.begin()) {
780             UpdateFormatFromSurfaceBuffer();
781         }
782         NotifyOmxToFillThisOutBuffer(*idleIter);
783         idleIter->omxBuffer->bufferhandle = nullptr;
784         return;
785     }
786 }
787 
NotifySurfaceToRenderOutputBuffer(BufferInfo & info)788 int32_t HDecoder::NotifySurfaceToRenderOutputBuffer(BufferInfo &info)
789 {
790     SCOPED_TRACE_WITH_ID(info.bufferId);
791     info.lastFlushTime = GetNowUs();
792     if (std::abs(lastFlushRate_ - codecRate_) > std::numeric_limits<float>::epsilon()) {
793         sptr<BufferExtraData> extraData = new BufferExtraDataImpl();
794         extraData->ExtraSet("VIDEO_RATE", codecRate_);
795         info.surfaceBuffer->SetExtraData(extraData);
796         lastFlushRate_ = codecRate_;
797         HLOGI("flush video rate(%d)", static_cast<int32_t>(codecRate_));
798     }
799     BufferFlushConfig cfg {
800         .damage = {.x = 0, .y = 0, .w = info.surfaceBuffer->GetWidth(), .h = info.surfaceBuffer->GetHeight() },
801         .timestamp = info.omxBuffer->pts,
802         .desiredPresentTimestamp = -1,
803     };
804     if (info.avBuffer->meta_->Find(OHOS::Media::Tag::VIDEO_DECODER_DESIRED_PRESENT_TIMESTAMP) !=
805         info.avBuffer->meta_->end()) {
806         info.avBuffer->meta_->Get<OHOS::Media::Tag::VIDEO_DECODER_DESIRED_PRESENT_TIMESTAMP>(
807             cfg.desiredPresentTimestamp);
808         info.avBuffer->meta_->Remove(OHOS::Media::Tag::VIDEO_DECODER_DESIRED_PRESENT_TIMESTAMP);
809     }
810     GSError ret = currSurface_.surface_->FlushBuffer(info.surfaceBuffer, -1, cfg);
811     if (ret != GSERROR_OK) {
812         HLOGW("surface(%" PRIu64 "), FlushBuffer(seq=%u) failed, GSError=%d",
813               currSurface_.surface_->GetUniqueId(), info.surfaceBuffer->GetSeqNum(), ret);
814         return AVCS_ERR_UNKNOWN;
815     }
816     ChangeOwner(info, BufferOwner::OWNED_BY_SURFACE);
817     return AVCS_ERR_OK;
818 }
819 
OnOMXEmptyBufferDone(uint32_t bufferId,BufferOperationMode mode)820 void HDecoder::OnOMXEmptyBufferDone(uint32_t bufferId, BufferOperationMode mode)
821 {
822     SCOPED_TRACE_WITH_ID(bufferId);
823     BufferInfo *info = FindBufferInfoByID(OMX_DirInput, bufferId);
824     if (info == nullptr) {
825         HLOGE("unknown buffer id %u", bufferId);
826         return;
827     }
828     if (info->owner != BufferOwner::OWNED_BY_OMX) {
829         HLOGE("wrong ownership: buffer id=%d, owner=%s", bufferId, ToString(info->owner));
830         return;
831     }
832     ChangeOwner(*info, BufferOwner::OWNED_BY_US);
833 
834     switch (mode) {
835         case KEEP_BUFFER:
836             return;
837         case RESUBMIT_BUFFER: {
838             if (!inputPortEos_) {
839                 NotifyUserToFillThisInBuffer(*info);
840             }
841             return;
842         }
843         default: {
844             HLOGE("SHOULD NEVER BE HERE");
845             return;
846         }
847     }
848 }
849 
OnReleaseOutputBuffer(const BufferInfo & info)850 void HDecoder::OnReleaseOutputBuffer(const BufferInfo &info)
851 {
852     if (currSurface_.surface_) {
853         HLOGI("outBufId = %u, discard by user, pts = %" PRId64, info.bufferId, info.omxBuffer->pts);
854     }
855 }
856 
OnRenderOutputBuffer(const MsgInfo & msg,BufferOperationMode mode)857 void HDecoder::OnRenderOutputBuffer(const MsgInfo &msg, BufferOperationMode mode)
858 {
859     if (currSurface_.surface_ == nullptr) {
860         HLOGE("can only render in surface mode");
861         ReplyErrorCode(msg.id, AVCS_ERR_INVALID_OPERATION);
862         return;
863     }
864     uint32_t bufferId = 0;
865     (void)msg.param->GetValue(BUFFER_ID, bufferId);
866     SCOPED_TRACE_WITH_ID(bufferId);
867     optional<size_t> idx = FindBufferIndexByID(OMX_DirOutput, bufferId);
868     if (!idx.has_value()) {
869         ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
870         return;
871     }
872     BufferInfo& info = outputBufferPool_[idx.value()];
873     if (info.owner != BufferOwner::OWNED_BY_USER) {
874         HLOGE("wrong ownership: buffer id=%d, owner=%s", bufferId, ToString(info.owner));
875         ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
876         return;
877     }
878     info.omxBuffer->pts = info.avBuffer->pts_;
879     ChangeOwner(info, BufferOwner::OWNED_BY_US);
880     ReplyErrorCode(msg.id, AVCS_ERR_OK);
881 
882     if (info.omxBuffer->filledLen != 0) {
883         NotifySurfaceToRenderOutputBuffer(info);
884     }
885     if (mode == FREE_BUFFER) {
886         EraseBufferFromPool(OMX_DirOutput, idx.value());
887     } else {
888         SubmitDynamicBufferIfPossible();
889     }
890 }
891 
OnEnterUninitializedState()892 void HDecoder::OnEnterUninitializedState()
893 {
894     currSurface_.Release();
895 }
896 
SurfaceItem(const sptr<Surface> & surface)897 HDecoder::SurfaceItem::SurfaceItem(const sptr<Surface> &surface)
898     : surface_(surface), originalTransform_(surface->GetTransform()) {}
899 
Release()900 void HDecoder::SurfaceItem::Release()
901 {
902     if (surface_) {
903         LOGI("release surface(%" PRIu64 ")", surface_->GetUniqueId());
904         if (originalTransform_.has_value()) {
905             surface_->SetTransform(originalTransform_.value());
906             originalTransform_ = std::nullopt;
907         }
908         surface_ = nullptr;
909     }
910 }
911 
OnSetOutputSurfaceWhenRunning(const sptr<Surface> & newSurface)912 int32_t HDecoder::OnSetOutputSurfaceWhenRunning(const sptr<Surface> &newSurface)
913 {
914     SCOPED_TRACE();
915     if (currSurface_.surface_ == nullptr) {
916         HLOGE("can only switch surface on surface mode");
917         return AVCS_ERR_INVALID_OPERATION;
918     }
919     if (newSurface == nullptr) {
920         HLOGE("surface is null");
921         return AVCS_ERR_INVALID_VAL;
922     }
923     if (newSurface->IsConsumer()) {
924         HLOGE("expect a producer surface but got a consumer surface");
925         return AVCS_ERR_INVALID_VAL;
926     }
927     uint64_t oldId = currSurface_.surface_->GetUniqueId();
928     uint64_t newId = newSurface->GetUniqueId();
929     HLOGI("surface %" PRIu64 " -> %" PRIu64, oldId, newId);
930     if (oldId == newId) {
931         HLOGI("same surface, no need to set again");
932         return AVCS_ERR_OK;
933     }
934     int32_t ret = RegisterListenerToSurface(newSurface);
935     if (ret != AVCS_ERR_OK) {
936         return ret;
937     }
938     ret = SetQueueSize(newSurface, outBufferCnt_);
939     if (ret != AVCS_ERR_OK) {
940         return ret;
941     }
942     ret = SwitchBetweenSurface(newSurface);
943     if (ret != AVCS_ERR_OK) {
944         return ret;
945     }
946     SetTransform();
947     SetScaleMode();
948     HLOGI("set surface(%" PRIu64 ")(%s) succ", newId, newSurface->GetName().c_str());
949     return AVCS_ERR_OK;
950 }
951 
SwitchBetweenSurface(const sptr<Surface> & newSurface)952 int32_t HDecoder::SwitchBetweenSurface(const sptr<Surface> &newSurface)
953 {
954     newSurface->Connect(); // cleancache will work only if the surface is connected by us
955     newSurface->CleanCache(); // make sure new surface is empty
956     // if owned by old surface, we need to transfer them to new surface
957     map<int64_t, size_t> ownedBySurfaceFlushTime2BufferIndex;
958     // the consumer of old surface may be destroyed, so flushbuffer will fail, and they are owned by us
959     vector<size_t> ownedByUs;
960     uint64_t newId = newSurface->GetUniqueId();
961     for (size_t i = 0; i < outputBufferPool_.size(); i++) {
962         BufferInfo& info = outputBufferPool_[i];
963         if (info.surfaceBuffer == nullptr) {
964             continue;
965         }
966         GSError err = newSurface->AttachBufferToQueue(info.surfaceBuffer);
967         if (err != GSERROR_OK) {
968             HLOGE("surface(%" PRIu64 "), AttachBufferToQueue(seq=%u) failed, GSError=%d",
969                   newId, info.surfaceBuffer->GetSeqNum(), err);
970             return AVCS_ERR_UNKNOWN;
971         }
972         if (info.owner == OWNED_BY_SURFACE) {
973             ownedBySurfaceFlushTime2BufferIndex[info.lastFlushTime] = i;
974         } else if (info.owner == OWNED_BY_US) {
975             ownedByUs.push_back(i);
976         }
977     }
978 
979     SurfaceItem oldSurface = currSurface_;
980     currSurface_ = SurfaceItem(newSurface);
981     for (auto [flushTime, i] : ownedBySurfaceFlushTime2BufferIndex) {
982         ChangeOwner(outputBufferPool_[i], BufferOwner::OWNED_BY_US);
983         NotifySurfaceToRenderOutputBuffer(outputBufferPool_[i]);
984     }
985     if (currState_->GetName() == "Running") {
986         for (size_t i : ownedByUs) {
987             NotifyOmxToFillThisOutBuffer(outputBufferPool_[i]);
988         }
989     }
990     oldSurface.surface_->CleanCache(true); // make sure old surface is empty and go black
991     oldSurface.Release();
992     return AVCS_ERR_OK;
993 }
994 } // namespace OHOS::MediaAVCodec