diff options
Diffstat (limited to 'chromium/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc')
-rw-r--r-- | chromium/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc | 363 |
1 files changed, 179 insertions, 184 deletions
diff --git a/chromium/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc b/chromium/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc index f436784d6ca..cf551b2f827 100644 --- a/chromium/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc +++ b/chromium/media/gpu/vaapi/vaapi_mjpeg_decode_accelerator.cc @@ -24,14 +24,15 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" #include "gpu/ipc/common/gpu_memory_buffer_impl.h" -#include "gpu/ipc/common/gpu_memory_buffer_support.h" #include "media/base/bind_to_current_loop.h" #include "media/base/bitstream_buffer.h" #include "media/base/format_utils.h" #include "media/base/unaligned_shared_memory.h" #include "media/base/video_frame.h" #include "media/base/video_frame_layout.h" +#include "media/base/video_util.h" #include "media/gpu/chromeos/fourcc.h" +#include "media/gpu/chromeos/libyuv_image_processor_backend.h" #include "media/gpu/chromeos/platform_video_frame_utils.h" #include "media/gpu/macros.h" #include "media/gpu/vaapi/va_surface.h" @@ -39,7 +40,6 @@ #include "media/gpu/vaapi/vaapi_utils.h" #include "media/gpu/vaapi/vaapi_wrapper.h" #include "third_party/abseil-cpp/absl/types/optional.h" -#include "third_party/libyuv/include/libyuv.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/gpu_memory_buffer.h" @@ -48,15 +48,15 @@ namespace media { namespace { -static void ReportToVAJDAResponseToClientUMA( +void ReportToVAJDAResponseToClientUMA( chromeos_camera::MjpegDecodeAccelerator::Error response) { UMA_HISTOGRAM_ENUMERATION( "Media.VAJDA.ResponseToClient", response, chromeos_camera::MjpegDecodeAccelerator::Error::MJDA_ERROR_CODE_MAX + 1); } -static chromeos_camera::MjpegDecodeAccelerator::Error -VaapiJpegDecodeStatusToError(VaapiImageDecodeStatus status) { +chromeos_camera::MjpegDecodeAccelerator::Error VaapiJpegDecodeStatusToError( + VaapiImageDecodeStatus status) { switch (status) { case VaapiImageDecodeStatus::kSuccess: return chromeos_camera::MjpegDecodeAccelerator::Error::NO_ERRORS; @@ -69,7 +69,7 @@ VaapiJpegDecodeStatusToError(VaapiImageDecodeStatus status) { } } -static bool VerifyDataSize(const VAImage* image) { +bool VerifyDataSize(const VAImage* image) { const gfx::Size dimensions(base::strict_cast<int>(image->width), base::strict_cast<int>(image->height)); size_t min_size = 0; @@ -85,6 +85,7 @@ static bool VerifyDataSize(const VAImage* image) { } return base::strict_cast<size_t>(image->data_size) >= min_size; } + } // namespace void VaapiMjpegDecodeAccelerator::NotifyError(int32_t task_id, Error error) { @@ -119,12 +120,13 @@ VaapiMjpegDecodeAccelerator::VaapiMjpegDecodeAccelerator( decoder_thread_("VaapiMjpegDecoderThread"), weak_this_factory_(this) {} -// Destroy |decoder_| and |vpp_vaapi_wrapper_| on |decoder_thread_|. +// Some members expect to be destroyed on the |decoder_thread_|. void VaapiMjpegDecodeAccelerator::CleanUpOnDecoderThread() { DCHECK(decoder_task_runner_->BelongsToCurrentThread()); DCHECK(vpp_vaapi_wrapper_->HasOneRef()); vpp_vaapi_wrapper_.reset(); decoder_.reset(); + image_processor_.reset(); } VaapiMjpegDecodeAccelerator::~VaapiMjpegDecodeAccelerator() { @@ -153,6 +155,7 @@ void VaapiMjpegDecodeAccelerator::InitializeOnDecoderTaskRunner( "Media.VaapiMjpegDecodeAccelerator.VAAPIError"))) { VLOGF(1) << "Failed initializing |decoder_|"; std::move(init_cb).Run(false); + return; } vpp_vaapi_wrapper_ = VaapiWrapper::Create( @@ -163,12 +166,14 @@ void VaapiMjpegDecodeAccelerator::InitializeOnDecoderTaskRunner( if (!vpp_vaapi_wrapper_) { VLOGF(1) << "Failed initializing VAAPI for VPP"; std::move(init_cb).Run(false); + return; } // Size is irrelevant for a VPP context. if (!vpp_vaapi_wrapper_->CreateContext(gfx::Size())) { VLOGF(1) << "Failed to create context for VPP"; std::move(init_cb).Run(false); + return; } std::move(init_cb).Run(true); @@ -183,9 +188,9 @@ void VaapiMjpegDecodeAccelerator::InitializeOnTaskRunner( if (!decoder_thread_.Start()) { VLOGF(1) << "Failed to start decoding thread."; std::move(init_cb).Run(false); + return; } decoder_task_runner_ = decoder_thread_.task_runner(); - gpu_memory_buffer_support_ = std::make_unique<gpu::GpuMemoryBufferSupport>(); // base::Unretained() is fine here because we control |decoder_task_runner_| // lifetime. @@ -211,179 +216,142 @@ void VaapiMjpegDecodeAccelerator::InitializeAsync( BindToCurrentLoop(std::move(init_cb)))); } +void VaapiMjpegDecodeAccelerator::CreateImageProcessor( + const VideoFrame* src_frame, + const VideoFrame* dst_frame) { + DCHECK(decoder_task_runner_->BelongsToCurrentThread()); + + // The fourcc of |src_frame| will be either Fourcc(YUYV) or Fourcc(YU12) based + // on the implementation of OutputPictureLibYuvOnTaskRunner(). The fourcc of + // |dst_frame| should have been validated in DecodeImpl(). + const auto src_fourcc = Fourcc::FromVideoPixelFormat(src_frame->format()); + DCHECK(src_fourcc.has_value()); + const auto dst_fourcc = Fourcc::FromVideoPixelFormat(dst_frame->format()); + DCHECK(dst_fourcc.has_value()); + const ImageProcessorBackend::PortConfig input_config( + *src_fourcc, src_frame->coded_size(), src_frame->layout().planes(), + src_frame->visible_rect(), {src_frame->storage_type()}); + const ImageProcessorBackend::PortConfig output_config( + *dst_fourcc, dst_frame->coded_size(), dst_frame->layout().planes(), + dst_frame->visible_rect(), {dst_frame->storage_type()}); + if (image_processor_ && image_processor_->input_config() == input_config && + image_processor_->output_config() == output_config) { + return; + } + + // The error callback is posted to the same thread that + // LibYUVImageProcessorBackend::Create() is called on + // (i.e., |decoder_thread_|) and we control the lifetime of |decoder_thread_|. + // Therefore, base::Unretained(this) is safe. + image_processor_ = LibYUVImageProcessorBackend::Create( + input_config, output_config, {ImageProcessorBackend::OutputMode::IMPORT}, + VIDEO_ROTATION_0, + base::BindRepeating(&VaapiMjpegDecodeAccelerator::OnImageProcessorError, + base::Unretained(this)), + decoder_task_runner_); +} + bool VaapiMjpegDecodeAccelerator::OutputPictureLibYuvOnTaskRunner( + int32_t task_id, std::unique_ptr<ScopedVAImage> scoped_image, - int32_t input_buffer_id, - scoped_refptr<VideoFrame> video_frame) { + scoped_refptr<VideoFrame> video_frame, + const gfx::Rect& crop_rect) { DCHECK(decoder_task_runner_->BelongsToCurrentThread()); - TRACE_EVENT1("jpeg", __func__, "input_buffer_id", input_buffer_id); + TRACE_EVENT1("jpeg", __func__, "task_id", task_id); DCHECK(scoped_image); const VAImage* image = scoped_image->image(); - - // For camera captures, we assume that the visible size is the same as the - // coded size. - DCHECK_EQ(video_frame->visible_rect().size(), video_frame->coded_size()); - DCHECK_EQ(0, video_frame->visible_rect().x()); - DCHECK_EQ(0, video_frame->visible_rect().y()); - DCHECK(decoder_->GetScopedVASurface()); - const gfx::Size visible_size(base::strict_cast<int>(image->width), - base::strict_cast<int>(image->height)); - if (visible_size != video_frame->visible_rect().size()) { - VLOGF(1) << "The decoded visible size is not the same as the video frame's"; - return false; - } - - // The decoded image size is aligned up to JPEG MCU size, so it may be larger - // than |video_frame|'s visible size. - if (base::strict_cast<int>(image->width) < visible_size.width() || - base::strict_cast<int>(image->height) < visible_size.height()) { - VLOGF(1) << "Decoded image size is smaller than output frame size"; - return false; - } DCHECK(VerifyDataSize(image)); + const gfx::Size src_size(base::strict_cast<int>(image->width), + base::strict_cast<int>(image->height)); + DCHECK(gfx::Rect(src_size).Contains(crop_rect)); - // Extract source pointers and strides. - auto* const mem = - static_cast<const uint8_t*>(scoped_image->va_buffer()->data()); - std::array<const uint8_t*, VideoFrame::kMaxPlanes> src_ptrs{}; - std::array<int, VideoFrame::kMaxPlanes> src_strides{}; - for (uint32_t i = 0; i < image->num_planes; i++) { - src_ptrs[i] = mem + image->offsets[i]; + // Wrap |image| into VideoFrame. + std::vector<int32_t> strides(image->num_planes); + for (uint32_t i = 0; i < image->num_planes; ++i) { if (!base::CheckedNumeric<uint32_t>(image->pitches[i]) - .AssignIfValid(&src_strides[i])) { - VLOGF(1) << "Can't extract the strides"; - return false; - } - } - - // Extract destination pointers and strides. - std::array<uint8_t*, VideoFrame::kMaxPlanes> dst_ptrs{}; - std::array<int, VideoFrame::kMaxPlanes> dst_strides{}; - base::ScopedClosureRunner buffer_unmapper; - if (video_frame->HasDmaBufs()) { - // Dmabuf-backed frame needs to be mapped for SW access. - DCHECK(gpu_memory_buffer_support_); - absl::optional<gfx::BufferFormat> gfx_format = - VideoPixelFormatToGfxBufferFormat(video_frame->format()); - if (!gfx_format) { - VLOGF(1) << "Unsupported format: " << video_frame->format(); + .AssignIfValid(&strides[i])) { + VLOGF(1) << "Invalid VAImage stride " << image->pitches[i] + << " for plane " << i; return false; } - auto gmb_handle = CreateGpuMemoryBufferHandle(video_frame.get()); - DCHECK(!gmb_handle.is_null()); - std::unique_ptr<gpu::GpuMemoryBufferImpl> gmb = - gpu_memory_buffer_support_->CreateGpuMemoryBufferImplFromHandle( - std::move(gmb_handle), video_frame->coded_size(), *gfx_format, - gfx::BufferUsage::SCANOUT_CPU_READ_WRITE, base::DoNothing()); - if (!gmb) { - VLOGF(1) << "Failed to create GPU memory buffer"; - return false; - } - if (!gmb->Map()) { - VLOGF(1) << "Failed to map GPU memory buffer"; - return false; - } - for (size_t i = 0; i < video_frame->layout().num_planes(); i++) { - dst_ptrs[i] = static_cast<uint8_t*>(gmb->memory(i)); - dst_strides[i] = gmb->stride(i); - } - buffer_unmapper.ReplaceClosure( - base::BindOnce(&gpu::GpuMemoryBufferImpl::Unmap, std::move(gmb))); - } else { - DCHECK(video_frame->IsMappable()); - for (size_t i = 0; i < video_frame->layout().num_planes(); i++) { - dst_ptrs[i] = video_frame->visible_data(i); - dst_strides[i] = video_frame->stride(i); - } } - + auto* const data = static_cast<uint8_t*>(scoped_image->va_buffer()->data()); + scoped_refptr<VideoFrame> src_frame; switch (image->format.fourcc) { - case VA_FOURCC_I420: - DCHECK_EQ(image->num_planes, 3u); - switch (video_frame->format()) { - case PIXEL_FORMAT_I420: - DCHECK_EQ(video_frame->layout().num_planes(), 3u); - if (libyuv::I420Copy(src_ptrs[0], src_strides[0], src_ptrs[1], - src_strides[1], src_ptrs[2], src_strides[2], - dst_ptrs[0], dst_strides[0], dst_ptrs[1], - dst_strides[1], dst_ptrs[2], dst_strides[2], - visible_size.width(), visible_size.height())) { - VLOGF(1) << "I420Copy failed"; - return false; - } - break; - case PIXEL_FORMAT_NV12: - DCHECK_EQ(video_frame->layout().num_planes(), 2u); - if (libyuv::I420ToNV12(src_ptrs[0], src_strides[0], src_ptrs[1], - src_strides[1], src_ptrs[2], src_strides[2], - dst_ptrs[0], dst_strides[0], dst_ptrs[1], - dst_strides[1], visible_size.width(), - visible_size.height())) { - VLOGF(1) << "I420ToNV12 failed"; - return false; - } - break; - default: - VLOGF(1) << "Can't convert image from I420 to " - << video_frame->format(); - return false; + case VA_FOURCC_YUY2: + case VA_FOURCC('Y', 'U', 'Y', 'V'): { + auto layout = VideoFrameLayout::CreateWithStrides(PIXEL_FORMAT_YUY2, + src_size, strides); + if (!layout.has_value()) { + VLOGF(1) << "Failed to create video frame layout"; + return false; } + src_frame = VideoFrame::WrapExternalDataWithLayout( + *layout, crop_rect, crop_rect.size(), data + image->offsets[0], + base::strict_cast<size_t>(image->data_size), base::TimeDelta()); break; - case VA_FOURCC_YUY2: - case VA_FOURCC('Y', 'U', 'Y', 'V'): - DCHECK_EQ(image->num_planes, 1u); - switch (video_frame->format()) { - case PIXEL_FORMAT_I420: - DCHECK_EQ(video_frame->layout().num_planes(), 3u); - if (libyuv::YUY2ToI420(src_ptrs[0], src_strides[0], dst_ptrs[0], - dst_strides[0], dst_ptrs[1], dst_strides[1], - dst_ptrs[2], dst_strides[2], - visible_size.width(), visible_size.height())) { - VLOGF(1) << "YUY2ToI420 failed"; - return false; - } - break; - case PIXEL_FORMAT_NV12: - DCHECK_EQ(video_frame->layout().num_planes(), 2u); - if (libyuv::YUY2ToNV12(src_ptrs[0], src_strides[0], dst_ptrs[0], - dst_strides[0], dst_ptrs[1], dst_strides[1], - visible_size.width(), visible_size.height())) { - VLOGF(1) << "YUY2ToNV12 failed"; - return false; - } - break; - default: - VLOGF(1) << "Can't convert image from YUYV to " - << video_frame->format(); - return false; + } + case VA_FOURCC_I420: { + auto layout = VideoFrameLayout::CreateWithStrides(PIXEL_FORMAT_I420, + src_size, strides); + if (!layout.has_value()) { + VLOGF(1) << "Failed to create video frame layout"; + return false; } + src_frame = VideoFrame::WrapExternalYuvDataWithLayout( + *layout, crop_rect, crop_rect.size(), data + image->offsets[0], + data + image->offsets[1], data + image->offsets[2], + base::TimeDelta()); break; + } default: - VLOGF(1) << "Can't convert image from " - << FourccToString(image->format.fourcc) << " to " - << video_frame->format(); + VLOGF(1) << "Unsupported VA image format: " + << FourccToString(image->format.fourcc); return false; } + if (!src_frame) { + VLOGF(1) << "Failed to create video frame"; + return false; + } - task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&VaapiMjpegDecodeAccelerator::VideoFrameReady, - weak_this_factory_.GetWeakPtr(), input_buffer_id)); - + CreateImageProcessor(src_frame.get(), video_frame.get()); + if (!image_processor_) { + VLOGF(1) << "Failed to create image processor"; + return false; + } + image_processor_->Process( + std::move(src_frame), std::move(video_frame), + base::BindOnce( + [](scoped_refptr<base::SingleThreadTaskRunner> runner, + base::OnceClosure cb, scoped_refptr<VideoFrame> frame) { + runner->PostTask(FROM_HERE, std::move(cb)); + }, + task_runner_, + base::BindOnce(&VaapiMjpegDecodeAccelerator::VideoFrameReady, + weak_this_factory_.GetWeakPtr(), task_id))); return true; } +void VaapiMjpegDecodeAccelerator::OnImageProcessorError() { + DCHECK(decoder_task_runner_->BelongsToCurrentThread()); + VLOGF(1) << "Failed to process frames using the libyuv image processor"; + NotifyError(kInvalidTaskId, PLATFORM_FAILURE); + image_processor_.reset(); +} + bool VaapiMjpegDecodeAccelerator::OutputPictureVppOnTaskRunner( + int32_t task_id, const ScopedVASurface* surface, - int32_t input_buffer_id, - scoped_refptr<VideoFrame> video_frame) { + scoped_refptr<VideoFrame> video_frame, + const gfx::Rect& crop_rect) { DCHECK(decoder_task_runner_->BelongsToCurrentThread()); DCHECK(surface); DCHECK(video_frame); + DCHECK(gfx::Rect(surface->size()).Contains(crop_rect)); - TRACE_EVENT1("jpeg", __func__, "input_buffer_id", input_buffer_id); + TRACE_EVENT1("jpeg", __func__, "task_id", task_id); scoped_refptr<gfx::NativePixmap> pixmap = CreateNativePixmapDmaBuf(video_frame.get()); @@ -395,50 +363,36 @@ bool VaapiMjpegDecodeAccelerator::OutputPictureVppOnTaskRunner( // Bind a VA surface to |video_frame|. scoped_refptr<VASurface> output_surface = vpp_vaapi_wrapper_->CreateVASurfaceForPixmap(std::move(pixmap)); - if (!output_surface) { VLOGF(1) << "Cannot create VA surface for output buffer"; return false; } - // Use VPP to blit the visible size region within |surface| into - // |output_surface|. BlitSurface() does scaling not cropping when source and - // destination sizes don't match, so we manipulate the sizes of surfaces to - // effectively do the cropping. - const gfx::Size& blit_size = video_frame->visible_rect().size(); - if (surface->size().width() < blit_size.width() || - surface->size().height() < blit_size.height()) { - VLOGF(1) << "Decoded surface size is smaller than target size"; - return false; - } scoped_refptr<VASurface> src_surface = base::MakeRefCounted<VASurface>( - surface->id(), blit_size, surface->format(), - base::DoNothing() /* release_cb */); - scoped_refptr<VASurface> dst_surface = base::MakeRefCounted<VASurface>( - output_surface->id(), blit_size, output_surface->format(), - base::DoNothing() /* release_cb */); + surface->id(), surface->size(), surface->format(), + /*release_cb=*/base::DoNothing()); // We should call vaSyncSurface() when passing surface between contexts. See: // https://lists.01.org/pipermail/intel-vaapi-media/2019-June/000131.html - if (!vpp_vaapi_wrapper_->SyncSurface(src_surface->id())) { + if (!vpp_vaapi_wrapper_->SyncSurface(surface->id())) { VLOGF(1) << "Cannot sync VPP input surface"; return false; } - if (!vpp_vaapi_wrapper_->BlitSurface(*src_surface, *dst_surface)) { + if (!vpp_vaapi_wrapper_->BlitSurface(*src_surface, *output_surface, + crop_rect)) { VLOGF(1) << "Cannot convert decoded image into output buffer"; return false; } // Sync target surface since the buffer is returning to client. - if (!vpp_vaapi_wrapper_->SyncSurface(dst_surface->id())) { + if (!vpp_vaapi_wrapper_->SyncSurface(output_surface->id())) { VLOGF(1) << "Cannot sync VPP output surface"; return false; } task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&VaapiMjpegDecodeAccelerator::VideoFrameReady, - weak_this_factory_.GetWeakPtr(), input_buffer_id)); + FROM_HERE, base::BindOnce(&VaapiMjpegDecodeAccelerator::VideoFrameReady, + weak_this_factory_.GetWeakPtr(), task_id)); return true; } @@ -490,11 +444,9 @@ void VaapiMjpegDecodeAccelerator::DecodeImpl( int32_t task_id, base::span<const uint8_t> src_image, scoped_refptr<VideoFrame> dst_frame) { - // TODO(andrescj): validate that the video frame's visible size is the same as - // the parsed JPEG's visible size when it is returned from Decode(), and - // remove the size checks in OutputPicture*(). VaapiImageDecodeStatus status = decoder_->Decode(src_image); if (status != VaapiImageDecodeStatus::kSuccess) { + VLOGF(1) << "Failed to decode JPEG image"; NotifyError(task_id, VaapiJpegDecodeStatusToError(status)); return; } @@ -502,30 +454,71 @@ void VaapiMjpegDecodeAccelerator::DecodeImpl( DCHECK(surface); DCHECK(surface->IsValid()); + // For camera captures, we assume that the visible size is the same as the + // coded size. + if (dst_frame->visible_rect().size() != dst_frame->coded_size() || + dst_frame->visible_rect().x() != 0 || + dst_frame->visible_rect().y() != 0) { + VLOGF(1) + << "The video frame visible size should be the same as the coded size"; + NotifyError(task_id, INVALID_ARGUMENT); + return; + } + + // Note that |surface->size()| is the visible size of the JPEG image. The + // underlying VASurface size (coded size) can be larger because of alignments. + if (surface->size().width() < dst_frame->visible_rect().width() || + surface->size().height() < dst_frame->visible_rect().height()) { + VLOGF(1) << "Invalid JPEG image and video frame sizes: " + << surface->size().ToString() << ", " + << dst_frame->visible_rect().size().ToString(); + NotifyError(task_id, INVALID_ARGUMENT); + return; + } + // For DMA-buf backed |dst_frame|, we will import it as a VA surface and use // VPP to convert the decoded |surface| into it, if the formats and sizes are // supported. - const auto video_frame_fourcc = + const auto dst_frame_fourcc = Fourcc::FromVideoPixelFormat(dst_frame->format()); - if (!video_frame_fourcc) { + if (!dst_frame_fourcc) { VLOGF(1) << "Unsupported video frame format: " << dst_frame->format(); NotifyError(task_id, PLATFORM_FAILURE); return; } - const auto video_frame_va_fourcc = video_frame_fourcc->ToVAFourCC(); - if (!video_frame_va_fourcc) { + const auto dst_frame_va_fourcc = dst_frame_fourcc->ToVAFourCC(); + if (!dst_frame_va_fourcc) { VLOGF(1) << "Unsupported video frame format: " << dst_frame->format(); NotifyError(task_id, PLATFORM_FAILURE); return; } + + // Crop and scale the decoded image into |dst_frame|. + // The VPP is known to have some problems with odd-sized buffers, so we + // request a crop rectangle whose dimensions are aligned to 2. + const gfx::Rect crop_rect = CropSizeForScalingToTarget( + surface->size(), dst_frame->visible_rect().size(), /*alignment=*/2u); + if (crop_rect.IsEmpty()) { + VLOGF(1) << "Failed to calculate crop rectangle for " + << surface->size().ToString() << " to " + << dst_frame->visible_rect().size().ToString(); + NotifyError(task_id, PLATFORM_FAILURE); + return; + } + // TODO(kamesan): move HasDmaBufs() to DCHECK when we deprecate // shared-memory-backed video frame. + // Check all the sizes involved until we figure out the definition of min/max + // resolutions in the VPP profile (b/195312242). if (dst_frame->HasDmaBufs() && VaapiWrapper::IsVppResolutionAllowed(surface->size()) && + VaapiWrapper::IsVppResolutionAllowed(crop_rect.size()) && + VaapiWrapper::IsVppResolutionAllowed(dst_frame->visible_rect().size()) && VaapiWrapper::IsVppSupportedForJpegDecodedSurfaceToFourCC( - surface->format(), *video_frame_va_fourcc)) { - if (!OutputPictureVppOnTaskRunner(surface, task_id, std::move(dst_frame))) { + surface->format(), *dst_frame_va_fourcc)) { + if (!OutputPictureVppOnTaskRunner(task_id, surface, std::move(dst_frame), + crop_rect)) { VLOGF(1) << "Output picture using VPP failed"; NotifyError(task_id, PLATFORM_FAILURE); } @@ -537,13 +530,15 @@ void VaapiMjpegDecodeAccelerator::DecodeImpl( // 2. VPP doesn't support the format conversion. This is intended for AMD // VAAPI driver whose VPP only supports converting decoded 4:2:0 JPEGs. std::unique_ptr<ScopedVAImage> image = - decoder_->GetImage(*video_frame_va_fourcc, &status); + decoder_->GetImage(*dst_frame_va_fourcc, &status); if (status != VaapiImageDecodeStatus::kSuccess) { NotifyError(task_id, VaapiJpegDecodeStatusToError(status)); return; } - if (!OutputPictureLibYuvOnTaskRunner(std::move(image), task_id, - std::move(dst_frame))) { + DCHECK_EQ(image->image()->width, surface->size().width()); + DCHECK_EQ(image->image()->height, surface->size().height()); + if (!OutputPictureLibYuvOnTaskRunner(task_id, std::move(image), + std::move(dst_frame), crop_rect)) { VLOGF(1) << "Output picture using libyuv failed"; NotifyError(task_id, PLATFORM_FAILURE); } |