libyuv API MJPGToI420() 的用法示例
Example usage of a libyuv API MJPGToI420()
我正在尝试使用 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_y
、dst_u
和dst_v
指针分配space。但是,我不知道要分配给他们多少space。我也对步幅应该是什么感到困惑,即参数 dst_stride_y
、dst_stride_u
和 dst_stride_v
应该是什么。
非常感谢任何正确方向的指示。
编辑: 这是来自 libyuv
来源 unit tests 的一段使用此函数的代码。但是,测试 returns 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;
}
您需要知道 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));
如果您想提交问题,包括更好的文档,post 在这里:
https://bugs.chromium.org/p/libyuv/issues/list
我正在尝试使用 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_y
、dst_u
和dst_v
指针分配space。但是,我不知道要分配给他们多少space。我也对步幅应该是什么感到困惑,即参数 dst_stride_y
、dst_stride_u
和 dst_stride_v
应该是什么。
非常感谢任何正确方向的指示。
编辑: 这是来自 libyuv
来源 unit tests 的一段使用此函数的代码。但是,测试 returns 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;
}
您需要知道 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));
如果您想提交问题,包括更好的文档,post 在这里: https://bugs.chromium.org/p/libyuv/issues/list