#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"
}
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) \
},
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)
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),
{});