[webcodecs] Support native input video frame in VideoEncoder
This CL supports native input video frame from user media video track.
The video frame is converted to I420 by libyuv for software encoder.
Bug: 1045248
Change-Id: I2afb1a3c9c9fdf2c8b15312120c430f8e898d2b4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2359715
Commit-Queue: Dan Sanders <sandersd@chromium.org>
Reviewed-by: Dan Sanders <sandersd@chromium.org>
Cr-Commit-Position: refs/heads/master@{#799818}
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
index b97d72fd..5f0e1a0 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
@@ -36,6 +36,7 @@
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
+#include "third_party/libyuv/include/libyuv.h"
namespace blink {
@@ -60,6 +61,37 @@
#endif // BUILDFLAG(ENABLE_LIBVPX)
}
+scoped_refptr<media::VideoFrame> ConvertToI420Frame(
+ scoped_refptr<media::VideoFrame> frame) {
+ DCHECK_EQ(frame->storage_type(),
+ media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER);
+
+ // TODO: Support more pixel formats
+ if (frame->format() != media::VideoPixelFormat::PIXEL_FORMAT_NV12)
+ return nullptr;
+
+ auto* gmb = frame->GetGpuMemoryBuffer();
+ if (!gmb->Map())
+ return nullptr;
+ scoped_refptr<media::VideoFrame> i420_frame = media::VideoFrame::CreateFrame(
+ media::VideoPixelFormat::PIXEL_FORMAT_I420, frame->coded_size(),
+ frame->visible_rect(), frame->natural_size(), frame->timestamp());
+ auto ret = libyuv::NV12ToI420(
+ static_cast<const uint8_t*>(gmb->memory(0)), gmb->stride(0),
+ static_cast<const uint8_t*>(gmb->memory(1)), gmb->stride(1),
+ i420_frame->data(media::VideoFrame::kYPlane),
+ i420_frame->stride(media::VideoFrame::kYPlane),
+ i420_frame->data(media::VideoFrame::kUPlane),
+ i420_frame->stride(media::VideoFrame::kUPlane),
+ i420_frame->data(media::VideoFrame::kVPlane),
+ i420_frame->stride(media::VideoFrame::kVPlane),
+ frame->coded_size().width(), frame->coded_size().height());
+ gmb->Unmap();
+ if (ret)
+ return nullptr;
+ return i420_frame;
+}
+
} // namespace
// static
@@ -251,10 +283,19 @@
return;
}
+ scoped_refptr<media::VideoFrame> frame = request->frame->frame();
+ if (frame->storage_type() == media::VideoFrame::STORAGE_GPU_MEMORY_BUFFER) {
+ frame = ConvertToI420Frame(frame);
+ if (!frame) {
+ HandleError(DOMExceptionCode::kOperationError, "Unexpected frame format");
+ return;
+ }
+ }
+
bool keyframe = request->encodeOpts->hasKeyFrameNonNull() &&
request->encodeOpts->keyFrameNonNull();
--requested_encodes_;
- media_encoder_->Encode(request->frame->frame(), keyframe,
+ media_encoder_->Encode(frame, keyframe,
WTF::Bind(done_callback, WrapWeakPersistent(this),
WrapPersistentIfNeeded(request)));
}