OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "remoting/codec/video_encoder_vpx.h" | 5 #include "remoting/codec/video_encoder_vpx.h" |
6 | 6 |
7 #include <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 image->w = size.width(); | 180 image->w = size.width(); |
181 image->d_h = size.height(); | 181 image->d_h = size.height(); |
182 image->h = size.height(); | 182 image->h = size.height(); |
183 | 183 |
184 // libvpx should derive chroma shifts from|fmt| but currently has a bug: | 184 // libvpx should derive chroma shifts from|fmt| but currently has a bug: |
185 // https://code.google.com/p/webm/issues/detail?id=627 | 185 // https://code.google.com/p/webm/issues/detail?id=627 |
186 if (use_i444) { | 186 if (use_i444) { |
187 image->fmt = VPX_IMG_FMT_I444; | 187 image->fmt = VPX_IMG_FMT_I444; |
188 image->x_chroma_shift = 0; | 188 image->x_chroma_shift = 0; |
189 image->y_chroma_shift = 0; | 189 image->y_chroma_shift = 0; |
190 } else { // I420 | 190 } else { // I420 |
191 image->fmt = VPX_IMG_FMT_YV12; | 191 image->fmt = VPX_IMG_FMT_YV12; |
192 image->x_chroma_shift = 1; | 192 image->x_chroma_shift = 1; |
193 image->y_chroma_shift = 1; | 193 image->y_chroma_shift = 1; |
194 } | 194 } |
195 | 195 |
196 // libyuv's fast-path requires 16-byte aligned pointers and strides, so pad | 196 // libyuv's fast-path requires 16-byte aligned pointers and strides, so pad |
197 // the Y, U and V planes' strides to multiples of 16 bytes. | 197 // the Y, U and V planes' strides to multiples of 16 bytes. |
198 const int y_stride = ((image->w - 1) & ~15) + 16; | 198 const int y_stride = ((image->w - 1) & ~15) + 16; |
199 const int uv_unaligned_stride = y_stride >> image->x_chroma_shift; | 199 const int uv_unaligned_stride = y_stride >> image->x_chroma_shift; |
200 const int uv_stride = ((uv_unaligned_stride - 1) & ~15) + 16; | 200 const int uv_stride = ((uv_unaligned_stride - 1) & ~15) + 16; |
(...skipping 21 matching lines...) Expand all Loading... |
222 image->planes[1] = image->planes[0] + y_stride * y_rows; | 222 image->planes[1] = image->planes[0] + y_stride * y_rows; |
223 image->planes[2] = image->planes[1] + uv_stride * uv_rows; | 223 image->planes[2] = image->planes[1] + uv_stride * uv_rows; |
224 image->stride[0] = y_stride; | 224 image->stride[0] = y_stride; |
225 image->stride[1] = uv_stride; | 225 image->stride[1] = uv_stride; |
226 image->stride[2] = uv_stride; | 226 image->stride[2] = uv_stride; |
227 | 227 |
228 *out_image = std::move(image); | 228 *out_image = std::move(image); |
229 *out_image_buffer = std::move(image_buffer); | 229 *out_image_buffer = std::move(image_buffer); |
230 } | 230 } |
231 | 231 |
232 } // namespace | 232 } // namespace |
233 | 233 |
234 // static | 234 // static |
235 std::unique_ptr<VideoEncoderVpx> VideoEncoderVpx::CreateForVP8() { | 235 std::unique_ptr<VideoEncoderVpx> VideoEncoderVpx::CreateForVP8() { |
236 return base::WrapUnique(new VideoEncoderVpx(false)); | 236 return base::WrapUnique(new VideoEncoderVpx(false)); |
237 } | 237 } |
238 | 238 |
239 // static | 239 // static |
240 std::unique_ptr<VideoEncoderVpx> VideoEncoderVpx::CreateForVP9() { | 240 std::unique_ptr<VideoEncoderVpx> VideoEncoderVpx::CreateForVP9() { |
241 return base::WrapUnique(new VideoEncoderVpx(true)); | 241 return base::WrapUnique(new VideoEncoderVpx(true)); |
242 } | 242 } |
(...skipping 11 matching lines...) Expand all Loading... |
254 Configure(webrtc::DesktopSize(codec_->config.enc->g_w, | 254 Configure(webrtc::DesktopSize(codec_->config.enc->g_w, |
255 codec_->config.enc->g_h)); | 255 codec_->config.enc->g_h)); |
256 } | 256 } |
257 } | 257 } |
258 | 258 |
259 void VideoEncoderVpx::SetLosslessColor(bool want_lossless) { | 259 void VideoEncoderVpx::SetLosslessColor(bool want_lossless) { |
260 if (use_vp9_ && (want_lossless != lossless_color_)) { | 260 if (use_vp9_ && (want_lossless != lossless_color_)) { |
261 lossless_color_ = want_lossless; | 261 lossless_color_ = want_lossless; |
262 // TODO(wez): Switch to ConfigureCodec() path once libvpx supports it. | 262 // TODO(wez): Switch to ConfigureCodec() path once libvpx supports it. |
263 // See https://code.google.com/p/webm/issues/detail?id=913. | 263 // See https://code.google.com/p/webm/issues/detail?id=913. |
264 //if (codec_) | 264 // if (codec_) |
265 // Configure(webrtc::DesktopSize(codec_->config.enc->g_w, | 265 // Configure(webrtc::DesktopSize(codec_->config.enc->g_w, |
266 // codec_->config.enc->g_h)); | 266 // codec_->config.enc->g_h)); |
267 codec_.reset(); | 267 codec_.reset(); |
268 } | 268 } |
269 } | 269 } |
270 | 270 |
271 std::unique_ptr<VideoPacket> VideoEncoderVpx::Encode( | 271 std::unique_ptr<VideoPacket> VideoEncoderVpx::Encode( |
272 const webrtc::DesktopFrame& frame) { | 272 const webrtc::DesktopFrame& frame, |
| 273 uint32_t flags) { |
273 DCHECK_LE(32, frame.size().width()); | 274 DCHECK_LE(32, frame.size().width()); |
274 DCHECK_LE(32, frame.size().height()); | 275 DCHECK_LE(32, frame.size().height()); |
275 | 276 |
276 // If there is nothing to encode, and nothing to top-off, then return nothing. | 277 // If there is nothing to encode, and nothing to top-off, then return nothing. |
277 if (frame.updated_region().is_empty() && !encode_unchanged_frame_) | 278 if (frame.updated_region().is_empty() && !encode_unchanged_frame_) |
278 return nullptr; | 279 return nullptr; |
279 | 280 |
280 // Create or reconfigure the codec to match the size of |frame|. | 281 // Create or reconfigure the codec to match the size of |frame|. |
281 if (!codec_ || | 282 if (!codec_ || |
282 (image_ && | 283 (image_ && |
(...skipping 10 matching lines...) Expand all Loading... |
293 | 294 |
294 // Apply active map to the encoder. | 295 // Apply active map to the encoder. |
295 vpx_active_map_t act_map; | 296 vpx_active_map_t act_map; |
296 act_map.rows = active_map_size_.height(); | 297 act_map.rows = active_map_size_.height(); |
297 act_map.cols = active_map_size_.width(); | 298 act_map.cols = active_map_size_.width(); |
298 act_map.active_map = active_map_.get(); | 299 act_map.active_map = active_map_.get(); |
299 if (vpx_codec_control(codec_.get(), VP8E_SET_ACTIVEMAP, &act_map)) { | 300 if (vpx_codec_control(codec_.get(), VP8E_SET_ACTIVEMAP, &act_map)) { |
300 LOG(ERROR) << "Unable to apply active map"; | 301 LOG(ERROR) << "Unable to apply active map"; |
301 } | 302 } |
302 | 303 |
| 304 if (flags & REQUEST_KEY_FRAME) |
| 305 vpx_codec_control(codec_.get(), VP8E_SET_FRAME_FLAGS, VPX_EFLAG_FORCE_KF); |
| 306 |
303 // Do the actual encoding. | 307 // Do the actual encoding. |
304 int timestamp = (clock_->NowTicks() - timestamp_base_).InMilliseconds(); | 308 int timestamp = (clock_->NowTicks() - timestamp_base_).InMilliseconds(); |
305 vpx_codec_err_t ret = vpx_codec_encode( | 309 vpx_codec_err_t ret = vpx_codec_encode( |
306 codec_.get(), image_.get(), timestamp, 1, 0, VPX_DL_REALTIME); | 310 codec_.get(), image_.get(), timestamp, 1, 0, VPX_DL_REALTIME); |
307 DCHECK_EQ(ret, VPX_CODEC_OK) | 311 DCHECK_EQ(ret, VPX_CODEC_OK) |
308 << "Encoding error: " << vpx_codec_err_to_string(ret) << "\n" | 312 << "Encoding error: " << vpx_codec_err_to_string(ret) << "\n" |
309 << "Details: " << vpx_codec_error(codec_.get()) << "\n" | 313 << "Details: " << vpx_codec_error(codec_.get()) << "\n" |
310 << vpx_codec_error_detail(codec_.get()); | 314 << vpx_codec_error_detail(codec_.get()); |
311 | 315 |
312 if (use_vp9_ && !lossless_encode_) { | 316 if (use_vp9_ && !lossless_encode_) { |
(...skipping 20 matching lines...) Expand all Loading... |
333 while (!got_data) { | 337 while (!got_data) { |
334 const vpx_codec_cx_pkt_t* vpx_packet = | 338 const vpx_codec_cx_pkt_t* vpx_packet = |
335 vpx_codec_get_cx_data(codec_.get(), &iter); | 339 vpx_codec_get_cx_data(codec_.get(), &iter); |
336 if (!vpx_packet) | 340 if (!vpx_packet) |
337 continue; | 341 continue; |
338 | 342 |
339 switch (vpx_packet->kind) { | 343 switch (vpx_packet->kind) { |
340 case VPX_CODEC_CX_FRAME_PKT: | 344 case VPX_CODEC_CX_FRAME_PKT: |
341 got_data = true; | 345 got_data = true; |
342 packet->set_data(vpx_packet->data.frame.buf, vpx_packet->data.frame.sz); | 346 packet->set_data(vpx_packet->data.frame.buf, vpx_packet->data.frame.sz); |
| 347 packet->set_key_frame(vpx_packet->data.frame.flags & VPX_FRAME_IS_KEY); |
343 break; | 348 break; |
344 default: | 349 default: |
345 break; | 350 break; |
346 } | 351 } |
347 } | 352 } |
348 | 353 |
349 return packet; | 354 return packet; |
350 } | 355 } |
351 | 356 |
352 VideoEncoderVpx::VideoEncoderVpx(bool use_vp9) | 357 VideoEncoderVpx::VideoEncoderVpx(bool use_vp9) |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
542 kMacroBlockSize * (y + 1))); | 547 kMacroBlockSize * (y + 1))); |
543 } | 548 } |
544 x0 = x1 + 1; | 549 x0 = x1 + 1; |
545 } | 550 } |
546 } | 551 } |
547 updated_region->IntersectWith( | 552 updated_region->IntersectWith( |
548 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); | 553 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); |
549 } | 554 } |
550 | 555 |
551 } // namespace remoting | 556 } // namespace remoting |
OLD | NEW |