3131
3232#include " ScreencastEncoder.h"
3333
34+ #include < algorithm>
3435#include < libyuv.h>
3536#include < vpx/vp8.h>
3637#include < vpx/vp8cx.h>
@@ -47,7 +48,8 @@ const int kMacroBlockSize = 16;
4748
4849void createImage (unsigned int width, unsigned int height,
4950 std::unique_ptr<vpx_image_t >& out_image,
50- std::unique_ptr<uint8_t []>& out_image_buffer) {
51+ std::unique_ptr<uint8_t []>& out_image_buffer,
52+ int & out_buffer_size) {
5153 std::unique_ptr<vpx_image_t > image (new vpx_image_t ());
5254 memset (image.get (), 0 , sizeof (vpx_image_t ));
5355
@@ -78,11 +80,11 @@ void createImage(unsigned int width, unsigned int height,
7880 const int uv_rows = y_rows >> image->y_chroma_shift ;
7981
8082 // Allocate a YUV buffer large enough for the aligned data & padding.
81- const int buffer_size = y_stride * y_rows + 2 *uv_stride * uv_rows;
82- std::unique_ptr<uint8_t []> image_buffer (new uint8_t [buffer_size ]);
83+ out_buffer_size = y_stride * y_rows + 2 *uv_stride * uv_rows;
84+ std::unique_ptr<uint8_t []> image_buffer (new uint8_t [out_buffer_size ]);
8385
8486 // Reset image value to 128 so we just need to fill in the y plane.
85- memset (image_buffer.get (), 128 , buffer_size );
87+ memset (image_buffer.get (), 128 , out_buffer_size );
8688
8789 // Fill in the information for |image_|.
8890 unsigned char * uchar_buffer =
@@ -180,13 +182,39 @@ class ScreencastEncoder::VPXFrame {
180182 uint8_t * u_data = image->planes [1 ];
181183 uint8_t * v_data = image->planes [2 ];
182184
183- libyuv::I420Copy (src->DataY (), src->StrideY (),
184- src->DataU (), src->StrideU (),
185- src->DataV (), src->StrideV (),
186- y_data, y_stride,
187- u_data, uv_stride,
188- v_data, uv_stride,
189- image->w , image->h );
185+ if (m_scale) {
186+ int src_width = src->width ();
187+ double dst_width = src_width * m_scale.value ();
188+ if (dst_width > image->w ) {
189+ src_width *= image->w / dst_width;
190+ dst_width = image->w ;
191+ }
192+ int src_height = src->height ();
193+ double dst_height = src_height * m_scale.value ();
194+ if (dst_height > image->h ) {
195+ src_height *= image->h / dst_height;
196+ dst_height = image->h ;
197+ }
198+ libyuv::I420Scale (src->DataY (), src->StrideY (),
199+ src->DataU (), src->StrideU (),
200+ src->DataV (), src->StrideV (),
201+ src_width, src_height,
202+ y_data, y_stride,
203+ u_data, uv_stride,
204+ v_data, uv_stride,
205+ dst_width, dst_height,
206+ libyuv::kFilterBilinear );
207+ } else {
208+ int width = std::min<int >(image->w , src->width ());
209+ int height = std::min<int >(image->h , src->height ());
210+ libyuv::I420Copy (src->DataY (), src->StrideY (),
211+ src->DataU (), src->StrideU (),
212+ src->DataV (), src->StrideV (),
213+ y_data, y_stride,
214+ u_data, uv_stride,
215+ v_data, uv_stride,
216+ width, height);
217+ }
190218 }
191219
192220private:
@@ -212,7 +240,7 @@ class ScreencastEncoder::VPXCodec {
212240
213241 ivf_write_file_header (m_file, &m_cfg, m_fourcc, 0 );
214242
215- createImage (cfg.g_w , cfg.g_h , m_image, m_imageBuffer);
243+ createImage (cfg.g_w , cfg.g_h , m_image, m_imageBuffer, m_imageBufferSize );
216244 }
217245
218246 ~VPXCodec () {
@@ -223,6 +251,7 @@ class ScreencastEncoder::VPXCodec {
223251 void encodeFrameAsync (std::unique_ptr<VPXFrame>&& frame)
224252 {
225253 m_encoderQueue->Dispatch (NS_NewRunnableFunction(" VPXCodec::encodeFrameAsync" , [this , frame = std::move (frame)] {
254+ memset (m_imageBuffer.get (), 128 , m_imageBufferSize);
226255 frame->convertToVpxImage (m_image.get ());
227256 // TODO: figure out why passing duration to the codec results in much
228257 // worse visual quality and makes video stutter.
@@ -292,6 +321,7 @@ class ScreencastEncoder::VPXCodec {
292321 int m_frameCount { 0 };
293322 int64_t m_pts { 0 };
294323 std::unique_ptr<uint8_t []> m_imageBuffer;
324+ int m_imageBufferSize { 0 };
295325 std::unique_ptr<vpx_image_t > m_image;
296326};
297327
0 commit comments