• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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_encoder.h"
17 #ifdef IMAGE_COLORSPACE_FLAG
18 #include "color_space.h"
19 #endif
20 #include "image_log.h"
21 #include "image_trace.h"
22 #include "include/core/SkColorSpace.h"
23 #include "include/core/SkImageInfo.h"
24 #include "jerror.h"
25 #include "media_errors.h"
26 #include "pixel_convert.h"
27 #ifdef USE_M133_SKIA
28 #include "src/encode/SkImageEncoderFns.h"
29 #else
30 #include "src/images/SkImageEncoderFns.h"
31 #endif
32 
33 #undef LOG_DOMAIN
34 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_PLUGIN
35 
36 #undef LOG_TAG
37 #define LOG_TAG "JpegEncoder"
38 
39 namespace OHOS {
40 namespace ImagePlugin {
41 using namespace MultimediaPlugin;
42 using namespace Media;
43 
44 constexpr uint32_t COMPONENT_NUM_ARGB = 4;
45 constexpr uint32_t COMPONENT_NUM_RGBA = 4;
46 constexpr uint32_t COMPONENT_NUM_BGRA = 4;
47 constexpr uint32_t COMPONENT_NUM_RGB = 3;
48 constexpr uint32_t COMPONENT_NUM_GRAY = 1;
49 constexpr uint32_t PIXEL_SIZE_RGBA_F16 = 8;
50 constexpr uint32_t PIXEL_SIZE_RGB565 = 2;
51 constexpr uint32_t BLOCK_SIZE = 16;
52 // yuv format
53 constexpr uint8_t COMPONENT_NUM_YUV420SP = 3;
54 constexpr uint8_t Y_SAMPLE_ROW = 16;
55 constexpr uint8_t UV_SAMPLE_ROW = 8;
56 constexpr uint8_t SAMPLE_FACTOR_ONE = 1;
57 constexpr uint8_t SAMPLE_FACTOR_TWO = 2;
58 constexpr uint8_t INDEX_ZERO = 0;
59 constexpr uint8_t INDEX_ONE = 1;
60 constexpr uint8_t INDEX_TWO = 2;
61 constexpr uint8_t SHIFT_MASK = 1;
62 
JpegDstMgr(OutputDataStream * stream)63 JpegDstMgr::JpegDstMgr(OutputDataStream *stream) : outputStream(stream)
64 {
65     init_destination = InitDstStream;
66     empty_output_buffer = EmptyOutputBuffer;
67     term_destination = TermDstStream;
68 }
69 
JpegEncoder()70 JpegEncoder::JpegEncoder() : dstMgr_(nullptr)
71 {
72     // create decompress struct
73     jpeg_create_compress(&encodeInfo_);
74 
75     // set error output
76     encodeInfo_.err = jpeg_std_error(&jerr_);
77     jerr_.error_exit = ErrorExit;
78     CHECK_ERROR_RETURN_LOG(encodeInfo_.err == nullptr, "create jpeg encoder failed.");
79     encodeInfo_.err->output_message = &OutputErrorMessage;
80 }
81 
StartEncode(OutputDataStream & outputStream,PlEncodeOptions & option)82 uint32_t JpegEncoder::StartEncode(OutputDataStream &outputStream, PlEncodeOptions &option)
83 {
84     ImageTrace imageTrace("JpegEncoder::StartEncode");
85     pixelMaps_.clear();
86     dstMgr_.outputStream = &outputStream;
87     encodeInfo_.dest = &dstMgr_;
88     encodeOpts_ = option;
89     return SUCCESS;
90 }
91 
GetEncodeFormat(PixelFormat format,int32_t & componentsNum)92 J_COLOR_SPACE JpegEncoder::GetEncodeFormat(PixelFormat format, int32_t &componentsNum)
93 {
94     J_COLOR_SPACE colorSpace = JCS_UNKNOWN;
95     int32_t components = 0;
96     switch (format) {
97         case PixelFormat::RGBA_F16:
98         case PixelFormat::RGBA_8888: {
99             colorSpace = JCS_EXT_RGBA;
100             components = COMPONENT_NUM_RGBA;
101             break;
102         }
103         case PixelFormat::BGRA_8888: {
104             colorSpace = JCS_EXT_BGRA;
105             components = COMPONENT_NUM_BGRA;
106             break;
107         }
108         case PixelFormat::ARGB_8888: {
109             colorSpace = JCS_EXT_ARGB;
110             components = COMPONENT_NUM_ARGB;
111             break;
112         }
113         case PixelFormat::ALPHA_8: {
114             colorSpace = JCS_GRAYSCALE;
115             components = COMPONENT_NUM_GRAY;
116             break;
117         }
118         case PixelFormat::RGB_565:
119         case PixelFormat::RGB_888: {
120             colorSpace = JCS_RGB;
121             components = COMPONENT_NUM_RGB;
122             break;
123         }
124         case PixelFormat::NV12:
125         case PixelFormat::NV21: {
126             colorSpace = JCS_YCbCr;
127             components = COMPONENT_NUM_YUV420SP;
128             break;
129         }
130         case PixelFormat::CMYK: {
131             colorSpace = JCS_CMYK;
132             components = COMPONENT_NUM_RGBA;
133             break;
134         }
135         default: {
136             IMAGE_LOGE("encode format:[%{public}d] is unsupported!", format);
137             break;
138         }
139     }
140     componentsNum = components;
141     return colorSpace;
142 }
143 
AddImage(Media::PixelMap & pixelMap)144 uint32_t JpegEncoder::AddImage(Media::PixelMap &pixelMap)
145 {
146     ImageTrace imageTrace("JpegEncoder::AddImage");
147     CHECK_ERROR_RETURN_RET_LOG(pixelMaps_.size() >= JPEG_IMAGE_NUM, ERR_IMAGE_ADD_PIXEL_MAP_FAILED,
148         "add pixel map out of range:[%{public}u].", JPEG_IMAGE_NUM);
149     pixelMaps_.push_back(&pixelMap);
150     return SUCCESS;
151 }
152 
AddPicture(Media::Picture & picture)153 uint32_t JpegEncoder::AddPicture(Media::Picture &picture)
154 {
155     ImageTrace imageTrace("JpegEncoder::AddPicture");
156     return ERR_IMAGE_ENCODE_FAILED;
157 }
158 
FinalizeEncode()159 uint32_t JpegEncoder::FinalizeEncode()
160 {
161     ImageTrace imageTrace("JpegEncoder::FinalizeEncode");
162     uint32_t errorCode = SetCommonConfig();
163     if (errorCode != SUCCESS) {
164         IMAGE_LOGE("set jpeg compress struct failed:%{public}u.", errorCode);
165         return errorCode;
166     }
167     const uint8_t *data = pixelMaps_[0]->GetPixels();
168     if (data == nullptr) {
169         IMAGE_LOGE("encode image buffer is null.");
170         return ERR_IMAGE_INVALID_PARAMETER;
171     }
172     PixelFormat pixelFormat = pixelMaps_[0]->GetPixelFormat();
173     if (pixelFormat == PixelFormat::NV21 || pixelFormat == PixelFormat::NV12) {
174         errorCode = Yuv420spEncoder(data);
175     } else if (pixelFormat == PixelFormat::RGBA_F16) {
176         errorCode = RGBAF16Encoder(data);
177     } else if (pixelFormat == PixelFormat::RGB_565) {
178         errorCode = RGB565Encoder(data);
179     } else {
180         errorCode = SequenceEncoder(data);
181     }
182     if (errorCode != SUCCESS) {
183         IMAGE_LOGE("encode jpeg failed:%{public}u.", errorCode);
184     }
185     return errorCode;
186 }
187 
SetCommonConfig()188 uint32_t JpegEncoder::SetCommonConfig()
189 {
190     if (pixelMaps_.empty()) {
191         IMAGE_LOGE("encode image failed, no pixel map input.");
192         return ERR_IMAGE_INVALID_PARAMETER;
193     }
194     CHECK_ERROR_RETURN_RET_LOG(pixelMaps_[0] == nullptr, ERR_IMAGE_INVALID_PARAMETER,
195         "encode image failed, pixel map is null.");
196     CHECK_ERROR_RETURN_RET_LOG(setjmp(jerr_.setjmp_buffer), ERR_IMAGE_ENCODE_FAILED,
197         "encode image error, set config failed.");
198     encodeInfo_.image_width = static_cast<uint32_t>(pixelMaps_[0]->GetWidth());
199     encodeInfo_.image_height = static_cast<uint32_t>(pixelMaps_[0]->GetHeight());
200     PixelFormat pixelFormat = pixelMaps_[0]->GetPixelFormat();
201     encodeInfo_.in_color_space = GetEncodeFormat(pixelFormat, encodeInfo_.input_components);
202     if (encodeInfo_.in_color_space == JCS_UNKNOWN) {
203         IMAGE_LOGE("set input jpeg color space invalid.");
204         return ERR_IMAGE_UNKNOWN_FORMAT;
205     }
206     IMAGE_LOGD("width=%{public}u, height=%{public}u, colorspace=%{public}d, components=%{public}d.",
207         encodeInfo_.image_width, encodeInfo_.image_height, encodeInfo_.in_color_space, encodeInfo_.input_components);
208     jpeg_set_defaults(&encodeInfo_);
209     int32_t quality = encodeOpts_.quality;
210     jpeg_set_quality(&encodeInfo_, quality, TRUE);
211     return SUCCESS;
212 }
213 
SequenceEncoder(const uint8_t * data)214 uint32_t JpegEncoder::SequenceEncoder(const uint8_t *data)
215 {
216     if (setjmp(jerr_.setjmp_buffer)) {
217         IMAGE_LOGE("encode image error.");
218         return ERR_IMAGE_ENCODE_FAILED;
219     }
220     jpeg_start_compress(&encodeInfo_, TRUE);
221 
222 #ifdef IMAGE_COLORSPACE_FLAG
223     // packing icc profile.
224     SkImageInfo skImageInfo;
225     OHOS::ColorManager::ColorSpace grColorSpace = pixelMaps_[0]->InnerGetGrColorSpace();
226     sk_sp<SkColorSpace> skColorSpace = grColorSpace.ToSkColorSpace();
227 
228     // when there is colorspace data, package it.
229     if (skColorSpace != nullptr) {
230         int width = 0;
231         int height = 0;
232         SkColorType ct = SkColorType::kUnknown_SkColorType;
233         SkAlphaType at = SkAlphaType::kUnknown_SkAlphaType;
234         skImageInfo = SkImageInfo::Make(width, height, ct, at, skColorSpace);
235         uint32_t iccPackedresult = iccProfileInfo_.PackingICCProfile(&encodeInfo_, skImageInfo);
236         CHECK_ERROR_RETURN_RET_LOG(iccPackedresult == OHOS::Media::ERR_IMAGE_ENCODE_ICC_FAILED, iccPackedresult,
237             "encode image icc error.");
238     }
239 #endif
240 
241     uint8_t *base = const_cast<uint8_t *>(data);
242     uint32_t rowStride = encodeInfo_.image_width * static_cast<uint32_t>(encodeInfo_.input_components);
243     uint8_t *buffer = nullptr;
244     while (encodeInfo_.next_scanline < encodeInfo_.image_height) {
245         buffer = base + encodeInfo_.next_scanline * rowStride;
246         jpeg_write_scanlines(&encodeInfo_, &buffer, RW_LINE_NUM);
247     }
248     jpeg_finish_compress(&encodeInfo_);
249     return SUCCESS;
250 }
251 
SetYuv420spExtraConfig()252 void JpegEncoder::SetYuv420spExtraConfig()
253 {
254     encodeInfo_.raw_data_in = TRUE;
255     encodeInfo_.dct_method = JDCT_IFAST;
256     encodeInfo_.comp_info[INDEX_ZERO].h_samp_factor = SAMPLE_FACTOR_TWO;
257     encodeInfo_.comp_info[INDEX_ZERO].v_samp_factor = SAMPLE_FACTOR_TWO;
258     encodeInfo_.comp_info[INDEX_ONE].h_samp_factor = SAMPLE_FACTOR_ONE;
259     encodeInfo_.comp_info[INDEX_ONE].v_samp_factor = SAMPLE_FACTOR_ONE;
260     encodeInfo_.comp_info[INDEX_TWO].h_samp_factor = SAMPLE_FACTOR_ONE;
261     encodeInfo_.comp_info[INDEX_TWO].v_samp_factor = SAMPLE_FACTOR_ONE;
262 }
263 
Yuv420spEncoder(const uint8_t * data)264 uint32_t JpegEncoder::Yuv420spEncoder(const uint8_t *data)
265 {
266     CHECK_ERROR_RETURN_RET_LOG(setjmp(jerr_.setjmp_buffer), ERR_IMAGE_ENCODE_FAILED, "encode image error.");
267     SetYuv420spExtraConfig();
268     jpeg_start_compress(&encodeInfo_, TRUE);
269     JSAMPROW y[Y_SAMPLE_ROW];
270     JSAMPROW u[UV_SAMPLE_ROW];
271     JSAMPROW v[UV_SAMPLE_ROW];
272     JSAMPARRAY planes[COMPONENT_NUM_YUV420SP]{ y, u, v };
273     uint32_t width = encodeInfo_.image_width;
274     uint32_t height = encodeInfo_.image_height;
275     uint32_t yPlaneSize = width * height;
276     uint8_t *yPlane = const_cast<uint8_t *>(data);
277     uint8_t *uvPlane = const_cast<uint8_t *>(data + yPlaneSize);
278     if (width % BLOCK_SIZE != 0 || height % BLOCK_SIZE != 0) {
279         IMAGE_LOGE("yuv420sp image width or height is not available.");
280         return ERR_IMAGE_DATA_ABNORMAL;
281     }
282     auto uPlane = std::make_unique<uint8_t[]>((width >> SHIFT_MASK) * UV_SAMPLE_ROW);
283     if (uPlane == nullptr) {
284         IMAGE_LOGE("allocate uPlane memory failed.");
285         return ERR_IMAGE_MALLOC_ABNORMAL;
286     }
287     auto vPlane = std::make_unique<uint8_t[]>((width >> SHIFT_MASK) * UV_SAMPLE_ROW);
288     if (vPlane == nullptr) {
289         IMAGE_LOGE("allocate vPlane memory failed.");
290         return ERR_IMAGE_MALLOC_ABNORMAL;
291     }
292     while (encodeInfo_.next_scanline < height) {
293         Deinterweave(uvPlane, uPlane.get(), vPlane.get(), encodeInfo_.next_scanline, width, height);
294         for (uint32_t i = 0; i < Y_SAMPLE_ROW; i++) {
295             y[i] = yPlane + (encodeInfo_.next_scanline + i) * width;
296             if ((i & SHIFT_MASK) == 0) {
297                 uint32_t offset = (i >> SHIFT_MASK) * (width >> SHIFT_MASK);
298                 u[i >> SHIFT_MASK] = uPlane.get() + offset;
299                 v[i >> SHIFT_MASK] = vPlane.get() + offset;
300             }
301         }
302         jpeg_write_raw_data(&encodeInfo_, planes, Y_SAMPLE_ROW);
303     }
304     jpeg_finish_compress(&encodeInfo_);
305     return SUCCESS;
306 }
307 
Deinterweave(uint8_t * uvPlane,uint8_t * uPlane,uint8_t * vPlane,uint32_t curRow,uint32_t width,uint32_t height)308 void JpegEncoder::Deinterweave(uint8_t *uvPlane, uint8_t *uPlane, uint8_t *vPlane, uint32_t curRow, uint32_t width,
309                                uint32_t height)
310 {
311     PixelFormat pixelFormat = pixelMaps_[0]->GetPixelFormat();
312     uint32_t rowNum = (height - curRow) >> SHIFT_MASK;
313     if (rowNum > UV_SAMPLE_ROW) {
314         rowNum = UV_SAMPLE_ROW;
315     }
316     uint8_t indexZero = INDEX_ZERO;
317     uint8_t indexOne = INDEX_ONE;
318     if (pixelFormat != PixelFormat::NV12) {
319         std::swap(indexZero, indexOne);
320     }
321 
322     for (uint32_t row = 0; row < rowNum; row++) {
323         uint32_t offset = ((curRow >> SHIFT_MASK) + row) * width;
324         uint8_t *uv = uvPlane + offset;
325         uint32_t col = width >> SHIFT_MASK;
326         for (uint32_t i = 0; i < col; i++) {
327             uint32_t index = row * col + i;
328             uPlane[index] = uv[indexZero];
329             vPlane[index] = uv[indexOne];
330             uv += INDEX_TWO;
331         }
332     }
333 }
334 
RGBAF16Encoder(const uint8_t * data)335 uint32_t JpegEncoder::RGBAF16Encoder(const uint8_t *data)
336 {
337     CHECK_ERROR_RETURN_RET_LOG(setjmp(jerr_.setjmp_buffer), ERR_IMAGE_ENCODE_FAILED, "encode image error.");
338     jpeg_start_compress(&encodeInfo_, TRUE);
339     uint8_t *base = const_cast<uint8_t *>(data);
340     uint32_t rowStride = encodeInfo_.image_width * static_cast<uint32_t>(encodeInfo_.input_components);
341     uint32_t orgRowStride = encodeInfo_.image_width * PIXEL_SIZE_RGBA_F16;
342     uint8_t *buffer = nullptr;
343     auto rowBuffer = std::make_unique<uint8_t[]>(rowStride);
344     while (encodeInfo_.next_scanline < encodeInfo_.image_height) {
345         buffer = base + encodeInfo_.next_scanline * orgRowStride;
346         for (uint32_t i = 0; i < rowStride;i++) {
347             float orgPlane = HalfToFloat(U8ToU16(buffer[i*2], buffer[i*2+1]));
348             rowBuffer[i] = static_cast<uint8_t>(orgPlane/MAX_HALF*ALPHA_OPAQUE);
349         }
350         uint8_t *rowBufferPtr = rowBuffer.get();
351         jpeg_write_scanlines(&encodeInfo_, &rowBufferPtr, RW_LINE_NUM);
352     }
353     jpeg_finish_compress(&encodeInfo_);
354     return SUCCESS;
355 }
356 
RGB565Encoder(const uint8_t * data)357 uint32_t JpegEncoder::RGB565Encoder(const uint8_t *data)
358 {
359     IMAGE_LOGD("RGB565Encoder IN.");
360     CHECK_ERROR_RETURN_RET_LOG(setjmp(jerr_.setjmp_buffer), ERR_IMAGE_ENCODE_FAILED, "encode image error.");
361 
362     jpeg_start_compress(&encodeInfo_, TRUE);
363 
364     uint8_t *base = const_cast<uint8_t *>(data);
365 
366     uint32_t orgRowStride = encodeInfo_.image_width * PIXEL_SIZE_RGB565;
367     uint8_t *orgRowBuffer = nullptr;
368 
369     uint32_t outRowStride = encodeInfo_.image_width * static_cast<uint32_t>(encodeInfo_.input_components);
370     auto outRowBuffer = std::make_unique<uint8_t[]>(outRowStride);
371 
372     while (encodeInfo_.next_scanline < encodeInfo_.image_height) {
373         orgRowBuffer = base + encodeInfo_.next_scanline * orgRowStride;
374         skcms(reinterpret_cast<char*>(&outRowBuffer[0]),
375             reinterpret_cast<const char*>(orgRowBuffer),
376             encodeInfo_.image_width,
377             skcms_PixelFormat_RGB_565,
378             skcms_AlphaFormat_Unpremul,
379             skcms_PixelFormat_RGB_888,
380             skcms_AlphaFormat_Unpremul);
381 
382         uint8_t *rowBufferPtr = outRowBuffer.get();
383         jpeg_write_scanlines(&encodeInfo_, &rowBufferPtr, RW_LINE_NUM);
384     }
385 
386     jpeg_finish_compress(&encodeInfo_);
387     IMAGE_LOGD("RGB565Encoder OUT.");
388     return SUCCESS;
389 }
390 
~JpegEncoder()391 JpegEncoder::~JpegEncoder()
392 {
393     jpeg_destroy_compress(&encodeInfo_);
394     pixelMaps_.clear();
395 }
396 } // namespace ImagePlugin
397 } // namespace OHOS
398