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