1 /*
2 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development 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 "video_source_encoder.h"
17 #include "avsharedmemory.h"
18 #include "common/common_macro.h"
19 #include "media_errors.h"
20 #include "protocol/frame/h264_frame.h"
21 #include "sharing_log.h"
22
23 namespace OHOS {
24 namespace Sharing {
25
OnError(Media::AVCodecErrorType errorType,int32_t errorCode)26 void VideoSourceEncoder::VideoEncodeCallback::OnError(Media::AVCodecErrorType errorType, int32_t errorCode)
27 {
28 SHARING_LOGD("trace.");
29 if (auto parent = parent_.lock()) {
30 parent->OnError(errorType, errorCode);
31 }
32 }
33
OnOutputFormatChanged(const Media::Format & format)34 void VideoSourceEncoder::VideoEncodeCallback::OnOutputFormatChanged(const Media::Format &format)
35 {
36 SHARING_LOGD("trace.");
37 if (auto parent = parent_.lock()) {
38 parent->OnOutputFormatChanged(format);
39 }
40 }
41
OnInputBufferAvailable(uint32_t index)42 void VideoSourceEncoder::VideoEncodeCallback::OnInputBufferAvailable(uint32_t index)
43 {
44 SHARING_LOGD("trace.");
45 if (auto parent = parent_.lock()) {
46 parent->OnInputBufferAvailable(index);
47 }
48 }
49
OnOutputBufferAvailable(uint32_t index,Media::AVCodecBufferInfo info,Media::AVCodecBufferFlag flag)50 void VideoSourceEncoder::VideoEncodeCallback::OnOutputBufferAvailable(uint32_t index, Media::AVCodecBufferInfo info,
51 Media::AVCodecBufferFlag flag)
52 {
53 SHARING_LOGD("trace.");
54 if (auto parent = parent_.lock()) {
55 parent->OnOutputBufferAvailable(index, info, flag);
56 }
57 }
58
~VideoSourceEncoder()59 VideoSourceEncoder::~VideoSourceEncoder()
60 {
61 SHARING_LOGD("trace.");
62 StopEncoder();
63 ReleaseEncoder();
64 encoderCb_ = nullptr;
65 }
66
InitEncoder(const VideoSourceConfigure & configure)67 bool VideoSourceEncoder::InitEncoder(const VideoSourceConfigure &configure)
68 {
69 SHARING_LOGD("trace.");
70 if (!CreateEncoder(configure)) {
71 SHARING_LOGE("Create encoder failed!");
72 return false;
73 }
74
75 if (!ConfigEncoder(configure)) {
76 SHARING_LOGE("Config encoder failed!");
77 ReleaseEncoder();
78 return false;
79 }
80
81 videoEncoderSurface_ = videoEncoder_->CreateInputSurface();
82 if (videoEncoderSurface_ == nullptr) {
83 SHARING_LOGE("Create encoder surface failed!");
84 ReleaseEncoder();
85 return false;
86 }
87
88 return true;
89 }
90
CreateEncoder(const VideoSourceConfigure & configure)91 bool VideoSourceEncoder::CreateEncoder(const VideoSourceConfigure &configure)
92 {
93 SHARING_LOGD("trace.");
94 switch (configure.codecType_) {
95 case CodecId::CODEC_H264:
96 videoEncoder_ = OHOS::Media::VideoEncoderFactory::CreateByMime("video/avc");
97 break;
98 case CodecId::CODEC_H265:
99 videoEncoder_ = OHOS::Media::VideoEncoderFactory::CreateByMime("video/hevc");
100 break;
101 default:
102 SHARING_LOGE("Encoder codecType is invalid!");
103 videoEncoder_ = nullptr;
104 }
105 if (videoEncoder_ == nullptr) {
106 SHARING_LOGE("Create Video Source Encoder failed!");
107 return false;
108 }
109 encoderCb_ = std::make_shared<VideoEncodeCallback>(shared_from_this());
110 int32_t ret = videoEncoder_->SetCallback(encoderCb_);
111 if (ret != Media::MSERR_OK) {
112 SHARING_LOGE("Set encoder callback failed!");
113 ReleaseEncoder();
114 return false;
115 }
116
117 return true;
118 }
119
ConfigEncoder(const VideoSourceConfigure & configure)120 bool VideoSourceEncoder::ConfigEncoder(const VideoSourceConfigure &configure)
121 {
122 SHARING_LOGD("trace.");
123 if (videoEncoder_ == nullptr) {
124 SHARING_LOGE("Encoder is null!");
125 return false;
126 }
127 Media::Format videoFormat;
128 switch (configure.codecType_) {
129 case CodecId::CODEC_H264:
130 videoFormat.PutStringValue("codec_mime", "video/avc");
131 break;
132 case CodecId::CODEC_H265:
133 videoFormat.PutStringValue("codec_mime", "video/hevc");
134 break;
135 default:
136 SHARING_LOGE("Encoder codecType is invalid!");
137 return false;
138 }
139 videoFormat.PutIntValue("pixel_format", configure.pixleFormat_);
140 videoFormat.PutLongValue("max_input_size", MAX_YUV420_BUFFER_SIZE);
141 videoFormat.PutIntValue("width", configure.videoWidth_);
142 videoFormat.PutIntValue("height", configure.videoHeight_);
143 videoFormat.PutIntValue("frame_rate", configure.frameRate_);
144 videoFormat.PutIntValue("bitrate", SCREEN_CAPTURE_ENCODE_BITRATE);
145 int32_t ret = videoEncoder_->Configure(videoFormat);
146 if (ret != Media::MSERR_OK) {
147 SHARING_LOGE("Configure encoder failed!");
148 return false;
149 }
150
151 return true;
152 }
153
GetEncoderSurface()154 sptr<Surface> &VideoSourceEncoder::GetEncoderSurface()
155 {
156 SHARING_LOGD("trace.");
157 return videoEncoderSurface_;
158 }
159
StartEncoder()160 bool VideoSourceEncoder::StartEncoder()
161 {
162 SHARING_LOGD("trace.");
163 if (videoEncoder_ == nullptr) {
164 SHARING_LOGE("Encoder is null!");
165 return false;
166 }
167
168 int32_t ret = videoEncoder_->Prepare();
169 if (ret != Media::MSERR_OK) {
170 SHARING_LOGE("Prepare encoder failed!");
171 return false;
172 }
173
174 ret = videoEncoder_->Start();
175 if (ret != Media::MSERR_OK) {
176 SHARING_LOGE("Start encoder failed!");
177 return false;
178 }
179
180 return true;
181 }
182
StopEncoder()183 bool VideoSourceEncoder::StopEncoder()
184 {
185 SHARING_LOGD("trace.");
186 if (videoEncoder_ == nullptr) {
187 SHARING_LOGE("Encoder is null!");
188 return false;
189 }
190
191 int32_t ret = videoEncoder_->Flush();
192 if (ret != Media::MSERR_OK) {
193 SHARING_LOGE("Flush encoder failed!");
194 }
195
196 ret = videoEncoder_->Stop();
197 if (ret != Media::MSERR_OK) {
198 SHARING_LOGE("Stop encoder failed!");
199 return false;
200 }
201
202 return true;
203 }
204
ReleaseEncoder()205 bool VideoSourceEncoder::ReleaseEncoder()
206 {
207 SHARING_LOGD("trace.");
208 if (videoEncoder_ == nullptr) {
209 SHARING_LOGE("encoder is null!");
210 return false;
211 }
212 int32_t ret = videoEncoder_->Release();
213 if (ret != Media::MSERR_OK) {
214 SHARING_LOGE("Release encoder failed.");
215 return false;
216 }
217 videoEncoder_ = nullptr;
218
219 return true;
220 }
221
OnOutputBufferAvailable(uint32_t index,Media::AVCodecBufferInfo info,Media::AVCodecBufferFlag flag)222 void VideoSourceEncoder::OnOutputBufferAvailable(uint32_t index, Media::AVCodecBufferInfo info,
223 Media::AVCodecBufferFlag flag)
224 {
225 SHARING_LOGI("index: %{public}u, size:%{public}u, pts: %{public}" PRIi64 ".", index, info.size,
226 info.presentationTimeUs);
227 if (!videoEncoder_) {
228 SHARING_LOGE("encoder is null!");
229 return;
230 }
231
232 auto videoSharedMemory = videoEncoder_->GetOutputBuffer(index);
233 if (videoSharedMemory == nullptr || videoSharedMemory->GetBase() == nullptr) {
234 SHARING_LOGE("Get output buffer null!");
235 return;
236 }
237 size_t dataSize = static_cast<size_t>(info.size);
238 if (dataSize == 0) {
239 SHARING_LOGE("params invalid, size: %{public}zu.", dataSize);
240 return;
241 }
242
243 const char *data = reinterpret_cast<const char *>(videoSharedMemory->GetBase());
244 if (auto listener = listener_.lock()) {
245 SplitH264(data, dataSize, 0, [&](const char *buf, size_t len, size_t prefix) {
246 if ((*(buf + prefix) & 0x1f) == 0x07) {
247 SHARING_LOGD("get sps, size:%{public}zu.", len);
248 Frame::Ptr videoFrame = FrameImpl::Create();
249 videoFrame->Assign(buf, len);
250 listener->OnFrame(videoFrame, SPS_FRAME, false);
251 videoFrame = nullptr;
252 return;
253 }
254 if ((*(buf + prefix) & 0x1f) == 0x08) {
255 SHARING_LOGD("get pps, size:%{public}zu.", len);
256 Frame::Ptr videoFrame = FrameImpl::Create();
257 videoFrame->Assign(buf, len);
258 listener->OnFrame(videoFrame, PPS_FRAME, false);
259 videoFrame = nullptr;
260 return;
261 }
262 SHARING_LOGD("get frame , size:%{public}zu.", len);
263 bool keyFrame = (*(buf + prefix) & 0x1f) == 0x05 ? true : false;
264 Frame::Ptr videoFrame = FrameImpl::Create();
265 videoFrame->Assign(buf, len);
266 listener->OnFrame(videoFrame, IDR_FRAME, keyFrame);
267 videoFrame = nullptr;
268 });
269 } else {
270 SHARING_LOGE("listener_ is null, call OnFrame failed!");
271 }
272
273 if (videoEncoder_->ReleaseOutputBuffer(index) != Media::MSERR_OK) {
274 SHARING_LOGW("release output buffer failed!");
275 }
276 }
277
OnInputBufferAvailable(uint32_t index)278 void VideoSourceEncoder::OnInputBufferAvailable(uint32_t index)
279 {
280 SHARING_LOGI("index:%{public}u.", index);
281 if (auto listener = listener_.lock()) {
282 listener->OnFrameBufferUsed();
283 }
284 }
285
OnOutputFormatChanged(const Media::Format & format)286 void VideoSourceEncoder::OnOutputFormatChanged(const Media::Format &format)
287 {
288 SHARING_LOGD("trace.");
289 (void)format;
290 }
291
OnError(Media::AVCodecErrorType errorType,int32_t errorCode)292 void VideoSourceEncoder::OnError(Media::AVCodecErrorType errorType, int32_t errorCode)
293 {
294 SHARING_LOGD("Encoder error, errorType(%{public}d), errorCode(%{public}d)!", errorType, errorCode);
295 }
296 } // namespace Sharing
297 } // namespace OHOS
298