1/*
2 * Copyright (c) 2023 Shenzhen Kaihong DID 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 "codec_jpeg_helper.h"
17#include <ashmem.h>
18#include <cerrno>
19#include <cstring>
20#include <securec.h>
21#include "hdf_log.h"
22
23static int8_t UnZigZagTable[64] = {
24    0,  1,  5,  6, 14, 15, 27, 28,
25    2,  4,  7, 13, 16, 26, 29, 42,
26    3,  8, 12, 17, 25, 30, 41, 43,
27    9, 11, 18, 24, 31, 40, 44, 53,
28    10, 19, 23, 32, 39, 45, 52, 54,
29    20, 22, 33, 38, 46, 51, 55, 60,
30    21, 34, 37, 47, 50, 56, 59, 61,
31    35, 36, 48, 49, 57, 58, 62, 63};
32
33using namespace OHOS::HDI::Codec::Image::V2_0;
34int32_t CodecJpegHelper::JpegAssemble(const struct CodecJpegDecInfo &decInfo, int8_t *buffer, int32_t fd)
35{
36    HDF_LOGI("enter");
37    int32_t curPos = 0;
38    // SOI
39    curPos = PutInt16(buffer, curPos, 0xffd8);
40    if (curPos < 0) {
41        HDF_LOGE("assemble SOI error");
42        return -1;
43    }
44
45    // DQT
46    curPos = JpegDqtAssemble(decInfo, buffer, curPos);
47    if (curPos < 0) {
48        HDF_LOGE("assemble DQT error");
49        return -1;
50    }
51
52    // DHT
53    curPos = JpegDhtAssemble(decInfo, buffer, curPos);
54    if (curPos < 0) {
55        HDF_LOGE("assemble DHT error");
56        return -1;
57    }
58    // DRI
59    curPos = JpegDriAssemble(decInfo, buffer, curPos);
60    if (curPos < 0) {
61        HDF_LOGE("assemble DRI error");
62        return -1;
63    }
64
65    // SOF
66    curPos = JpegSofAssemble(decInfo, buffer, curPos);
67    if (curPos < 0) {
68        HDF_LOGE("assemble SOF error");
69        return -1;
70    }
71    // SOS
72    curPos = JpegSosAssemble(decInfo, buffer, curPos);
73    if (curPos < 0) {
74        HDF_LOGE("assemble SOS error");
75        return -1;
76    }
77    // DATA
78    curPos = JpegDataAssemble(buffer, curPos, fd);
79    if (curPos < 0) {
80        HDF_LOGE("assemble CompressedData error");
81        return -1;
82    }
83    // EOI
84    curPos = PutInt16(buffer, curPos, 0xffd9);
85    if (curPos < 0) {
86        HDF_LOGE("assemble EOI error");
87        return -1;
88    }
89    return curPos;
90}
91
92bool CodecJpegHelper::DessambleJpeg(int8_t *buffer, size_t bufferLen, struct CodecJpegDecInfo &decInfo,
93                                    std::unique_ptr<int8_t[]> &compressBuffer, uint32_t &comBufLen, uint32_t &dataStart)
94{
95    HDF_LOGI("enter");
96    int8_t *start = buffer;
97    const int8_t *end = buffer + bufferLen;
98    while (start < end) {
99        JpegMarker marker = (JpegMarker)FindMarker(start);
100        start += 2;  // 2: marker len
101        switch (marker) {
102            case SOI:
103            case EOI:
104                break;
105            case SOF0:
106                start += DessambleSof(start, decInfo);
107                break;
108            case DHT:
109                start += DessambleDht(start, decInfo);
110                break;
111            case SOS: {
112                start += DessambleSos(start, decInfo);
113                dataStart = start - buffer;
114                // compressed data start
115                auto len = DessambleCompressData(start, compressBuffer, comBufLen);
116                if (len < 0) {
117                    HDF_LOGE("copy compressed data error");
118                    return false;
119                }
120                start += len;
121                break;
122            }
123
124            case DQT:
125                start += DessambleDqt(start, decInfo);
126                break;
127            case DRI: {
128                start += 2;  // 2: marker len
129                decInfo.restartInterval = GetInt16(start);
130                start += 2;  // 2: interval len
131                break;
132            }
133            default: {
134                short len = GetInt16(start);
135                start += len;
136                HDF_LOGW("skip marker[%{public}x], len[%{public}d]", marker, len);
137                break;
138            }
139        }
140    }
141    return true;
142}
143int32_t CodecJpegHelper::JpegDqtAssemble(const struct CodecJpegDecInfo &decInfo, int8_t *buffer, int32_t curPos)
144{
145    HDF_LOGI("enter. curPos = %{public}d", curPos);
146    // flag
147    curPos = PutInt16(buffer, curPos, 0xffdb);
148    if (curPos < 0) {
149        HDF_LOGE("assemble DQT flag error");
150        return curPos;
151    }
152
153    // skip len first
154    int32_t lenPos = curPos;
155    curPos += 2;  // 2: marker len
156
157    // data
158    for (size_t i = 0; i < decInfo.quantTbl.size(); i++) {
159        if (!decInfo.quantTbl[i].tableFlag) {
160            break;
161        }
162        uint8_t index = 0;         // precision 1:16bit, 0: 8bit, deault:1
163        index = (index << 4) | i;  // precision << 4 | tableid
164        curPos = PutInt8(buffer, curPos, index);
165        if (curPos < 0) {
166            HDF_LOGE("assemble precision and tableid error");
167            return curPos;
168        }
169
170        for (size_t j = 0; j < decInfo.quantTbl[i].quantVal.size(); j++) {
171            HDF_LOGI("decInfo.quantTbl[%{public}zu].quantVal[%{public}zu] = %{public}d", i, j,
172                decInfo.quantTbl[i].quantVal[j]);
173            curPos = PutInt16(buffer, curPos, decInfo.quantTbl[i].quantVal[j]);
174        }
175    }
176    int16_t bufferLen = static_cast<int16_t>(curPos - lenPos);
177    auto ret = PutInt16(buffer, lenPos, bufferLen);
178    if (ret < 0) {
179        HDF_LOGE("assemble len error");
180        return ret;
181    }
182    return curPos;
183}
184int32_t CodecJpegHelper::JpegDriAssemble(const struct CodecJpegDecInfo &decInfo, int8_t *buffer, int32_t curPos)
185{
186    HDF_LOGI("enter, restartInterval = %{public}d curPos = %{public}d", decInfo.restartInterval, curPos);
187    if (decInfo.restartInterval <= 0) {
188        return curPos;
189    }
190    curPos = PutInt16(buffer, curPos, 0xffdd);
191    if (curPos < 0) {
192        HDF_LOGE("assemble DRI flag error");
193        return curPos;
194    }
195
196    curPos = PutInt16(buffer, curPos, 4);  // 4: dri data len( marker len included)
197    if (curPos < 0) {
198        HDF_LOGE("assemble DRI len error");
199        return curPos;
200    }
201
202    curPos = PutInt16(buffer, curPos, decInfo.restartInterval);
203    if (curPos < 0) {
204        HDF_LOGE("assemble dri value error");
205        return curPos;
206    }
207    return curPos;
208}
209int32_t CodecJpegHelper::JpegDhtAssemble(const struct CodecJpegDecInfo &decInfo, int8_t *buffer, int32_t curPos)
210{
211    HDF_LOGI("enter. curPos = %{public}d", curPos);
212    curPos = JpegDhtAssemble(decInfo.dcHuffTbl, buffer, curPos);
213    if (curPos < 0) {
214        HDF_LOGE("assemble dc hufman error");
215        return curPos;
216    }
217
218    curPos = JpegDhtAssemble(decInfo.acHuffTbl, buffer, curPos, false);
219    if (curPos < 0) {
220        HDF_LOGE("assemble ac hufman error");
221    }
222    return curPos;
223}
224int32_t CodecJpegHelper::JpegDhtAssemble(const std::vector<CodecJpegHuffTable> &table, int8_t *buffer, int32_t curPos,
225                                         bool dc)
226{
227    HDF_LOGI("enter. curPos = %{public}d", curPos);
228    // DC Hufman
229    curPos = PutInt16(buffer, curPos, 0xffc4);
230    if (curPos < 0) {
231        HDF_LOGE("assemble hufman flag error");
232        return curPos;
233    }
234    // skip len
235    int32_t lenPos = curPos;
236    curPos += 2;  // 2: marker len
237    for (size_t i = 0; i < table.size(); i++) {
238        if (!table[i].tableFlag) {
239            break;
240        }
241        uint8_t type = 0;  // type  0:DC, 1:AC
242        if (!dc) {
243            type = 1;
244        }
245        type = (type << 4) | i;  // type << 4 | tableid
246        curPos = PutInt8(buffer, curPos, type);
247        if (curPos < 0) {
248            HDF_LOGE("assemble tableid and dc/ac error");
249            return curPos;
250        }
251        // bits
252        auto ret = memcpy_s(buffer + curPos, table[i].bits.size(), table[i].bits.data(), table[i].bits.size());
253        if (ret != EOK) {
254            char buf[MAX_BUFFER_LEN] = {0};
255            strerror_r(errno, buf, sizeof(buf));
256            HDF_LOGE("assemble bits error ret = %{public}s", buf);
257            return ret;
258        }
259        curPos += table[i].bits.size();
260        // val
261        ret = memcpy_s(buffer + curPos, table[i].huffVal.size(), table[i].huffVal.data(), table[i].huffVal.size());
262        if (ret != EOK) {
263            HDF_LOGE("assemble huffVal error, ret = %{public}d", ret);
264            return ret;
265        }
266        curPos += table[i].huffVal.size();
267    }
268    int16_t bufferLen = static_cast<int16_t>(curPos - lenPos);
269    auto ret = PutInt16(buffer, lenPos, bufferLen);
270    if (ret < 0) {
271        HDF_LOGE("assemble len error");
272        return ret;
273    }
274    return curPos;
275}
276
277int32_t CodecJpegHelper::JpegSofAssemble(const struct CodecJpegDecInfo &decInfo, int8_t *buffer, int32_t curPos)
278{
279    HDF_LOGI("enter. curPos = %{public}d", curPos);
280    // flag
281    curPos = PutInt16(buffer, curPos, 0xffc0);
282    if (curPos < 0) {
283        HDF_LOGE("assemble SOF flag error");
284        return curPos;
285    }
286
287    int16_t len = decInfo.numComponents * 3 + 8; // * rgb channel + other data
288    curPos = PutInt16(buffer, curPos, len);
289    if (curPos < 0) {
290        HDF_LOGE("assemble SOF len error");
291        return curPos;
292    }
293
294    int8_t precision = decInfo.dataPrecision & 0xFF;
295    curPos = PutInt8(buffer, curPos, precision);
296    if (curPos < 0) {
297        HDF_LOGE("assemble SOF precision error");
298        return curPos;
299    }
300
301    // width
302    int16_t width = decInfo.imageHeight & 0xFFFF;
303    curPos = PutInt16(buffer, curPos, width);
304    if (curPos < 0) {
305        HDF_LOGE("assemble SOF width error");
306        return curPos;
307    }
308
309    //  height
310    int16_t height = decInfo.imageWidth & 0xFFFF;
311    curPos = PutInt16(buffer, curPos, height);
312    if (curPos < 0) {
313        HDF_LOGE("assemble SOF width error");
314        return curPos;
315    }
316    // components
317    int8_t components = decInfo.numComponents & 0xFF;
318    curPos = PutInt8(buffer, curPos, components);
319    if (curPos < 0) {
320        HDF_LOGE("assemble SOF components error");
321        return curPos;
322    }
323    for (size_t i = 0; i < decInfo.compInfo.size(); i++) {
324        int8_t componentId = decInfo.compInfo[i].componentId;
325        // byte offset
326        int8_t sampFactor = ((decInfo.compInfo[i].hSampFactor & 0xFF) << 4) | (decInfo.compInfo[i].vSampFactor & 0xFF);
327        int8_t quantity = decInfo.compInfo[i].quantTableNo;
328        int8_t bufferValue[] = {componentId, sampFactor, quantity};
329        auto ret = memcpy_s(buffer + curPos, sizeof(bufferValue), bufferValue, sizeof(bufferValue));
330        if (ret != EOK) {
331            HDF_LOGE("assemble component error, ret = %{public}d", ret);
332            return ret;
333        }
334        curPos += sizeof(bufferValue);
335    }
336    return curPos;
337}
338int32_t CodecJpegHelper::JpegSosAssemble(const struct CodecJpegDecInfo &decInfo, int8_t *buffer, int32_t curPos)
339{
340    HDF_LOGI("enter. curPos = %{public}d", curPos);
341    // flag
342    curPos = PutInt16(buffer, curPos, 0xffda);
343    if (curPos < 0) {
344        HDF_LOGE("assemble SOS flag error");
345        return curPos;
346    }
347
348    int16_t len = decInfo.numComponents * 2 + 6; // * rgb table length + other data
349    curPos = PutInt16(buffer, curPos, len);
350    if (curPos < 0) {
351        HDF_LOGE("assemble SOS len error");
352        return curPos;
353    }
354
355    int8_t components = decInfo.numComponents & 0xFF;
356    curPos = PutInt8(buffer, curPos, components);
357    if (curPos < 0) {
358        HDF_LOGE("assemble SOS components error");
359        return curPos;
360    }
361
362    for (size_t i = 0; i < decInfo.compInfo.size(); i++) {
363        int8_t componentId = decInfo.compInfo[i].componentId;
364        int8_t indexNo = ((decInfo.compInfo[i].dcTableNo & 0xFF) << 4) | (decInfo.compInfo[i].acTableNo & 0xFF);
365        int16_t value = ((componentId << 8) | indexNo) & 0xffff;
366        curPos = PutInt16(buffer, curPos, value);
367        if (curPos < 0) {
368            HDF_LOGE("assemble SOS component value error");
369            return curPos;
370        }
371    }
372    int8_t dataStart[] = {0x00, 0x3F, 0x00};
373    auto ret = memcpy_s(buffer + curPos, sizeof(dataStart), dataStart, sizeof(dataStart));
374    if (ret != EOK) {
375        HDF_LOGE("assemble SOS data flag error, ret = %{public}d", ret);
376        return ret;
377    }
378    curPos += sizeof(dataStart);
379    return curPos;
380}
381int32_t CodecJpegHelper::JpegDataAssemble(int8_t *buffer, int32_t curPos, int32_t fd)
382{
383    HDF_LOGI("enter. curPos = %{public}d", curPos);
384    int32_t size = OHOS::AshmemGetSize(fd);
385    HDF_LOGI("get size %{public}d from fd %{public}d", size, fd);
386    OHOS::Ashmem mem(fd, size);
387    // check ret value
388    mem.MapReadOnlyAshmem();
389    auto addr = const_cast<void *>(mem.ReadFromAshmem(0, 0));
390    auto ret = memcpy_s(buffer + curPos, size, addr, size);
391    if (ret != EOK) {
392        HDF_LOGE("assemble compressed data error, ret = %{public}d", ret);
393        mem.UnmapAshmem();
394        if (ret > 0) {
395            return -ret;
396        }
397        return ret;
398    }
399    mem.UnmapAshmem();
400    mem.CloseAshmem();
401    curPos += size;
402    return curPos;
403}
404
405int32_t CodecJpegHelper::DessambleSof(int8_t *buffer, struct CodecJpegDecInfo &decInfo)
406{
407    HDF_LOGI("dessamble SOI");
408    // len
409    int32_t len = GetInt16(buffer);
410    buffer += 2;  // 2: marker len
411    // precision
412    decInfo.dataPrecision = GetInt8(buffer);
413    buffer++;
414    // height
415    decInfo.imageHeight = GetInt16(buffer);
416    buffer += 2;  // 2: height len
417    // width
418    decInfo.imageWidth = GetInt16(buffer);
419    buffer += 2;  // 2: width len
420
421    decInfo.numComponents = GetInt8(buffer);
422    buffer++;
423
424    HDF_LOGI("image width[%{public}d],height[%{public}d],components[%{public}d]", decInfo.imageWidth,
425        decInfo.imageHeight, decInfo.numComponents);
426    for (size_t i = 0; i < decInfo.numComponents; i++) {
427        CodecJpegCompInfo comInfo;
428
429        comInfo.infoFlag = true;
430        comInfo.componentId = GetInt8(buffer);
431        buffer++;
432
433        int8_t sampFactor = GetInt8(buffer);
434        buffer++;
435        comInfo.hSampFactor = (sampFactor >> 4) & 0xFF;  // 4: hsampfactor offset
436        comInfo.vSampFactor = sampFactor & 0x0F;
437
438        comInfo.quantTableNo = GetInt8(buffer);
439        buffer++;
440        decInfo.compInfo.push_back(std::move(comInfo));
441        HDF_LOGI("componentId[%{public}d],hSampFactor[%{public}d],vSampFactor[%{public}d],quantTableNo[%{public}d]",
442            comInfo.componentId, comInfo.hSampFactor, comInfo.vSampFactor, comInfo.quantTableNo);
443    }
444    return len;
445}
446int32_t CodecJpegHelper::DessambleSos(int8_t *buffer, struct CodecJpegDecInfo &decInfo)
447{
448    HDF_LOGI("dessamble SOS");
449    int32_t len = GetInt16(buffer);
450    buffer += 2;  // 2:marker len
451
452    int32_t components = GetInt8(buffer);
453    buffer++;
454
455    for (int32_t i = 0; i < components; i++) {
456        decInfo.compInfo[i].infoFlag = true;
457
458        int32_t componentId = GetInt8(buffer);
459        (void)componentId;
460        buffer++;
461        // index not used
462        auto data = GetInt8(buffer);
463        buffer++;
464        decInfo.compInfo[i].dcTableNo = (data >> 4) & 0x0F;  // 4: dctable offset
465        decInfo.compInfo[i].acTableNo = data & 0x0F;
466        HDF_LOGI("componentId[%{public}d],dcTableNo[%{public}d],acTableNo[%{public}d]", componentId,
467            decInfo.compInfo[i].dcTableNo, decInfo.compInfo[i].acTableNo);
468    }
469    buffer += 3;  // skip 0x003F00
470    return len;
471}
472int32_t CodecJpegHelper::DessambleCompressData(int8_t *buffer, std::unique_ptr<int8_t[]> &compressBuffer,
473                                               uint32_t &comBufLen)
474{
475    int8_t *dataStart = buffer;
476    do {
477        int32_t v = GetInt8(buffer);
478        buffer++;
479        if (v != 0xff) {
480            continue;
481        }
482        v = GetInt8(buffer);
483        buffer++;
484        if (v != 0xd9) {
485            continue;
486        }
487        buffer -= 2;  // 2: marker len
488        break;
489    } while (1);
490    comBufLen = (int32_t)(buffer - dataStart) + 1;
491    compressBuffer = std::make_unique<int8_t[]>(comBufLen);
492    auto ret = memcpy_s(compressBuffer.get(), comBufLen, dataStart, comBufLen);
493    if (ret != EOK) {
494        HDF_LOGE("copy compressed data error, dataLen %{public}d, ret %{public}d", comBufLen, ret);
495        compressBuffer = nullptr;
496        return ret;
497    }
498    return comBufLen;
499}
500int32_t CodecJpegHelper::DessambleDqt(int8_t *buffer, struct CodecJpegDecInfo &decInfo)
501{
502    HDF_LOGI("dessamble DQT");
503    int8_t *bufferOri = buffer;
504    int32_t len = GetInt16(buffer);
505    buffer += 2;  // 2: marker len
506    // maybe has more dqt table
507    while ((buffer - bufferOri) < len) {
508        auto data = GetInt8(buffer);
509        buffer++;
510        int32_t tableId = data & 0x000f;
511        (void)tableId;
512        int32_t size = 64;
513        CodecJpegQuantTable table;
514        table.tableFlag = true;
515        table.quantVal.resize(size);
516        std::vector<uint16_t> mtx;
517        HDF_LOGI("tableid[%{public}d]", tableId);
518        for (int32_t i = 0; i < size; i++) {
519            if (((data >> 4) & 0x0f) == 1) { // 4: low 4 bits, 1: for 16 bits
520                mtx.push_back(static_cast<int16_t>(GetInt16(buffer)));
521                buffer += 2;  // 2: data offset
522            } else {
523                mtx.push_back(static_cast<int8_t>(GetInt8(buffer)));
524                buffer += 1;  // 1: data offset
525            }
526        }
527        // unzigzag quant table
528        for (int32_t i = 0; i < size; i++) {
529            table.quantVal[i] = mtx[UnZigZagTable[i]];
530        }
531        decInfo.quantTbl.push_back(std::move(table));
532    }
533    return len;
534}
535int32_t CodecJpegHelper::DessambleDht(int8_t *buffer, struct CodecJpegDecInfo &decInfo)
536{
537    HDF_LOGI("dessamble DHT");
538    int8_t *bufferOri = buffer;
539    int32_t len = GetInt16(buffer);
540    buffer += 2;  // 2: marker len
541    // 可能存在多个表在同一个dht marker 中
542    while ((buffer - bufferOri) < len) {
543        auto data = GetInt8(buffer);
544        buffer++;
545        int32_t tableId = data & 0x000f;
546        (void)tableId;
547        int32_t acOrDc = (data >> 4) & 0x0f;  // 0:DC, 1:AC, 4: ac/dc data offset
548        CodecJpegHuffTable table;
549        table.tableFlag = true;
550        int32_t num = 0;
551        for (size_t i = 0; i < 16; i++) {  // 16: Data size
552            auto data = GetInt8(buffer);
553            buffer++;
554            table.bits.push_back(data);
555            num += data & 0x00ff;
556        }
557        HDF_LOGI("tableid[%{public}d], acOrDc[%{public}d], num[%{public}d]", tableId, acOrDc, num);
558        // val
559        for (int32_t i = 0; i < num; i++) {
560            table.huffVal.push_back(*buffer++);
561        }
562        if (acOrDc == 1) {
563            decInfo.acHuffTbl.push_back(std::move(table));
564        } else {
565            decInfo.dcHuffTbl.push_back(std::move(table));
566        }
567    }
568    return len;
569}
570
571int32_t CodecJpegHelper::FindMarker(int8_t *start)
572{
573    int32_t marker = GetInt16(start);
574    return marker;
575}
576
577int32_t CodecJpegHelper::PutInt16(int8_t *buffer, int32_t curPos, int16_t value)
578{
579    int8_t data[] = {value >> 8, value & 0xFF};
580    auto ret = memcpy_s(buffer + curPos, sizeof(data), data, sizeof(data));
581    if (ret != EOK) {
582        HDF_LOGE("memcpy ret err %{public}d", ret);
583        return -1;
584    }
585    return curPos + sizeof(data);
586}
587
588int32_t CodecJpegHelper::PutInt8(int8_t *buffer, int32_t curPos, int8_t value)
589{
590    auto ret = memcpy_s(buffer + curPos, sizeof(value), &value, sizeof(value));
591    if (ret != EOK) {
592        HDF_LOGE("memcpy ret err %{public}d", ret);
593        return -1;
594    }
595    return curPos + sizeof(value);
596}
597
598int32_t CodecJpegHelper::GetInt8(int8_t *buffer)
599{
600    return buffer[0] & 0x00ff;
601}
602
603int32_t CodecJpegHelper::GetInt16(int8_t *buffer)
604{
605    return ((buffer[0] << 8) & 0x00ff00) | (buffer[1] & 0x00ff);  // 8:data offset
606}
607