[TTVD] Crop video to be encoded according to visible rect 36/314636/4
authorJakub Gajownik <j.gajownik2@samsung.com>
Mon, 8 Jul 2024 08:14:19 +0000 (10:14 +0200)
committerBot Blink <blinkbot@samsung.com>
Wed, 17 Jul 2024 14:56:47 +0000 (14:56 +0000)
When data is passed to encoder, it must be cropped according
to visible rect from the given video frame. It was not done
before this CL for Tizen hardware encoder implementation.
The results was that fully captured video from camera was
encoded (not the one cropped by video track adapter),
possibly squeezing it in one direction.
Moreover in such scenario, video being tighly packed in not
sufficient, as hardware encoder is not capable of applying
any stride other than width.

In general scenario, we can apply software cropping before
data is given to platform encoder. Similar is applied when
data is not tighly packed, otherwise it wouldn't be encoded.

Bug: https://jira-eu.sec.samsung.net/browse/VDGAME-534
Change-Id: I72fa02f9dd8545dd998561d21d2446a469dd6917
Signed-off-by: Jakub Gajownik <j.gajownik2@samsung.com>
media/gpu/tizen/tizen_video_encode_accelerator.cc
media/gpu/tizen/tizen_video_encode_accelerator_utils.cc

index 6fbe4d64290ac2685bf99f82498b96fccfaed7c9..95ecb9649bd8365f8e7d40177604f5dace767be4 100644 (file)
@@ -719,9 +719,9 @@ void TizenVideoEncodeAccelerator::PushFrameToPlatformEncoder(
     CHECK_AND_RETURN_MEDIA_FORMAT(
         media_format_set_video_mime(media_format.get(), MEDIA_FORMAT_NV12));
     CHECK_AND_RETURN_MEDIA_FORMAT(media_format_set_video_width(
-        media_format.get(), frame->coded_size().width()));
+        media_format.get(), frame->visible_rect().width()));
     CHECK_AND_RETURN_MEDIA_FORMAT(media_format_set_video_height(
-        media_format.get(), frame->coded_size().height()));
+        media_format.get(), frame->visible_rect().height()));
     CHECK_AND_RETURN_MEDIA_FORMAT(media_format_set_video_frame_rate(
         media_format.get(), kDefaultFramerate));
   }
index 6632431c9eb4b8827996ddd34edfbca22622ce47..243da195cf090ca516b3a239c643cc84dc649f45 100644 (file)
@@ -11,6 +11,7 @@
 #include "media/gpu/tizen/tizen_video_encode_accelerator.h"
 #include "media/gpu/tizen/tizen_video_encode_accelerator_helper.h"
 #include "third_party/libyuv/include/libyuv/convert_from.h"
+#include "third_party/libyuv/include/libyuv/planar_functions.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/tbm_surface.h"
 
@@ -70,6 +71,33 @@ bool IsTighlyPacked(VideoPixelFormat format,
   }
   return true;
 }
+
+std::vector<uint8_t> CopyVisibleData(scoped_refptr<VideoFrame> video_frame) {
+  std::vector<uint8_t> data;
+  data.resize(VideoFrame::AllocationSize(PIXEL_FORMAT_NV12,
+                                         video_frame->visible_rect().size()));
+
+  const auto y_stride =
+      VideoFrame::RowBytes(VideoFrame::kYPlane, PIXEL_FORMAT_NV12,
+                           video_frame->visible_rect().width());
+  libyuv::CopyPlane(video_frame->visible_data(VideoFrame::kYPlane),
+                    video_frame->stride(VideoFrame::kYPlane), data.data(),
+                    y_stride, video_frame->visible_rect().width(),
+                    video_frame->visible_rect().height());
+
+  const auto uv_stride =
+      VideoFrame::RowBytes(VideoFrame::kUVPlane, PIXEL_FORMAT_NV12,
+                           video_frame->visible_rect().width());
+  libyuv::CopyPlane(video_frame->visible_data(VideoFrame::kUVPlane),
+                    video_frame->stride(VideoFrame::kUVPlane),
+                    data.data() + VideoFrame::PlaneSize(
+                                      PIXEL_FORMAT_NV12, VideoFrame::kYPlane,
+                                      video_frame->visible_rect().size())
+                                      .GetArea(),
+                    uv_stride, video_frame->visible_rect().width(),
+                    video_frame->visible_rect().height() / 2);
+  return data;
+}
 }  // namespace
 
 #define DECLARE_CASE_VALUE(param) \
@@ -266,14 +294,7 @@ MediaPacketTuple CreateMediaPacketFromGpuMemoryBuffer(
       },
       std::move(gmb)));
 
-  if (!IsTighlyPacked(video_frame->format(), video_frame->coded_size(),
-                      gmb_ptr)) {
-    TIZEN_MEDIA_LOG_NO_INSTANCE(ERROR)
-        << "Video frame data is not tighly packed";
-    return {};
-  }
-
-  auto* data_to_encode = reinterpret_cast<uint8_t*>(gmb_ptr->memory(0));
+  uint8_t* data_to_encode = reinterpret_cast<uint8_t*>(gmb_ptr->memory(0));
 
   if (!data_to_encode) {
     TIZEN_MEDIA_LOG_NO_INSTANCE(ERROR)
@@ -281,12 +302,48 @@ MediaPacketTuple CreateMediaPacketFromGpuMemoryBuffer(
     return {};
   }
 
+  // HW encoder accepts only data in tightly packed format (single buffer,
+  // planes stored one after another, without padding). It means that when video
+  // is cropped, we also cannot pass mapped data directly.
+  if (video_frame->coded_size() != video_frame->visible_rect().size() ||
+      !IsTighlyPacked(video_frame->format(), video_frame->coded_size(),
+                      gmb_ptr)) {
+    const size_t num_planes = VideoFrame::NumPlanes(video_frame->format());
+    uint8_t* plane_addrs[VideoFrame::kMaxPlanes] = {};
+    int plane_stride[VideoFrame::kMaxPlanes] = {};
+    for (size_t i = 0; i < num_planes; i++) {
+      plane_addrs[i] = static_cast<uint8_t*>(gmb_ptr->memory(i));
+      if (plane_addrs[i] == nullptr) {
+        TIZEN_MEDIA_LOG_NO_INSTANCE(ERROR)
+            << "Cannot map data using GpuMemoryBuffer";
+        return {};
+      }
+      plane_stride[i] = gmb_ptr->stride(i);
+    }
+
+    auto mapped_frame = VideoFrame::WrapExternalYuvData(
+        video_frame->format(), video_frame->coded_size(),
+        video_frame->visible_rect(), video_frame->natural_size(),
+        plane_stride[0], plane_stride[1], plane_stride[2], plane_addrs[0],
+        plane_addrs[1], plane_addrs[2], video_frame->timestamp());
+    if (!mapped_frame) {
+      TIZEN_MEDIA_LOG_NO_INSTANCE(ERROR)
+          << "Cannot pack GpuMemoryBuffer memory";
+      return {};
+    }
+
+    auto data = CopyVisibleData(mapped_frame);
+    data_to_encode = data.data();
+    destruction_cb = base::ScopedClosureRunner(
+        base::BindOnce([](std::vector<uint8_t>) {}, std::move(data)));
+  }
+
   media_packet_h media_packet_ptr;
   CHECK_AND_RETURN_MEDIA_PACKET(
       media_packet_new_from_external_memory(
           media_format.get(), data_to_encode,
           VideoFrame::AllocationSize(video_frame->format(),
-                                     video_frame->coded_size()),
+                                     video_frame->visible_rect().size()),
           TizenVideoEncodeAcceleratorHelper::OnPacketProcessedByEncoderCallback,
           thiz, &media_packet_ptr),
       {});