【鸿蒙使用libjpeg-turbo库将RGB888格式图像转换为MJPEG(Motion JPEG)格式】

鸿蒙使用libjpeg-turbo库将RGB888格式图像转换为MJPEG(Motion JPEG)格式,本质上是将单帧RGB数据压缩为JPEG格式,作为视频流的一帧。

libjpeg-turbo提供了两种API:传统的libjpeg接口和更高效的TurboJPEG接口。推荐使用TurboJPEG接口(turbojpeg.h),因其代码更简洁且性能更高。关键函数为tjCompress2,其参数包括输入数据、宽高、像素格式、压缩质量等。
以下是实现此功能的核心步骤及代码示例:

static napi_value compress_rgb_to_jpeg(napi_env env, napi_callback_info info) {
    napi_value result;
    int ret; // 传出
    // 传入参数
    int rgbWidth, rgbHeight;
    size_t argc = 4;
    napi_value args[4] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    // 检查参数是否为 Uint8Array
    napi_typedarray_type arrayType;
    int data_size;
    void *rgb_data;
    napi_value arrayBuffer;
    size_t byteOffset;
    napi_get_value_int32(env, args[0], &data_size);
    size_t length = data_size;
    napi_get_typedarray_info(env, args[1], &arrayType, &length, &rgb_data, &arrayBuffer, &byteOffset);
    if (arrayType != napi_uint8_array) {
        napi_throw_error(env, nullptr, "Expected Uint8Array");
        return nullptr;
    }

    napi_get_value_int32(env, args[2], &rgbWidth);
    napi_get_value_int32(env, args[3], &rgbHeight);

    tjhandle handle = tjInitCompress();
    if (!handle) {
        napi_create_int32(env, -1, &result);
        return result;
    }
    unsigned char *jpeg_data = nullptr;
    unsigned long jpeg_size = 0;

    // 像素格式设为RGB(TJPF_RGB对应RGB888)
    ret = tjCompress2(handle, (unsigned char *)rgb_data, rgbWidth, 0, rgbHeight, TJPF_RGB, &jpeg_data, &jpeg_size,
                      TJSAMP_444, 90, TJFLAG_FASTDCT);
    if (ret == 0) {
        // 将jpeg_data写入文件或流(MJPEG流需连续调用此函数处理每一帧)
        napi_create_object(env, &result);
        napi_value width, height, size, data;
        napi_create_int32(env, rgbWidth, &width);
        napi_create_int32(env, rgbHeight, &height);
        napi_create_int32(env, jpeg_size, &size);
        napi_set_named_property(env, result, "width", width);
        napi_set_named_property(env, result, "height", height);
        napi_set_named_property(env, result, "size", size);

        saveFile("/data/storage/el2/base/haps/entry/files/test.jpg", jpeg_data, jpeg_size);

        int length = jpeg_size;
        void *dataTmp = malloc(length);
        napi_value buffer = nullptr;
        napi_create_arraybuffer(env, length, &dataTmp, &buffer);
        memcpy(dataTmp, (void *)jpeg_data, length);
        napi_create_typedarray(env, napi_uint8_array, length, buffer, 0, &data);
        napi_set_named_property(env, result, "data", data);
    }
    tjFree(jpeg_data); // 释放内存
    tjDestroy(handle);
    return result;
}

预览页面上使用createPixelMap进行绘制

  private source_opts: image.SourceOptions = {
    sourceDensity: 120,
    sourcePixelFormat: image.PixelMapFormat.RGBA_8888,
    sourceSize: { width: 480, height: 640 }
  };
  private decodingOptions?: image.DecodingOptions = {
    sampleSize: 1,
    editable: true,
    desiredSize: { width: 480, height: 640 },
    desiredPixelFormat: image.PixelMapFormat.RGBA_8888,
    desiredRegion: { size: { height: 640, width: 480 }, x: 0, y: 0 },
    index: 0
  };
async getColorImageData2(imageData: Uint8Array) {
    console.debug(TAG, "getColorImageData buffer:" + imageData);
    let imageSource = image.createImageSource(imageData.buffer.slice(0), this.source_opts);
    console.debug(TAG, "getColorImageData imageSource:" + imageData.buffer);
    console.debug(TAG, "imageSource:" + JSON.stringify(imageSource));
    let num = imageSource.getFrameCount();
    console.debug(TAG, "num:" + num);
    //
    try {
      if (this.showRgbMutex.tryLock()) {
        imageSource.createPixelMap(this.decodingOptions , (err: BusinessError, pixelMap: image.PixelMap) => {
          if (err != undefined) {
            console.error(TAG, `Failed to create pixelMap.code is ${err.code},message is ${err.message}`);
            console.error(TAG, "Failed to create pixelMap.code:" + err);
            console.error(TAG, "Failed to create pixelMap :" + JSON.stringify(pixelMap));
          } else {
            console.info('Succeeded in creating pixelMap object.');
            this.canvasContext.drawImage(pixelMap, 0, 0, px2vp(480), px2vp(640));
            imageSource.release();
            pixelMap.release();
            this.showRgbMutex.unlock();
          }
        });
      }
    } catch (e) {
      console.error(TAG, "createPixelMap error" + e);
    }
  }

你可能感兴趣的:(harmonyos,华为)