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

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

Issue 1211973012: [Experimental] MediaStreamRecorder playground (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Removed FFmpegMuxer, using instead libwebm::IMkvMuxer, which is partially added Created 5 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/renderer/media/video_track_recorder.h ('k') | content/renderer/renderer_blink_platform_impl.h » ('j') | 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
new file mode 100644
index 0000000000000000000000000000000000000000..fa3057668f34332b0c15f59889cf1d520135b4ef
--- /dev/null
+++ b/content/renderer/media/video_track_recorder.cc
@@ -0,0 +1,181 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/media/video_track_recorder.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/trace_event/trace_event.h"
+#include "media/base/bind_to_current_loop.h"
+#include "media/base/video_capture_types.h"
+#include "media/base/video_frame.h"
+
+#define VPX_CODEC_DISABLE_COMPAT 1
+#include "third_party/libvpx/source/libvpx/vpx/vp8cx.h"
+#include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h"
+#define interface (vpx_codec_vp8_cx())
+
+namespace content {
+
+const uint32 kVideoFrequency = 90000;
+
+class VideoTrackRecorder::Encoder : public base::RefCountedThreadSafe<Encoder> {
+ public:
+ Encoder(const VideoEncoderCB& callback);
+
+ void EncodeOnIo(const scoped_refptr<media::VideoFrame>& frame,
+ const base::TimeTicks& estimated_capture_time);
+
+ void CancelEncoding();
+
+ private:
+ friend class base::RefCountedThreadSafe<Encoder>;
+ virtual ~Encoder();
+
+ // Used to DCHECK that we are called on the correct thread.
+ base::ThreadChecker thread_checker_;
+
+ VideoEncoderCB callback_;
+ bool first_frame_;
+
+ // VP8 internal objects. TODO(mcasas): make scoped_ptr<>?
+ vpx_codec_ctx_t codec_;
+ vpx_codec_enc_cfg_t cfg_;
+ vpx_image_t* raw_image_;
+ int frame_cnt_;
+
+ base::TimeTicks timestamp_base_;
+};
+
+VideoTrackRecorder::Encoder::Encoder(const VideoEncoderCB& callback)
+ : callback_(callback),
+ first_frame_(false),
+ raw_image_(nullptr),
+ frame_cnt_(0) {
+ DVLOG(3) << __FUNCTION__;
+}
+
+VideoTrackRecorder::Encoder::~Encoder() {
+ DVLOG(3) << __FUNCTION__;
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (first_frame_)
+ vpx_codec_destroy(&codec_);
+ vpx_img_free(raw_image_);
+}
+
+void VideoTrackRecorder::Encoder::EncodeOnIo(
+ const scoped_refptr<media::VideoFrame>& frame,
+ const base::TimeTicks& estimated_capture_time) {
+ DVLOG(3) << __FUNCTION__;
+ DCHECK(thread_checker_.CalledOnValidThread());
+ TRACE_EVENT0("video", "VideoTrackRecorder::Encoder::EncodeOnIo");
+ if (callback_.is_null())
+ return;
+
+ const base::TimeTicks encode_start_time = base::TimeTicks::Now();
+ if(!first_frame_) {
+ vpx_codec_enc_config_default(interface, &cfg_, 0);
+
+ /* Update the default configuration with our settings */
+ cfg_.rc_target_bitrate =
+ frame->natural_size().width() * frame->natural_size().height() *
+ cfg_.rc_target_bitrate / cfg_.g_w / cfg_.g_h;
+ cfg_.g_w = frame->natural_size().width();
+ cfg_.g_h = frame->natural_size().height();
+
+ // Setting the codec time base.
+ cfg_.g_timebase.num = 1;
+ cfg_.g_timebase.den = kVideoFrequency;
+ cfg_.g_lag_in_frames = 0;
+// cfg_.kf_mode = VPX_KF_DISABLED;
+ cfg_.kf_mode = VPX_KF_AUTO;
+ cfg_.kf_min_dist = 300;
+ cfg_.kf_max_dist = 300;
+
+ vpx_codec_err_t ret = vpx_codec_enc_init(&codec_, interface, &cfg_, 0);
+ DCHECK(ret == VPX_CODEC_OK);
+
+ // Creating a wrapper to the image - setting image data to NULL. Actual
+ // pointer will be set during encode. Setting align to 1, as it is
+ // meaningless (actual memory is not allocated).
+ raw_image_ =
+ vpx_img_wrap(nullptr, VPX_IMG_FMT_I420, frame->natural_size().width(),
+ frame->natural_size().height(), 1, nullptr);
+
+ first_frame_ = false;
+ timestamp_base_ = encode_start_time;
+ }
+
+ // TODO(mcasas): get this from |frame|.
+ const float frame_rate = 30.0f;
+ const int timestamp = (encode_start_time - timestamp_base_).InMilliseconds();
+ const int duration = kVideoFrequency / frame_rate;
+ // Image in vpx_image_t format.
+ // Input image is const. VP8's raw image is not defined as const.
+ raw_image_->planes[VPX_PLANE_Y] =
+ const_cast<uint8*>(frame->data(media::VideoFrame::kYPlane));
+ raw_image_->planes[VPX_PLANE_U] =
+ const_cast<uint8*>(frame->data(media::VideoFrame::kUPlane));
+ raw_image_->planes[VPX_PLANE_V] =
+ const_cast<uint8*>(frame->data(media::VideoFrame::kVPlane));
+
+ raw_image_->stride[VPX_PLANE_Y] = frame->stride(media::VideoFrame::kYPlane);
+ raw_image_->stride[VPX_PLANE_U] = frame->stride(media::VideoFrame::kUPlane);
+ raw_image_->stride[VPX_PLANE_V] = frame->stride(media::VideoFrame::kVPlane);
+
+
+ int flags = 0;
+ vpx_codec_err_t ret = vpx_codec_encode(&codec_, raw_image_, timestamp,
+ duration, flags, VPX_DL_REALTIME);
+
+ DCHECK_EQ(ret, VPX_CODEC_OK)
+ << "Encoding error: " << vpx_codec_err_to_string(ret) << "\n"
+ << "Details: " << vpx_codec_error(&codec_) << "\n"
+ << vpx_codec_error_detail(&codec_);
+
+ std::string data;
+ bool keyframe = false;
+ const vpx_codec_cx_pkt_t *pkt;
+ vpx_codec_iter_t iter = nullptr;
+ while( (pkt = vpx_codec_get_cx_data(&codec_, &iter)) ) {
+ if (pkt->kind != VPX_CODEC_CX_FRAME_PKT)
+ continue;
+
+ data.append(static_cast<const char*>(pkt->data.frame.buf),
+ pkt->data.frame.sz);
+ keyframe = !!(pkt->data.frame.flags & VPX_FRAME_IS_KEY);
+ LOG(ERROR) << "keyframe" << keyframe;
+ break;
+ }
+ callback_.Run(data,
+ estimated_capture_time,
+ keyframe,
+ frame->natural_size(),
+ frame_rate);
+}
+
+void VideoTrackRecorder::Encoder::CancelEncoding() {
+ callback_.Reset();
+}
+
+VideoTrackRecorder::VideoTrackRecorder(const blink::WebMediaStreamTrack& track,
+ const VideoEncoderCB& callback)
+ : web_track_(track),
+ encoder_(new VideoTrackRecorder::Encoder(callback)) {
+ DVLOG(3) << __FUNCTION__;
+ AddToVideoTrack(
+ this,
+ media::BindToCurrentLoop(
+ base::Bind(&VideoTrackRecorder::Encoder::EncodeOnIo, encoder_)),
+ web_track_);
+
+}
+
+VideoTrackRecorder::~VideoTrackRecorder() {
+ DVLOG(3) << __FUNCTION__;
+ RemoveFromVideoTrack(this, web_track_);
+ encoder_->CancelEncoding();
+}
+
+} // namespace content
« no previous file with comments | « content/renderer/media/video_track_recorder.h ('k') | content/renderer/renderer_blink_platform_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698