@@ -81,7 +81,7 @@ FrameType ConvertToVideoFrameType(EVideoFrameType type) {
8181// exclude the start codes.
8282static void RtpFragmentize (EncodedImage* encoded_image,
8383 std::unique_ptr<uint8_t []>* encoded_image_buffer,
84- const VideoFrame& frame ,
84+ const VideoFrameBuffer& frame_buffer ,
8585 SFrameBSInfo* info,
8686 RTPFragmentationHeader* frag_header) {
8787 // Calculate minimum buffer size required to hold encoded data.
@@ -102,7 +102,8 @@ static void RtpFragmentize(EncodedImage* encoded_image,
102102 // should be more than enough to hold any encoded data of future frames of
103103 // the same size (avoiding possible future reallocation due to variations in
104104 // required size).
105- encoded_image->_size = CalcBufferSize (kI420 , frame.width (), frame.height ());
105+ encoded_image->_size =
106+ CalcBufferSize (kI420 , frame_buffer.width (), frame_buffer.height ());
106107 if (encoded_image->_size < required_size) {
107108 // Encoded data > unencoded data. Allocate required bytes.
108109 LOG (LS_WARNING ) << " Encoding produced more bytes than the original image "
@@ -198,66 +199,24 @@ int32_t H264EncoderImpl::InitEncode(const VideoCodec* codec_settings,
198199 }
199200 // else WELS_LOG_DEFAULT is used by default.
200201
202+ number_of_cores_ = number_of_cores;
201203 codec_settings_ = *codec_settings;
202204 if (codec_settings_.targetBitrate == 0 )
203205 codec_settings_.targetBitrate = codec_settings_.startBitrate ;
204206
205- // Initialization parameters.
206- // There are two ways to initialize. There is SEncParamBase (cleared with
207- // memset(&p, 0, sizeof(SEncParamBase)) used in Initialize, and SEncParamExt
208- // which is a superset of SEncParamBase (cleared with GetDefaultParams) used
209- // in InitializeExt.
210- SEncParamExt init_params;
211- openh264_encoder_->GetDefaultParams (&init_params);
212- if (codec_settings_.mode == kRealtimeVideo ) {
213- init_params.iUsageType = CAMERA_VIDEO_REAL_TIME ;
214- } else if (codec_settings_.mode == kScreensharing ) {
215- init_params.iUsageType = SCREEN_CONTENT_REAL_TIME ;
216- } else {
217- ReportError ();
218- return WEBRTC_VIDEO_CODEC_ERR_PARAMETER ;
219- }
220- init_params.iPicWidth = codec_settings_.width ;
221- init_params.iPicHeight = codec_settings_.height ;
222- // |init_params| uses bit/s, |codec_settings_| uses kbit/s.
223- init_params.iTargetBitrate = codec_settings_.targetBitrate * 1000 ;
224- init_params.iMaxBitrate = codec_settings_.maxBitrate * 1000 ;
225- // Rate Control mode
226- init_params.iRCMode = RC_BITRATE_MODE ;
227- init_params.fMaxFrameRate = static_cast <float >(codec_settings_.maxFramerate );
228-
229- // The following parameters are extension parameters (they're in SEncParamExt,
230- // not in SEncParamBase).
231- init_params.bEnableFrameSkip =
232- codec_settings_.codecSpecific .H264 .frameDroppingOn ;
233- // |uiIntraPeriod| - multiple of GOP size
234- // |keyFrameInterval| - number of frames
235- init_params.uiIntraPeriod =
236- codec_settings_.codecSpecific .H264 .keyFrameInterval ;
237- init_params.uiMaxNalSize = 0 ;
238- // Threading model: use auto.
239- // 0: auto (dynamic imp. internal encoder)
240- // 1: single thread (default value)
241- // >1: number of threads
242- init_params.iMultipleThreadIdc = NumberOfThreads (init_params.iPicWidth ,
243- init_params.iPicHeight ,
244- number_of_cores);
245- // The base spatial layer 0 is the only one we use.
246- init_params.sSpatialLayers [0 ].iVideoWidth = init_params.iPicWidth ;
247- init_params.sSpatialLayers [0 ].iVideoHeight = init_params.iPicHeight ;
248- init_params.sSpatialLayers [0 ].fFrameRate = init_params.fMaxFrameRate ;
249- init_params.sSpatialLayers [0 ].iSpatialBitrate = init_params.iTargetBitrate ;
250- init_params.sSpatialLayers [0 ].iMaxSpatialBitrate = init_params.iMaxBitrate ;
251- // Slice num according to number of threads.
252- init_params.sSpatialLayers [0 ].sSliceCfg .uiSliceMode = SM_AUTO_SLICE ;
253-
207+ SEncParamExt encoder_params = CreateEncoderParams ();
254208 // Initialize.
255- if (openh264_encoder_->InitializeExt (&init_params ) != 0 ) {
209+ if (openh264_encoder_->InitializeExt (&encoder_params ) != 0 ) {
256210 LOG (LS_ERROR ) << " Failed to initialize OpenH264 encoder" ;
257211 Release ();
258212 ReportError ();
259213 return WEBRTC_VIDEO_CODEC_ERROR ;
260214 }
215+ // TODO(pbos): Base init params on these values before submitting.
216+ quality_scaler_.Init (QualityScaler::kLowH264QpThreshold ,
217+ QualityScaler::kBadH264QpThreshold ,
218+ codec_settings_.startBitrate , codec_settings_.width ,
219+ codec_settings_.height , codec_settings_.maxFramerate );
261220 int video_format = EVideoFormatType::videoFormatI420;
262221 openh264_encoder_->SetOption (ENCODER_OPTION_DATAFORMAT ,
263222 &video_format);
@@ -276,18 +235,12 @@ int32_t H264EncoderImpl::InitEncode(const VideoCodec* codec_settings,
276235
277236int32_t H264EncoderImpl::Release () {
278237 if (openh264_encoder_) {
279- int uninit_ret = openh264_encoder_->Uninitialize ();
280- if (uninit_ret != 0 ) {
281- LOG (LS_WARNING ) << " OpenH264 encoder's Uninitialize() returned "
282- << " unsuccessful: " << uninit_ret;
283- }
238+ RTC_CHECK_EQ (0 , openh264_encoder_->Uninitialize ());
284239 WelsDestroySVCEncoder (openh264_encoder_);
285240 openh264_encoder_ = nullptr ;
286241 }
287- if (encoded_image_._buffer != nullptr ) {
288- encoded_image_._buffer = nullptr ;
289- encoded_image_buffer_.reset ();
290- }
242+ encoded_image_._buffer = nullptr ;
243+ encoded_image_buffer_.reset ();
291244 return WEBRTC_VIDEO_CODEC_OK ;
292245}
293246
@@ -303,6 +256,7 @@ int32_t H264EncoderImpl::SetRates(uint32_t bitrate, uint32_t framerate) {
303256 }
304257 codec_settings_.targetBitrate = bitrate;
305258 codec_settings_.maxFramerate = framerate;
259+ quality_scaler_.ReportFramerate (framerate);
306260
307261 SBitrateInfo target_bitrate;
308262 memset (&target_bitrate, 0 , sizeof (SBitrateInfo));
@@ -316,14 +270,14 @@ int32_t H264EncoderImpl::SetRates(uint32_t bitrate, uint32_t framerate) {
316270 return WEBRTC_VIDEO_CODEC_OK ;
317271}
318272
319- int32_t H264EncoderImpl::Encode (
320- const VideoFrame& frame, const CodecSpecificInfo* codec_specific_info,
321- const std::vector<FrameType>* frame_types) {
273+ int32_t H264EncoderImpl::Encode (const VideoFrame& input_frame,
274+ const CodecSpecificInfo* codec_specific_info,
275+ const std::vector<FrameType>* frame_types) {
322276 if (!IsInitialized ()) {
323277 ReportError ();
324278 return WEBRTC_VIDEO_CODEC_UNINITIALIZED ;
325279 }
326- if (frame .IsZeroSize ()) {
280+ if (input_frame .IsZeroSize ()) {
327281 ReportError ();
328282 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER ;
329283 }
@@ -333,13 +287,20 @@ int32_t H264EncoderImpl::Encode(
333287 ReportError ();
334288 return WEBRTC_VIDEO_CODEC_UNINITIALIZED ;
335289 }
336- if (frame.width () != codec_settings_.width ||
337- frame.height () != codec_settings_.height ) {
338- LOG (LS_WARNING ) << " Encoder initialized for " << codec_settings_.width
339- << " x" << codec_settings_.height << " but trying to encode "
340- << frame.width () << " x" << frame.height () << " frame." ;
341- ReportError ();
342- return WEBRTC_VIDEO_CODEC_ERR_SIZE ;
290+
291+ quality_scaler_.OnEncodeFrame (input_frame.width (), input_frame.height ());
292+ rtc::scoped_refptr<const VideoFrameBuffer> frame_buffer =
293+ quality_scaler_.GetScaledBuffer (input_frame.video_frame_buffer ());
294+ if (frame_buffer->width () != codec_settings_.width ||
295+ frame_buffer->height () != codec_settings_.height ) {
296+ LOG (LS_INFO ) << " Encoder reinitialized from " << codec_settings_.width
297+ << " x" << codec_settings_.height << " to "
298+ << frame_buffer->width () << " x" << frame_buffer->height ();
299+ codec_settings_.width = frame_buffer->width ();
300+ codec_settings_.height = frame_buffer->height ();
301+ SEncParamExt encoder_params = CreateEncoderParams ();
302+ openh264_encoder_->SetOption (ENCODER_OPTION_SVC_ENCODE_PARAM_EXT ,
303+ &encoder_params);
343304 }
344305
345306 bool force_key_frame = false ;
@@ -363,16 +324,16 @@ int32_t H264EncoderImpl::Encode(
363324 // EncodeFrame input.
364325 SSourcePicture picture;
365326 memset (&picture, 0 , sizeof (SSourcePicture));
366- picture.iPicWidth = frame. width ();
367- picture.iPicHeight = frame. height ();
327+ picture.iPicWidth = frame_buffer-> width ();
328+ picture.iPicHeight = frame_buffer-> height ();
368329 picture.iColorFormat = EVideoFormatType::videoFormatI420;
369- picture.uiTimeStamp = frame .ntp_time_ms ();
370- picture.iStride [0 ] = frame. video_frame_buffer () ->StrideY ();
371- picture.iStride [1 ] = frame. video_frame_buffer () ->StrideU ();
372- picture.iStride [2 ] = frame. video_frame_buffer () ->StrideV ();
373- picture.pData [0 ] = const_cast <uint8_t *>(frame. video_frame_buffer () ->DataY ());
374- picture.pData [1 ] = const_cast <uint8_t *>(frame. video_frame_buffer () ->DataU ());
375- picture.pData [2 ] = const_cast <uint8_t *>(frame. video_frame_buffer () ->DataV ());
330+ picture.uiTimeStamp = input_frame .ntp_time_ms ();
331+ picture.iStride [0 ] = frame_buffer ->StrideY ();
332+ picture.iStride [1 ] = frame_buffer ->StrideU ();
333+ picture.iStride [2 ] = frame_buffer ->StrideV ();
334+ picture.pData [0 ] = const_cast <uint8_t *>(frame_buffer ->DataY ());
335+ picture.pData [1 ] = const_cast <uint8_t *>(frame_buffer ->DataU ());
336+ picture.pData [2 ] = const_cast <uint8_t *>(frame_buffer ->DataV ());
376337
377338 // EncodeFrame output.
378339 SFrameBSInfo info;
@@ -387,17 +348,17 @@ int32_t H264EncoderImpl::Encode(
387348 return WEBRTC_VIDEO_CODEC_ERROR ;
388349 }
389350
390- encoded_image_._encodedWidth = frame. width ();
391- encoded_image_._encodedHeight = frame. height ();
392- encoded_image_._timeStamp = frame .timestamp ();
393- encoded_image_.ntp_time_ms_ = frame .ntp_time_ms ();
394- encoded_image_.capture_time_ms_ = frame .render_time_ms ();
395- encoded_image_.rotation_ = frame .rotation ();
351+ encoded_image_._encodedWidth = frame_buffer-> width ();
352+ encoded_image_._encodedHeight = frame_buffer-> height ();
353+ encoded_image_._timeStamp = input_frame .timestamp ();
354+ encoded_image_.ntp_time_ms_ = input_frame .ntp_time_ms ();
355+ encoded_image_.capture_time_ms_ = input_frame .render_time_ms ();
356+ encoded_image_.rotation_ = input_frame .rotation ();
396357 encoded_image_._frameType = ConvertToVideoFrameType (info.eFrameType );
397358
398359 // Split encoded image up into fragments. This also updates |encoded_image_|.
399360 RTPFragmentationHeader frag_header;
400- RtpFragmentize (&encoded_image_, &encoded_image_buffer_, frame , &info,
361+ RtpFragmentize (&encoded_image_, &encoded_image_buffer_, *frame_buffer , &info,
401362 &frag_header);
402363
403364 // Encoder can skip frames to save bandwidth in which case
@@ -406,9 +367,17 @@ int32_t H264EncoderImpl::Encode(
406367 // Deliver encoded image.
407368 CodecSpecificInfo codec_specific;
408369 codec_specific.codecType = kVideoCodecH264 ;
409- encoded_image_callback_->Encoded (encoded_image_,
410- &codec_specific,
370+ encoded_image_callback_->Encoded (encoded_image_, &codec_specific,
411371 &frag_header);
372+
373+ // Parse and report QP.
374+ h264_bitstream_parser_.ParseBitstream (encoded_image_._buffer ,
375+ encoded_image_._length );
376+ int qp = -1 ;
377+ if (h264_bitstream_parser_.GetLastSliceQp (&qp))
378+ quality_scaler_.ReportQP (qp);
379+ } else {
380+ quality_scaler_.ReportDroppedFrame ();
412381 }
413382 return WEBRTC_VIDEO_CODEC_OK ;
414383}
@@ -417,6 +386,61 @@ bool H264EncoderImpl::IsInitialized() const {
417386 return openh264_encoder_ != nullptr ;
418387}
419388
389+ // Initialization parameters.
390+ // There are two ways to initialize. There is SEncParamBase (cleared with
391+ // memset(&p, 0, sizeof(SEncParamBase)) used in Initialize, and SEncParamExt
392+ // which is a superset of SEncParamBase (cleared with GetDefaultParams) used
393+ // in InitializeExt.
394+ SEncParamExt H264EncoderImpl::CreateEncoderParams () const {
395+ RTC_DCHECK (openh264_encoder_);
396+ SEncParamExt encoder_params;
397+ openh264_encoder_->GetDefaultParams (&encoder_params);
398+ if (codec_settings_.mode == kRealtimeVideo ) {
399+ encoder_params.iUsageType = CAMERA_VIDEO_REAL_TIME ;
400+ } else if (codec_settings_.mode == kScreensharing ) {
401+ encoder_params.iUsageType = SCREEN_CONTENT_REAL_TIME ;
402+ } else {
403+ RTC_NOTREACHED ();
404+ }
405+ encoder_params.iPicWidth = codec_settings_.width ;
406+ encoder_params.iPicHeight = codec_settings_.height ;
407+ // |encoder_params| uses bit/s, |codec_settings_| uses kbit/s.
408+ encoder_params.iTargetBitrate = codec_settings_.targetBitrate * 1000 ;
409+ encoder_params.iMaxBitrate = codec_settings_.maxBitrate * 1000 ;
410+ // Rate Control mode
411+ encoder_params.iRCMode = RC_BITRATE_MODE ;
412+ encoder_params.fMaxFrameRate =
413+ static_cast <float >(codec_settings_.maxFramerate );
414+
415+ // The following parameters are extension parameters (they're in SEncParamExt,
416+ // not in SEncParamBase).
417+ encoder_params.bEnableFrameSkip =
418+ codec_settings_.codecSpecific .H264 .frameDroppingOn ;
419+ // |uiIntraPeriod| - multiple of GOP size
420+ // |keyFrameInterval| - number of frames
421+ encoder_params.uiIntraPeriod =
422+ codec_settings_.codecSpecific .H264 .keyFrameInterval ;
423+ encoder_params.uiMaxNalSize = 0 ;
424+ // Threading model: use auto.
425+ // 0: auto (dynamic imp. internal encoder)
426+ // 1: single thread (default value)
427+ // >1: number of threads
428+ encoder_params.iMultipleThreadIdc = NumberOfThreads (
429+ encoder_params.iPicWidth , encoder_params.iPicHeight , number_of_cores_);
430+ // The base spatial layer 0 is the only one we use.
431+ encoder_params.sSpatialLayers [0 ].iVideoWidth = encoder_params.iPicWidth ;
432+ encoder_params.sSpatialLayers [0 ].iVideoHeight = encoder_params.iPicHeight ;
433+ encoder_params.sSpatialLayers [0 ].fFrameRate = encoder_params.fMaxFrameRate ;
434+ encoder_params.sSpatialLayers [0 ].iSpatialBitrate =
435+ encoder_params.iTargetBitrate ;
436+ encoder_params.sSpatialLayers [0 ].iMaxSpatialBitrate =
437+ encoder_params.iMaxBitrate ;
438+ // Slice num according to number of threads.
439+ encoder_params.sSpatialLayers [0 ].sSliceCfg .uiSliceMode = SM_AUTO_SLICE ;
440+
441+ return encoder_params;
442+ }
443+
420444void H264EncoderImpl::ReportInit () {
421445 if (has_reported_init_)
422446 return ;
@@ -445,6 +469,7 @@ int32_t H264EncoderImpl::SetPeriodicKeyFrames(bool enable) {
445469}
446470
447471void H264EncoderImpl::OnDroppedFrame () {
472+ quality_scaler_.ReportDroppedFrame ();
448473}
449474
450475} // namespace webrtc
0 commit comments