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

Unified Diff: content/renderer/pepper/video_encoder_shim.cc

Issue 956893002: content: pepper: VideoEncoder: add software encoder support (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 10 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
Index: content/renderer/pepper/video_encoder_shim.cc
diff --git a/content/renderer/pepper/video_encoder_shim.cc b/content/renderer/pepper/video_encoder_shim.cc
new file mode 100644
index 0000000000000000000000000000000000000000..fb7ea24f98b99f59f7c5e5497734dae918bbacc3
--- /dev/null
+++ b/content/renderer/pepper/video_encoder_shim.cc
@@ -0,0 +1,278 @@
+// 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/pepper/video_encoder_shim.h"
+
+#include <deque>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/scoped_vector.h"
+#include "base/memory/shared_memory.h"
+#include "base/message_loop/message_loop.h"
+#include "content/renderer/pepper/pepper_video_encoder_host.h"
+#include "content/renderer/render_thread_impl.h"
+#include "media/cast/cast_config.h"
+#include "media/cast/sender/vp8_encoder.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace content {
+
+const int32_t kMaxWidth = 1920;
+const int32_t kMaxHeight = 1080;
+
+class VideoEncoderShim::EncoderImpl {
+ public:
+ explicit EncoderImpl(const base::WeakPtr<VideoEncoderShim>& proxy);
+ ~EncoderImpl();
+
+ void Initialize(media::VideoFrame::Format input_format,
+ const gfx::Size& input_visible_size,
+ media::VideoCodecProfile output_profile,
+ uint32 initial_bitrate);
+ void Encode(const scoped_refptr<media::VideoFrame>& frame,
+ bool force_keyframe);
+ void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer,
+ uint8_t* mem);
+ void RequestEncodingParametersChange(uint32 bitrate, uint32 framerate);
+ void Stop();
+
+ private:
+ struct Frame {
+ Frame(const scoped_refptr<media::VideoFrame>& frame, bool force_keyframe)
+ : frame(frame), force_keyframe(force_keyframe) {}
+ ~Frame() {}
+
+ scoped_refptr<media::VideoFrame> frame;
+ bool force_keyframe;
+ };
+
+ struct BitstreamBuffer {
+ BitstreamBuffer(const media::BitstreamBuffer buffer, uint8_t* mem)
+ : buffer(buffer), mem(mem) {}
+ ~BitstreamBuffer() {}
+
+ media::BitstreamBuffer buffer;
+ uint8_t* mem;
+ };
+
+ void DoEncode();
+
+ base::WeakPtr<VideoEncoderShim> shim_;
+ scoped_refptr<base::SingleThreadTaskRunner> shim_task_runner_;
+
+ scoped_ptr<media::cast::Vp8Encoder> encoder_;
bbudge 2015/02/25 17:58:22 Could we make this SoftwareVideoEncoder in case ot
llandwerlin-old 2015/02/26 13:02:13 Done.
+ std::deque<Frame> frames_;
+ std::deque<BitstreamBuffer> buffers_;
+};
+
+VideoEncoderShim::EncoderImpl::EncoderImpl(
+ const base::WeakPtr<VideoEncoderShim>& proxy)
+ : shim_(proxy), shim_task_runner_(base::MessageLoopProxy::current()) {
+}
+
+VideoEncoderShim::EncoderImpl::~EncoderImpl() {
+}
+
+void VideoEncoderShim::EncoderImpl::Initialize(
+ media::VideoFrame::Format input_format,
+ const gfx::Size& input_visible_size,
+ media::VideoCodecProfile output_profile,
+ uint32 initial_bitrate) {
+ media::cast::VideoSenderConfig config;
+
+ config.max_number_of_video_buffers_used =
+ 3; // media::cast::Vp8Encoder::kNumberOfVp8VideoBuffers;
+ config.number_of_encode_threads = 1;
+ encoder_.reset(new media::cast::Vp8Encoder(config));
+
+ encoder_->UpdateRates(initial_bitrate);
+
+ shim_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VideoEncoderShim::OnRequireBitstreamBuffers, shim_,
+ 3, input_visible_size, 4 * 1000000));
+}
+
+void VideoEncoderShim::EncoderImpl::Encode(
+ const scoped_refptr<media::VideoFrame>& frame,
+ bool force_keyframe) {
+ frames_.push_back(Frame(frame, force_keyframe));
+ DoEncode();
+}
+
+void VideoEncoderShim::EncoderImpl::UseOutputBitstreamBuffer(
+ const media::BitstreamBuffer& buffer,
+ uint8_t* mem) {
+ buffers_.push_back(BitstreamBuffer(buffer, mem));
+ DoEncode();
+}
+
+void VideoEncoderShim::EncoderImpl::RequestEncodingParametersChange(
+ uint32 bitrate,
+ uint32 framerate) {
+ encoder_->UpdateRates(bitrate);
+}
+
+void VideoEncoderShim::EncoderImpl::Stop() {
+ frames_.clear();
+ buffers_.clear();
+ encoder_.reset();
+}
+
+void VideoEncoderShim::EncoderImpl::DoEncode() {
+ if (frames_.empty() || buffers_.empty())
+ return;
+
+ while (!frames_.empty() && !buffers_.empty()) {
+ Frame frame = frames_.front();
+ frames_.pop_front();
+
+ if (frame.force_keyframe)
+ encoder_->GenerateKeyFrame();
+
+ scoped_ptr<media::cast::EncodedFrame> encoded_frame(
+ new media::cast::EncodedFrame());
+ encoder_->Encode(frame.frame, base::TimeTicks::Now(), encoded_frame.get());
+
+ BitstreamBuffer buffer = buffers_.front();
+ buffers_.pop_front();
+
+ CHECK(buffer.buffer.size() >= encoded_frame->data.size());
+ memcpy(buffer.mem, encoded_frame->bytes(), encoded_frame->data.size());
+
+ shim_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &VideoEncoderShim::OnBitstreamBufferReady, shim_,
+ // Pass the media::VideoFrame back
+ // to the renderer thread so it's
+ // freed on the right thread.
+ frame.frame, buffer.buffer.id(), encoded_frame->data.size(),
+ encoded_frame->dependency == media::cast::EncodedFrame::KEY));
+ }
+}
+
+// VideoEncoderShim :
+
+VideoEncoderShim::VideoEncoderShim(PepperVideoEncoderHost* host)
+ : host_(host),
+ media_task_runner_(
+ RenderThreadImpl::current()->GetMediaThreadTaskRunner()),
+ weak_ptr_factory_(this) {
+ encoder_impl_.reset(new EncoderImpl(weak_ptr_factory_.GetWeakPtr()));
+}
+
+VideoEncoderShim::~VideoEncoderShim() {
+ DCHECK(RenderThreadImpl::current());
+
+ media_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VideoEncoderShim::EncoderImpl::Stop,
+ base::Owned(encoder_impl_.release())));
+}
+
+std::vector<media::VideoEncodeAccelerator::SupportedProfile>
+VideoEncoderShim::GetSupportedProfiles() {
+ media::VideoEncodeAccelerator::SupportedProfile profile = {
+ media::VP8PROFILE_ANY,
+ // TODO(llandwerlin): find correct values from libvpx.
+ gfx::Size(kMaxWidth, kMaxHeight),
+ media::cast::kDefaultMaxFrameRate,
+ 1};
+ std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles;
+ profiles.push_back(profile);
+ return profiles;
+}
+
+bool VideoEncoderShim::Initialize(
+ media::VideoFrame::Format input_format,
+ const gfx::Size& input_visible_size,
+ media::VideoCodecProfile output_profile,
+ uint32 initial_bitrate,
+ media::VideoEncodeAccelerator::Client* client) {
+ DCHECK(RenderThreadImpl::current());
+ DCHECK_EQ(client, host_);
+
+ if (input_format != media::VideoFrame::I420)
+ return false;
+ if (output_profile != media::VP8PROFILE_ANY)
+ return false;
+ if (input_visible_size.width() > kMaxWidth ||
+ input_visible_size.height() > kMaxHeight)
+ return false;
+
+ media_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&VideoEncoderShim::EncoderImpl::Initialize,
+ base::Unretained(encoder_impl_.get()), input_format,
+ input_visible_size, output_profile, initial_bitrate));
+
+ return true;
+}
+
+void VideoEncoderShim::Encode(const scoped_refptr<media::VideoFrame>& frame,
+ bool force_keyframe) {
+ DCHECK(RenderThreadImpl::current());
+
+ media_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&VideoEncoderShim::EncoderImpl::Encode,
+ base::Unretained(encoder_impl_.get()), frame, force_keyframe));
+}
+
+void VideoEncoderShim::UseOutputBitstreamBuffer(
+ const media::BitstreamBuffer& buffer) {
+ DCHECK(RenderThreadImpl::current());
+
+ media_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&VideoEncoderShim::EncoderImpl::UseOutputBitstreamBuffer,
+ base::Unretained(encoder_impl_.get()), buffer,
+ host_->ShmHandleToAddress(buffer.id())));
+}
+
+void VideoEncoderShim::RequestEncodingParametersChange(uint32 bitrate,
+ uint32 framerate) {
+ DCHECK(RenderThreadImpl::current());
+
+ media_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &VideoEncoderShim::EncoderImpl::RequestEncodingParametersChange,
+ base::Unretained(encoder_impl_.get()), bitrate, framerate));
+}
+
+void VideoEncoderShim::Destroy() {
+ DCHECK(RenderThreadImpl::current());
+
+ delete this;
+}
+
+void VideoEncoderShim::OnRequireBitstreamBuffers(
+ unsigned int input_count,
+ const gfx::Size& input_coded_size,
+ size_t output_buffer_size) {
+ DCHECK(RenderThreadImpl::current());
+
+ host_->RequireBitstreamBuffers(input_count, input_coded_size,
+ output_buffer_size);
+}
+
+void VideoEncoderShim::OnBitstreamBufferReady(
+ scoped_refptr<media::VideoFrame> frame,
+ int32 bitstream_buffer_id,
+ size_t payload_size,
+ bool key_frame) {
+ DCHECK(RenderThreadImpl::current());
+
+ host_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame);
+}
+
+void VideoEncoderShim::OnNotifyError(
+ media::VideoEncodeAccelerator::Error error) {
+ DCHECK(RenderThreadImpl::current());
+
+ host_->NotifyError(error);
+}
+
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698