Пример использования libyuv API MJPGToI420()

Я пытаюсь использовать API libyuv, более конкретно 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_y, dst_u, а также dst_v указатели. Однако я не знаю, сколько места им выделять. Я также запутался в том, какими должны быть шаги, т. Е. Каковы параметры dst_stride_y, dst_stride_u а также dst_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;
}

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 имеют размер ((ширина + 1) / 2) * ((высота + 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

Другие вопросы по тегам