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( ...@@ -154,9 +154,17 @@ void VaapiJpegEncodeAccelerator::Encoder::EncodeTask(
exif_buffer = static_cast<uint8_t*>(request->exif_shm->memory()); exif_buffer = static_cast<uint8_t*>(request->exif_shm->memory());
exif_buffer_size = request->exif_shm->size(); exif_buffer_size = request->exif_shm->size();
} }
if (!jpeg_encoder_->Encode(input_size, exif_buffer, exif_buffer_size,
request->quality, va_surface_id, // When the exif buffer contains a thumbnail, the VAAPI encoder would
cached_output_buffer_id_)) { // 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"; VLOGF(1) << "Encode JPEG failed";
notify_error_cb_.Run(buffer_id, PLATFORM_FAILURE); notify_error_cb_.Run(buffer_id, PLATFORM_FAILURE);
return; return;
...@@ -173,6 +181,10 @@ void VaapiJpegEncodeAccelerator::Encoder::EncodeTask( ...@@ -173,6 +181,10 @@ void VaapiJpegEncodeAccelerator::Encoder::EncodeTask(
notify_error_cb_.Run(buffer_id, PLATFORM_FAILURE); 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); video_frame_ready_cb_.Run(buffer_id, encoded_size);
} }
......
...@@ -174,7 +174,8 @@ size_t FillJpegHeader(const gfx::Size& input_size, ...@@ -174,7 +174,8 @@ size_t FillJpegHeader(const gfx::Size& input_size,
const uint8_t* exif_buffer, const uint8_t* exif_buffer,
size_t exif_buffer_size, size_t exif_buffer_size,
int quality, int quality,
uint8_t* header) { uint8_t* header,
size_t* exif_offset) {
unsigned int width = input_size.width(); unsigned int width = input_size.width();
unsigned int height = input_size.height(); unsigned int height = input_size.height();
...@@ -193,6 +194,7 @@ size_t FillJpegHeader(const gfx::Size& input_size, ...@@ -193,6 +194,7 @@ size_t FillJpegHeader(const gfx::Size& input_size,
static_cast<uint8_t>(exif_segment_size % 256)}; static_cast<uint8_t>(exif_segment_size % 256)};
memcpy(header + idx, kAppSegment, sizeof(kAppSegment)); memcpy(header + idx, kAppSegment, sizeof(kAppSegment));
idx += sizeof(kAppSegment); idx += sizeof(kAppSegment);
*exif_offset = idx;
memcpy(header + idx, exif_buffer, exif_buffer_size); memcpy(header + idx, exif_buffer, exif_buffer_size);
idx += exif_buffer_size; idx += exif_buffer_size;
} else { } else {
...@@ -369,7 +371,8 @@ bool VaapiJpegEncoder::Encode(const gfx::Size& input_size, ...@@ -369,7 +371,8 @@ bool VaapiJpegEncoder::Encode(const gfx::Size& input_size,
size_t exif_buffer_size, size_t exif_buffer_size,
int quality, int quality,
VASurfaceID surface_id, VASurfaceID surface_id,
VABufferID output_buffer_id) { VABufferID output_buffer_id,
size_t* exif_offset) {
DCHECK_NE(surface_id, VA_INVALID_SURFACE); DCHECK_NE(surface_id, VA_INVALID_SURFACE);
if (input_size.width() > kMaxDimension || if (input_size.width() > kMaxDimension ||
...@@ -421,8 +424,9 @@ bool VaapiJpegEncoder::Encode(const gfx::Size& input_size, ...@@ -421,8 +424,9 @@ bool VaapiJpegEncoder::Encode(const gfx::Size& input_size,
? kJpegDefaultHeaderSize + exif_buffer_size ? kJpegDefaultHeaderSize + exif_buffer_size
: kJpegDefaultHeaderSize + kJFIFApp0Size; : kJpegDefaultHeaderSize + kJFIFApp0Size;
jpeg_header.resize(jpeg_header_size); jpeg_header.resize(jpeg_header_size);
size_t length_in_bits = FillJpegHeader( size_t length_in_bits =
input_size, exif_buffer, exif_buffer_size, quality, jpeg_header.data()); FillJpegHeader(input_size, exif_buffer, exif_buffer_size, quality,
jpeg_header.data(), exif_offset);
VAEncPackedHeaderParameterBuffer header_param; VAEncPackedHeaderParameterBuffer header_param;
memset(&header_param, 0, sizeof(header_param)); memset(&header_param, 0, sizeof(header_param));
......
...@@ -40,13 +40,15 @@ class MEDIA_GPU_EXPORT VaapiJpegEncoder { ...@@ -40,13 +40,15 @@ class MEDIA_GPU_EXPORT VaapiJpegEncoder {
// |output_buffer_id| is the ID of VA buffer that encoded image will be // |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 // stored. The size of it should be at least as large as
// GetMaxCodedBufferSize(). // GetMaxCodedBufferSize().
// |exif_offset| is the offset where Exif data should be filled into.
// Return false on failure. // Return false on failure.
bool Encode(const gfx::Size& input_size, bool Encode(const gfx::Size& input_size,
const uint8_t* exif_buffer, const uint8_t* exif_buffer,
size_t exif_buffer_size, size_t exif_buffer_size,
int quality, int quality,
VASurfaceID surface_id, VASurfaceID surface_id,
VABufferID output_buffer_id); VABufferID output_buffer_id,
size_t* exif_offset);
// Gets the maximum possible encoded result size. // Gets the maximum possible encoded result size.
// |size| is the dimension of the YUV image to be encoded. // |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