@@ -497,6 +497,10 @@ int LibvpxVp8Encoder::InitEncode(const VideoCodec* inst,
497
497
return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
498
498
}
499
499
500
+ // Use the previous pixel format to avoid extra image allocations.
501
+ vpx_img_fmt_t pixel_format =
502
+ raw_images_.empty () ? VPX_IMG_FMT_I420 : raw_images_[0 ].fmt ;
503
+
500
504
int retVal = Release ();
501
505
if (retVal < 0 ) {
502
506
return retVal;
@@ -650,8 +654,8 @@ int LibvpxVp8Encoder::InitEncode(const VideoCodec* inst,
650
654
// Creating a wrapper to the image - setting image data to NULL.
651
655
// Actual pointer will be set in encode. Setting align to 1, as it
652
656
// is meaningless (no memory allocation is done here).
653
- libvpx_->img_wrap (&raw_images_[0 ], VPX_IMG_FMT_I420 , inst->width ,
654
- inst-> height , 1 , NULL );
657
+ libvpx_->img_wrap (&raw_images_[0 ], pixel_format , inst->width , inst-> height , 1 ,
658
+ NULL );
655
659
656
660
// Note the order we use is different from webm, we have lowest resolution
657
661
// at position 0 and they have highest resolution at position 0.
@@ -699,10 +703,9 @@ int LibvpxVp8Encoder::InitEncode(const VideoCodec* inst,
699
703
// Setting alignment to 32 - as that ensures at least 16 for all
700
704
// planes (32 for Y, 16 for U,V). Libvpx sets the requested stride for
701
705
// the y plane, but only half of it to the u and v planes.
702
- libvpx_->img_alloc (&raw_images_[i], VPX_IMG_FMT_I420,
703
- inst->simulcastStream [stream_idx].width ,
704
- inst->simulcastStream [stream_idx].height ,
705
- kVp832ByteAlign );
706
+ libvpx_->img_alloc (
707
+ &raw_images_[i], pixel_format, inst->simulcastStream [stream_idx].width ,
708
+ inst->simulcastStream [stream_idx].height , kVp832ByteAlign );
706
709
SetStreamState (stream_bitrates[stream_idx] > 0 , stream_idx);
707
710
vpx_configs_[i].rc_target_bitrate = stream_bitrates[stream_idx];
708
711
if (stream_bitrates[stream_idx] > 0 ) {
@@ -1014,26 +1017,12 @@ int LibvpxVp8Encoder::Encode(const VideoFrame& frame,
1014
1017
flags[i] = send_key_frame ? VPX_EFLAG_FORCE_KF : EncodeFlags (tl_configs[i]);
1015
1018
}
1016
1019
1017
- rtc::scoped_refptr<I420BufferInterface> input_image =
1018
- frame.video_frame_buffer ()->ToI420 ();
1019
- // Since we are extracting raw pointers from |input_image| to
1020
- // |raw_images_[0]|, the resolution of these frames must match.
1021
- RTC_DCHECK_EQ (input_image->width (), raw_images_[0 ].d_w );
1022
- RTC_DCHECK_EQ (input_image->height (), raw_images_[0 ].d_h );
1023
-
1024
- // Image in vpx_image_t format.
1025
- // Input image is const. VP8's raw image is not defined as const.
1026
- raw_images_[0 ].planes [VPX_PLANE_Y] =
1027
- const_cast <uint8_t *>(input_image->DataY ());
1028
- raw_images_[0 ].planes [VPX_PLANE_U] =
1029
- const_cast <uint8_t *>(input_image->DataU ());
1030
- raw_images_[0 ].planes [VPX_PLANE_V] =
1031
- const_cast <uint8_t *>(input_image->DataV ());
1032
-
1033
- raw_images_[0 ].stride [VPX_PLANE_Y] = input_image->StrideY ();
1034
- raw_images_[0 ].stride [VPX_PLANE_U] = input_image->StrideU ();
1035
- raw_images_[0 ].stride [VPX_PLANE_V] = input_image->StrideV ();
1036
-
1020
+ rtc::scoped_refptr<VideoFrameBuffer> input_image = frame.video_frame_buffer ();
1021
+ if (input_image->type () != VideoFrameBuffer::Type::kI420 &&
1022
+ input_image->type () != VideoFrameBuffer::Type::kNV12 ) {
1023
+ input_image = input_image->ToI420 ();
1024
+ }
1025
+ PrepareRawImagesForEncoding (input_image);
1037
1026
struct CleanUpOnExit {
1038
1027
explicit CleanUpOnExit (vpx_image_t & raw_image) : raw_image_(raw_image) {}
1039
1028
~CleanUpOnExit () {
@@ -1044,22 +1033,6 @@ int LibvpxVp8Encoder::Encode(const VideoFrame& frame,
1044
1033
vpx_image_t & raw_image_;
1045
1034
} clean_up_on_exit (raw_images_[0 ]);
1046
1035
1047
- for (size_t i = 1 ; i < encoders_.size (); ++i) {
1048
- // Scale the image down a number of times by downsampling factor
1049
- libyuv::I420Scale (
1050
- raw_images_[i - 1 ].planes [VPX_PLANE_Y],
1051
- raw_images_[i - 1 ].stride [VPX_PLANE_Y],
1052
- raw_images_[i - 1 ].planes [VPX_PLANE_U],
1053
- raw_images_[i - 1 ].stride [VPX_PLANE_U],
1054
- raw_images_[i - 1 ].planes [VPX_PLANE_V],
1055
- raw_images_[i - 1 ].stride [VPX_PLANE_V], raw_images_[i - 1 ].d_w ,
1056
- raw_images_[i - 1 ].d_h , raw_images_[i].planes [VPX_PLANE_Y],
1057
- raw_images_[i].stride [VPX_PLANE_Y], raw_images_[i].planes [VPX_PLANE_U],
1058
- raw_images_[i].stride [VPX_PLANE_U], raw_images_[i].planes [VPX_PLANE_V],
1059
- raw_images_[i].stride [VPX_PLANE_V], raw_images_[i].d_w ,
1060
- raw_images_[i].d_h , libyuv::kFilterBilinear );
1061
- }
1062
-
1063
1036
if (send_key_frame) {
1064
1037
// Adapt the size of the key frame when in screenshare with 1 temporal
1065
1038
// layer.
@@ -1309,6 +1282,105 @@ int LibvpxVp8Encoder::RegisterEncodeCompleteCallback(
1309
1282
return WEBRTC_VIDEO_CODEC_OK;
1310
1283
}
1311
1284
1285
+ void LibvpxVp8Encoder::PrepareRawImagesForEncoding (
1286
+ const rtc::scoped_refptr<VideoFrameBuffer>& frame) {
1287
+ // Since we are extracting raw pointers from |input_image| to
1288
+ // |raw_images_[0]|, the resolution of these frames must match.
1289
+ RTC_DCHECK_EQ (frame->width (), raw_images_[0 ].d_w );
1290
+ RTC_DCHECK_EQ (frame->height (), raw_images_[0 ].d_h );
1291
+ switch (frame->type ()) {
1292
+ case VideoFrameBuffer::Type::kI420 :
1293
+ return PrepareI420Image (frame->GetI420 ());
1294
+ case VideoFrameBuffer::Type::kNV12 :
1295
+ return PrepareNV12Image (frame->GetNV12 ());
1296
+ default :
1297
+ RTC_NOTREACHED ();
1298
+ }
1299
+ }
1300
+
1301
+ void LibvpxVp8Encoder::MaybeUpdatePixelFormat (vpx_img_fmt fmt) {
1302
+ RTC_DCHECK (!raw_images_.empty ());
1303
+ if (raw_images_[0 ].fmt == fmt) {
1304
+ RTC_DCHECK (std::all_of (
1305
+ std::next (raw_images_.begin ()), raw_images_.end (),
1306
+ [fmt](const vpx_image_t & raw_img) { return raw_img.fmt == fmt; }))
1307
+ << " Not all raw images had the right format!" ;
1308
+ return ;
1309
+ }
1310
+ RTC_LOG (INFO) << " Updating vp8 encoder pixel format to "
1311
+ << (fmt == VPX_IMG_FMT_NV12 ? " NV12" : " I420" );
1312
+ for (size_t i = 0 ; i < raw_images_.size (); ++i) {
1313
+ vpx_image_t & img = raw_images_[i];
1314
+ auto d_w = img.d_w ;
1315
+ auto d_h = img.d_h ;
1316
+ libvpx_->img_free (&img);
1317
+ // First image is wrapping the input frame, the rest are allocated.
1318
+ if (i == 0 ) {
1319
+ libvpx_->img_wrap (&img, fmt, d_w, d_h, 1 , NULL );
1320
+ } else {
1321
+ libvpx_->img_alloc (&img, fmt, d_w, d_h, kVp832ByteAlign );
1322
+ }
1323
+ }
1324
+ }
1325
+
1326
+ void LibvpxVp8Encoder::PrepareI420Image (const I420BufferInterface* frame) {
1327
+ RTC_DCHECK (!raw_images_.empty ());
1328
+ MaybeUpdatePixelFormat (VPX_IMG_FMT_I420);
1329
+ // Image in vpx_image_t format.
1330
+ // Input image is const. VP8's raw image is not defined as const.
1331
+ raw_images_[0 ].planes [VPX_PLANE_Y] = const_cast <uint8_t *>(frame->DataY ());
1332
+ raw_images_[0 ].planes [VPX_PLANE_U] = const_cast <uint8_t *>(frame->DataU ());
1333
+ raw_images_[0 ].planes [VPX_PLANE_V] = const_cast <uint8_t *>(frame->DataV ());
1334
+
1335
+ raw_images_[0 ].stride [VPX_PLANE_Y] = frame->StrideY ();
1336
+ raw_images_[0 ].stride [VPX_PLANE_U] = frame->StrideU ();
1337
+ raw_images_[0 ].stride [VPX_PLANE_V] = frame->StrideV ();
1338
+
1339
+ for (size_t i = 1 ; i < encoders_.size (); ++i) {
1340
+ // Scale the image down a number of times by downsampling factor
1341
+ libyuv::I420Scale (
1342
+ raw_images_[i - 1 ].planes [VPX_PLANE_Y],
1343
+ raw_images_[i - 1 ].stride [VPX_PLANE_Y],
1344
+ raw_images_[i - 1 ].planes [VPX_PLANE_U],
1345
+ raw_images_[i - 1 ].stride [VPX_PLANE_U],
1346
+ raw_images_[i - 1 ].planes [VPX_PLANE_V],
1347
+ raw_images_[i - 1 ].stride [VPX_PLANE_V], raw_images_[i - 1 ].d_w ,
1348
+ raw_images_[i - 1 ].d_h , raw_images_[i].planes [VPX_PLANE_Y],
1349
+ raw_images_[i].stride [VPX_PLANE_Y], raw_images_[i].planes [VPX_PLANE_U],
1350
+ raw_images_[i].stride [VPX_PLANE_U], raw_images_[i].planes [VPX_PLANE_V],
1351
+ raw_images_[i].stride [VPX_PLANE_V], raw_images_[i].d_w ,
1352
+ raw_images_[i].d_h , libyuv::kFilterBilinear );
1353
+ }
1354
+ }
1355
+
1356
+ void LibvpxVp8Encoder::PrepareNV12Image (const NV12BufferInterface* frame) {
1357
+ RTC_DCHECK (!raw_images_.empty ());
1358
+ MaybeUpdatePixelFormat (VPX_IMG_FMT_NV12);
1359
+ // Image in vpx_image_t format.
1360
+ // Input image is const. VP8's raw image is not defined as const.
1361
+ raw_images_[0 ].planes [VPX_PLANE_Y] = const_cast <uint8_t *>(frame->DataY ());
1362
+ raw_images_[0 ].planes [VPX_PLANE_U] = const_cast <uint8_t *>(frame->DataUV ());
1363
+ raw_images_[0 ].planes [VPX_PLANE_V] = raw_images_[0 ].planes [VPX_PLANE_U] + 1 ;
1364
+ raw_images_[0 ].stride [VPX_PLANE_Y] = frame->StrideY ();
1365
+ raw_images_[0 ].stride [VPX_PLANE_U] = frame->StrideUV ();
1366
+ raw_images_[0 ].stride [VPX_PLANE_V] = frame->StrideUV ();
1367
+
1368
+ for (size_t i = 1 ; i < encoders_.size (); ++i) {
1369
+ // Scale the image down a number of times by downsampling factor
1370
+ libyuv::NV12Scale (
1371
+ raw_images_[i - 1 ].planes [VPX_PLANE_Y],
1372
+ raw_images_[i - 1 ].stride [VPX_PLANE_Y],
1373
+ raw_images_[i - 1 ].planes [VPX_PLANE_U],
1374
+ raw_images_[i - 1 ].stride [VPX_PLANE_U], raw_images_[i - 1 ].d_w ,
1375
+ raw_images_[i - 1 ].d_h , raw_images_[i].planes [VPX_PLANE_Y],
1376
+ raw_images_[i].stride [VPX_PLANE_Y], raw_images_[i].planes [VPX_PLANE_U],
1377
+ raw_images_[i].stride [VPX_PLANE_U], raw_images_[i].d_w ,
1378
+ raw_images_[i].d_h , libyuv::kFilterBilinear );
1379
+ raw_images_[i].planes [VPX_PLANE_V] = raw_images_[i].planes [VPX_PLANE_U] + 1 ;
1380
+ raw_images_[i].stride [VPX_PLANE_V] = raw_images_[i].stride [VPX_PLANE_U] + 1 ;
1381
+ }
1382
+ }
1383
+
1312
1384
// static
1313
1385
LibvpxVp8Encoder::VariableFramerateExperiment
1314
1386
LibvpxVp8Encoder::ParseVariableFramerateConfig (std::string group_name) {
0 commit comments