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

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: Another android dep fix Created 5 years, 9 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/pepper/video_encoder_shim.h ('k') | ppapi/examples/video_encode/video_encode.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..a89f18c719965061fcf6f5b98ea87bf1693642f8
--- /dev/null
+++ b/content/renderer/pepper/video_encoder_shim.cc
@@ -0,0 +1,279 @@
+// 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 <inttypes.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 {
+
+// TODO(llandwerlin): Libvpx doesn't seem to have a maximum frame size
+// limitation. We currently limit the size of the frames to encode at
+// 1080p (%64 pixels blocks), this seems like a reasonable limit for
+// software encoding.
+const int32_t kMaxWidth = 1920;
+const int32_t kMaxHeight = 1088;
+
+// Bitstream buffer size.
+const uint32_t kBitstreamBufferSize = 2 * 1024 * 1024;
+
+// Number of frames needs at any given time.
+const uint32_t kInputFrameCount = 1;
+
+class VideoEncoderShim::EncoderImpl {
+ public:
+ explicit EncoderImpl(const base::WeakPtr<VideoEncoderShim>& shim);
+ ~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 PendingEncode {
+ PendingEncode(const scoped_refptr<media::VideoFrame>& frame,
+ bool force_keyframe)
+ : frame(frame), force_keyframe(force_keyframe) {}
+ ~PendingEncode() {}
+
+ 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> media_task_runner_;
+
+ scoped_ptr<media::cast::SoftwareVideoEncoder> encoder_;
+ std::deque<PendingEncode> frames_;
+ std::deque<BitstreamBuffer> buffers_;
+};
+
+VideoEncoderShim::EncoderImpl::EncoderImpl(
+ const base::WeakPtr<VideoEncoderShim>& shim)
+ : shim_(shim), media_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 = kInputFrameCount;
+ config.number_of_encode_threads = 1;
+ encoder_.reset(new media::cast::Vp8Encoder(config));
+
+ encoder_->UpdateRates(initial_bitrate);
+
+ media_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&VideoEncoderShim::OnRequireBitstreamBuffers, shim_,
+ kInputFrameCount, input_visible_size,
+ kBitstreamBufferSize));
+}
+
+void VideoEncoderShim::EncoderImpl::Encode(
+ const scoped_refptr<media::VideoFrame>& frame,
+ bool force_keyframe) {
+ frames_.push_back(PendingEncode(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() {
+ while (!frames_.empty() && !buffers_.empty()) {
+ PendingEncode 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());
+
+ // Pass the media::VideoFrame back to the renderer thread so it's
+ // freed on the right thread.
+ media_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &VideoEncoderShim::OnBitstreamBufferReady, shim_,
+ frame.frame, buffer.buffer.id(), encoded_frame->data.size(),
+ encoded_frame->dependency == media::cast::EncodedFrame::KEY));
+ }
+}
+
+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,
+ 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;
+
+ 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
« no previous file with comments | « content/renderer/pepper/video_encoder_shim.h ('k') | ppapi/examples/video_encode/video_encode.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698