diff --git a/webrtc/api/androidvideotracksource.cc b/webrtc/api/androidvideotracksource.cc index d232f5ebad..000337d34d 100644 --- a/webrtc/api/androidvideotracksource.cc +++ b/webrtc/api/androidvideotracksource.cc @@ -12,9 +12,6 @@ #include -#include "third_party/libyuv/include/libyuv/convert.h" -#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" - namespace webrtc { AndroidVideoTrackSource::AndroidVideoTrackSource(rtc::Thread* signaling_thread, @@ -109,70 +106,42 @@ void AndroidVideoTrackSource::OnByteBufferFrameCaptured(const void* frame_data, return; } + int rotated_width = crop_width; + int rotated_height = crop_height; + + rtc::CritScope lock(&apply_rotation_crit_); + if (apply_rotation_ && (rotation == 90 || rotation == 270)) { + std::swap(adapted_width, adapted_height); + std::swap(rotated_width, rotated_height); + } + + rtc::scoped_refptr buffer = + pre_scale_pool_.CreateBuffer(rotated_width, rotated_height); + const uint8_t* y_plane = static_cast(frame_data); const uint8_t* uv_plane = y_plane + width * height; - const int uv_width = (width + 1) / 2; + int uv_width = (width + 1) / 2; RTC_CHECK_GE(length, width * height + 2 * uv_width * ((height + 1) / 2)); // Can only crop at even pixels. crop_x &= ~1; crop_y &= ~1; - // Crop just by modifying pointers. - y_plane += width * crop_y + crop_x; - uv_plane += uv_width * crop_y + crop_x; - rtc::scoped_refptr buffer = - buffer_pool_.CreateBuffer(adapted_width, adapted_height); + libyuv::NV12ToI420Rotate( + y_plane + width * crop_y + crop_x, width, + uv_plane + uv_width * crop_y + crop_x, width, buffer->MutableDataY(), + buffer->StrideY(), + // Swap U and V, since we have NV21, not NV12. + buffer->MutableDataV(), buffer->StrideV(), buffer->MutableDataU(), + buffer->StrideU(), crop_width, crop_height, + static_cast(apply_rotation_ ? rotation : 0)); - if (adapted_width == crop_width && adapted_height == crop_height) { - // No scaling. - libyuv::NV12ToI420( - y_plane, width, - uv_plane, uv_width * 2, - buffer->MutableDataY(), buffer->StrideY(), - // Swap U and V, since we have NV21, not NV12. - buffer->MutableDataV(), buffer->StrideV(), - buffer->MutableDataU(), buffer->StrideU(), - buffer->width(), buffer->height()); - - } else { - // Scaling. - const int crop_uv_width = (crop_width + 1) / 2; - const int crop_uv_height = (crop_height + 1) / 2; - unscaled_uv_planes_.resize(crop_uv_width * crop_uv_height * 2); - - NV12ToI420Scale( - unscaled_uv_planes_.data(), - y_plane, width, - uv_plane, uv_width * 2, - crop_width, crop_height, - buffer->MutableDataY(), buffer->StrideY(), - // Swap U and V, since we have NV21, not NV12. - buffer->MutableDataV(), buffer->StrideV(), - buffer->MutableDataU(), buffer->StrideU(), - buffer->width(), buffer->height()); - } - - // Applying rotation is only supported for legacy reasons, and the performance - // for this path is not critical. - rtc::CritScope lock(&apply_rotation_crit_); - if (apply_rotation_ && rotation != 0) { - rtc::scoped_refptr rotated_buffer = I420Buffer::Create( - rotation == 180 ? buffer->width() : buffer->height(), - rotation == 180 ? buffer->height() : buffer->width()); - - libyuv::I420Rotate( - buffer->DataY(), buffer->StrideY(), - buffer->DataU(), buffer->StrideU(), - buffer->DataV(), buffer->StrideV(), - rotated_buffer->MutableDataY(), rotated_buffer->StrideY(), - rotated_buffer->MutableDataU(), rotated_buffer->StrideU(), - rotated_buffer->MutableDataV(), rotated_buffer->StrideV(), - buffer->width(), buffer->height(), - static_cast(rotation)); - - buffer = rotated_buffer; + if (adapted_width != buffer->width() || adapted_height != buffer->height()) { + rtc::scoped_refptr scaled_buffer( + post_scale_pool_.CreateBuffer(adapted_width, adapted_height)); + scaled_buffer->ScaleFrom(buffer); + buffer = scaled_buffer; } OnFrame(cricket::WebRtcVideoFrame( diff --git a/webrtc/api/androidvideotracksource.h b/webrtc/api/androidvideotracksource.h index 5cf52d07f8..2bbecc82c9 100644 --- a/webrtc/api/androidvideotracksource.h +++ b/webrtc/api/androidvideotracksource.h @@ -23,6 +23,7 @@ #include "webrtc/media/base/videoadapter.h" #include "webrtc/media/base/videobroadcaster.h" #include "webrtc/media/base/videosinkinterface.h" +#include "third_party/libyuv/include/libyuv/convert.h" namespace webrtc { @@ -91,8 +92,8 @@ class AndroidVideoTrackSource : public Notifier { cricket::VideoAdapter video_adapter_; rtc::CriticalSection apply_rotation_crit_; bool apply_rotation_ GUARDED_BY(apply_rotation_crit_); - std::vector unscaled_uv_planes_; - webrtc::I420BufferPool buffer_pool_; + webrtc::I420BufferPool pre_scale_pool_; + webrtc::I420BufferPool post_scale_pool_; rtc::scoped_refptr surface_texture_helper_; const bool is_screencast_; diff --git a/webrtc/common_video/libyuv/include/webrtc_libyuv.h b/webrtc/common_video/libyuv/include/webrtc_libyuv.h index 1ceca4d43f..ec3720e442 100644 --- a/webrtc/common_video/libyuv/include/webrtc_libyuv.h +++ b/webrtc/common_video/libyuv/include/webrtc_libyuv.h @@ -123,19 +123,6 @@ double I420PSNR(const VideoFrame* ref_frame, const VideoFrame* test_frame); // Compute SSIM for an I420 frame (all planes). double I420SSIM(const VideoFrame* ref_frame, const VideoFrame* test_frame); -// Helper function for directly converting and scaling NV12 to I420. The -// |tmp_data| argument will be used for intermediary splitting the UV plane into -// separate U and V planes, so the size of that memory region must be at least -// 2 * ((src_width + 1) / 2) * ((src_height + 1) / 2). -void NV12ToI420Scale(uint8_t* tmp_data, - const uint8_t* src_y, int src_stride_y, - const uint8_t* src_uv, int src_stride_uv, - int src_width, int src_height, - 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 dst_width, int dst_height); - } // namespace webrtc #endif // WEBRTC_COMMON_VIDEO_LIBYUV_INCLUDE_WEBRTC_LIBYUV_H_ diff --git a/webrtc/common_video/libyuv/webrtc_libyuv.cc b/webrtc/common_video/libyuv/webrtc_libyuv.cc index 5d9ab57367..44577e9ac8 100644 --- a/webrtc/common_video/libyuv/webrtc_libyuv.cc +++ b/webrtc/common_video/libyuv/webrtc_libyuv.cc @@ -341,34 +341,4 @@ double I420SSIM(const VideoFrame* ref_frame, const VideoFrame* test_frame) { test_frame->video_frame_buffer()->StrideV(), test_frame->width(), test_frame->height()); } - -void NV12ToI420Scale(uint8_t* tmp_data, - const uint8_t* src_y, int src_stride_y, - const uint8_t* src_uv, int src_stride_uv, - int src_width, int src_height, - 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 dst_width, int dst_height) { - // Split source UV plane into separate U and V plane using the temporary data. - const int src_uv_width = (src_width + 1) / 2; - const int src_uv_height = (src_height + 1) / 2; - uint8_t* const src_u = tmp_data; - uint8_t* const src_v = tmp_data + src_uv_width * src_uv_height; - libyuv::SplitUVPlane(src_uv, src_stride_uv, - src_u, src_uv_width, - src_v, src_uv_width, - src_uv_width, src_uv_height); - // Scale the planes into the destination. - libyuv::I420Scale(src_y, src_stride_y, - src_u, src_uv_width, - src_v, src_uv_width, - src_width, src_height, - dst_y, dst_stride_y, - dst_u, dst_stride_u, - dst_v, dst_stride_v, - dst_width, dst_height, - libyuv::kFilterBox); -} - } // namespace webrtc