1 /*
2  * Copyright (c) 2024 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 "media_codec_encoder_adapter_impl.h"
17 #include "ohos_buffer_adapter_impl.h"
18 #include "buffer_info_adapter_impl.h"
19 #include "capability_data_adapter_impl.h"
20 #include "codec_format_adapter_impl.h"
21 
22 #include <unordered_map>
23 
24 #include "nweb_log.h"
25 
26 namespace OHOS::NWeb {
27 namespace {
28 const std::unordered_map<OHOS::MediaAVCodec::AVCodecErrorType, ErrorType> ERROR_TYPE_MAP = {
29     { OHOS::MediaAVCodec::AVCodecErrorType::AVCODEC_ERROR_INTERNAL, ErrorType::CODEC_ERROR_INTERNAL },
30     { OHOS::MediaAVCodec::AVCodecErrorType::AVCODEC_ERROR_EXTEND_START, ErrorType::CODEC_ERROR_EXTEND_START }
31 };
32 
33 const std::unordered_map<OHOS::MediaAVCodec::AVCodecBufferFlag, BufferFlag> BUFFER_FLAG_MAP = {
34     { OHOS::MediaAVCodec::AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_NONE, BufferFlag::CODEC_BUFFER_FLAG_NONE },
35     { OHOS::MediaAVCodec::AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_EOS, BufferFlag::CODEC_BUFFER_FLAG_EOS },
36     { OHOS::MediaAVCodec::AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_SYNC_FRAME, BufferFlag::CODEC_BUFFER_FLAG_SYNC_FRAME },
37     { OHOS::MediaAVCodec::AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_PARTIAL_FRAME,
38         BufferFlag::CODEC_BUFFER_FLAG_PARTIAL_FRAME },
39     { OHOS::MediaAVCodec::AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_CODEC_DATA, BufferFlag::CODEC_BUFFER_FLAG_CODEC_DATA }
40 };
41 
42 const std::unordered_map<BufferFlag, OHOS::MediaAVCodec::AVCodecBufferFlag> AV_BUFFER_FLAG_MAP = {
43     { BufferFlag::CODEC_BUFFER_FLAG_NONE, OHOS::MediaAVCodec::AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_NONE },
44     { BufferFlag::CODEC_BUFFER_FLAG_EOS, OHOS::MediaAVCodec::AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_EOS },
45     { BufferFlag::CODEC_BUFFER_FLAG_SYNC_FRAME, OHOS::MediaAVCodec::AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_SYNC_FRAME },
46     { BufferFlag::CODEC_BUFFER_FLAG_PARTIAL_FRAME,
47         OHOS::MediaAVCodec::AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_PARTIAL_FRAME },
48     { BufferFlag::CODEC_BUFFER_FLAG_CODEC_DATA, OHOS::MediaAVCodec::AVCodecBufferFlag::AVCODEC_BUFFER_FLAG_CODEC_DATA }
49 };
50 } // namespace
51 
CreateVideoCodecByMime(const std::string mimetype)52 CodecCodeAdapter MediaCodecEncoderAdapterImpl::CreateVideoCodecByMime(const std::string mimetype)
53 {
54     encoder_ = VideoEncoderFactory::CreateByMime(mimetype);
55     if (encoder_ == nullptr) {
56         WVLOG_E("MediaCodecEncoder create by mime failed.");
57         return CodecCodeAdapter::ERROR;
58     }
59 
60     return CodecCodeAdapter::OK;
61 }
62 
CreateVideoCodecByName(const std::string name)63 CodecCodeAdapter MediaCodecEncoderAdapterImpl::CreateVideoCodecByName(const std::string name)
64 {
65     encoder_ = VideoEncoderFactory::CreateByName(name);
66     if (encoder_ == nullptr) {
67         WVLOG_E("MediaCodecEncoder create by name failed.");
68         return CodecCodeAdapter::ERROR;
69     }
70 
71     return CodecCodeAdapter::OK;
72 }
73 
SetCodecCallback(const std::shared_ptr<CodecCallbackAdapter> callback)74 CodecCodeAdapter MediaCodecEncoderAdapterImpl::SetCodecCallback(const std::shared_ptr<CodecCallbackAdapter> callback)
75 {
76     if (callback == nullptr) {
77         WVLOG_E("Media Callback is NULL.");
78         return CodecCodeAdapter::ERROR;
79     }
80 
81     callback_ = std::make_shared<EncoderCallbackImpl>(callback);
82     if (callback_ == nullptr) {
83         WVLOG_E("create Callback failed.");
84         return CodecCodeAdapter::ERROR;
85     }
86 
87     if (encoder_ == nullptr) {
88         WVLOG_E("MediaCodecEncoder is nullptr.");
89         return CodecCodeAdapter::ERROR;
90     }
91 
92     int32_t ret = encoder_->SetCallback(callback_);
93     if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) {
94         WVLOG_E("MediaCodecEncoder set callback failed.");
95         return CodecCodeAdapter::ERROR;
96     }
97     return CodecCodeAdapter::OK;
98 }
99 
Configure(const std::shared_ptr<CodecConfigParaAdapter> config)100 CodecCodeAdapter MediaCodecEncoderAdapterImpl::Configure(const std::shared_ptr<CodecConfigParaAdapter> config)
101 {
102     if (encoder_ == nullptr) {
103         WVLOG_E("MediaCodecEncoder is nullptr when ConfigureEncoder.");
104         return CodecCodeAdapter::ERROR;
105     }
106 
107     if (config == nullptr) {
108         WVLOG_E("config is nullptr when ConfigureEncoder.");
109         return CodecCodeAdapter::ERROR;
110     }
111 
112     OHOS::MediaAVCodec::Format avCodecFormat;
113 
114     avCodecFormat.PutIntValue(OHOS::MediaAVCodec::MediaDescriptionKey::MD_KEY_WIDTH, config->GetWidth());
115     avCodecFormat.PutIntValue(OHOS::MediaAVCodec::MediaDescriptionKey::MD_KEY_HEIGHT, config->GetHeight());
116     avCodecFormat.PutDoubleValue(OHOS::MediaAVCodec::MediaDescriptionKey::MD_KEY_FRAME_RATE, config->GetFrameRate());
117     avCodecFormat.PutLongValue(OHOS::MediaAVCodec::MediaDescriptionKey::MD_KEY_BITRATE, config->GetBitRate());
118     avCodecFormat.PutIntValue(
119         OHOS::MediaAVCodec::MediaDescriptionKey::MD_KEY_VIDEO_ENCODE_BITRATE_MODE, VideoEncodeBitrateMode::CBR);
120     avCodecFormat.PutIntValue(
121         OHOS::MediaAVCodec::MediaDescriptionKey::MD_KEY_PIXEL_FORMAT, (int32_t)VideoPixelFormat::YUVI420);
122     WVLOG_I("Configure width: %{public}d, height: %{public}d, bitRate: %{public}d, framerate: %{public}lf,",
123         config->GetWidth(), config->GetHeight(), (int32_t)config->GetBitRate(), config->GetFrameRate());
124     int32_t ret = encoder_->Configure(avCodecFormat);
125     if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) {
126         WVLOG_E("encoder config error.");
127         return CodecCodeAdapter::ERROR;
128     }
129     return CodecCodeAdapter::OK;
130 }
131 
Prepare()132 CodecCodeAdapter MediaCodecEncoderAdapterImpl::Prepare()
133 {
134     if (encoder_ == nullptr) {
135         WVLOG_E("MediaCodecEncoder is nullptr when PrepareEncoder.");
136         return CodecCodeAdapter::ERROR;
137     }
138 
139     int32_t ret = encoder_->Prepare();
140     if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) {
141         WVLOG_E("encoder PrepareEncoder error.");
142         return CodecCodeAdapter::ERROR;
143     }
144     return CodecCodeAdapter::OK;
145 }
146 
Start()147 CodecCodeAdapter MediaCodecEncoderAdapterImpl::Start()
148 {
149     if (encoder_ == nullptr) {
150         WVLOG_E("MediaCodecEncoder is nullptr when StartEncoder.");
151         return CodecCodeAdapter::ERROR;
152     }
153 
154     int32_t ret = encoder_->Start();
155     if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) {
156         WVLOG_E("encoder Start error.");
157         return CodecCodeAdapter::ERROR;
158     }
159     return CodecCodeAdapter::OK;
160 }
161 
Stop()162 CodecCodeAdapter MediaCodecEncoderAdapterImpl::Stop()
163 {
164     if (encoder_ == nullptr) {
165         WVLOG_E("MediaCodecEncoder is nullptr when StopEncoder.");
166         return CodecCodeAdapter::ERROR;
167     }
168 
169     int32_t ret = encoder_->Stop();
170     if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) {
171         WVLOG_E("encoder Stop error.");
172         return CodecCodeAdapter::ERROR;
173     }
174     return CodecCodeAdapter::OK;
175 }
176 
Reset()177 CodecCodeAdapter MediaCodecEncoderAdapterImpl::Reset()
178 {
179     if (encoder_ == nullptr) {
180         WVLOG_E("MediaCodecEncoder is nullptr when ResetEncoder.");
181         return CodecCodeAdapter::ERROR;
182     }
183 
184     int32_t ret = encoder_->Reset();
185     if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) {
186         WVLOG_E("encoder Reset error.");
187         return CodecCodeAdapter::ERROR;
188     }
189     return CodecCodeAdapter::OK;
190 }
191 
Release()192 CodecCodeAdapter MediaCodecEncoderAdapterImpl::Release()
193 {
194     if (encoder_ == nullptr) {
195         WVLOG_E("MediaCodecEncoder is nullptr when ReleaseEncoder.");
196         return CodecCodeAdapter::ERROR;
197     }
198 
199     int32_t ret = encoder_->Release();
200     if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) {
201         WVLOG_E("encoder Release error.");
202         return CodecCodeAdapter::ERROR;
203     }
204     return CodecCodeAdapter::OK;
205 }
206 
CreateInputSurface()207 std::shared_ptr<ProducerSurfaceAdapter> MediaCodecEncoderAdapterImpl::CreateInputSurface()
208 {
209     if (encoder_ == nullptr) {
210         WVLOG_E("MediaCodecEncoder is nullptr when CreateInputSurface.");
211         return nullptr;
212     }
213 
214     auto avCodecEncoderSurface = encoder_->CreateInputSurface();
215     if (avCodecEncoderSurface == nullptr) {
216         WVLOG_E("encoder create input surface error.");
217         return nullptr;
218     }
219 
220     return std::make_shared<ProducerSurfaceAdapterImpl>(avCodecEncoderSurface);
221 }
222 
ReleaseOutputBuffer(uint32_t index,bool isRender)223 CodecCodeAdapter MediaCodecEncoderAdapterImpl::ReleaseOutputBuffer(uint32_t index, bool isRender)
224 {
225     if (encoder_ == nullptr) {
226         WVLOG_E("MediaCodecEncoder is nullptr.");
227         return CodecCodeAdapter::ERROR;
228     }
229 
230     int32_t ret = encoder_->ReleaseOutputBuffer(index);
231     if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) {
232         WVLOG_E("release buffer failed.");
233         return CodecCodeAdapter::ERROR;
234     }
235     return CodecCodeAdapter::OK;
236 }
237 
RequestKeyFrameSoon()238 CodecCodeAdapter MediaCodecEncoderAdapterImpl::RequestKeyFrameSoon()
239 {
240     if (encoder_ == nullptr) {
241         WVLOG_E("MediaCodecEncoder is nullptr when RequestKeyFrameSoon.");
242         return CodecCodeAdapter::ERROR;
243     }
244 
245     OHOS::MediaAVCodec::Format avCodecFormat;
246     avCodecFormat.PutIntValue(OHOS::MediaAVCodec::MediaDescriptionKey::MD_KEY_REQUEST_I_FRAME, true);
247 
248     int32_t ret = encoder_->SetParameter(avCodecFormat);
249     if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) {
250         WVLOG_E("encoder SetParameter error.");
251         return CodecCodeAdapter::ERROR;
252     }
253     return CodecCodeAdapter::OK;
254 }
255 
GetErrorType(AVCodecErrorType codecErrorType)256 ErrorType MediaCodecEncoderAdapterImpl::GetErrorType(AVCodecErrorType codecErrorType)
257 {
258     auto type = ERROR_TYPE_MAP.find(codecErrorType);
259     if (type == ERROR_TYPE_MAP.end()) {
260         WVLOG_E("error type not found.");
261         return ErrorType::CODEC_ERROR_INTERNAL;
262     }
263     return type->second;
264 }
265 
GetBufferFlag(AVCodecBufferFlag codecBufferFlag)266 BufferFlag MediaCodecEncoderAdapterImpl::GetBufferFlag(AVCodecBufferFlag codecBufferFlag)
267 {
268     auto flag = BUFFER_FLAG_MAP.find(codecBufferFlag);
269     if (flag == BUFFER_FLAG_MAP.end()) {
270         WVLOG_E("buffer flag not found.");
271         return BufferFlag::CODEC_BUFFER_FLAG_NONE;
272     }
273     return flag->second;
274 }
275 
EncoderCallbackImpl(std::shared_ptr<CodecCallbackAdapter> cb)276 EncoderCallbackImpl::EncoderCallbackImpl(std::shared_ptr<CodecCallbackAdapter> cb) : cb_(cb) {};
277 
OnError(AVCodecErrorType errorType,int32_t errorCode)278 void EncoderCallbackImpl::OnError(AVCodecErrorType errorType, int32_t errorCode)
279 {
280     if (!cb_) {
281         WVLOG_E("callback is null.");
282         return;
283     }
284 
285     ErrorType errType = MediaCodecEncoderAdapterImpl::GetErrorType(errorType);
286 
287     cb_->OnError(errType, errorCode);
288 }
289 
OnOutputFormatChanged(const Format & format)290 void EncoderCallbackImpl::OnOutputFormatChanged(const Format& format)
291 {
292     if (!cb_) {
293         WVLOG_E("callback is null.");
294         return;
295     }
296 
297     std::shared_ptr<CodecFormatAdapterImpl> formatAdapter = std::make_shared<CodecFormatAdapterImpl>();
298     if (!formatAdapter) {
299         WVLOG_E("formatAdapter is null");
300         return;
301     }
302 
303     int32_t width = 0;
304     int32_t height = 0;
305     format.GetIntValue(OHOS::MediaAVCodec::MediaDescriptionKey::MD_KEY_WIDTH, width);
306     format.GetIntValue(OHOS::MediaAVCodec::MediaDescriptionKey::MD_KEY_HEIGHT, height);
307     formatAdapter->SetWidth(width);
308     formatAdapter->SetHeight(height);
309     cb_->OnStreamChanged(formatAdapter);
310 }
311 
OnInputBufferAvailable(uint32_t index,std::shared_ptr<AVSharedMemory> buffer)312 void EncoderCallbackImpl::OnInputBufferAvailable(uint32_t index, std::shared_ptr<AVSharedMemory> buffer)
313 {
314     if (!cb_) {
315         WVLOG_E("callback is null.");
316         return;
317     }
318 
319     if (buffer == nullptr || buffer->GetBase() == nullptr) {
320         WVLOG_E("callback input buffer is null");
321         return;
322     }
323 
324     std::shared_ptr<OhosBufferAdapterImpl> ohosBuffer = std::make_shared<OhosBufferAdapterImpl>();
325     if (!ohosBuffer) {
326         WVLOG_E("new OhosBufferAdapterImpl failed");
327         return;
328     }
329 
330     ohosBuffer->SetAddr(buffer->GetBase());
331     ohosBuffer->SetBufferSize(buffer->GetSize());
332     cb_->OnNeedInputData(index, ohosBuffer);
333 }
334 
OnOutputBufferAvailable(uint32_t index,AVCodecBufferInfo info,AVCodecBufferFlag flag,std::shared_ptr<AVSharedMemory> buffer)335 void EncoderCallbackImpl::OnOutputBufferAvailable(
336     uint32_t index, AVCodecBufferInfo info, AVCodecBufferFlag flag, std::shared_ptr<AVSharedMemory> buffer)
337 {
338     if (!cb_) {
339         WVLOG_E("callback is null.");
340         return;
341     }
342 
343     if (buffer == nullptr || buffer->GetBase() == nullptr) {
344         WVLOG_E("callback output buffer is null");
345         return;
346     }
347 
348     std::shared_ptr<BufferInfoAdapterImpl> bufferInfo = std::make_shared<BufferInfoAdapterImpl>();
349     if (bufferInfo == nullptr) {
350         WVLOG_E("new bufferInfoAdapterImpl failed");
351         return;
352     }
353 
354     std::shared_ptr<OhosBufferAdapterImpl> ohosBuffer = std::make_shared<OhosBufferAdapterImpl>();
355     if (ohosBuffer == nullptr) {
356         WVLOG_E("new OhosBufferAdapterImpl failed");
357         return;
358     }
359 
360     bufferInfo->SetPresentationTimeUs(info.presentationTimeUs);
361     bufferInfo->SetSize(info.size);
362     bufferInfo->SetOffset(info.offset);
363 
364     BufferFlag flagAdapter = MediaCodecEncoderAdapterImpl::GetBufferFlag(flag);
365 
366     ohosBuffer->SetAddr(buffer->GetBase());
367     ohosBuffer->SetBufferSize(info.size);
368     cb_->OnNeedOutputData(index, bufferInfo, flagAdapter, ohosBuffer);
369 }
370 } // namespace OHOS::NWeb
371