Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(965)

Unified Diff: content/renderer/media/video_track_recorder.cc

Issue 2147753002: VideoTrackRecorder: add support for texture backed ARGB VideoFrames (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: emircan@s comments Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « content/browser/media/webrtc/webrtc_media_recorder_browsertest.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/renderer/media/video_track_recorder.cc
diff --git a/content/renderer/media/video_track_recorder.cc b/content/renderer/media/video_track_recorder.cc
index e5d477a18be2037f4f23a7461e7a8a65cdb9f370..ea69e45ba4799628c19852cf03f4b61f8189d2fa 100644
--- a/content/renderer/media/video_track_recorder.cc
+++ b/content/renderer/media/video_track_recorder.cc
@@ -15,12 +15,18 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
+#include "content/common/gpu/client/context_provider_command_buffer.h"
#include "content/renderer/media/renderer_gpu_video_accelerator_factories.h"
#include "content/renderer/render_thread_impl.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/video_frame.h"
#include "media/base/video_util.h"
-#include "third_party/libyuv/include/libyuv/convert.h"
+#include "media/filters/context_3d.h"
+#include "media/renderers/skcanvas_video_renderer.h"
+#include "skia/ext/platform_canvas.h"
+#include "third_party/libyuv/include/libyuv.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkSurface.h"
#include "ui/gfx/geometry/size.h"
#if BUILDFLAG(RTC_USE_H264)
@@ -105,8 +111,8 @@ media::VideoCodecProfile CodecIdToVEAProfile(
// ref-counted to allow the MediaStreamVideoTrack to hold a reference to it (via
// the callback that MediaStreamVideoSink passes along) and to jump back and
// forth to an internal encoder thread. Moreover, this class:
-// - is created and destroyed on its parent's thread (usually the main Render
-// thread), |main_task_runner_|.
+// - is created on its parent's thread (usually the main Render thread),
+// that is, |main_task_runner_|.
// - receives VideoFrames on |origin_task_runner_| and runs OnEncodedVideoCB on
// that thread as well. This task runner is cached on first frame arrival, and
// is supposed to be the render IO thread (but this is not enforced);
@@ -136,15 +142,21 @@ class VideoTrackRecorder::Encoder : public base::RefCountedThreadSafe<Encoder> {
// Start encoding |frame|, returning via |on_encoded_video_callback_|. This
// call will also trigger a ConfigureEncoderOnEncodingTaskRunner() upon first
// frame arrival or parameter change, and an EncodeOnEncodingTaskRunner() to
- // actually encode the frame.
+ // actually encode the frame. If the |frame|'s data is not directly available
+ // (e.g. it's a texture) then RetrieveFrameOnMainThread() is called, and if
+ // even that fails, black frames are sent instead.
void StartFrameEncode(const scoped_refptr<VideoFrame>& frame,
base::TimeTicks capture_timestamp);
+ void RetrieveFrameOnMainThread(const scoped_refptr<VideoFrame>& video_frame,
+ base::TimeTicks capture_timestamp);
void SetPaused(bool paused);
protected:
friend class base::RefCountedThreadSafe<Encoder>;
- virtual ~Encoder() {}
+ virtual ~Encoder() {
+ main_task_runner_->DeleteSoon(FROM_HERE, video_renderer_.release());
+ }
virtual void EncodeOnEncodingTaskRunner(
const scoped_refptr<VideoFrame>& frame,
@@ -172,6 +184,11 @@ class VideoTrackRecorder::Encoder : public base::RefCountedThreadSafe<Encoder> {
// Target bitrate for video encoding. If 0, a standard bitrate is used.
const int32_t bits_per_second_;
+ // Used to retrieve incoming opaque VideoFrames (i.e. VideoFrames backed by
+ // textures). Created on-demand on |main_task_runner_|.
+ std::unique_ptr<media::SkCanvasVideoRenderer> video_renderer_;
+ sk_sp<SkSurface> surface_;
+
DISALLOW_COPY_AND_ASSIGN(Encoder);
};
@@ -187,10 +204,19 @@ void VideoTrackRecorder::Encoder::StartFrameEncode(
if (!(video_frame->format() == media::PIXEL_FORMAT_I420 ||
video_frame->format() == media::PIXEL_FORMAT_YV12 ||
+ video_frame->format() == media::PIXEL_FORMAT_ARGB ||
video_frame->format() == media::PIXEL_FORMAT_YV12A)) {
- NOTREACHED();
+ NOTREACHED() << media::VideoPixelFormatToString(video_frame->format());
+ return;
+ }
+
+ if (video_frame->HasTextures()) {
+ main_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&Encoder::RetrieveFrameOnMainThread, this,
+ video_frame, capture_timestamp));
return;
}
+
scoped_refptr<media::VideoFrame> frame = video_frame;
// Drop alpha channel since we do not support it yet.
if (frame->format() == media::PIXEL_FORMAT_YV12A)
@@ -201,6 +227,84 @@ void VideoTrackRecorder::Encoder::StartFrameEncode(
capture_timestamp));
}
+void VideoTrackRecorder::Encoder::RetrieveFrameOnMainThread(
+ const scoped_refptr<VideoFrame>& video_frame,
+ base::TimeTicks capture_timestamp) {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+
+ scoped_refptr<media::VideoFrame> frame;
+
+ // |context_provider| is null if the GPU process has crashed or isn't there.
+ ContextProviderCommandBuffer* const context_provider =
+ RenderThreadImpl::current()->SharedMainThreadContextProvider().get();
+ if (!context_provider) {
+ // Send black frames (yuv = {0, 127, 127}).
+ frame = media::VideoFrame::CreateColorFrame(
+ video_frame->visible_rect().size(), 0u, 0x80, 0x80,
+ video_frame->timestamp());
+ } else {
+ // Accelerated decoders produce ARGB/ABGR texture-backed frames (see
+ // https://crbug.com/585242), fetch them using a SkCanvasVideoRenderer.
+ DCHECK(video_frame->HasTextures());
+ DCHECK_EQ(media::PIXEL_FORMAT_ARGB, video_frame->format());
+
+ frame = media::VideoFrame::CreateFrame(
+ media::PIXEL_FORMAT_I420, video_frame->coded_size(),
+ video_frame->visible_rect(), video_frame->natural_size(),
+ video_frame->timestamp());
+
+ const SkImageInfo info = SkImageInfo::MakeN32(
+ frame->visible_rect().width(), frame->visible_rect().height(),
+ kOpaque_SkAlphaType);
+
+ // Create |surface_| if it doesn't exist or incoming resolution has changed.
+ if (!surface_ || surface_->width() != info.width() ||
+ surface_->height() != info.height()) {
+ surface_ = SkSurface::MakeRaster(info);
+ }
+ if (!video_renderer_)
+ video_renderer_.reset(new media::SkCanvasVideoRenderer);
+
+ DCHECK(context_provider->ContextGL());
+ video_renderer_->Copy(video_frame.get(), surface_->getCanvas(),
+ media::Context3D(context_provider->ContextGL(),
+ context_provider->GrContext()));
+
+ SkPixmap pixmap;
+ if (!skia::GetWritablePixels(surface_->getCanvas(), &pixmap)) {
+ DLOG(ERROR) << "Error trying to map SkSurface's pixels";
+ return;
+ }
+ // TODO(mcasas): Use the incoming frame's rotation when
+ // https://bugs.chromium.org/p/webrtc/issues/detail?id=6069 is closed.
+ const libyuv::RotationMode source_rotation = libyuv::kRotate0;
+ const uint32 source_pixel_format =
+ (kN32_SkColorType == kRGBA_8888_SkColorType) ? libyuv::FOURCC_ABGR
+ : libyuv::FOURCC_ARGB;
+ if (libyuv::ConvertToI420(static_cast<uint8*>(pixmap.writable_addr()),
+ pixmap.getSafeSize(),
+ frame->visible_data(media::VideoFrame::kYPlane),
+ frame->stride(media::VideoFrame::kYPlane),
+ frame->visible_data(media::VideoFrame::kUPlane),
+ frame->stride(media::VideoFrame::kUPlane),
+ frame->visible_data(media::VideoFrame::kVPlane),
+ frame->stride(media::VideoFrame::kVPlane),
+ 0 /* crop_x */, 0 /* crop_y */,
+ pixmap.width(), pixmap.height(),
+ frame->visible_rect().width(),
+ frame->visible_rect().height(),
+ source_rotation,
+ source_pixel_format) != 0) {
+ DLOG(ERROR) << "Error converting frame to I420";
+ return;
+ }
+ }
+
+ encoding_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&Encoder::EncodeOnEncodingTaskRunner, this, frame,
+ capture_timestamp));
+}
+
void VideoTrackRecorder::Encoder::SetPaused(bool paused) {
if (!encoding_task_runner_->BelongsToCurrentThread()) {
encoding_task_runner_->PostTask(
« no previous file with comments | « content/browser/media/webrtc/webrtc_media_recorder_browsertest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698