/* * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "video/partial_frame_assembler.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/ref_counted_object.h" namespace webrtc { PartialFrameAssembler::PartialFrameAssembler() = default; PartialFrameAssembler::~PartialFrameAssembler() = default; bool PartialFrameAssembler::ApplyPartialUpdate( const rtc::scoped_refptr& input_buffer, VideoFrame* uncompressed_frame, const VideoFrame::PartialFrameDescription* partial_desc) { const int changed_rect_width = input_buffer ? input_buffer->width() : 0; const int changed_rect_height = input_buffer ? input_buffer->height() : 0; if (partial_desc == nullptr) { // Full update. Copy whole picture to the cached buffer. May need to // resize or create the cache buffer. if (!cached_frame_buffer_ || cached_frame_buffer_->height() < input_buffer->height() || cached_frame_buffer_->width() < input_buffer->width()) { cached_frame_buffer_ = I420Buffer::Create(input_buffer->width(), input_buffer->height()); } cached_frame_buffer_->PasteFrom(*input_buffer->ToI420().get(), 0, 0); } else { // Have to apply partial input picture to the cached buffer. // Check all possible error situations. if (!cached_frame_buffer_) { RTC_LOG(LS_ERROR) << "Partial picture received but no cached full picture" "present."; return false; } if (partial_desc->offset_x % 2 != 0 || partial_desc->offset_y % 2 != 0) { RTC_LOG(LS_ERROR) << "Partial picture required to be at even offset." " Actual: (" << partial_desc->offset_x << ", " << partial_desc->offset_y << ")."; cached_frame_buffer_ = nullptr; return false; } if ((changed_rect_width % 2 != 0 && changed_rect_width + partial_desc->offset_x < cached_frame_buffer_->width()) || (changed_rect_height % 2 != 0 && changed_rect_height + partial_desc->offset_y < cached_frame_buffer_->height())) { RTC_LOG(LS_ERROR) << "Partial picture required to have even dimensions." " Actual: " << input_buffer->width() << "x" << input_buffer->height() << "."; cached_frame_buffer_ = nullptr; return false; } if (partial_desc->offset_x < 0 || partial_desc->offset_x + changed_rect_width > cached_frame_buffer_->width() || partial_desc->offset_y < 0 || partial_desc->offset_y + changed_rect_height > cached_frame_buffer_->height()) { RTC_LOG(LS_ERROR) << "Partial picture is outside of bounds."; cached_frame_buffer_ = nullptr; return false; } // No errors: apply new image to the cache and use the result. if (input_buffer) { cached_frame_buffer_->PasteFrom(*input_buffer->ToI420().get(), partial_desc->offset_x, partial_desc->offset_y); } } // Remove partial frame description, as it doesn't make sense after update // is applied. uncompressed_frame->set_partial_frame_description(absl::nullopt); uncompressed_frame->set_video_frame_buffer( I420Buffer::Copy(*cached_frame_buffer_.get())); return true; } void PartialFrameAssembler::Reset() { cached_frame_buffer_ = nullptr; } } // namespace webrtc