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_log.h"
17 #include "codec/video/encoder/video_encoder.h"
18 #include <native_avcapability.h>
19 #include <native_avcodec_videoencoder.h>
20 #include <native_averrors.h>
21 #include <native_avformat.h>
22 #include <external_window.h>
23
24 namespace OHOS {
25 namespace Media {
26 namespace {
27 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_VIDEOEDITOR, "VideoEditorEncode"};
28 }
29
VideoEncoder(uint64_t id,const OnNewOutputDataCallBack & cb)30 VideoEncoder::VideoEncoder(uint64_t id, const OnNewOutputDataCallBack& cb) : onNewOutputDataCallBack_(cb)
31 {
32 logTag_ = "video-encoder-" + std::to_string(id);
33 }
34
~VideoEncoder()35 VideoEncoder::~VideoEncoder()
36 {
37 MEDIA_LOGD("[%{public}s] destruct.", logTag_.c_str());
38 encoderMutex_.lock();
39 if (encoder_) {
40 OH_VideoEncoder_Destroy(encoder_);
41 encoder_ = nullptr;
42 }
43 encoderMutex_.unlock();
44 if (nativeWindow_) {
45 OH_NativeWindow_DestroyNativeWindow(nativeWindow_);
46 nativeWindow_ = nullptr;
47 }
48 MEDIA_LOGD("[%{public}s] destruct finish.", logTag_.c_str());
49 }
50
CodecOnError(OH_AVCodec * codec,int32_t errorCode,void * userData)51 void VideoEncoder::CodecOnError(OH_AVCodec* codec, int32_t errorCode, void* userData)
52 {
53 if (codec == nullptr || userData == nullptr) {
54 MEDIA_LOGE("CodecOnError invalid parameter, codec or userData or attr is nullptr.");
55 return;
56 }
57 auto encoder = static_cast<VideoEncoder*>(userData);
58 MEDIA_LOGE("[%{public}s] CodecOnError occurred error: %{public}d.", encoder->logTag_.c_str(), errorCode);
59 }
60
CodecOnNewOutputData(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr,void * userData)61 void VideoEncoder::CodecOnNewOutputData(OH_AVCodec* codec, uint32_t index, OH_AVMemory* data,
62 OH_AVCodecBufferAttr* attr, void* userData)
63 {
64 if (codec == nullptr || data == nullptr || attr == nullptr || userData == nullptr) {
65 MEDIA_LOGE("CodecOnNewOutputData invalid parameter.");
66 return;
67 }
68 auto encoder = static_cast<VideoEncoder*>(userData);
69 MEDIA_LOGD("[%{public}s] CodecOnNewOutputData index: %{public}d.", encoder->logTag_.c_str(), index);
70 encoder->WriteFrame(data, attr);
71 { // 此处codec其实就是VideoEncoder::encoder_对象,两个是同一个对象,加锁.
72 std::lock_guard<ffrt::mutex> lk(encoder->encoderMutex_);
73 OH_VideoEncoder_FreeOutputData(codec, index);
74 }
75 }
76
CodecOnStreamChanged(OH_AVCodec * codec,OH_AVFormat * format,void * userData)77 void VideoEncoder::CodecOnStreamChanged(OH_AVCodec* codec, OH_AVFormat* format, void* userData)
78 {
79 if (codec == nullptr || format == nullptr || userData == nullptr) {
80 MEDIA_LOGE("CodecOnStreamChanged invalid parameter.");
81 return;
82 }
83 auto encoder = static_cast<VideoEncoder*>(userData);
84 MEDIA_LOGI("[%{public}s] CodecOnStreamChanged.", encoder->logTag_.c_str());
85 }
86
CodecOnNeedInputData(OH_AVCodec *,uint32_t,OH_AVMemory *,void *)87 void VideoEncoder::CodecOnNeedInputData(OH_AVCodec*, uint32_t, OH_AVMemory*, void*) {}
88
WriteFrame(OH_AVMemory * data,OH_AVCodecBufferAttr * attr)89 VEFError VideoEncoder::WriteFrame(OH_AVMemory* data, OH_AVCodecBufferAttr* attr)
90 {
91 if (codecState_ == false) {
92 MEDIA_LOGI("[%{public}s] encoder has been stopped, drop it pts=%{public}" PRIu64 ".",
93 logTag_.c_str(), attr->pts);
94 return VEFError::ERR_OK;
95 }
96 if (onNewOutputDataCallBack_) {
97 onNewOutputDataCallBack_(data, attr);
98 }
99 return VEFError::ERR_OK;
100 }
101
CreateEncoder(OH_AVFormat * format)102 VEFError VideoEncoder::CreateEncoder(OH_AVFormat* format)
103 {
104 std::lock_guard<ffrt::mutex> lk(encoderMutex_);
105 const char* mime = nullptr;
106 if (!OH_AVFormat_GetStringValue(format, OH_MD_KEY_CODEC_MIME, &mime)) {
107 MEDIA_LOGE("[%{public}s] get [%{public}s] from video format failed.", logTag_.c_str(), OH_MD_KEY_CODEC_MIME);
108 return VEFError::ERR_INTERNAL_ERROR;
109 }
110 MEDIA_LOGI("[%{public}s] create encoder, video mime = %{public}s.", logTag_.c_str(), mime);
111 encoder_ = OH_VideoEncoder_CreateByMime(mime);
112 if (encoder_ == nullptr) {
113 MEDIA_LOGI("[%{public}s] create encoder failed, mime = %{public}s.", logTag_.c_str(), mime);
114 return VEFError::ERR_INTERNAL_ERROR;
115 }
116
117 OH_AVCodecAsyncCallback callback = { CodecOnError, CodecOnStreamChanged, CodecOnNeedInputData,
118 CodecOnNewOutputData };
119 auto ret = OH_VideoEncoder_SetCallback(encoder_, callback, this);
120 if (ret != AV_ERR_OK) {
121 MEDIA_LOGI("[%{public}s] set callback failed, OH_VideoEncoder_SetCallback return: %{public}d.",
122 logTag_.c_str(), ret);
123 return VEFError::ERR_INTERNAL_ERROR;
124 }
125
126 return VEFError::ERR_OK;
127 }
128
ConfigureEncoder(OH_AVFormat * format)129 VEFError VideoEncoder::ConfigureEncoder(OH_AVFormat* format)
130 {
131 std::lock_guard<ffrt::mutex> lk(encoderMutex_);
132 MEDIA_LOGI("[%{public}s] configure.", logTag_.c_str());
133 if (format == nullptr) {
134 MEDIA_LOGE("[%{public}s] configure failed, parameter format is nullptr.", logTag_.c_str());
135 return VEFError::ERR_INTERNAL_ERROR;
136 }
137
138 auto ret = OH_VideoEncoder_Configure(encoder_, format);
139 if (ret != AV_ERR_OK) {
140 MEDIA_LOGE("[%{public}s]configure failed, OH_VideoEncoder_Configure return: %{public}d.", logTag_.c_str(), ret);
141 return VEFError::ERR_INTERNAL_ERROR;
142 }
143
144 ret = OH_VideoEncoder_GetSurface(encoder_, &nativeWindow_);
145 if (ret != AV_ERR_OK) {
146 MEDIA_LOGE("[%{public}s] configure failed, OH_VideoEncoder_GetSurface return: %{public}d.", logTag_.c_str(),
147 ret);
148 return VEFError::ERR_INTERNAL_ERROR;
149 }
150
151 int32_t width = 0;
152 if (!OH_AVFormat_GetIntValue(format, OH_MD_KEY_WIDTH, &width)) {
153 MEDIA_LOGE("[%{public}s] configure failed, OH_AVFormat_GetIntValue get [%{public}s].", logTag_.c_str(),
154 OH_MD_KEY_WIDTH);
155 return VEFError::ERR_INTERNAL_ERROR;
156 }
157 int32_t height = 0;
158 if (!OH_AVFormat_GetIntValue(format, OH_MD_KEY_HEIGHT, &height)) {
159 MEDIA_LOGE("[%{public}s] configure failed, OH_AVFormat_GetIntValue get [%{public}s].", logTag_.c_str(),
160 OH_MD_KEY_HEIGHT);
161 return VEFError::ERR_INTERNAL_ERROR;
162 }
163 auto retCode = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow_, SET_BUFFER_GEOMETRY, width, height);
164 if (retCode != AV_ERR_OK) {
165 MEDIA_LOGE("[%{public}s] configure failed, OH_NativeWindow_NativeWindowHandleOpt return: %{public}d.",
166 logTag_.c_str(), retCode);
167 return VEFError::ERR_INTERNAL_ERROR;
168 }
169 MEDIA_LOGI("[%{public}s] configure success.", logTag_.c_str());
170 return VEFError::ERR_OK;
171 }
172
Start()173 VEFError VideoEncoder::Start()
174 {
175 std::lock_guard<ffrt::mutex> lk(encoderMutex_);
176 MEDIA_LOGI("[%{public}s] start encoder.", logTag_.c_str());
177 codecState_ = true;
178 auto ret = OH_VideoEncoder_Prepare(encoder_);
179 if (ret != AV_ERR_OK) {
180 MEDIA_LOGE("[%{public}s] start encoder failed, OH_VideoEncoder_Prepare return: %{public}d.", logTag_.c_str(),
181 ret);
182 return VEFError::ERR_INTERNAL_ERROR;
183 }
184
185 ret = OH_VideoEncoder_Start(encoder_);
186 if (ret != AV_ERR_OK) {
187 MEDIA_LOGE("[%{public}s]start encoder failed, OH_VideoEncoder_Start return: %{public}d.", logTag_.c_str(), ret);
188 return VEFError::ERR_INTERNAL_ERROR;
189 }
190 MEDIA_LOGI("[%{public}s] start encoder success.", logTag_.c_str());
191 return VEFError::ERR_OK;
192 }
193
Stop()194 VEFError VideoEncoder::Stop()
195 {
196 std::lock_guard<ffrt::mutex> lk(encoderMutex_);
197 MEDIA_LOGI("[%{public}s] stop encoder.", logTag_.c_str());
198 codecState_ = false;
199 OH_AVErrCode ret = OH_VideoEncoder_Stop(encoder_);
200 if (ret != AV_ERR_OK) {
201 MEDIA_LOGE("[%{public}s] stop encoder failed, OH_VideoEncoder_Stop return: %{public}d.", logTag_.c_str(), ret);
202 return VEFError::ERR_INTERNAL_ERROR;
203 }
204 MEDIA_LOGI("[%{public}s] stop encoder success.", logTag_.c_str());
205 return VEFError::ERR_OK;
206 }
207
SendEos()208 VEFError VideoEncoder::SendEos()
209 {
210 OH_AVErrCode ret = OH_VideoEncoder_NotifyEndOfStream(encoder_);
211 if (ret != AV_ERR_OK) {
212 MEDIA_LOGE("[%{public}s] OH_VideoEncoder_NotifyEndOfStream return: %{public}d.", logTag_.c_str(), ret);
213 return VEFError::ERR_INTERNAL_ERROR;
214 }
215 MEDIA_LOGD("[%{public}s] notify eos encoder finish.", logTag_.c_str());
216 return VEFError::ERR_OK;
217 }
218
Flush()219 VEFError VideoEncoder::Flush()
220 {
221 std::lock_guard<ffrt::mutex> lk(encoderMutex_);
222 MEDIA_LOGI("[%{public}s] finish, flush encoder.", logTag_.c_str());
223 OH_AVErrCode ret = OH_VideoEncoder_Flush(encoder_);
224 if (ret != AV_ERR_OK) {
225 MEDIA_LOGE("[%{public}s] OH_VideoEncoder_Flush return: %{public}d.", logTag_.c_str(), ret);
226 return VEFError::ERR_INTERNAL_ERROR;
227 }
228 MEDIA_LOGD("[%{public}s] notify eos encoder finish.", logTag_.c_str());
229 return VEFError::ERR_OK;
230 }
231
Init(OH_AVFormat * format)232 VEFError VideoEncoder::Init(OH_AVFormat* format)
233 {
234 MEDIA_LOGI("[%{public}s] init encoder.", logTag_.c_str());
235 std::string dumpInfo = OH_AVFormat_DumpInfo(format);
236 MEDIA_LOGI("[%{public}s] initializing encoder, format: %{public}s.", logTag_.c_str(), dumpInfo.c_str());
237 VEFError error = CreateEncoder(format);
238 if (error != VEFError::ERR_OK) {
239 MEDIA_LOGE("[%{public}s] init AVCodec-encoder failed with error: %{public}d.", logTag_.c_str(), error);
240 return VEFError::ERR_INTERNAL_ERROR;
241 }
242 error = ConfigureEncoder(format);
243 if (error != VEFError::ERR_OK) {
244 MEDIA_LOGE("[%{public}s] configure AVCodec-encoder failed with error: %{public}d.", logTag_.c_str(), error);
245 return VEFError::ERR_INTERNAL_ERROR;
246 }
247 MEDIA_LOGI("[%{public}s] init encoder success.", logTag_.c_str());
248 return VEFError::ERR_OK;
249 }
250
GetOHNativeWindow() const251 OHNativeWindow* VideoEncoder::GetOHNativeWindow() const
252 {
253 return nativeWindow_;
254 }
255 } // namespace Media
256 } // namespace OHOS
257