• 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 "utils/hdf_base.h"
19 #include "codec_omx_ext.h"
20 #include "media_description.h"  // foundation/multimedia/av_codec/interfaces/inner_api/native/
21 #include "sync_fence.h"  // foundation/graphic/graphic_2d/utils/sync_fence/export/
22 #include "OMX_VideoExt.h"
23 #include "hcodec_log.h"
24 #include "type_converter.h"
25 
26 namespace OHOS::MediaAVCodec {
27 using namespace std;
28 using namespace OHOS::HDI::Codec::V1_0;
29 
OnConfigure(const Format & format)30 int32_t HDecoder::OnConfigure(const Format &format)
31 {
32     configFormat_ = make_shared<Format>(format);
33 
34     return SetupPort(format);
35 }
36 
SetupPort(const Format & format)37 int32_t HDecoder::SetupPort(const Format &format)
38 {
39     int32_t width;
40     if (!format.GetIntValue(MediaDescriptionKey::MD_KEY_WIDTH, width) || width <= 0) {
41         HLOGE("format should contain width");
42         return AVCS_ERR_INVALID_VAL;
43     }
44     int32_t height;
45     if (!format.GetIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, height) || height <= 0) {
46         HLOGE("format should contain height");
47         return AVCS_ERR_INVALID_VAL;
48     }
49     HLOGI("user set width %{public}d, height %{public}d", width, height);
50     if (!GetPixelFmtFromUser(format)) {
51         return AVCS_ERR_INVALID_VAL;
52     }
53 
54     optional<double> frameRate = GetFrameRateFromUser(format);
55     if (!frameRate.has_value()) {
56         HLOGI("user don't set valid frame rate, use default 30.0");
57         frameRate = 30.0;  // default frame rate 30.0
58     }
59 
60     PortInfo inputPortInfo {static_cast<uint32_t>(width), static_cast<uint32_t>(height), std::nullopt,
61                             codingType_, std::nullopt, frameRate.value()};
62     int32_t maxInputSize = 0;
63     (void)format.GetIntValue(MediaDescriptionKey::MD_KEY_MAX_INPUT_SIZE, maxInputSize);
64     if (maxInputSize > 0) {
65         inputPortInfo.inputBufSize = static_cast<uint32_t>(maxInputSize);
66     }
67     int32_t ret = SetVideoPortInfo(OMX_DirInput, inputPortInfo);
68     if (ret != AVCS_ERR_OK) {
69         return ret;
70     }
71 
72     PortInfo outputPortInfo = {static_cast<uint32_t>(width), static_cast<uint32_t>(height), std::nullopt,
73                                OMX_VIDEO_CodingUnused, configuredFmt_, frameRate.value()};
74     ret = SetVideoPortInfo(OMX_DirOutput, outputPortInfo);
75     if (ret != AVCS_ERR_OK) {
76         return ret;
77     }
78 
79     return AVCS_ERR_OK;
80 }
81 
UpdateInPortFormat()82 int32_t HDecoder::UpdateInPortFormat()
83 {
84     OMX_PARAM_PORTDEFINITIONTYPE def;
85     InitOMXParam(def);
86     def.nPortIndex = OMX_DirInput;
87     if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
88         HLOGE("get input port definition failed");
89         return AVCS_ERR_UNKNOWN;
90     }
91     PrintPortDefinition(def);
92     if (inputFormat_ == nullptr) {
93         inputFormat_ = make_shared<Format>();
94     }
95     inputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, def.format.video.nFrameWidth);
96     inputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, def.format.video.nFrameHeight);
97     inputFormat_->PutIntValue("stride", def.format.video.nStride);
98     return AVCS_ERR_OK;
99 }
100 
UpdateOutPortFormat()101 int32_t HDecoder::UpdateOutPortFormat()
102 {
103     OMX_PARAM_PORTDEFINITIONTYPE def;
104     InitOMXParam(def);
105     def.nPortIndex = OMX_DirOutput;
106     if (!GetParameter(OMX_IndexParamPortDefinition, def)) {
107         HLOGE("get output port definition failed");
108         return AVCS_ERR_UNKNOWN;
109     }
110     PrintPortDefinition(def);
111     if (def.nBufferCountActual == 0) {
112         HLOGE("invalid bufferCount");
113         return AVCS_ERR_UNKNOWN;
114     }
115     uint32_t w = def.format.video.nFrameWidth;
116     uint32_t h = def.format.video.nFrameHeight;
117 
118     // save into member variable
119     outBufferCnt_ = def.nBufferCountActual;
120     requestCfg_.timeout = 0;
121     requestCfg_.width = w;
122     requestCfg_.height = h;
123     requestCfg_.strideAlignment = STRIDE_ALIGNMENT;
124     requestCfg_.format = configuredFmt_.graphicFmt;
125     requestCfg_.usage = GetUsageFromOmx();
126     GetCropFromOmx(w, h);
127 
128     // save into format
129     if (outputFormat_ == nullptr) {
130         outputFormat_ = make_shared<Format>();
131     }
132     outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_WIDTH, w);
133     outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_HEIGHT, h);
134     outputFormat_->PutIntValue(MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, configuredFmt_.innerFmt);
135 
136     sharedBufferFormat_ = { w, h, def.format.video.nStride, OMX_VIDEO_CodingUnused, configuredFmt_ };
137     return AVCS_ERR_OK;
138 }
139 
GetCropFromOmx(uint32_t w,uint32_t h)140 void HDecoder::GetCropFromOmx(uint32_t w, uint32_t h)
141 {
142     flushCfg_.damage.x = 0;
143     flushCfg_.damage.y = 0;
144     flushCfg_.damage.w = w;
145     flushCfg_.damage.h = h;
146 
147     OMX_CONFIG_RECTTYPE rect;
148     InitOMXParam(rect);
149     rect.nPortIndex = OMX_DirOutput;
150     if (!GetParameter(OMX_IndexConfigCommonOutputCrop, rect, true)) {
151         HLOGW("get crop failed, use default");
152         return;
153     }
154     if (rect.nLeft < 0 || rect.nTop < 0 ||
155         rect.nWidth == 0 || rect.nHeight == 0 ||
156         rect.nLeft + rect.nWidth > w ||
157         rect.nTop + rect.nHeight > h) {
158         HLOGW("wrong crop rect (%{public}d, %{public}d, %{public}u, %{public}u) vs. frame (%{public}u," \
159               "%{public}u), use default", rect.nLeft, rect.nTop, rect.nWidth, rect.nHeight, w, h);
160         return;
161     }
162     HLOGI("crop rect (%{public}d, %{public}d, %{public}u, %{public}u)",
163           rect.nLeft, rect.nTop, rect.nWidth, rect.nHeight);
164     flushCfg_.damage.x = rect.nLeft;
165     flushCfg_.damage.y = rect.nTop;
166     flushCfg_.damage.w = rect.nWidth;
167     flushCfg_.damage.h = rect.nHeight;
168 }
169 
GetUsageFromOmx()170 uint64_t HDecoder::GetUsageFromOmx()
171 {
172     GetBufferHandleUsageParams usageParams;
173     InitOMXParamExt(usageParams);
174     usageParams.portIndex = static_cast<uint32_t>(OMX_DirOutput);
175     if (!GetParameter(OMX_IndexParamGetBufferHandleUsage, usageParams)) {
176         HLOGW("get buffer handle usage failed, use default");
177         return BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA;
178     }
179     return usageParams.usage;
180 }
181 
OnSetOutputSurface(const sptr<Surface> & surface)182 int32_t HDecoder::OnSetOutputSurface(const sptr<Surface> &surface)
183 {
184     if (surface == nullptr) {
185         HLOGE("surface is null");
186         return AVCS_ERR_INVALID_VAL;
187     }
188     if (surface->IsConsumer()) {
189         HLOGE("expect a producer surface but got a consumer surface");
190         return AVCS_ERR_INVALID_VAL;
191     }
192     GSError err = surface->RegisterReleaseListener([this](sptr<SurfaceBuffer> &buffer) {
193         return OnBufferReleasedByConsumer(buffer);
194     });
195     if (err != GSERROR_OK) {
196         HLOGE("RegisterReleaseListener failed, GSError=%{public}d", err);
197         return AVCS_ERR_UNKNOWN;
198     }
199     UseBufferType param;
200     InitOMXParamExt(param);
201     param.portIndex = OMX_DirOutput;
202     param.bufferType = CODEC_BUFFER_TYPE_HANDLE;
203     if (!SetParameter(OMX_IndexParamUseBufferType, param)) {
204         HLOGE("component don't support CODEC_BUFFER_TYPE_HANDLE");
205         return AVCS_ERR_INVALID_OPERATION;
206     }
207     outputSurface_ = surface;
208     HLOGI("set surface (%{public}s) succ", surface->GetName().c_str());
209     return AVCS_ERR_OK;
210 }
211 
OnSetParameters(const Format & format)212 int32_t HDecoder::OnSetParameters(const Format &format)
213 {
214     int32_t rotate;
215     if (outputSurface_ && format.GetIntValue(MediaDescriptionKey::MD_KEY_ROTATION_ANGLE, rotate)) {
216         optional<GraphicTransformType> transform = TypeConverter::InnerRotateToDisplayRotate((VideoRotation)rotate);
217         if (!transform.has_value()) {
218             return AVCS_ERR_INVALID_VAL;
219         }
220         GSError err = outputSurface_->SetTransform(transform.value());
221         if (err != GSERROR_OK) {
222             HLOGE("set rotate angle %{public}d to surface failed", transform.value());
223             return AVCS_ERR_UNKNOWN;
224         }
225         HLOGI("set rotate angle %{public}d to surface succ", rotate);
226     }
227     return AVCS_ERR_OK;
228 }
229 
OnBufferReleasedByConsumer(sptr<SurfaceBuffer> & buffer)230 GSError HDecoder::OnBufferReleasedByConsumer(sptr<SurfaceBuffer> &buffer)
231 {
232     SendAsyncMsg(MsgWhat::GET_BUFFER_FROM_SURFACE, nullptr);
233     return GSERROR_OK;
234 }
235 
SubmitOutputBuffersToOmxNode()236 int32_t HDecoder::SubmitOutputBuffersToOmxNode()
237 {
238     for (BufferInfo& info : outputBufferPool_) {
239         switch (info.owner) {
240             case BufferOwner::OWNED_BY_US: {
241                 int32_t ret = NotifyOmxToFillThisOutBuffer(info);
242                 if (ret != AVCS_ERR_OK) {
243                     return ret;
244                 }
245                 continue;
246             }
247             case BufferOwner::OWNED_BY_SURFACE: {
248                 continue;
249             }
250             case BufferOwner::OWNED_BY_OMX: {
251                 continue;
252             }
253             default: {
254                 HLOGE("buffer id %{public}u has invalid owner %{public}d", info.bufferId, info.owner);
255                 return AVCS_ERR_UNKNOWN;
256             }
257         }
258     }
259     return AVCS_ERR_OK;
260 }
261 
ReadyToStart()262 bool HDecoder::ReadyToStart()
263 {
264     if (callback_ == nullptr || outputFormat_ == nullptr || inputFormat_ == nullptr) {
265         return false;
266     }
267     if (outputSurface_ == nullptr) {
268         outputBufferType_ = BufferType::PRESET_ASHM_BUFFER;
269         HLOGI("buffer mode");
270         return true;
271     }
272     HLOGI("surface mode");
273     outputBufferType_ = BufferType::PRESET_SURFACE_BUFFER;
274     if (configFormat_) {
275         OnSetParameters(*configFormat_);
276     }
277     return true;
278 }
279 
SubmitAllBuffersOwnedByUs()280 int32_t HDecoder::SubmitAllBuffersOwnedByUs()
281 {
282     HLOGI(">>");
283     if (isBufferCirculating_) {
284         HLOGI("buffer is already circulating, no need to do again");
285         return AVCS_ERR_OK;
286     }
287     int32_t ret = SubmitOutputBuffersToOmxNode();
288     if (ret != AVCS_ERR_OK) {
289         return ret;
290     }
291     for (BufferInfo& info : inputBufferPool_) {
292         if (info.owner == BufferOwner::OWNED_BY_US) {
293             NotifyUserToFillThisInBuffer(info);
294         }
295     }
296     isBufferCirculating_ = true;
297     return AVCS_ERR_OK;
298 }
299 
EraseBufferFromPool(OMX_DIRTYPE portIndex,size_t i)300 void HDecoder::EraseBufferFromPool(OMX_DIRTYPE portIndex, size_t i)
301 {
302     vector<BufferInfo>& pool = (portIndex == OMX_DirInput) ? inputBufferPool_ : outputBufferPool_;
303     if (i >= pool.size()) {
304         return;
305     }
306     BufferInfo& info = pool[i];
307     if (portIndex == OMX_DirOutput && outputSurface_ &&
308         info.owner != BufferOwner::OWNED_BY_SURFACE) {
309         CancelBufferToSurface(info);
310     }
311     FreeOmxBuffer(portIndex, info);
312     pool.erase(pool.begin() + i);
313 }
314 
SurfaceBufferToOmxBuffer(const sptr<SurfaceBuffer> & surfaceBuffer)315 shared_ptr<OmxCodecBuffer> HDecoder::SurfaceBufferToOmxBuffer(const sptr<SurfaceBuffer>& surfaceBuffer)
316 {
317     BufferHandle* bufferHandle = surfaceBuffer->GetBufferHandle();
318     if (bufferHandle == nullptr) {
319         HLOGE("null BufferHandle");
320         return nullptr;
321     }
322     std::shared_ptr<OmxCodecBuffer> omxBuffer = std::make_shared<OmxCodecBuffer>();
323     omxBuffer->size = sizeof(OmxCodecBuffer);
324     omxBuffer->version.version.majorVersion = 1;
325     omxBuffer->bufferType = CODEC_BUFFER_TYPE_HANDLE;
326     omxBuffer->bufferhandle = new NativeBuffer(bufferHandle);
327     omxBuffer->allocLen = surfaceBuffer->GetSize();
328     omxBuffer->fenceFd = -1;
329     omxBuffer->pts = 0;
330     omxBuffer->flag = 0;
331     return omxBuffer;
332 }
333 
AllocateOutputBuffersFromSurface()334 int32_t HDecoder::AllocateOutputBuffersFromSurface()
335 {
336     GSError err = outputSurface_->CleanCache();
337     if (err != GSERROR_OK) {
338         HLOGW("clean cache failed");
339     }
340     err = outputSurface_->SetQueueSize(outBufferCnt_);
341     if (err != GSERROR_OK) {
342         HLOGE("set surface queue size failed");
343         return AVCS_ERR_INVALID_VAL;
344     }
345     if (!outputBufferPool_.empty()) {
346         HLOGW("output buffer pool should be empty");
347     }
348     outputBufferPool_.clear();
349     for (uint32_t i = 0; i < outBufferCnt_; ++i) {
350         sptr<SurfaceBuffer> surfaceBuffer;
351         {
352             sptr<SyncFence> fence;
353             err = outputSurface_->RequestBuffer(surfaceBuffer, fence, requestCfg_);
354             if (err != GSERROR_OK || surfaceBuffer == nullptr) {
355                 HLOGE("RequestBuffer %{public}u failed, GSError=%{public}d", i, err);
356                 return AVCS_ERR_UNKNOWN;
357             }
358         }
359 
360         shared_ptr<OmxCodecBuffer> omxBuffer = SurfaceBufferToOmxBuffer(surfaceBuffer);
361         if (omxBuffer == nullptr) {
362             outputSurface_->CancelBuffer(surfaceBuffer);
363             return AVCS_ERR_UNKNOWN;
364         }
365         shared_ptr<OmxCodecBuffer> outBuffer = make_shared<OmxCodecBuffer>();
366         int32_t ret = compNode_->UseBuffer(OMX_DirOutput, *omxBuffer, *outBuffer);
367         if (ret != HDF_SUCCESS) {
368             outputSurface_->CancelBuffer(surfaceBuffer);
369             HLOGE("Failed to UseBuffer with output port");
370             return AVCS_ERR_NO_MEMORY;
371         }
372         outBuffer->fenceFd = -1;
373         BufferInfo info {};
374         info.isInput = false;
375         info.owner = BufferOwner::OWNED_BY_US;
376         info.surfaceBuffer = surfaceBuffer;
377         info.sharedBuffer = nullptr;
378         info.omxBuffer = outBuffer;
379         info.bufferId = outBuffer->bufferId;
380         outputBufferPool_.push_back(info);
381     }
382     return AVCS_ERR_OK;
383 }
384 
AllocateBuffersOnPort(OMX_DIRTYPE portIndex)385 int32_t HDecoder::AllocateBuffersOnPort(OMX_DIRTYPE portIndex)
386 {
387     if ((portIndex == OMX_DirOutput) && (outputBufferType_ == BufferType::PRESET_SURFACE_BUFFER)) {
388         return AllocateOutputBuffersFromSurface();
389     } else {
390         return AllocateSharedBuffers(portIndex, (portIndex == OMX_DirOutput));
391     }
392 }
393 
CancelBufferToSurface(BufferInfo & info)394 void HDecoder::CancelBufferToSurface(BufferInfo& info)
395 {
396     HLOGD("outBufId = %{public}u", info.bufferId);
397     GSError ret = outputSurface_->CancelBuffer(info.surfaceBuffer);
398     if (ret != OHOS::GSERROR_OK) {
399         HLOGW("bufferId=%{public}u cancel failed, GSError=%{public}d", info.bufferId, ret);
400     }
401     ChangeOwner(info, BufferOwner::OWNED_BY_SURFACE); // change owner even if cancel failed
402 }
403 
OnGetBufferFromSurface()404 void HDecoder::OnGetBufferFromSurface()
405 {
406     while (true) {
407         if (!GetOneBufferFromSurface()) {
408             break;
409         }
410     }
411 }
412 
GetOneBufferFromSurface()413 bool HDecoder::GetOneBufferFromSurface()
414 {
415     sptr<SurfaceBuffer> buffer;
416     sptr<SyncFence> fence;
417     GSError ret = outputSurface_->RequestBuffer(buffer, fence, requestCfg_);
418     if (ret != GSERROR_OK || buffer == nullptr) {
419         return false;
420     }
421     if (fence != nullptr && fence->IsValid()) {
422         int waitRes = fence->Wait(WAIT_FENCE_MS);
423         if (waitRes != 0) {
424             HLOGW("wait fence time out");
425         }
426     }
427     for (BufferInfo& info : outputBufferPool_) {
428         if (info.owner == BufferOwner::OWNED_BY_SURFACE &&
429             info.surfaceBuffer->GetBufferHandle() == buffer->GetBufferHandle()) {
430             int32_t err = NotifyOmxToFillThisOutBuffer(info);
431             if (err == AVCS_ERR_OK) {
432                 return true;
433             }
434             break;
435         }
436     }
437     HLOGW("cannot find slot or submit to omx failed, cancel it");
438     outputSurface_->CancelBuffer(buffer);
439     return false;
440 }
441 
NotifySurfaceToRenderOutputBuffer(BufferInfo & info)442 int32_t HDecoder::NotifySurfaceToRenderOutputBuffer(BufferInfo &info)
443 {
444     flushCfg_.timestamp = info.omxBuffer->pts;
445     GSError ret = outputSurface_->FlushBuffer(info.surfaceBuffer, -1, flushCfg_);
446     if (ret != GSERROR_OK) {
447         HLOGE("FlushBuffer failed, GSError=%{public}d", ret);
448         return AVCS_ERR_UNKNOWN;
449     }
450     HLOGD("outBufId = %{public}u, render succ, pts = %{public}" PRId64 ", "
451         "[%{public}d %{public}d %{public}d %{public}d]", info.bufferId, flushCfg_.timestamp,
452         flushCfg_.damage.x, flushCfg_.damage.y, flushCfg_.damage.w, flushCfg_.damage.h);
453     ChangeOwner(info, BufferOwner::OWNED_BY_SURFACE);
454     return AVCS_ERR_OK;
455 }
456 
OnOMXEmptyBufferDone(uint32_t bufferId,BufferOperationMode mode)457 void HDecoder::OnOMXEmptyBufferDone(uint32_t bufferId, BufferOperationMode mode)
458 {
459     BufferInfo *info = FindBufferInfoByID(OMX_DirInput, bufferId);
460     if (info == nullptr) {
461         HLOGE("unknown buffer id %{public}u", bufferId);
462         return;
463     }
464     if (info->owner != BufferOwner::OWNED_BY_OMX) {
465         HLOGE("wrong ownership: buffer id=%{public}d, owner=%{public}s", bufferId, ToString(info->owner));
466         return;
467     }
468     ChangeOwner(*info, BufferOwner::OWNED_BY_US);
469 
470     switch (mode) {
471         case KEEP_BUFFER:
472             return;
473         case RESUBMIT_BUFFER: {
474             if (!inputPortEos_) {
475                 NotifyUserToFillThisInBuffer(*info);
476             }
477             return;
478         }
479         default: {
480             HLOGE("SHOULD NEVER BE HERE");
481             return;
482         }
483     }
484 }
485 
OnRenderOutputBuffer(const MsgInfo & msg,BufferOperationMode mode)486 void HDecoder::OnRenderOutputBuffer(const MsgInfo &msg, BufferOperationMode mode)
487 {
488     if (outputBufferType_ == BufferType::PRESET_ASHM_BUFFER) {
489         HLOGE("can only render in surface mode");
490         ReplyErrorCode(msg.id, AVCS_ERR_INVALID_OPERATION);
491         return;
492     }
493     uint32_t bufferId;
494     (void)msg.param->GetValue(BUFFER_ID, bufferId);
495     optional<size_t> idx = FindBufferIndexByID(OMX_DirOutput, bufferId);
496     if (!idx.has_value()) {
497         ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
498         return;
499     }
500     BufferInfo& info = outputBufferPool_[idx.value()];
501     if (info.owner != BufferOwner::OWNED_BY_USER) {
502         HLOGE("wrong ownership: buffer id=%{public}d, owner=%{public}s", bufferId, ToString(info.owner));
503         ReplyErrorCode(msg.id, AVCS_ERR_INVALID_VAL);
504         return;
505     }
506     HLOGD("outBufId = %{public}u", info.bufferId);
507     ChangeOwner(info, BufferOwner::OWNED_BY_US);
508     ReplyErrorCode(msg.id, AVCS_ERR_OK);
509 
510     NotifySurfaceToRenderOutputBuffer(info);
511     if (mode == FREE_BUFFER) {
512         EraseBufferFromPool(OMX_DirOutput, idx.value());
513     }
514 }
515 } // namespace OHOS::MediaAVCodec