Commit 62e06800 authored by Sheng-Hao Tsao's avatar Sheng-Hao Tsao Committed by Commit Bot

Fix a bug that VAAPI JEA generates corrupted JPEG

VAAPI JEA generates incorrect encoded image when the APP1 segment in the
header has a thumbnail image. This CL works around the problem by
providing an all-zero APP1 buffer with the same size and fill in the
real APP1 buffer data after the encode is done.

BUG=b:79840013
TEST=Verified on nautilus that GCA can take photos.

Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: Ic8dd17487a03af7a881a6d2804baee73bbbd13a1
Reviewed-on: https://chromium-review.googlesource.com/1061277Reviewed-by: default avatarRicky Liang <jcliang@chromium.org>
Commit-Queue: Sheng-hao Tsao <shenghao@google.com>
Cr-Commit-Position: refs/heads/master@{#559436}
parent 68a56878
......@@ -154,9 +154,17 @@ void VaapiJpegEncodeAccelerator::Encoder::EncodeTask(
exif_buffer = static_cast<uint8_t*>(request->exif_shm->memory());
exif_buffer_size = request->exif_shm->size();
}
if (!jpeg_encoder_->Encode(input_size, exif_buffer, exif_buffer_size,
request->quality, va_surface_id,
cached_output_buffer_id_)) {
// When the exif buffer contains a thumbnail, the VAAPI encoder would
// generate a corrupted JPEG. We can work around the problem by supplying an
// all-zero buffer with the same size and fill in the real exif buffer after
// encoding.
// TODO(shenghao): Remove this mechanism after b/79840013 is fixed.
std::vector<uint8_t> exif_buffer_dummy(exif_buffer_size, 0);
size_t exif_offset = 0;
if (!jpeg_encoder_->Encode(input_size, exif_buffer_dummy.data(),
exif_buffer_size, request->quality, va_surface_id,
cached_output_buffer_id_, &exif_offset)) {
VLOGF(1) << "Encode JPEG failed";
notify_error_cb_.Run(buffer_id, PLATFORM_FAILURE);
return;
......@@ -173,6 +181,10 @@ void VaapiJpegEncodeAccelerator::Encoder::EncodeTask(
notify_error_cb_.Run(buffer_id, PLATFORM_FAILURE);
}
// Copy the real exif buffer into preserved space.
memcpy(static_cast<uint8_t*>(request->output_shm->memory()) + exif_offset,
exif_buffer, exif_buffer_size);
video_frame_ready_cb_.Run(buffer_id, encoded_size);
}
......
......@@ -174,7 +174,8 @@ size_t FillJpegHeader(const gfx::Size& input_size,
const uint8_t* exif_buffer,
size_t exif_buffer_size,
int quality,
uint8_t* header) {
uint8_t* header,
size_t* exif_offset) {
unsigned int width = input_size.width();
unsigned int height = input_size.height();
......@@ -193,6 +194,7 @@ size_t FillJpegHeader(const gfx::Size& input_size,
static_cast<uint8_t>(exif_segment_size % 256)};
memcpy(header + idx, kAppSegment, sizeof(kAppSegment));
idx += sizeof(kAppSegment);
*exif_offset = idx;
memcpy(header + idx, exif_buffer, exif_buffer_size);
idx += exif_buffer_size;
} else {
......@@ -369,7 +371,8 @@ bool VaapiJpegEncoder::Encode(const gfx::Size& input_size,
size_t exif_buffer_size,
int quality,
VASurfaceID surface_id,
VABufferID output_buffer_id) {
VABufferID output_buffer_id,
size_t* exif_offset) {
DCHECK_NE(surface_id, VA_INVALID_SURFACE);
if (input_size.width() > kMaxDimension ||
......@@ -421,8 +424,9 @@ bool VaapiJpegEncoder::Encode(const gfx::Size& input_size,
? kJpegDefaultHeaderSize + exif_buffer_size
: kJpegDefaultHeaderSize + kJFIFApp0Size;
jpeg_header.resize(jpeg_header_size);
size_t length_in_bits = FillJpegHeader(
input_size, exif_buffer, exif_buffer_size, quality, jpeg_header.data());
size_t length_in_bits =
FillJpegHeader(input_size, exif_buffer, exif_buffer_size, quality,
jpeg_header.data(), exif_offset);
VAEncPackedHeaderParameterBuffer header_param;
memset(&header_param, 0, sizeof(header_param));
......
......@@ -40,13 +40,15 @@ class MEDIA_GPU_EXPORT VaapiJpegEncoder {
// |output_buffer_id| is the ID of VA buffer that encoded image will be
// stored. The size of it should be at least as large as
// GetMaxCodedBufferSize().
// |exif_offset| is the offset where Exif data should be filled into.
// Return false on failure.
bool Encode(const gfx::Size& input_size,
const uint8_t* exif_buffer,
size_t exif_buffer_size,
int quality,
VASurfaceID surface_id,
VABufferID output_buffer_id);
VABufferID output_buffer_id,
size_t* exif_offset);
// Gets the maximum possible encoded result size.
// |size| is the dimension of the YUV image to be encoded.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment