Index: media/cast/sender/vp8_encoder.cc |
diff --git a/media/cast/sender/vp8_encoder.cc b/media/cast/sender/vp8_encoder.cc |
index e0f84078acee7053963a8fb6d759ed5c39882fdf..bf430c1869c082e0d90a5e911ee36af74643ae01 100644 |
--- a/media/cast/sender/vp8_encoder.cc |
+++ b/media/cast/sender/vp8_encoder.cc |
@@ -28,8 +28,8 @@ |
use_multiple_video_buffers_( |
cast_config_.max_number_of_video_buffers_used == |
kNumberOfVp8VideoBuffers), |
+ raw_image_(nullptr), |
key_frame_requested_(true), |
- bitrate_kbit_(cast_config_.start_bitrate / 1000), |
last_encoded_frame_id_(kStartFrameId), |
last_acked_frame_id_(kStartFrameId), |
undroppable_frames_(0) { |
@@ -53,40 +53,18 @@ |
DCHECK(thread_checker_.CalledOnValidThread()); |
if (is_initialized()) |
vpx_codec_destroy(&encoder_); |
+ vpx_img_free(raw_image_); |
} |
void Vp8Encoder::Initialize() { |
DCHECK(thread_checker_.CalledOnValidThread()); |
DCHECK(!is_initialized()); |
- // The encoder will be created/configured when the first frame encode is |
- // requested. |
-} |
- |
-void Vp8Encoder::ConfigureForNewFrameSize(const gfx::Size& frame_size) { |
- if (is_initialized()) { |
- // Workaround for VP8 bug: If the new size is strictly less-than-or-equal to |
- // the old size, in terms of area, the existing encoder instance can |
- // continue. Otherwise, completely tear-down and re-create a new encoder to |
- // avoid a shutdown crash. |
- if (frame_size.GetArea() <= gfx::Size(config_.g_w, config_.g_h).GetArea()) { |
- DVLOG(1) << "Continuing to use existing encoder at smaller frame size: " |
- << gfx::Size(config_.g_w, config_.g_h).ToString() << " --> " |
- << frame_size.ToString(); |
- config_.g_w = frame_size.width(); |
- config_.g_h = frame_size.height(); |
- CHECK_EQ(vpx_codec_enc_config_set(&encoder_, &config_), VPX_CODEC_OK) |
- << "Failed to update frame size in encoder config."; |
- return; |
- } |
- |
- DVLOG(1) << "Destroying/Re-Creating encoder for larger frame size: " |
- << gfx::Size(config_.g_w, config_.g_h).ToString() << " --> " |
- << frame_size.ToString(); |
- vpx_codec_destroy(&encoder_); |
- } else { |
- DVLOG(1) << "Creating encoder for the first frame; size: " |
- << frame_size.ToString(); |
- } |
+ |
+ // Creating a wrapper to the image - setting image data to NULL. Actual |
+ // pointer will be set during encode. Setting align to 1, as it is |
+ // meaningless (actual memory is not allocated). |
+ raw_image_ = vpx_img_wrap( |
+ NULL, VPX_IMG_FMT_I420, cast_config_.width, cast_config_.height, 1, NULL); |
for (int i = 0; i < kNumberOfVp8VideoBuffers; ++i) { |
buffer_state_[i].frame_id = kStartFrameId; |
@@ -94,12 +72,15 @@ |
} |
// Populate encoder configuration with default values. |
- CHECK_EQ(vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config_, 0), |
- VPX_CODEC_OK); |
+ if (vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config_, 0)) { |
+ NOTREACHED() << "Invalid return value"; |
+ config_.g_timebase.den = 0; // Do not call vpx_codec_destroy() in dtor. |
+ return; |
+ } |
config_.g_threads = cast_config_.number_of_encode_threads; |
- config_.g_w = frame_size.width(); |
- config_.g_h = frame_size.height(); |
+ config_.g_w = cast_config_.width; |
+ config_.g_h = cast_config_.height; |
// Set the timebase to match that of base::TimeDelta. |
config_.g_timebase.num = 1; |
config_.g_timebase.den = base::Time::kMicrosecondsPerSecond; |
@@ -108,8 +89,6 @@ |
// codec requirements. |
config_.g_error_resilient = 1; |
} |
- // |g_pass| and |g_lag_in_frames| must be "one pass" and zero, respectively, |
- // in order for VP8 to support changing frame sizes during encoding: |
config_.g_pass = VPX_RC_ONE_PASS; |
config_.g_lag_in_frames = 0; // Immediate data output for each frame. |
@@ -117,7 +96,7 @@ |
config_.rc_dropframe_thresh = 0; // The encoder may not drop any frames. |
config_.rc_resize_allowed = 0; // TODO(miu): Why not? Investigate this. |
config_.rc_end_usage = VPX_CBR; |
- config_.rc_target_bitrate = bitrate_kbit_; |
+ config_.rc_target_bitrate = cast_config_.start_bitrate / 1000; // In kbit/s. |
config_.rc_min_quantizer = cast_config_.min_qp; |
config_.rc_max_quantizer = cast_config_.max_qp; |
// TODO(miu): Revisit these now that the encoder is being successfully |
@@ -134,22 +113,24 @@ |
config_.kf_mode = VPX_KF_DISABLED; |
vpx_codec_flags_t flags = 0; |
- CHECK_EQ(vpx_codec_enc_init(&encoder_, vpx_codec_vp8_cx(), &config_, flags), |
- VPX_CODEC_OK); |
+ if (vpx_codec_enc_init(&encoder_, vpx_codec_vp8_cx(), &config_, flags)) { |
+ NOTREACHED() << "vpx_codec_enc_init() failed."; |
+ config_.g_timebase.den = 0; // Do not call vpx_codec_destroy() in dtor. |
+ return; |
+ } |
// Raise the threshold for considering macroblocks as static. The default is |
// zero, so this setting makes the encoder less sensitive to motion. This |
// lowers the probability of needing to utilize more CPU to search for motion |
// vectors. |
- CHECK_EQ(vpx_codec_control(&encoder_, VP8E_SET_STATIC_THRESHOLD, 1), |
- VPX_CODEC_OK); |
+ vpx_codec_control(&encoder_, VP8E_SET_STATIC_THRESHOLD, 1); |
// Improve quality by enabling sets of codec features that utilize more CPU. |
// The default is zero, with increasingly more CPU to be used as the value is |
// more negative. |
// TODO(miu): Document why this value was chosen and expected behaviors. |
// Should this be dynamic w.r.t. hardware performance? |
- CHECK_EQ(vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, -6), VPX_CODEC_OK); |
+ vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, -6); |
} |
void Vp8Encoder::Encode(const scoped_refptr<media::VideoFrame>& video_frame, |
@@ -158,11 +139,20 @@ |
DCHECK(thread_checker_.CalledOnValidThread()); |
DCHECK(encoded_frame); |
- // Initialize on-demand. Later, if the video frame size has changed, update |
- // the encoder configuration. |
- const gfx::Size frame_size = video_frame->visible_rect().size(); |
- if (!is_initialized() || gfx::Size(config_.g_w, config_.g_h) != frame_size) |
- ConfigureForNewFrameSize(frame_size); |
+ CHECK(is_initialized()); // No illegal reference to |config_| or |encoder_|. |
+ |
+ // Image in vpx_image_t format. |
+ // Input image is const. VP8's raw image is not defined as const. |
+ raw_image_->planes[VPX_PLANE_Y] = |
+ const_cast<uint8*>(video_frame->data(VideoFrame::kYPlane)); |
+ raw_image_->planes[VPX_PLANE_U] = |
+ const_cast<uint8*>(video_frame->data(VideoFrame::kUPlane)); |
+ raw_image_->planes[VPX_PLANE_V] = |
+ const_cast<uint8*>(video_frame->data(VideoFrame::kVPlane)); |
+ |
+ raw_image_->stride[VPX_PLANE_Y] = video_frame->stride(VideoFrame::kYPlane); |
+ raw_image_->stride[VPX_PLANE_U] = video_frame->stride(VideoFrame::kUPlane); |
+ raw_image_->stride[VPX_PLANE_V] = video_frame->stride(VideoFrame::kVPlane); |
uint32 latest_frame_id_to_reference; |
Vp8Buffers buffer_to_update; |
@@ -180,27 +170,6 @@ |
buffer_to_update = GetNextBufferToUpdate(); |
GetCodecUpdateFlags(buffer_to_update, &flags); |
} |
- |
- // Wrapper for vpx_codec_encode() to access the YUV data in the |video_frame|. |
- // Only the VISIBLE rectangle within |video_frame| is exposed to the codec. |
- vpx_image_t vpx_image; |
- vpx_image_t* const result = vpx_img_wrap( |
- &vpx_image, |
- VPX_IMG_FMT_I420, |
- frame_size.width(), |
- frame_size.height(), |
- 1, |
- video_frame->data(VideoFrame::kYPlane)); |
- DCHECK_EQ(result, &vpx_image); |
- vpx_image.planes[VPX_PLANE_Y] = |
- video_frame->visible_data(VideoFrame::kYPlane); |
- vpx_image.planes[VPX_PLANE_U] = |
- video_frame->visible_data(VideoFrame::kUPlane); |
- vpx_image.planes[VPX_PLANE_V] = |
- video_frame->visible_data(VideoFrame::kVPlane); |
- vpx_image.stride[VPX_PLANE_Y] = video_frame->stride(VideoFrame::kYPlane); |
- vpx_image.stride[VPX_PLANE_U] = video_frame->stride(VideoFrame::kUPlane); |
- vpx_image.stride[VPX_PLANE_V] = video_frame->stride(VideoFrame::kVPlane); |
// The frame duration given to the VP8 codec affects a number of important |
// behaviors, including: per-frame bandwidth, CPU time spent encoding, |
@@ -226,7 +195,7 @@ |
// entirely on |predicted_frame_duration| and the target bitrate setting being |
// micro-managed via calls to UpdateRates(). |
CHECK_EQ(vpx_codec_encode(&encoder_, |
- &vpx_image, |
+ raw_image_, |
0, |
predicted_frame_duration.InMicroseconds(), |
flags, |
@@ -433,7 +402,7 @@ |
if (config_.rc_target_bitrate == new_bitrate_kbit) |
return; |
- config_.rc_target_bitrate = bitrate_kbit_ = new_bitrate_kbit; |
+ config_.rc_target_bitrate = new_bitrate_kbit; |
// Update encoder context. |
if (vpx_codec_enc_config_set(&encoder_, &config_)) { |