1 /*
2  * Copyright (c) 2022-2025 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 "image_source_encoder.h"
17 
18 #include <dlfcn.h>
19 #include <fstream>
20 #include <iostream>
21 #include <securec.h>
22 #include <csetjmp>
23 #include <cstddef>
24 #include <string>
25 #include <ctime>
26 
27 #include "dscreen_constants.h"
28 #include "dscreen_errcode.h"
29 #include "dscreen_hisysevent.h"
30 #include "dscreen_log.h"
31 #include "jpeglib.h"
32 
33 using GetDscreenDBGItfFunc = OHOS::DistributedHardware::IDScreenDBGItf* (*)();
34 using GetImageDirtyFunc = OHOS::DistributedHardware::IImageSetDirty* (*)();
35 namespace OHOS {
36 namespace DistributedHardware {
37 const std::string DBG_SO_NAME = "libdistributed_screen_dbg_itf.z.so";
OnBufferAvailable()38 void ConsumerBufferListener::OnBufferAvailable()
39 {
40     DHLOGI("%{public}s: OnBufferAvailable, receiv data from RS.", DSCREEN_LOG_TAG);
41     encoder_->ConsumeSurface();
42 }
43 
InitDscreenDBG()44 void ImageSourceEncoder::InitDscreenDBG()
45 {
46     pHandler_ = dlopen(DBG_SO_NAME.c_str(), RTLD_LAZY | RTLD_NODELETE | RTLD_GLOBAL);
47     if (pHandler_ == nullptr) {
48         DHLOGE("so: %{public}s load failed, fail reason: %{public}s.", DBG_SO_NAME.c_str(), dlerror());
49         return;
50     }
51     GetDscreenDBGItfFunc getDscreenDBGItfFunc = (GetDscreenDBGItfFunc)dlsym(pHandler_, GET_DBG_ITF_FUNC.c_str());
52     GetImageDirtyFunc getImageDirtyFunc = (GetImageDirtyFunc)dlsym(pHandler_, GET_IMAGE_DIRTY_FUNC.c_str());
53     if (getDscreenDBGItfFunc == nullptr || getImageDirtyFunc == nullptr) {
54         DHLOGE("get FUNC failed, failed reason: %{public}s.", dlerror());
55         return;
56     }
57     dscreenDbgItfPtr_ = getDscreenDBGItfFunc();
58     imageSetDirtyPtr_ = getImageDirtyFunc();
59     if (dscreenDbgItfPtr_ == nullptr || imageSetDirtyPtr_ == nullptr) {
60         DHLOGE("Get interface failed.");
61         return;
62     }
63     DHLOGI("InitDscreenDBG success.");
64     dscreenDbgItfPtr_->Init();
65 }
66 
ConsumeSurface()67 void ImageSourceEncoder::ConsumeSurface()
68 {
69     DHLOGI("%{public}s: ConsumeSurface.", DSCREEN_LOG_TAG);
70     std::unique_lock<std::mutex> bufLock(bufferMtx_);
71     if (consumerSurface_ == nullptr) {
72         DHLOGE("%{public}s: consumerSurface_ is nullptr.", DSCREEN_LOG_TAG);
73         return;
74     }
75     sptr<SurfaceBuffer> surfaceBuffer = nullptr;
76     syncFence_ = SyncFence::INVALID_FENCE;
77     int64_t timestamp = 0;
78     OHOS::Rect damage = {0, 0, 0, 0};
79     SurfaceError surfaceErr = consumerSurface_->AcquireBuffer(surfaceBuffer, syncFence_, timestamp, damage);
80     if (surfaceErr != SURFACE_ERROR_OK) {
81         DHLOGE("%{public}s: consumerSurface_ acquire buffer failed, errcode: %{public}" PRId32, DSCREEN_LOG_TAG,
82             surfaceErr);
83         consumerSurface_->ReleaseBuffer(surfaceBuffer, -1);
84         return;
85     }
86     int32_t retcode = syncFence_->Wait(SURFACE_SYNC_FENCE_TIMEOUT);
87     if (retcode == -ETIME) {
88         DHLOGE("%{public}s: Sync fence wait timeout, retcode is %{public}" PRId32, DSCREEN_LOG_TAG, retcode);
89         return;
90     }
91     if (pHandler_ != nullptr) {
92         eventContent_.clear();
93         eventContent_ = imageSetDirtyPtr_->GetDamage();
94     }
95     std::vector<OHOS::Rect> damages = VecToDamage(eventContent_);
96     std::shared_ptr<IImageSourceProcessorListener> listener = imageProcessorListener_.lock();
97     if (listener == nullptr) {
98         DHLOGE("%{public}s: Processor listener is null", DSCREEN_LOG_TAG);
99         consumerSurface_->ReleaseBuffer(surfaceBuffer, -1);
100         return;
101     }
102     listener->OnDamageProcessDone(surfaceBuffer, damages);
103     consumerSurface_->ReleaseBuffer(surfaceBuffer, -1);
104 }
105 
ConfigureEncoder(const VideoParam & configParam)106 int32_t ImageSourceEncoder::ConfigureEncoder(const VideoParam &configParam)
107 {
108     DHLOGI("%{public}s: ConfigureEncoder.", DSCREEN_LOG_TAG);
109     int32_t ret = InitVideoEncoder(configParam);
110     if (ret != DH_SUCCESS) {
111         DHLOGE("%{public}s: Init encoder failed ret: %{public}" PRId32, DSCREEN_LOG_TAG, ret);
112         return ret;
113     }
114 
115     ret = SetEncoderFormat(configParam);
116     if (ret != DH_SUCCESS) {
117         DHLOGE("%{public}s: Set encoder format failed ret: %{public}" PRId32, DSCREEN_LOG_TAG, ret);
118         return ret;
119     }
120 
121     encoderSurface_ = videoEncoder_->CreateInputSurface();
122     if (encoderSurface_ == nullptr) {
123         DHLOGE("%{public}s: Create encoder surface failed.", DSCREEN_LOG_TAG);
124         return ERR_DH_SCREEN_CODEC_SURFACE_ERROR;
125     }
126     configParam_ = configParam;
127     ret = AddSurface();
128     if (ret != DH_SUCCESS) {
129         DHLOGE("%{public}s: Add surface failed ret: %{public}" PRId32, DSCREEN_LOG_TAG, ret);
130         consumerSurface_ = nullptr;
131         producerSurface_ = nullptr;
132         return ret;
133     }
134     return DH_SUCCESS;
135 }
136 
AddSurface()137 int32_t ImageSourceEncoder::AddSurface()
138 {
139     DHLOGI("%{public}s: AddSurface.", DSCREEN_LOG_TAG);
140     consumerSurface_ = IConsumerSurface::Create();
141     if (consumerSurface_ == nullptr) {
142         DHLOGE("%{public}s: creat consumer surface failed.", DSCREEN_LOG_TAG);
143         return ERR_DH_SCREEN_CODEC_SURFACE_ERROR;
144     }
145     sptr<IBufferProducer> producer = consumerSurface_->GetProducer();
146     if (producer == nullptr) {
147         DHLOGE("%{public}s: Creat producer surface failed.", DSCREEN_LOG_TAG);
148         return ERR_DH_SCREEN_CODEC_SURFACE_ERROR;
149     }
150     producerSurface_ = Surface::CreateSurfaceAsProducer(producer);
151     if (producerSurface_ == nullptr) {
152         DHLOGE("%{public}s: Create preducer surface failed.", DSCREEN_LOG_TAG);
153         return ERR_DH_SCREEN_CODEC_SURFACE_ERROR;
154     }
155     consumerBufferListener_ = new ConsumerBufferListener(shared_from_this());
156     consumerSurface_->RegisterConsumerListener(consumerBufferListener_);
157     return DH_SUCCESS;
158 }
159 
GetConsumerSurface()160 sptr<Surface> ImageSourceEncoder::GetConsumerSurface()
161 {
162     DHLOGI("%{public}s: GetConsumerSurface.", DSCREEN_LOG_TAG);
163     return consumerSurface_;
164 }
165 
GetInputSurface()166 sptr<Surface> &ImageSourceEncoder::GetInputSurface()
167 {
168     DHLOGI("%{public}s: GetInputSurface.", DSCREEN_LOG_TAG);
169     if (producerSurface_ == nullptr || !configParam_.GetPartialRefreshFlag()) {
170         return encoderSurface_;
171     }
172     return producerSurface_;
173 }
174 
VecToDamage(std::vector<std::vector<int32_t>> eventContent)175 std::vector<OHOS::Rect> ImageSourceEncoder::VecToDamage(std::vector<std::vector<int32_t>> eventContent)
176 {
177     DHLOGI("%{public}s: VecToDamage.", DSCREEN_LOG_TAG);
178     std::vector<OHOS::Rect> damages;
179     for (auto item : eventContent) {
180         OHOS::Rect damage = {0, 0, 0, 0};
181         damage.x = item[0];
182         damage.y = item[1];
183         damage.w = item[2];
184         damage.h = item[3];
185         damages.push_back(damage);
186     }
187     return damages;
188 }
189 
GetEncoderInputSurfaceBuffer()190 sptr<SurfaceBuffer> ImageSourceEncoder::GetEncoderInputSurfaceBuffer()
191 {
192     DHLOGI("%{public}s: GetEncoderInputSurfaceBuffer.", DSCREEN_LOG_TAG);
193     OHOS::BufferRequestConfig requestConfig;
194     requestConfig.width = static_cast<int32_t>(configParam_.GetVideoWidth());
195     requestConfig.height = static_cast<int32_t>(configParam_.GetVideoHeight());
196     requestConfig.usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA;
197     requestConfig.strideAlignment = STRIDE_ALIGNMENT;
198     requestConfig.format = GraphicPixelFormat::GRAPHIC_PIXEL_FMT_RGBA_8888;
199     requestConfig.timeout = 0;
200     sptr<OHOS::SurfaceBuffer> encoderSurfaceBuffer = nullptr;
201     int32_t releaseFence = -1;
202     SurfaceError surfaceErr = encoderSurface_->RequestBuffer(encoderSurfaceBuffer, releaseFence, requestConfig);
203     if (surfaceErr != GSERROR_OK || encoderSurfaceBuffer == nullptr) {
204         DHLOGE("%{public}s: RequestBuffer failed.", DSCREEN_LOG_TAG);
205         encoderSurface_->CancelBuffer(encoderSurfaceBuffer);
206     }
207     return encoderSurfaceBuffer;
208 }
209 
FeedEncoderData(sptr<SurfaceBuffer> & surfaceBuffer)210 int32_t ImageSourceEncoder::FeedEncoderData(sptr<SurfaceBuffer> &surfaceBuffer)
211 {
212     sptr<OHOS::SurfaceBuffer> encoderSurfaceBuffer = GetEncoderInputSurfaceBuffer();
213     if (encoderSurfaceBuffer == nullptr) {
214         DHLOGE("Get encoder input producer surface buffer failed.");
215         return ERR_DH_SCREEN_CODEC_SURFACE_ERROR;
216     }
217     uint32_t screenDataSize = configParam_.GetVideoWidth() * configParam_.GetVideoHeight() * RGBA_CHROMA;
218     auto encoderSurfaceAddr = static_cast<uint8_t*>(encoderSurfaceBuffer->GetVirAddr());
219     auto surfaceAddr = static_cast<uint8_t*>(surfaceBuffer->GetVirAddr());
220     int32_t ret = memcpy_s(encoderSurfaceAddr, screenDataSize, surfaceAddr, screenDataSize);
221     if (ret != EOK) {
222         DHLOGE("%{public}s: surfaceBuffer memcpy_s run failed.", DSCREEN_LOG_TAG);
223         consumerSurface_->ReleaseBuffer(surfaceBuffer, -1);
224         encoderSurface_->CancelBuffer(encoderSurfaceBuffer);
225         return ret;
226     }
227     BufferFlushConfig flushConfig = { {0, 0, encoderSurfaceBuffer->GetWidth(), encoderSurfaceBuffer->GetHeight()}, 0};
228     DHLOGI("%{public}s: FeedEncoderData to encoder.", DSCREEN_LOG_TAG);
229     SurfaceError surfaceErr = encoderSurface_->FlushBuffer(encoderSurfaceBuffer, -1, flushConfig);
230     if (surfaceErr != SURFACE_ERROR_OK) {
231         DHLOGE("%{public}s: encoderSurface_ flush buffer failed.", DSCREEN_LOG_TAG);
232         consumerSurface_->ReleaseBuffer(surfaceBuffer, -1);
233         encoderSurface_->CancelBuffer(encoderSurfaceBuffer);
234         return surfaceErr;
235     }
236     consumerSurface_->ReleaseBuffer(surfaceBuffer, -1);
237     return DH_SUCCESS;
238 }
239 
ReleaseEncoder()240 int32_t ImageSourceEncoder::ReleaseEncoder()
241 {
242     DHLOGI("%{public}s: ReleaseEncoder.", DSCREEN_LOG_TAG);
243     if (videoEncoder_ == nullptr) {
244         DHLOGE("%{public}s: Encoder is null.", DSCREEN_LOG_TAG);
245         return ERR_DH_SCREEN_TRANS_NULL_VALUE;
246     }
247 
248     int32_t ret = videoEncoder_->Release();
249     if (ret != MediaAVCodec::AVCS_ERR_OK) {
250         DHLOGE("%{public}s: Release encoder failed.", DSCREEN_LOG_TAG);
251         return ERR_DH_SCREEN_CODEC_RELEASE_FAILED;
252     }
253     if (pHandler_ != nullptr) {
254         dscreenDbgItfPtr_->Release();
255         dlclose(pHandler_);
256     }
257     encodeVideoCallback_ = nullptr;
258     videoEncoder_ = nullptr;
259     consumerBufferListener_ = nullptr;
260     return DH_SUCCESS;
261 }
262 
StartEncoder()263 int32_t ImageSourceEncoder::StartEncoder()
264 {
265     DHLOGI("%{public}s: StartEncoder.", DSCREEN_LOG_TAG);
266     if (videoEncoder_ == nullptr) {
267         DHLOGE("%{public}s: Encoder is null.", DSCREEN_LOG_TAG);
268         return ERR_DH_SCREEN_TRANS_NULL_VALUE;
269     }
270 
271     int32_t ret = videoEncoder_->Prepare();
272     if (ret != MediaAVCodec::AVCS_ERR_OK) {
273         DHLOGE("%{public}s: Prepare encoder failed.", DSCREEN_LOG_TAG);
274         return ERR_DH_SCREEN_CODEC_PREPARE_FAILED;
275     }
276 
277     ret = videoEncoder_->Start();
278     if (ret != MediaAVCodec::AVCS_ERR_OK) {
279         DHLOGE("%{public}s: Start encoder failed.", DSCREEN_LOG_TAG);
280         return ERR_DH_SCREEN_CODEC_START_FAILED;
281     }
282     InitDscreenDBG();
283     return DH_SUCCESS;
284 }
285 
StopEncoder()286 int32_t ImageSourceEncoder::StopEncoder()
287 {
288     DHLOGI("%{public}s: StopEncoder.", DSCREEN_LOG_TAG);
289     if (videoEncoder_ == nullptr) {
290         DHLOGE("%{public}s: Encoder is null.", DSCREEN_LOG_TAG);
291         return ERR_DH_SCREEN_TRANS_NULL_VALUE;
292     }
293 
294     int32_t ret = videoEncoder_->Flush();
295     if (ret != MediaAVCodec::AVCS_ERR_OK) {
296         DHLOGE("%{public}s: Flush encoder failed.", DSCREEN_LOG_TAG);
297     }
298 
299     ret = videoEncoder_->Stop();
300     if (ret != MediaAVCodec::AVCS_ERR_OK) {
301         DHLOGE("%{public}s: Stop encoder failed.", DSCREEN_LOG_TAG);
302         return ERR_DH_SCREEN_CODEC_STOP_FAILED;
303     }
304     std::unique_lock<std::mutex> bufLock(bufferMtx_);
305     if (consumerSurface_ != nullptr) {
306         ret = consumerSurface_->UnregisterConsumerListener();
307         if (ret != SURFACE_ERROR_OK) {
308             DHLOGE("Unregister Consumer Listener failed.");
309         }
310         consumerSurface_ = nullptr;
311     }
312     producerSurface_ = nullptr;
313     return DH_SUCCESS;
314 }
315 
InitVideoEncoder(const VideoParam & configParam)316 int32_t ImageSourceEncoder::InitVideoEncoder(const VideoParam &configParam)
317 {
318     DHLOGI("%{public}s: InitVideoEncoder.", DSCREEN_LOG_TAG);
319     switch (configParam.GetCodecType()) {
320         case VIDEO_CODEC_TYPE_VIDEO_H264:
321             videoEncoder_ = MediaAVCodec::VideoEncoderFactory::CreateByMime(
322                 std::string(MediaAVCodec::CodecMimeType::VIDEO_AVC));
323             break;
324         case VIDEO_CODEC_TYPE_VIDEO_H265:
325             videoEncoder_ = MediaAVCodec::VideoEncoderFactory::CreateByMime(
326                 std::string(MediaAVCodec::CodecMimeType::VIDEO_HEVC));
327             break;
328         default:
329             DHLOGE("%{public}s: codecType is invalid!", DSCREEN_LOG_TAG);
330             videoEncoder_ = nullptr;
331     }
332 
333     if (videoEncoder_ == nullptr) {
334         DHLOGE("%{public}s: Create videoEncoder failed.", DSCREEN_LOG_TAG);
335         return ERR_DH_SCREEN_TRANS_CREATE_CODEC_FAILED;
336     }
337 
338     encodeVideoCallback_ = std::make_shared<ImageEncoderCallback>(shared_from_this());
339     int32_t ret = videoEncoder_->SetCallback(encodeVideoCallback_);
340     if (ret != MediaAVCodec::AVCS_ERR_OK) {
341         DHLOGE("%{public}s: Set codec callback failed.", DSCREEN_LOG_TAG);
342         return ERR_DH_SCREEN_CODEC_SET_CALLBACK_FAILED;
343     }
344 
345     return DH_SUCCESS;
346 }
347 
SetEncoderFormat(const VideoParam & configParam)348 int32_t ImageSourceEncoder::SetEncoderFormat(const VideoParam &configParam)
349 {
350     DHLOGI("%{public}s: SetEncoderFormat.", DSCREEN_LOG_TAG);
351     if (videoEncoder_ == nullptr) {
352         DHLOGE("%{public}s: Encoder is null.", DSCREEN_LOG_TAG);
353         return ERR_DH_SCREEN_TRANS_NULL_VALUE;
354     }
355 
356     switch (configParam.GetCodecType()) {
357         case VIDEO_CODEC_TYPE_VIDEO_H264:
358             imageFormat_.PutStringValue("codec_mime", MediaAVCodec::CodecMimeType::VIDEO_AVC);
359             break;
360         case VIDEO_CODEC_TYPE_VIDEO_H265:
361             imageFormat_.PutStringValue("codec_mime", MediaAVCodec::CodecMimeType::VIDEO_HEVC);
362             break;
363         default:
364             DHLOGE("%{public}s: Codec type is invalid.", DSCREEN_LOG_TAG);
365             return ERR_DH_SCREEN_TRANS_ILLEGAL_PARAM;
366     }
367 
368     imageFormat_.PutIntValue("pixel_format", static_cast<int32_t>(MediaAVCodec::VideoPixelFormat::RGBA));
369     imageFormat_.PutLongValue("max_input_size", MAX_YUV420_BUFFER_SIZE);
370     imageFormat_.PutIntValue("width", configParam.GetVideoWidth());
371     imageFormat_.PutIntValue("height", configParam.GetVideoHeight());
372     imageFormat_.PutDoubleValue("frame_rate", configParam.GetFps());
373 
374     int32_t ret = videoEncoder_->Configure(imageFormat_);
375     if (ret != MediaAVCodec::AVCS_ERR_OK) {
376         DHLOGE("%{public}s: Configure encoder failed.", DSCREEN_LOG_TAG);
377         return ERR_DH_SCREEN_CODEC_CONFIGURE_FAILED;
378     }
379     return DH_SUCCESS;
380 }
381 
OnError(MediaAVCodec::AVCodecErrorType errorType,int32_t errorCode)382 void ImageSourceEncoder::OnError(MediaAVCodec::AVCodecErrorType errorType, int32_t errorCode)
383 {
384     DHLOGI("%{public}s: Encoder error, errorType:%{public}" PRId32 ", errorCode:%{public}" PRId32, DSCREEN_LOG_TAG,
385         errorType, errorCode);
386     std::shared_ptr<IImageSourceProcessorListener> listener = imageProcessorListener_.lock();
387     if (listener == nullptr) {
388         DHLOGE("%{public}s: Processor listener is null", DSCREEN_LOG_TAG);
389         return;
390     }
391     listener->OnProcessorStateNotify(errorCode);
392 }
393 
OnOutputBufferAvailable(uint32_t index,MediaAVCodec::AVCodecBufferInfo info,MediaAVCodec::AVCodecBufferFlag flag,std::shared_ptr<Media::AVSharedMemory> buffer)394 void ImageSourceEncoder::OnOutputBufferAvailable(uint32_t index, MediaAVCodec::AVCodecBufferInfo info,
395     MediaAVCodec::AVCodecBufferFlag flag, std::shared_ptr<Media::AVSharedMemory> buffer)
396 {
397     DHLOGD("%{public}s: OnOutputBufferAvailable, receiv H264 data from encoder.", DSCREEN_LOG_TAG);
398     std::shared_ptr<IImageSourceProcessorListener> listener = imageProcessorListener_.lock();
399     if (listener == nullptr) {
400         DHLOGE("%{public}s: Processor listener is null", DSCREEN_LOG_TAG);
401         return;
402     }
403     if (videoEncoder_ == nullptr) {
404         DHLOGE("%{public}s: Encoder is null.", DSCREEN_LOG_TAG);
405         return;
406     }
407 
408     encoderBufferInfo_ = info;
409     if (buffer == nullptr) {
410         DHLOGE("%{public}s: Buffer is null, index = %{public}d", DSCREEN_LOG_TAG, index);
411         return;
412     }
413 
414     size_t dataSize = static_cast<size_t>(info.size);
415     if (dataSize == 0 || dataSize > DATA_BUFFER_MAX_SIZE) {
416         DHLOGE("%{public}s:OnOutputBufferAvailable params invalid, size: %{public}zu", DSCREEN_LOG_TAG, dataSize);
417         return;
418     }
419     auto dataBuf = std::make_shared<DataBuffer>(dataSize);
420     int32_t ret = memcpy_s(dataBuf->Data(), dataBuf->Capacity(), buffer->GetBase(), dataSize);
421     if (ret != EOK) {
422         DHLOGE("%{public}s: Copy data failed.", DSCREEN_LOG_TAG);
423         return;
424     }
425     dataBuf->SetDataType(VIDEO_FULL_SCREEN_DATA);
426     dataBuf->SetSize(dataSize);
427     listener->OnImageProcessDone(dataBuf);
428     ret = videoEncoder_->ReleaseOutputBuffer(index);
429     if (ret != MediaAVCodec::AVCS_ERR_OK) {
430         DHLOGE("%{public}s: videoEncoder ReleaseOutputBuffer failed.", DSCREEN_LOG_TAG);
431     }
432 }
433 
OnInputBufferAvailable(uint32_t index,std::shared_ptr<Media::AVSharedMemory> buffer)434 void ImageSourceEncoder::OnInputBufferAvailable(uint32_t index, std::shared_ptr<Media::AVSharedMemory> buffer)
435 {
436     (void) index;
437 }
438 
OnOutputFormatChanged(const Media::Format & format)439 void ImageSourceEncoder::OnOutputFormatChanged(const Media::Format &format)
440 {
441     (void) format;
442 }
443 } // namespace DistributedHardware
444 } // namespace OHOS
445