• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "jpeg_image_processor.h"
17 
18 #include <cstring>
19 #include <fstream>
20 #include <iostream>
21 #include "jpeglib.h"
22 #include <securec.h>
23 #include <string>
24 
25 #ifdef LIBYUV
26 #include <libyuv/convert_from_argb.h>
27 #endif
28 
29 #include "dscreen_errcode.h"
30 #include "dscreen_log.h"
31 
32 namespace OHOS {
33 namespace DistributedHardware {
SetOutputSurface(sptr<Surface> surface)34 int32_t JpegImageProcessor::SetOutputSurface(sptr<Surface> surface)
35 {
36     DHLOGI("%s: SetOutputSurface.", LOG_TAG);
37     if (surface == nullptr) {
38         DHLOGE("%s: SetOutputSurface surface is nullptr.", LOG_TAG);
39         return ERR_DH_SCREEN_TRANS_NULL_VALUE;
40     }
41     imageSurface_ = surface;
42     return DH_SUCCESS;
43 }
44 
FillDirtyImages2Surface(const std::shared_ptr<DataBuffer> & data,uint8_t * lastFrame)45 int32_t JpegImageProcessor::FillDirtyImages2Surface(const std::shared_ptr<DataBuffer> &data, uint8_t *lastFrame)
46 {
47     DHLOGI("%s: FillDirtyImages2Surface.", LOG_TAG);
48     if (imageSurface_ == nullptr) {
49         DHLOGE("%s: imageSurface_ is nullptr.", LOG_TAG);
50         return ERR_DH_SCREEN_SURFACE_INVALIED;
51     }
52     uint32_t lastFrameSize = configParam_.GetScreenWidth() * configParam_.GetScreenHeight() * RGB_CHROMA / TWO;
53     int32_t ret = DecodeDamageData(data, lastFrame);
54     if (ret != DH_SUCCESS) {
55         DHLOGE("%s: Merge dirty failed, ret: %." PRId32, LOG_TAG, ret);
56         return ret;
57     }
58     sptr<OHOS::SurfaceBuffer> windowSurfaceBuffer = nullptr;
59     int32_t releaseFence = -1;
60     OHOS::BufferRequestConfig requestConfig = {
61         .width = configParam_.GetScreenWidth(),
62         .height = configParam_.GetScreenHeight(),
63         .strideAlignment = STRIDE_ALIGNMENT,
64         .format = GRAPHIC_PIXEL_FMT_YCBCR_420_SP,
65         .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
66     };
67     SurfaceError surfaceErr = imageSurface_->RequestBuffer(windowSurfaceBuffer, releaseFence, requestConfig);
68     if (surfaceErr != SURFACE_ERROR_OK || windowSurfaceBuffer == nullptr) {
69         DHLOGE("%s: imageSurface request buffer failed, surfaceErr: %." PRId32, LOG_TAG, surfaceErr);
70         imageSurface_->CancelBuffer(windowSurfaceBuffer);
71         return surfaceErr;
72     }
73     uint32_t surfaceBuffeSize = windowSurfaceBuffer->GetSize();
74     auto windowSurfaceAddr = static_cast<uint8_t*>(windowSurfaceBuffer->GetVirAddr());
75     ret = memcpy_s(windowSurfaceAddr, surfaceBuffeSize, lastFrame, lastFrameSize);
76     if (ret != DH_SUCCESS) {
77         DHLOGE("%s: memcpy lastFrame failed,ret: %." PRId32, LOG_TAG, ret);
78         imageSurface_->CancelBuffer(windowSurfaceBuffer);
79         return ret;
80     }
81     BufferFlushConfig flushConfig = { {0, 0, windowSurfaceBuffer->GetWidth(), windowSurfaceBuffer-> GetHeight()}, 0};
82     surfaceErr = imageSurface_->FlushBuffer(windowSurfaceBuffer, -1, flushConfig);
83     if (surfaceErr != SURFACE_ERROR_OK) {
84         DHLOGE("%s: imageSurface flush buffer failed, surfaceErr: %." PRId32, LOG_TAG, surfaceErr);
85         imageSurface_->CancelBuffer(windowSurfaceBuffer);
86         return surfaceErr;
87     }
88     DHLOGI("%s: FillDirtyImages2Surface success.", LOG_TAG);
89     return DH_SUCCESS;
90 }
91 
ProcessDamageSurface(sptr<SurfaceBuffer> & surfaceBuffer,const std::vector<OHOS::Rect> & damages)92 int32_t JpegImageProcessor::ProcessDamageSurface(sptr<SurfaceBuffer> &surfaceBuffer,
93     const std::vector<OHOS::Rect> &damages)
94 {
95     DHLOGI("%s: ProcessDamageSurface.", LOG_TAG);
96     std::shared_ptr<DataBuffer> dataBuf = std::make_shared<DataBuffer>(configParam_.GetScreenWidth() *
97         configParam_.GetScreenHeight() * RGBA_CHROMA);
98     dataBuf->SetSize(0);
99     for (auto item : damages) {
100         EncodeDamageData(surfaceBuffer, item, dataBuf);
101     }
102     std::shared_ptr<IImageSourceProcessorListener> listener = imageProcessorListener_.lock();
103     if (listener == nullptr) {
104         DHLOGE("%s: Processor listener is null.", LOG_TAG);
105         imageSurface_->ReleaseBuffer(surfaceBuffer, -1);
106         return ERR_DH_SCREEN_CODEC_SURFACE_ERROR;
107     }
108     dataBuf->SetDataType(VIDEO_PART_SCREEN_DATA);
109     listener->OnImageProcessDone(dataBuf);
110     return DH_SUCCESS;
111 }
112 
SetImageProcessListener(std::shared_ptr<IImageSourceProcessorListener> & listener)113 int32_t JpegImageProcessor::SetImageProcessListener(std::shared_ptr<IImageSourceProcessorListener> &listener)
114 {
115     DHLOGI("%s: SetImageProcessorListener.", LOG_TAG);
116     imageProcessorListener_ = listener;
117     return DH_SUCCESS;
118 }
119 
EncodeDamageData(sptr<SurfaceBuffer> & surfaceBuffer,const OHOS::Rect & damage,std::shared_ptr<DataBuffer> & data)120 void JpegImageProcessor::EncodeDamageData(sptr<SurfaceBuffer> &surfaceBuffer,
121     const OHOS::Rect &damage, std::shared_ptr<DataBuffer> &data)
122 {
123     DHLOGI("%s: EncodeDamageData.", LOG_TAG);
124     uint32_t partialSize = damage.w * damage.h * RGBA_CHROMA;
125     unsigned char *partialBuffer = new unsigned char[partialSize];
126     unsigned char *partialBufferIdx = partialBuffer;
127     auto surfaceAddrIdx = static_cast<uint8_t*>(surfaceBuffer->GetVirAddr());
128     surfaceAddrIdx += damage.y * configParam_.GetScreenWidth() * RGBA_CHROMA + damage.x * RGBA_CHROMA;
129     for (int32_t row = 0 ; row < damage.h ; row++) {
130         int32_t ret = memcpy_s(partialBufferIdx, damage.w * RGBA_CHROMA, surfaceAddrIdx, damage.w * RGBA_CHROMA);
131         if (ret != DH_SUCCESS) {
132             DHLOGE("%s: get partail data failed.", LOG_TAG);
133             imageSurface_->ReleaseBuffer(surfaceBuffer, -1);
134             delete [] partialBuffer;
135             return;
136         }
137         partialBufferIdx += damage.w * RGBA_CHROMA;
138         surfaceAddrIdx += configParam_.GetScreenWidth() * RGBA_CHROMA;
139     }
140     uint32_t jpegSize = CompressRgbaToJpeg(damage, partialBuffer, partialSize, data);
141     DHLOGI("CompressRgbaToJpeg end, jpegSize %." PRId32, jpegSize);
142     delete [] partialBuffer;
143 }
144 
DecodeDamageData(const std::shared_ptr<DataBuffer> & data,uint8_t * lastFrame)145 int32_t JpegImageProcessor::DecodeDamageData(const std::shared_ptr<DataBuffer> &data, uint8_t *lastFrame)
146 {
147     DHLOGI("%s: DecodeDamageData.", LOG_TAG);
148     std::vector<DirtyRect> dirtyRectVec = data->GetDirtyRectVec();
149     int32_t offset = 0;
150     int32_t screenWidth = static_cast<int32_t>(configParam_.GetScreenWidth());
151     int32_t screenHeight = static_cast<int32_t>(configParam_.GetScreenHeight());
152     for (auto item : dirtyRectVec) {
153         if (item.xPos > screenWidth || item.yPos > screenHeight ||
154             item.width > screenWidth - item.xPos || item.height > screenHeight - item.yPos) {
155             DHLOGE("%s: Dirty rect invalid.", LOG_TAG);
156             return ERR_DH_SCREEN_INPUT_PARAM_INVALID;
157         }
158         uint8_t *jpegData = new uint8_t[item.dirtySize] {0};
159         int32_t ret = data->GetData(offset, item.dirtySize, jpegData);
160         if (ret != DH_SUCCESS) {
161             delete [] jpegData;
162             return ret;
163         }
164         offset += item.dirtySize;
165         uint8_t *dirtyImageData = new uint8_t[item.width * item.height * RGB_CHROMA] {0};
166         DHLOGI("%s: DecompressJpegToNV12.", LOG_TAG);
167         DecompressJpegToNV12(item.dirtySize, jpegData, dirtyImageData);
168         DHLOGI("%s: DecompressJpegToNV12 success.", LOG_TAG);
169         ret = ReplaceDamage2LastFrame(lastFrame, dirtyImageData, item);
170         if (ret != DH_SUCCESS) {
171             DHLOGE("ReplaceDamage2LastFrame failed, ret: %." PRId32, ret);
172             delete [] jpegData;
173             delete [] dirtyImageData;
174             return ret;
175         }
176         delete [] jpegData;
177         delete [] dirtyImageData;
178     }
179     DHLOGI("%s: DecodeDamageData success.", LOG_TAG);
180     return DH_SUCCESS;
181 }
182 
ReplaceDamage2LastFrame(uint8_t * lastFrame,uint8_t * dirtyImageData,const DirtyRect rect)183 int32_t JpegImageProcessor::ReplaceDamage2LastFrame(uint8_t *lastFrame, uint8_t *dirtyImageData, const DirtyRect rect)
184 {
185     DHLOGI("%s: ReplaceDamage2LastFrame.", LOG_TAG);
186     uint8_t *lastFrameIdx = lastFrame;
187     uint8_t *yData = lastFrameIdx + static_cast<uint32_t>(configParam_.GetScreenWidth() * rect.yPos + rect.xPos);
188     uint8_t *uData = lastFrameIdx + configParam_.GetScreenWidth() * configParam_.GetScreenHeight() +
189                 static_cast<uint32_t>(configParam_.GetScreenWidth() * (rect.yPos / TWO) + rect.xPos);
190     uint8_t *yDirtyData = dirtyImageData;
191     uint8_t *uDirtyData = dirtyImageData + rect.width * rect.height;
192     uint8_t *yTempData = nullptr;
193     uint8_t *uTempData = nullptr;
194     for (int32_t i = 0 ; i < rect.height ; i++) {
195         yTempData = yData + static_cast<uint32_t>(i) * configParam_.GetScreenWidth();
196         int32_t ret = memcpy_s(yTempData, rect.width, yDirtyData, rect.width);
197         if (ret != EOK) {
198             DHLOGE("%s: memcpy yData failed.", LOG_TAG);
199             return ret;
200         }
201         yDirtyData += static_cast<uint32_t>(rect.width);
202         if (i % TWO) {
203             uTempData = uData + configParam_.GetScreenWidth() * (static_cast<uint32_t>(i) / TWO);
204             ret = memcpy_s(uTempData, rect.width, uDirtyData, rect.width);
205             if (ret != EOK) {
206                 DHLOGE("%s: memcpy uData failed.", LOG_TAG);
207                 return ret;
208             }
209             uDirtyData += static_cast<uint32_t>(rect.width);
210             }
211     }
212     DHLOGI("%s: ReplaceDamage2LastFrame success.", LOG_TAG);
213     return DH_SUCCESS;
214 }
215 
CompressRgbaToJpeg(const OHOS::Rect & damage,uint8_t * inputData,uint32_t inputDataSize,std::shared_ptr<DataBuffer> & data)216 uint32_t JpegImageProcessor::CompressRgbaToJpeg(const OHOS::Rect &damage,
217     uint8_t *inputData, uint32_t inputDataSize, std::shared_ptr<DataBuffer> &data)
218 {
219     DHLOGI("%s: CompressRgbaToJpeg.", LOG_TAG);
220     if (inputDataSize != damage.w * damage.h * RGBA_CHROMA) {
221         return ERR_DH_SCREEN_CODEC_PARTAIL_DATA_ERROR;
222     }
223     jpeg_compress_struct cinfo;
224     jpeg_error_mgr jerr;
225     JSAMPROW row_pointer[1];
226     cinfo.err = jpeg_std_error(&jerr);
227     jpeg_create_compress(&cinfo);
228     unsigned char *outBuffer = nullptr;
229     unsigned long outSize = 0;
230     jpeg_mem_dest(&cinfo, &outBuffer, &outSize);
231     cinfo.image_width = damage.w;
232     cinfo.image_height = damage.h;
233     cinfo.input_components = RGB_CHROMA;
234     cinfo.in_color_space = JCS_RGB;
235     jpeg_set_defaults(&cinfo);
236     jpeg_set_quality(&cinfo, JPEG_QUALITY, TRUE);
237     jpeg_start_compress(&cinfo, TRUE);
238     unsigned char rgb_buffer[damage.w * RGB_CHROMA];
239     unsigned char *pB = inputData;
240     unsigned char *pG = inputData + 1;
241     unsigned char *pR = inputData + TWO;
242     while (cinfo.next_scanline < cinfo.image_height) {
243         int index = 0;
244         for (int i = 0 ; i < damage.w ; i++) {
245             rgb_buffer[index++] = *pB;
246             rgb_buffer[index++] = *pG;
247             rgb_buffer[index++] = *pR;
248             pB += RGBA_CHROMA;
249             pG += RGBA_CHROMA;
250             pR += RGBA_CHROMA;
251         }
252         row_pointer[0] = rgb_buffer;
253         (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
254     }
255     jpeg_finish_compress(&cinfo);
256     DirtyRect rect = {damage.x, damage.y, damage.w, damage.h, outSize};
257     data->AddData(static_cast<size_t>(outSize), outBuffer);
258     data->AddDirtyRect(rect);
259     jpeg_destroy_compress(&cinfo);
260     if (outBuffer != NULL) {
261         free(outBuffer);
262         outBuffer = NULL;
263     }
264     return (uint32_t)outSize;
265 }
266 
DecompressJpegToNV12(size_t jpegSize,uint8_t * inputData,uint8_t * outputData)267 void JpegImageProcessor::DecompressJpegToNV12(size_t jpegSize, uint8_t *inputData, uint8_t *outputData)
268 {
269     jpeg_decompress_struct cinfo;
270     jpeg_error_mgr jerr;
271     cinfo.err = jpeg_std_error(&jerr);
272     jpeg_create_decompress(&cinfo);
273     jpeg_mem_src(&cinfo, inputData, jpegSize);
274     (void)jpeg_read_header(&cinfo, TRUE);
275     (void)jpeg_start_decompress(&cinfo);
276     int32_t row_stride = static_cast<int32_t>(cinfo.output_width) * cinfo.output_components;
277     JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);
278     uint32_t uvIndex = cinfo.output_width * cinfo.output_height;
279     int32_t i = 0;
280 #ifdef LIBYUV
281     uint8_t *rgb = new uint8_t[cinfo.output_width * cinfo.output_height * RGBA_CHROMA];
282     int32_t rgbIndex = 0;
283 #else
284     int32_t yIndex = 0;
285 #endif
286     while (cinfo.output_scanline < cinfo.output_height) {
287         (void)jpeg_read_scanlines(&cinfo, buffer, 1);
288         for (unsigned int j = 0 ; j < cinfo.output_width ; j++) {
289 #ifdef LIBYUV
290             rgb[rgbIndex++] = buffer[0][j * RGB_CHROMA + TWO];
291             rgb[rgbIndex++] = buffer[0][j * RGB_CHROMA + 1];
292             rgb[rgbIndex++] = buffer[0][j * RGB_CHROMA];
293             rgb[rgbIndex++] = 0xff;
294 #else
295             int32_t y = ((YR_PARAM * buffer[0][j * RGB_CHROMA] + YG_PARAM * buffer[0][j * RGB_CHROMA + 1] +
296                 YB_PARAM * buffer[0][j * RGB_CHROMA + TWO] + UA_PARAM) >> MOVEBITS) + YA_PARAM;
297             int32_t u = ((UB_PARAM * buffer[0][j * RGB_CHROMA + TWO] - UR_PARAM * buffer[0][j * RGB_CHROMA] -
298             UG_PARAM * buffer[0][j * RGB_CHROMA + 1] + UA_PARAM) >> MOVEBITS) + UA_PARAM;
299             int32_t v = ((UB_PARAM * buffer[0][j * RGB_CHROMA] - VG_PARAM * buffer[0][j * RGB_CHROMA + 1] -
300                 VB_PARAM * buffer[0][j * RGB_CHROMA + TWO] + UA_PARAM) >> MOVEBITS) + UA_PARAM;
301             outputData[yIndex++] = static_cast<uint8_t>((y < 0) ? 0 : (y > YUV_PARAM) ? YUV_PARAM : y);
302             if ((i % TWO == 0) && (j % TWO == 0)) {
303                 outputData[uvIndex++] = static_cast<uint8_t>((u < 0) ? 0 : (u > YUV_PARAM) ? YUV_PARAM : u);
304                 outputData[uvIndex++] = static_cast<uint8_t>((v < 0) ? 0 : (v > YUV_PARAM) ? YUV_PARAM : v);
305             }
306 #endif
307         }
308         ++i;
309     }
310     (void)jpeg_finish_decompress(&cinfo);
311     jpeg_destroy_decompress(&cinfo);
312 #ifdef LIBYUV
313     libyuv::ARGBToNV12(rgb, cinfo.output_width * RGBA_CHROMA, outputData, cinfo.output_width,
314         outputData + uvIndex, cinfo.output_width, cinfo.output_width, cinfo.output_height);
315     delete [] rgb;
316 #endif
317 }
318 } // namespace DistributedHardware
319 } // namespace OHOS