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