0

我正在尝试使用libyuv API,更具体地说MJPGToI420()

我想首先将 jpeg 图像作为输入MJPGToI420(),其签名如下:

int MJPGToI420(const uint8_t* sample,
               size_t sample_size,
               uint8_t* dst_y,
               int dst_stride_y,
               uint8_t* dst_u,
               int dst_stride_u,
               uint8_t* dst_v,
               int dst_stride_v,
               int src_width,
               int src_height,
               int dst_width,
               int dst_height);

然后,我想为dst_ydst_udst_v指针分配空间。但是,我不知道要为他们分配多少空间。我也对应该是什么步幅感到困惑,即参数和dst_stride_y应该是什么。dst_stride_udst_stride_v

非常感谢任何正确方向的指示。

编辑:这是使用此函数的libyuv单元测试中的一段代码。但是,测试返回 1,这是函数失败的预期行为。该测试也只对数据使用零,而不是实际的 MJPG 文件。

TEST_F(LibYUVConvertTest, MJPGToI420) {
  const int kOff = 10;
  const int kMinJpeg = 64;
  const int kImageSize = benchmark_width_ * benchmark_height_ >= kMinJpeg
                             ? benchmark_width_ * benchmark_height_
                             : kMinJpeg;
  const int kSize = kImageSize + kOff;
  align_buffer_page_end(orig_pixels, kSize);
  align_buffer_page_end(dst_y_opt, benchmark_width_ * benchmark_height_);
  align_buffer_page_end(dst_u_opt, SUBSAMPLE(benchmark_width_, 2) *
                                       SUBSAMPLE(benchmark_height_, 2));
  align_buffer_page_end(dst_v_opt, SUBSAMPLE(benchmark_width_, 2) *
                                       SUBSAMPLE(benchmark_height_, 2));

  // EOI, SOI to make MJPG appear valid.
  memset(orig_pixels, 0, kSize);
  orig_pixels[0] = 0xff;
  orig_pixels[1] = 0xd8;  // SOI.
  orig_pixels[kSize - kOff + 0] = 0xff;
  orig_pixels[kSize - kOff + 1] = 0xd9;  // EOI.

  for (int times = 0; times < benchmark_iterations_; ++times) {
    int ret =
        MJPGToI420(orig_pixels, kSize, dst_y_opt, benchmark_width_, dst_u_opt,
                   SUBSAMPLE(benchmark_width_, 2), dst_v_opt,
                   SUBSAMPLE(benchmark_width_, 2), benchmark_width_,
                   benchmark_height_, benchmark_width_, benchmark_height_);
    // Expect failure because image is not really valid.
    EXPECT_EQ(1, ret);
  }

  free_aligned_buffer_page_end(dst_y_opt);
  free_aligned_buffer_page_end(dst_u_opt);
  free_aligned_buffer_page_end(dst_v_opt);
  free_aligned_buffer_page_end(orig_pixels);
}

编辑 2:此外,这是我尝试过的,但是,最终的 yuv 文件甚至在 yuv 查看器(使用缓冲区dst_u_opt和创建dst_y_opt)中都无法查看,这让我相信我可能会搞砸功能:

int convertMJPGToI420() {

    auto fileSize = filesize(IMG_NAME);

    // load image into memory
    uint8_t* my_img = (uint8_t*) calloc(fileSize, 1);
    std::ifstream fin(IMG_NAME, ios::in | ios::binary);
    fin.read(reinterpret_cast<char*>(my_img), fileSize);

    // exif data offset 
    // This is the size of the exif data
    const int kOff = 4096;

    // 4k image is being sent in
    int benchmark_width_ = 3840;
    int benchmark_height_ = 2160;

    const int kSize = fileSize;

    // align_buffer_page_end is a macro (look at link posted for unit tests above)
    // I'm not sure if the size allocation for these is correct
    // I have tried to model it based off the example
    align_buffer_page_end(orig_pixels, kSize);
    align_buffer_page_end(dst_y_opt, benchmark_width_ * benchmark_height_);
    align_buffer_page_end(dst_u_opt, SUBSAMPLE(benchmark_width_, 2) * 
                                        SUBSAMPLE(benchmark_height_, 2));
    align_buffer_page_end(dst_v_opt, SUBSAMPLE(benchmark_width_, 2) * 
                                        SUBSAMPLE(benchmark_height_, 2));

    // EOI, SOI to make MJPG appear valid
    memset(orig_pixels, 0, kSize);
    orig_pixels[0] = 0xff;
    orig_pixels[1] = 0xd8; // SOI

    memcpy(orig_pixels + 2, my_img, kSize - kOff - 3);

    orig_pixels[kSize - kOff + 0] = 0xff;
    orig_pixels[kSize - kOff + 1] = 0xd9; // EOI

    // using async as this function might be ansynchronous
    std::future<int> ret = std::async(libyuv::MJPGToI420, orig_pixels, kSize, dst_y_opt, benchmark_width_,
                        dst_u_opt, SUBSAMPLE(benchmark_width_, 2),
                        dst_v_opt, SUBSAMPLE(benchmark_width_, 2), 
                        benchmark_width_, benchmark_height_, 
                        benchmark_width_, benchmark_height_);

    ret.wait();

    // ret is always one, which means there was a failure
    if(ret.get() == 0) {
        cout << "return value was zero" << endl;
    } else {
        cout << "return value was one" << endl;
    }

    FILE* file = fopen("/data/dst_u_opt", "wb");
    fwrite(dst_y_opt, 1, SUBSAMPLE(benchmark_width_, 2) * SUBSAMPLE(benchmark_height_, 2) , file);
    fclose(file);

    file = fopen("/data/dst_v_opt", "wb");
    fwrite(dst_y_opt, 1, SUBSAMPLE(benchmark_width_, 2) *  SUBSAMPLE(benchmark_height_, 2), file);
    fclose(file);

    free_aligned_buffer_page_end(dst_y_opt);
    free_aligned_buffer_page_end(dst_u_opt);
    free_aligned_buffer_page_end(dst_v_opt);
    free_aligned_buffer_page_end(orig_pixels);

    return 0;
}
4

1 回答 1

1

您需要知道 jpeg 的宽度和高度。

I420 是 420 次采样的 YUV。Y 平面是宽度 * 高度(以字节为单位)。dst_stride_y 值是宽度,例如

char* dst_y = malloc(width * height);

U 和 V 平面是宽度和高度的一半。要处理奇数大小,您应该四舍五入。

dst_stride_u = (width + 1) / 2;
dst_stride_v = (width + 1) / 2;

u 和 v 平面是 ((width + 1) / 2) * ((height + 1) / 2) 字节。

char* dst_u = malloc(((width + 1) / 2) * ((height + 1) / 2));
char* dst_y = malloc(((width + 1) / 2) * ((height + 1) / 2));

如果您想提交问题,包括更好的文档,请在此处发布: https ://bugs.chromium.org/p/libyuv/issues/list

于 2018-08-02T00:20:46.820 回答