Index: media/cast/sender/external_video_encoder.cc |
diff --git a/media/cast/sender/external_video_encoder.cc b/media/cast/sender/external_video_encoder.cc |
index 3eb7740a3c5ba7621b48054c4c7bd1a171a7ef8e..c2fe2fdc602b5c28570b7f2dbd1e3f6c330507d4 100644 |
--- a/media/cast/sender/external_video_encoder.cc |
+++ b/media/cast/sender/external_video_encoder.cc |
@@ -35,6 +35,72 @@ namespace { |
enum { MAX_H264_QUANTIZER = 51 }; |
static const size_t kOutputBufferCount = 3; |
+// Copy buffer to match the required coded size. |
+// Cropping or padding is done as required. |
+bool StridedBufferCopy(const uint8_t* src, |
+ const gfx::Size& visible_rect, |
+ int src_stride, |
+ uint8_t* dst, |
+ const gfx::Size& dst_coded_size) { |
+ if (!src || !dst) |
+ return false; |
+ |
+ const int src_width = visible_rect.width(); |
+ const int src_height = visible_rect.height(); |
+ const int dst_stride = dst_coded_size.width(); |
+ const int dst_height = dst_coded_size.height(); |
+ const int copy_width = src_width < dst_stride ? src_width : dst_stride; |
+ const int copy_height = src_height < dst_height ? src_height : dst_height; |
+ |
+ for (int i = 0; i < copy_height; ++i) { |
+ std::memcpy(dst, src, copy_width); |
+ // Padding the remaining columns by repeating the last column of the source. |
+ if (copy_width < dst_stride) |
+ std::memset(dst + copy_width, src[copy_width - 1], |
+ dst_stride - copy_width); |
+ src += src_stride; |
+ dst += dst_stride; |
+ } |
+ |
+ // Padding the remaining rows by repeating the last row of the source. |
+ src = dst - dst_stride; |
+ for (int i = copy_height; i < dst_height; ++i) { |
+ memcpy(dst, src, dst_stride); |
+ dst += dst_stride; |
+ } |
+ |
+ return true; |
+} |
+ |
+// Copy video frame to match the required coded size. |
+bool StridedFrameCopy(const scoped_refptr<media::VideoFrame> src_frame, |
miu
2016/04/25 23:39:39
Oh! Oops, I forgot to mention these routines alre
xjz
2016/04/26 17:42:30
Done. Added dependency on libyuv. This copy does n
miu
2016/04/26 19:20:17
Oh. IMO, the padding was a nice thing to have. A
xjz
2016/04/27 22:13:54
Done. Padding is nice to improve coding efficiency
|
+ scoped_refptr<media::VideoFrame> dst_frame) { |
+ if (!StridedBufferCopy(src_frame->data(media::VideoFrame::kYPlane), |
+ src_frame->visible_rect().size(), |
+ src_frame->stride(media::VideoFrame::kYPlane), |
+ dst_frame->data(media::VideoFrame::kYPlane), |
+ dst_frame->coded_size())) |
+ return false; |
+ |
+ const gfx::Size uv_visible_size(src_frame->visible_rect().width() / 2, |
+ src_frame->visible_rect().height() / 2); |
+ const gfx::Size uv_coded_size(dst_frame->coded_size().width() / 2, |
+ dst_frame->coded_size().height() / 2); |
+ if (!StridedBufferCopy( |
+ src_frame->data(media::VideoFrame::kUPlane), uv_visible_size, |
+ src_frame->stride(media::VideoFrame::kUPlane), |
+ dst_frame->data(media::VideoFrame::kUPlane), uv_coded_size)) |
+ return false; |
+ |
+ if (!StridedBufferCopy( |
+ src_frame->data(media::VideoFrame::kVPlane), uv_visible_size, |
+ src_frame->stride(media::VideoFrame::kVPlane), |
+ dst_frame->data(media::VideoFrame::kVPlane), uv_coded_size)) |
+ return false; |
+ |
+ return true; |
+} |
+ |
} // namespace |
namespace media { |
@@ -149,8 +215,29 @@ class ExternalVideoEncoder::VEAClientImpl |
video_frame, reference_time, frame_encoded_callback, |
requested_bit_rate_)); |
+ scoped_refptr<media::VideoFrame> frame = video_frame; |
+ if (video_frame->coded_size() != frame_coded_size_) { |
+ VLOG(1) << "ExternalVideoEncoder copy required. " |
miu
2016/04/25 23:39:39
nit: Maybe make these logging statements VLOG(2) s
xjz
2016/04/26 17:42:30
Removed this log.
|
+ << "Source coded size: " << video_frame->coded_size().ToString() |
+ << " Required coded size: " << frame_coded_size_.ToString(); |
+ |
+ frame = VideoFrame::CreateFrame( |
+ video_frame->format(), frame_coded_size_, video_frame->visible_rect(), |
+ video_frame->natural_size(), video_frame->timestamp()); |
+ if (!frame.get()) { |
+ VLOG(1) << "Error: ExternalVideoEncoder: CreateFrame failed."; |
+ return; |
+ } |
+ |
+ // Copy the input frame to match the input requirements for the encoder. |
+ if (!StridedFrameCopy(video_frame, frame)) { |
+ VLOG(1) << "ERROR: ExternalVideoEncoder: Copy failed."; |
+ return; |
+ } |
+ } |
+ |
// BitstreamBufferReady will be called once the encoder is done. |
- video_encode_accelerator_->Encode(video_frame, key_frame_requested); |
+ video_encode_accelerator_->Encode(frame, key_frame_requested); |
} |
protected: |
@@ -177,6 +264,8 @@ class ExternalVideoEncoder::VEAClientImpl |
size_t output_buffer_size) final { |
DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
+ frame_coded_size_ = input_coded_size; |
+ |
// TODO(miu): Investigate why we are ignoring |input_count| (4) and instead |
// using |kOutputBufferCount| (3) here. |
for (size_t j = 0; j < kOutputBufferCount; ++j) { |
miu
2016/04/25 23:39:39
BTW--In a follow-up change, perhaps you could take
xjz
2016/04/26 17:42:30
|input_count| is how many frames the encoder will
|
@@ -476,6 +565,10 @@ class ExternalVideoEncoder::VEAClientImpl |
// TODO(miu): Remove after discovering cause. http://crbug.com/519022 |
bool has_seen_zero_length_encoded_frame_; |
+ // The coded size of the video frame required by Encoder. This size is |
+ // obtained from VEA through |RequireBitstreamBuffers()|. |
+ gfx::Size frame_coded_size_; |
+ |
DISALLOW_COPY_AND_ASSIGN(VEAClientImpl); |
}; |