Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/renderer/pepper/video_encoder_shim.h" | |
| 6 | |
| 7 #include <deque> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/bind_helpers.h" | |
| 11 #include "base/memory/scoped_vector.h" | |
| 12 #include "base/memory/shared_memory.h" | |
| 13 #include "base/message_loop/message_loop.h" | |
| 14 #include "content/renderer/pepper/pepper_video_encoder_host.h" | |
| 15 #include "content/renderer/render_thread_impl.h" | |
| 16 #include "media/cast/cast_config.h" | |
| 17 #include "media/cast/sender/vp8_encoder.h" | |
| 18 #include "ui/gfx/geometry/size.h" | |
| 19 | |
| 20 namespace content { | |
| 21 | |
| 22 const int32_t kMaxWidth = 1920; | |
| 23 const int32_t kMaxHeight = 1080; | |
| 24 | |
| 25 class VideoEncoderShim::EncoderImpl { | |
| 26 public: | |
| 27 explicit EncoderImpl(const base::WeakPtr<VideoEncoderShim>& proxy); | |
| 28 ~EncoderImpl(); | |
| 29 | |
| 30 void Initialize(media::VideoFrame::Format input_format, | |
| 31 const gfx::Size& input_visible_size, | |
| 32 media::VideoCodecProfile output_profile, | |
| 33 uint32 initial_bitrate); | |
| 34 void Encode(const scoped_refptr<media::VideoFrame>& frame, | |
| 35 bool force_keyframe); | |
| 36 void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer, | |
| 37 uint8_t* mem); | |
| 38 void RequestEncodingParametersChange(uint32 bitrate, uint32 framerate); | |
| 39 void Stop(); | |
| 40 | |
| 41 private: | |
| 42 struct Frame { | |
| 43 Frame(const scoped_refptr<media::VideoFrame>& frame, bool force_keyframe) | |
| 44 : frame(frame), force_keyframe(force_keyframe) {} | |
| 45 ~Frame() {} | |
| 46 | |
| 47 scoped_refptr<media::VideoFrame> frame; | |
| 48 bool force_keyframe; | |
| 49 }; | |
| 50 | |
| 51 struct BitstreamBuffer { | |
| 52 BitstreamBuffer(const media::BitstreamBuffer buffer, uint8_t* mem) | |
| 53 : buffer(buffer), mem(mem) {} | |
| 54 ~BitstreamBuffer() {} | |
| 55 | |
| 56 media::BitstreamBuffer buffer; | |
| 57 uint8_t* mem; | |
| 58 }; | |
| 59 | |
| 60 void DoEncode(); | |
| 61 | |
| 62 base::WeakPtr<VideoEncoderShim> shim_; | |
| 63 scoped_refptr<base::SingleThreadTaskRunner> shim_task_runner_; | |
| 64 | |
| 65 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.
| |
| 66 std::deque<Frame> frames_; | |
| 67 std::deque<BitstreamBuffer> buffers_; | |
| 68 }; | |
| 69 | |
| 70 VideoEncoderShim::EncoderImpl::EncoderImpl( | |
| 71 const base::WeakPtr<VideoEncoderShim>& proxy) | |
| 72 : shim_(proxy), shim_task_runner_(base::MessageLoopProxy::current()) { | |
| 73 } | |
| 74 | |
| 75 VideoEncoderShim::EncoderImpl::~EncoderImpl() { | |
| 76 } | |
| 77 | |
| 78 void VideoEncoderShim::EncoderImpl::Initialize( | |
| 79 media::VideoFrame::Format input_format, | |
| 80 const gfx::Size& input_visible_size, | |
| 81 media::VideoCodecProfile output_profile, | |
| 82 uint32 initial_bitrate) { | |
| 83 media::cast::VideoSenderConfig config; | |
| 84 | |
| 85 config.max_number_of_video_buffers_used = | |
| 86 3; // media::cast::Vp8Encoder::kNumberOfVp8VideoBuffers; | |
| 87 config.number_of_encode_threads = 1; | |
| 88 encoder_.reset(new media::cast::Vp8Encoder(config)); | |
| 89 | |
| 90 encoder_->UpdateRates(initial_bitrate); | |
| 91 | |
| 92 shim_task_runner_->PostTask( | |
| 93 FROM_HERE, base::Bind(&VideoEncoderShim::OnRequireBitstreamBuffers, shim_, | |
| 94 3, input_visible_size, 4 * 1000000)); | |
| 95 } | |
| 96 | |
| 97 void VideoEncoderShim::EncoderImpl::Encode( | |
| 98 const scoped_refptr<media::VideoFrame>& frame, | |
| 99 bool force_keyframe) { | |
| 100 frames_.push_back(Frame(frame, force_keyframe)); | |
| 101 DoEncode(); | |
| 102 } | |
| 103 | |
| 104 void VideoEncoderShim::EncoderImpl::UseOutputBitstreamBuffer( | |
| 105 const media::BitstreamBuffer& buffer, | |
| 106 uint8_t* mem) { | |
| 107 buffers_.push_back(BitstreamBuffer(buffer, mem)); | |
| 108 DoEncode(); | |
| 109 } | |
| 110 | |
| 111 void VideoEncoderShim::EncoderImpl::RequestEncodingParametersChange( | |
| 112 uint32 bitrate, | |
| 113 uint32 framerate) { | |
| 114 encoder_->UpdateRates(bitrate); | |
| 115 } | |
| 116 | |
| 117 void VideoEncoderShim::EncoderImpl::Stop() { | |
| 118 frames_.clear(); | |
| 119 buffers_.clear(); | |
| 120 encoder_.reset(); | |
| 121 } | |
| 122 | |
| 123 void VideoEncoderShim::EncoderImpl::DoEncode() { | |
| 124 if (frames_.empty() || buffers_.empty()) | |
| 125 return; | |
| 126 | |
| 127 while (!frames_.empty() && !buffers_.empty()) { | |
| 128 Frame frame = frames_.front(); | |
| 129 frames_.pop_front(); | |
| 130 | |
| 131 if (frame.force_keyframe) | |
| 132 encoder_->GenerateKeyFrame(); | |
| 133 | |
| 134 scoped_ptr<media::cast::EncodedFrame> encoded_frame( | |
| 135 new media::cast::EncodedFrame()); | |
| 136 encoder_->Encode(frame.frame, base::TimeTicks::Now(), encoded_frame.get()); | |
| 137 | |
| 138 BitstreamBuffer buffer = buffers_.front(); | |
| 139 buffers_.pop_front(); | |
| 140 | |
| 141 CHECK(buffer.buffer.size() >= encoded_frame->data.size()); | |
| 142 memcpy(buffer.mem, encoded_frame->bytes(), encoded_frame->data.size()); | |
| 143 | |
| 144 shim_task_runner_->PostTask( | |
| 145 FROM_HERE, | |
| 146 base::Bind( | |
| 147 &VideoEncoderShim::OnBitstreamBufferReady, shim_, | |
| 148 // Pass the media::VideoFrame back | |
| 149 // to the renderer thread so it's | |
| 150 // freed on the right thread. | |
| 151 frame.frame, buffer.buffer.id(), encoded_frame->data.size(), | |
| 152 encoded_frame->dependency == media::cast::EncodedFrame::KEY)); | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 // VideoEncoderShim : | |
| 157 | |
| 158 VideoEncoderShim::VideoEncoderShim(PepperVideoEncoderHost* host) | |
| 159 : host_(host), | |
| 160 media_task_runner_( | |
| 161 RenderThreadImpl::current()->GetMediaThreadTaskRunner()), | |
| 162 weak_ptr_factory_(this) { | |
| 163 encoder_impl_.reset(new EncoderImpl(weak_ptr_factory_.GetWeakPtr())); | |
| 164 } | |
| 165 | |
| 166 VideoEncoderShim::~VideoEncoderShim() { | |
| 167 DCHECK(RenderThreadImpl::current()); | |
| 168 | |
| 169 media_task_runner_->PostTask( | |
| 170 FROM_HERE, base::Bind(&VideoEncoderShim::EncoderImpl::Stop, | |
| 171 base::Owned(encoder_impl_.release()))); | |
| 172 } | |
| 173 | |
| 174 std::vector<media::VideoEncodeAccelerator::SupportedProfile> | |
| 175 VideoEncoderShim::GetSupportedProfiles() { | |
| 176 media::VideoEncodeAccelerator::SupportedProfile profile = { | |
| 177 media::VP8PROFILE_ANY, | |
| 178 // TODO(llandwerlin): find correct values from libvpx. | |
| 179 gfx::Size(kMaxWidth, kMaxHeight), | |
| 180 media::cast::kDefaultMaxFrameRate, | |
| 181 1}; | |
| 182 std::vector<media::VideoEncodeAccelerator::SupportedProfile> profiles; | |
| 183 profiles.push_back(profile); | |
| 184 return profiles; | |
| 185 } | |
| 186 | |
| 187 bool VideoEncoderShim::Initialize( | |
| 188 media::VideoFrame::Format input_format, | |
| 189 const gfx::Size& input_visible_size, | |
| 190 media::VideoCodecProfile output_profile, | |
| 191 uint32 initial_bitrate, | |
| 192 media::VideoEncodeAccelerator::Client* client) { | |
| 193 DCHECK(RenderThreadImpl::current()); | |
| 194 DCHECK_EQ(client, host_); | |
| 195 | |
| 196 if (input_format != media::VideoFrame::I420) | |
| 197 return false; | |
| 198 if (output_profile != media::VP8PROFILE_ANY) | |
| 199 return false; | |
| 200 if (input_visible_size.width() > kMaxWidth || | |
| 201 input_visible_size.height() > kMaxHeight) | |
| 202 return false; | |
| 203 | |
| 204 media_task_runner_->PostTask( | |
| 205 FROM_HERE, | |
| 206 base::Bind(&VideoEncoderShim::EncoderImpl::Initialize, | |
| 207 base::Unretained(encoder_impl_.get()), input_format, | |
| 208 input_visible_size, output_profile, initial_bitrate)); | |
| 209 | |
| 210 return true; | |
| 211 } | |
| 212 | |
| 213 void VideoEncoderShim::Encode(const scoped_refptr<media::VideoFrame>& frame, | |
| 214 bool force_keyframe) { | |
| 215 DCHECK(RenderThreadImpl::current()); | |
| 216 | |
| 217 media_task_runner_->PostTask( | |
| 218 FROM_HERE, | |
| 219 base::Bind(&VideoEncoderShim::EncoderImpl::Encode, | |
| 220 base::Unretained(encoder_impl_.get()), frame, force_keyframe)); | |
| 221 } | |
| 222 | |
| 223 void VideoEncoderShim::UseOutputBitstreamBuffer( | |
| 224 const media::BitstreamBuffer& buffer) { | |
| 225 DCHECK(RenderThreadImpl::current()); | |
| 226 | |
| 227 media_task_runner_->PostTask( | |
| 228 FROM_HERE, | |
| 229 base::Bind(&VideoEncoderShim::EncoderImpl::UseOutputBitstreamBuffer, | |
| 230 base::Unretained(encoder_impl_.get()), buffer, | |
| 231 host_->ShmHandleToAddress(buffer.id()))); | |
| 232 } | |
| 233 | |
| 234 void VideoEncoderShim::RequestEncodingParametersChange(uint32 bitrate, | |
| 235 uint32 framerate) { | |
| 236 DCHECK(RenderThreadImpl::current()); | |
| 237 | |
| 238 media_task_runner_->PostTask( | |
| 239 FROM_HERE, | |
| 240 base::Bind( | |
| 241 &VideoEncoderShim::EncoderImpl::RequestEncodingParametersChange, | |
| 242 base::Unretained(encoder_impl_.get()), bitrate, framerate)); | |
| 243 } | |
| 244 | |
| 245 void VideoEncoderShim::Destroy() { | |
| 246 DCHECK(RenderThreadImpl::current()); | |
| 247 | |
| 248 delete this; | |
| 249 } | |
| 250 | |
| 251 void VideoEncoderShim::OnRequireBitstreamBuffers( | |
| 252 unsigned int input_count, | |
| 253 const gfx::Size& input_coded_size, | |
| 254 size_t output_buffer_size) { | |
| 255 DCHECK(RenderThreadImpl::current()); | |
| 256 | |
| 257 host_->RequireBitstreamBuffers(input_count, input_coded_size, | |
| 258 output_buffer_size); | |
| 259 } | |
| 260 | |
| 261 void VideoEncoderShim::OnBitstreamBufferReady( | |
| 262 scoped_refptr<media::VideoFrame> frame, | |
| 263 int32 bitstream_buffer_id, | |
| 264 size_t payload_size, | |
| 265 bool key_frame) { | |
| 266 DCHECK(RenderThreadImpl::current()); | |
| 267 | |
| 268 host_->BitstreamBufferReady(bitstream_buffer_id, payload_size, key_frame); | |
| 269 } | |
| 270 | |
| 271 void VideoEncoderShim::OnNotifyError( | |
| 272 media::VideoEncodeAccelerator::Error error) { | |
| 273 DCHECK(RenderThreadImpl::current()); | |
| 274 | |
| 275 host_->NotifyError(error); | |
| 276 } | |
| 277 | |
| 278 } // namespace content | |
| OLD | NEW |