1 /*
2 * Copyright (c) 2022 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_sink_decoder.h"
17
18 #include <chrono>
19 #include <securec.h>
20
21 #include "dscreen_constants.h"
22 #include "dscreen_errcode.h"
23 #include "dscreen_log.h"
24
25 namespace OHOS {
26 namespace DistributedHardware {
ConfigureDecoder(const VideoParam & configParam)27 int32_t ImageSinkDecoder::ConfigureDecoder(const VideoParam &configParam)
28 {
29 DHLOGI("%s: ConfigureDecoder.", LOG_TAG);
30 int32_t ret = InitVideoDecoder(configParam);
31 if (ret != DH_SUCCESS) {
32 DHLOGE("%s: InitVideoDecoder failed.", LOG_TAG);
33 return ret;
34 }
35
36 ret = SetDecoderFormat(configParam);
37 if (ret != DH_SUCCESS) {
38 DHLOGE("%s: SetDecoderFormat failed.", LOG_TAG);
39 return ret;
40 }
41
42 return DH_SUCCESS;
43 }
44
ReleaseDecoder()45 int32_t ImageSinkDecoder::ReleaseDecoder()
46 {
47 DHLOGI("%s: ReleaseDecoder.", LOG_TAG);
48 if (!videoDecoder_) {
49 DHLOGE("%s: Decoder is null.", LOG_TAG);
50 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
51 }
52
53 int32_t ret = videoDecoder_->Release();
54 if (ret != Media::MSERR_OK) {
55 DHLOGE("%s: ReleaseDecoder failed.", LOG_TAG);
56 return ERR_DH_SCREEN_CODEC_RELEASE_FAILED;
57 }
58 decodeVideoCallback_ = nullptr;
59 videoDecoder_ = nullptr;
60
61 return DH_SUCCESS;
62 }
63
StartDecoder()64 int32_t ImageSinkDecoder::StartDecoder()
65 {
66 DHLOGI("%s: StartDecoder.", LOG_TAG);
67 if (!videoDecoder_) {
68 DHLOGE("%s: Decoder is null.", LOG_TAG);
69 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
70 }
71
72 int32_t ret = videoDecoder_->Prepare();
73 if (ret != Media::MSERR_OK) {
74 DHLOGE("%s: Prepare decoder failed.", LOG_TAG);
75 return ERR_DH_SCREEN_CODEC_PREPARE_FAILED;
76 }
77
78 ret = videoDecoder_->Start();
79 if (ret != Media::MSERR_OK) {
80 DHLOGE("%s: Start decoder failed.", LOG_TAG);
81 return ERR_DH_SCREEN_CODEC_START_FAILED;
82 }
83 StartInputThread();
84
85 return DH_SUCCESS;
86 }
87
StopDecoder()88 int32_t ImageSinkDecoder::StopDecoder()
89 {
90 DHLOGI("%s: StopDecoder.", LOG_TAG);
91 if (!videoDecoder_) {
92 DHLOGE("%s: Decoder is null.", LOG_TAG);
93 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
94 }
95
96 int32_t ret = videoDecoder_->Flush();
97 if (ret != Media::MSERR_OK) {
98 DHLOGE("%s: Flush decoder failed.", LOG_TAG);
99 return ERR_DH_SCREEN_CODEC_FLUSH_FAILED;
100 }
101
102 ret = videoDecoder_->Stop();
103 if (ret != Media::MSERR_OK) {
104 DHLOGE("%s: Stop decoder failed.", LOG_TAG);
105 return ERR_DH_SCREEN_CODEC_STOP_FAILED;
106 }
107 StopInputThread();
108
109 return DH_SUCCESS;
110 }
111
InitVideoDecoder(const VideoParam & configParam)112 int32_t ImageSinkDecoder::InitVideoDecoder(const VideoParam &configParam)
113 {
114 DHLOGI("%s: InitVideoDecoder.", LOG_TAG);
115 switch (configParam.GetCodecType()) {
116 case VIDEO_CODEC_TYPE_VIDEO_H264:
117 videoDecoder_ = Media::VideoDecoderFactory::CreateByMime("video/avc");
118 break;
119 case VIDEO_CODEC_TYPE_VIDEO_H265:
120 videoDecoder_ = Media::VideoDecoderFactory::CreateByMime("video/hevc");
121 break;
122 case VIDEO_CODEC_TYPE_VIDEO_MPEG4:
123 videoDecoder_ = Media::VideoDecoderFactory::CreateByMime("video/mp4v-es");
124 break;
125 default:
126 DHLOGE("%s: codecType is invalid!", LOG_TAG);
127 videoDecoder_ = nullptr;
128 }
129
130 if (videoDecoder_ == nullptr) {
131 DHLOGE("%s: Create videoEncode failed.", LOG_TAG);
132 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
133 }
134
135 decodeVideoCallback_ = std::make_shared<ImageDecoderCallback>(shared_from_this());
136 int32_t ret = videoDecoder_->SetCallback(decodeVideoCallback_);
137 if (ret != Media::MSERR_OK) {
138 DHLOGE("%s: Set decoder callback failed.", LOG_TAG);
139 return ERR_DH_SCREEN_CODEC_SET_CALLBACK_FAILED;
140 }
141
142 return DH_SUCCESS;
143 }
144
SetDecoderFormat(const VideoParam & configParam)145 int32_t ImageSinkDecoder::SetDecoderFormat(const VideoParam &configParam)
146 {
147 DHLOGI("%s: SetDecoderFormat.", LOG_TAG);
148 if (!videoDecoder_) {
149 DHLOGE("%s: Decoder is null.", LOG_TAG);
150 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
151 }
152
153 switch (configParam.GetCodecType()) {
154 case VIDEO_CODEC_TYPE_VIDEO_H264:
155 imageFormat_.PutStringValue("codec_mime", "video/avc");
156 break;
157 case VIDEO_CODEC_TYPE_VIDEO_H265:
158 imageFormat_.PutStringValue("codec_mime", "video/hevc");
159 break;
160 case VIDEO_CODEC_TYPE_VIDEO_MPEG4:
161 imageFormat_.PutStringValue("codec_mime", "video/mp4v-es");
162 break;
163 default:
164 DHLOGE("The current codec type does not support decoding.");
165 return ERR_DH_SCREEN_TRANS_ILLEGAL_OPERATION;
166 }
167 switch (configParam.GetVideoFormat()) {
168 case VIDEO_DATA_FORMAT_YUVI420:
169 imageFormat_.PutIntValue("pixel_format", Media::VideoPixelFormat::YUVI420);
170 break;
171 case VIDEO_DATA_FORMAT_NV12:
172 imageFormat_.PutIntValue("pixel_format", Media::VideoPixelFormat::NV12);
173 break;
174 case VIDEO_DATA_FORMAT_NV21:
175 imageFormat_.PutIntValue("pixel_format", Media::VideoPixelFormat::NV21);
176 break;
177 case VIDEO_DATA_FORMAT_RGBA8888:
178 imageFormat_.PutIntValue("pixel_format", Media::VideoPixelFormat::RGBA);
179 break;
180 default:
181 DHLOGE("The current pixel format does not support decoding.");
182 return ERR_DH_SCREEN_TRANS_ILLEGAL_OPERATION;
183 }
184
185 imageFormat_.PutLongValue("max_input_size", MAX_YUV420_BUFFER_SIZE);
186 imageFormat_.PutIntValue("width", configParam.GetVideoWidth());
187 imageFormat_.PutIntValue("height", configParam.GetVideoHeight());
188 imageFormat_.PutIntValue("frame_rate", configParam.GetFps());
189
190 int32_t ret = videoDecoder_->Configure(imageFormat_);
191 if (ret != Media::MSERR_OK) {
192 DHLOGE("%s: configure decoder format param failed.", LOG_TAG);
193 return ERR_DH_SCREEN_CODEC_CONFIGURE_FAILED;
194 }
195
196 return DH_SUCCESS;
197 }
198
SetOutputSurface(sptr<Surface> & surface)199 int32_t ImageSinkDecoder::SetOutputSurface(sptr<Surface> &surface)
200 {
201 DHLOGI("%s: SetOutputSurface.", LOG_TAG);
202 if (!videoDecoder_) {
203 DHLOGE("%s: Decoder is null.", LOG_TAG);
204 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
205 }
206
207 int32_t ret = videoDecoder_->SetOutputSurface(surface);
208 if (ret != Media::MSERR_OK) {
209 DHLOGE("%s: SetOutputSurface failed.", LOG_TAG);
210 return ERR_DH_SCREEN_CODEC_SURFACE_ERROR;
211 }
212
213 return DH_SUCCESS;
214 }
215
InputScreenData(const std::shared_ptr<DataBuffer> & data)216 int32_t ImageSinkDecoder::InputScreenData(const std::shared_ptr<DataBuffer> &data)
217 {
218 DHLOGD("%s: InputScreenData.", LOG_TAG);
219 std::lock_guard<std::mutex> dataLock(dataMutex_);
220 while (videoDataQueue_.size() >= DATA_QUEUE_MAX_SIZE) {
221 DHLOGE("%s: videoData queue overflow.", LOG_TAG);
222 videoDataQueue_.pop();
223 }
224 videoDataQueue_.push(data);
225 decodeCond_.notify_all();
226
227 return DH_SUCCESS;
228 }
229
OnError(Media::AVCodecErrorType errorType,int32_t errorCode)230 void ImageSinkDecoder::OnError(Media::AVCodecErrorType errorType, int32_t errorCode)
231 {
232 DHLOGI("%s: OnImageDecodeError, errorType(%d), errorCode(%d)", LOG_TAG, errorType, errorCode);
233 std::shared_ptr<IImageSinkProcessorListener> listener = imageProcessorListener_.lock();
234 if (!listener) {
235 DHLOGE("%s: Listener is null.", LOG_TAG);
236 return;
237 }
238 listener->OnProcessorStateNotify(errorCode);
239 }
240
OnInputBufferAvailable(uint32_t index)241 void ImageSinkDecoder::OnInputBufferAvailable(uint32_t index)
242 {
243 DHLOGI("%s: OnDecodeInputBufferAvailable: %u.", LOG_TAG, index);
244 std::lock_guard<std::mutex> dataLock(dataMutex_);
245 bufferIndexQueue_.push(index);
246 }
247
OnOutputBufferAvailable(uint32_t index,Media::AVCodecBufferInfo info,Media::AVCodecBufferFlag flag)248 void ImageSinkDecoder::OnOutputBufferAvailable(uint32_t index, Media::AVCodecBufferInfo info,
249 Media::AVCodecBufferFlag flag)
250 {
251 DHLOGI("%s: OnDecodeOutputBufferAvailable.", LOG_TAG);
252 if (!videoDecoder_) {
253 DHLOGE("%s: Decoder is null.", LOG_TAG);
254 return;
255 }
256
257 decoderBufferInfo_ = info;
258 int32_t ret = videoDecoder_->ReleaseOutputBuffer(index, true);
259 if (ret != Media::MSERR_OK) {
260 DHLOGD("%s: ReleaseOutputBuffer failed.", LOG_TAG);
261 }
262 }
263
OnOutputFormatChanged(const Media::Format & format)264 void ImageSinkDecoder::OnOutputFormatChanged(const Media::Format &format)
265 {
266 (void) format;
267 }
268
StartInputThread()269 int32_t ImageSinkDecoder::StartInputThread()
270 {
271 DHLOGI("%s: StartInputThread.", LOG_TAG);
272 isDecoderReady_ = true;
273 decodeThread_ = std::thread(&ImageSinkDecoder::DecodeScreenData, this);
274
275 return DH_SUCCESS;
276 }
277
StopInputThread()278 int32_t ImageSinkDecoder::StopInputThread()
279 {
280 DHLOGI("%s: StopInputThread.", LOG_TAG);
281 isDecoderReady_ = false;
282 decodeThread_.join();
283 std::lock_guard<std::mutex> dataLock(dataMutex_);
284 while (!bufferIndexQueue_.empty()) {
285 bufferIndexQueue_.pop();
286 }
287 while (!videoDataQueue_.empty()) {
288 videoDataQueue_.pop();
289 }
290
291 return DH_SUCCESS;
292 }
293
DecodeScreenData()294 void ImageSinkDecoder::DecodeScreenData()
295 {
296 while (isDecoderReady_) {
297 std::shared_ptr<DataBuffer> screenData;
298 int32_t bufferIndex = 0;
299 {
300 std::unique_lock<std::mutex> lock(dataMutex_);
301 decodeCond_.wait_for(lock, std::chrono::milliseconds(DECODE_WAIT_MILLISECONDS),
302 [this]() { return (!videoDataQueue_.empty() && !bufferIndexQueue_.empty()); });
303
304 if (videoDataQueue_.empty() || bufferIndexQueue_.empty()) {
305 DHLOGD("%s: Index queue or data queue is empty.", LOG_TAG);
306 continue;
307 }
308 bufferIndex = bufferIndexQueue_.front();
309 bufferIndexQueue_.pop();
310 screenData = videoDataQueue_.front();
311 videoDataQueue_.pop();
312 }
313
314 int32_t ret = ProcessData(screenData, bufferIndex);
315 if (ret == ERR_DH_SCREEN_TRANS_NULL_VALUE) {
316 return;
317 } else if (ret != DH_SUCCESS) {
318 continue;
319 }
320 }
321 }
322
ProcessData(const std::shared_ptr<DataBuffer> & screenData,const int32_t bufferIndex)323 int32_t ImageSinkDecoder::ProcessData(const std::shared_ptr<DataBuffer> &screenData, const int32_t bufferIndex)
324 {
325 if (!videoDecoder_) {
326 DHLOGE("%s: Decoder is null.", LOG_TAG);
327 return ERR_DH_SCREEN_TRANS_NULL_VALUE;
328 }
329
330 auto inputBuffer = videoDecoder_->GetInputBuffer(bufferIndex);
331 if (inputBuffer == nullptr) {
332 DHLOGE("%s: GetInputBuffer failed.", LOG_TAG);
333 return ERR_DH_SCREEN_CODEC_SURFACE_ERROR;
334 }
335
336 int32_t ret = memcpy_s(inputBuffer->GetBase(), inputBuffer->GetSize(), screenData->Data(), screenData->Capacity());
337 if (ret != EOK) {
338 DHLOGE("%s: Copy data failed.", LOG_TAG);
339 return ERR_DH_SCREEN_CODEC_SURFACE_ERROR;
340 }
341
342 DHLOGD("%s: Decode screen data.", LOG_TAG);
343 Media::AVCodecBufferInfo bufferInfo;
344 bufferInfo.presentationTimeUs = 0;
345 bufferInfo.size = static_cast<int32_t>(screenData->Capacity());
346 bufferInfo.offset = 0;
347 ret = videoDecoder_->QueueInputBuffer(bufferIndex, bufferInfo, Media::AVCODEC_BUFFER_FLAG_NONE);
348 if (ret != Media::MSERR_OK) {
349 DHLOGE("%s: QueueInputBuffer failed.", LOG_TAG);
350 return ERR_DH_SCREEN_CODEC_SURFACE_ERROR;
351 }
352 return DH_SUCCESS;
353 }
354 } // namespace DistributedHardware
355 } // namespace OHOS
356