Home | History | Annotate | Download | only in vp8
      1 /*
      2  *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "webrtc/modules/video_coding/codecs/vp8/simulcast_encoder_adapter.h"
     12 
     13 #include <algorithm>
     14 
     15 // NOTE(ajm): Path provided by gyp.
     16 #include "libyuv/scale.h"  // NOLINT
     17 
     18 #include "webrtc/base/checks.h"
     19 #include "webrtc/common.h"
     20 #include "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h"
     21 
     22 namespace {
     23 
     24 const unsigned int kDefaultMinQp = 2;
     25 const unsigned int kDefaultMaxQp = 56;
     26 // Max qp for lowest spatial resolution when doing simulcast.
     27 const unsigned int kLowestResMaxQp = 45;
     28 
     29 uint32_t SumStreamTargetBitrate(int streams, const webrtc::VideoCodec& codec) {
     30   uint32_t bitrate_sum = 0;
     31   for (int i = 0; i < streams; ++i) {
     32     bitrate_sum += codec.simulcastStream[i].targetBitrate;
     33   }
     34   return bitrate_sum;
     35 }
     36 
     37 uint32_t SumStreamMaxBitrate(int streams, const webrtc::VideoCodec& codec) {
     38   uint32_t bitrate_sum = 0;
     39   for (int i = 0; i < streams; ++i) {
     40     bitrate_sum += codec.simulcastStream[i].maxBitrate;
     41   }
     42   return bitrate_sum;
     43 }
     44 
     45 int NumberOfStreams(const webrtc::VideoCodec& codec) {
     46   int streams =
     47       codec.numberOfSimulcastStreams < 1 ? 1 : codec.numberOfSimulcastStreams;
     48   uint32_t simulcast_max_bitrate = SumStreamMaxBitrate(streams, codec);
     49   if (simulcast_max_bitrate == 0) {
     50     streams = 1;
     51   }
     52   return streams;
     53 }
     54 
     55 bool ValidSimulcastResolutions(const webrtc::VideoCodec& codec,
     56                                int num_streams) {
     57   if (codec.width != codec.simulcastStream[num_streams - 1].width ||
     58       codec.height != codec.simulcastStream[num_streams - 1].height) {
     59     return false;
     60   }
     61   for (int i = 0; i < num_streams; ++i) {
     62     if (codec.width * codec.simulcastStream[i].height !=
     63         codec.height * codec.simulcastStream[i].width) {
     64       return false;
     65     }
     66   }
     67   return true;
     68 }
     69 
     70 int VerifyCodec(const webrtc::VideoCodec* inst) {
     71   if (inst == NULL) {
     72     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
     73   }
     74   if (inst->maxFramerate < 1) {
     75     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
     76   }
     77   // allow zero to represent an unspecified maxBitRate
     78   if (inst->maxBitrate > 0 && inst->startBitrate > inst->maxBitrate) {
     79     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
     80   }
     81   if (inst->width <= 1 || inst->height <= 1) {
     82     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
     83   }
     84   if (inst->codecSpecific.VP8.feedbackModeOn &&
     85       inst->numberOfSimulcastStreams > 1) {
     86     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
     87   }
     88   if (inst->codecSpecific.VP8.automaticResizeOn &&
     89       inst->numberOfSimulcastStreams > 1) {
     90     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
     91   }
     92   return WEBRTC_VIDEO_CODEC_OK;
     93 }
     94 
     95 // TL1 FrameDropper's max time to drop frames.
     96 const float kTl1MaxTimeToDropFrames = 20.0f;
     97 
     98 struct ScreenshareTemporalLayersFactory : webrtc::TemporalLayers::Factory {
     99   ScreenshareTemporalLayersFactory()
    100       : tl1_frame_dropper_(kTl1MaxTimeToDropFrames) {}
    101 
    102   virtual ~ScreenshareTemporalLayersFactory() {}
    103 
    104   virtual webrtc::TemporalLayers* Create(int num_temporal_layers,
    105                                          uint8_t initial_tl0_pic_idx) const {
    106     return new webrtc::ScreenshareLayers(num_temporal_layers, rand());
    107   }
    108 
    109   mutable webrtc::FrameDropper tl0_frame_dropper_;
    110   mutable webrtc::FrameDropper tl1_frame_dropper_;
    111 };
    112 
    113 // An EncodedImageCallback implementation that forwards on calls to a
    114 // SimulcastEncoderAdapter, but with the stream index it's registered with as
    115 // the first parameter to Encoded.
    116 class AdapterEncodedImageCallback : public webrtc::EncodedImageCallback {
    117  public:
    118   AdapterEncodedImageCallback(webrtc::SimulcastEncoderAdapter* adapter,
    119                               size_t stream_idx)
    120       : adapter_(adapter), stream_idx_(stream_idx) {}
    121 
    122   int32_t Encoded(
    123       const webrtc::EncodedImage& encodedImage,
    124       const webrtc::CodecSpecificInfo* codecSpecificInfo = NULL,
    125       const webrtc::RTPFragmentationHeader* fragmentation = NULL) override {
    126     return adapter_->Encoded(stream_idx_, encodedImage, codecSpecificInfo,
    127                              fragmentation);
    128   }
    129 
    130  private:
    131   webrtc::SimulcastEncoderAdapter* const adapter_;
    132   const size_t stream_idx_;
    133 };
    134 
    135 }  // namespace
    136 
    137 namespace webrtc {
    138 
    139 SimulcastEncoderAdapter::SimulcastEncoderAdapter(VideoEncoderFactory* factory)
    140     : factory_(factory), encoded_complete_callback_(NULL) {
    141   memset(&codec_, 0, sizeof(webrtc::VideoCodec));
    142 }
    143 
    144 SimulcastEncoderAdapter::~SimulcastEncoderAdapter() {
    145   Release();
    146 }
    147 
    148 int SimulcastEncoderAdapter::Release() {
    149   // TODO(pbos): Keep the last encoder instance but call ::Release() on it, then
    150   // re-use this instance in ::InitEncode(). This means that changing
    151   // resolutions doesn't require reallocation of the first encoder, but only
    152   // reinitialization, which makes sense. Then Destroy this instance instead in
    153   // ~SimulcastEncoderAdapter().
    154   while (!streaminfos_.empty()) {
    155     VideoEncoder* encoder = streaminfos_.back().encoder;
    156     EncodedImageCallback* callback = streaminfos_.back().callback;
    157     factory_->Destroy(encoder);
    158     delete callback;
    159     streaminfos_.pop_back();
    160   }
    161   return WEBRTC_VIDEO_CODEC_OK;
    162 }
    163 
    164 int SimulcastEncoderAdapter::InitEncode(const VideoCodec* inst,
    165                                         int number_of_cores,
    166                                         size_t max_payload_size) {
    167   if (number_of_cores < 1) {
    168     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
    169   }
    170 
    171   int ret = VerifyCodec(inst);
    172   if (ret < 0) {
    173     return ret;
    174   }
    175 
    176   ret = Release();
    177   if (ret < 0) {
    178     return ret;
    179   }
    180 
    181   int number_of_streams = NumberOfStreams(*inst);
    182   bool doing_simulcast = (number_of_streams > 1);
    183 
    184   if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) {
    185     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
    186   }
    187 
    188   codec_ = *inst;
    189 
    190   // Special mode when screensharing on a single stream.
    191   if (number_of_streams == 1 && inst->mode == kScreensharing) {
    192     screensharing_extra_options_.reset(new Config());
    193     screensharing_extra_options_->Set<TemporalLayers::Factory>(
    194         new ScreenshareTemporalLayersFactory());
    195     codec_.extra_options = screensharing_extra_options_.get();
    196   }
    197 
    198   // Create |number_of_streams| of encoder instances and init them.
    199   for (int i = 0; i < number_of_streams; ++i) {
    200     VideoCodec stream_codec;
    201     bool send_stream = true;
    202     if (!doing_simulcast) {
    203       stream_codec = codec_;
    204       stream_codec.numberOfSimulcastStreams = 1;
    205     } else {
    206       bool highest_resolution_stream = (i == (number_of_streams - 1));
    207       PopulateStreamCodec(&codec_, i, number_of_streams,
    208                           highest_resolution_stream, &stream_codec,
    209                           &send_stream);
    210     }
    211 
    212     // TODO(ronghuawu): Remove once this is handled in VP8EncoderImpl.
    213     if (stream_codec.qpMax < kDefaultMinQp) {
    214       stream_codec.qpMax = kDefaultMaxQp;
    215     }
    216 
    217     VideoEncoder* encoder = factory_->Create();
    218     ret = encoder->InitEncode(&stream_codec, number_of_cores, max_payload_size);
    219     if (ret < 0) {
    220       Release();
    221       return ret;
    222     }
    223     EncodedImageCallback* callback = new AdapterEncodedImageCallback(this, i);
    224     encoder->RegisterEncodeCompleteCallback(callback);
    225     streaminfos_.push_back(StreamInfo(encoder, callback, stream_codec.width,
    226                                       stream_codec.height, send_stream));
    227   }
    228   return WEBRTC_VIDEO_CODEC_OK;
    229 }
    230 
    231 int SimulcastEncoderAdapter::Encode(
    232     const VideoFrame& input_image,
    233     const CodecSpecificInfo* codec_specific_info,
    234     const std::vector<FrameType>* frame_types) {
    235   if (!Initialized()) {
    236     return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
    237   }
    238   if (encoded_complete_callback_ == NULL) {
    239     return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
    240   }
    241 
    242   // All active streams should generate a key frame if
    243   // a key frame is requested by any stream.
    244   bool send_key_frame = false;
    245   if (frame_types) {
    246     for (size_t i = 0; i < frame_types->size(); ++i) {
    247       if (frame_types->at(i) == kVideoFrameKey) {
    248         send_key_frame = true;
    249         break;
    250       }
    251     }
    252   }
    253   for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
    254     if (streaminfos_[stream_idx].key_frame_request &&
    255         streaminfos_[stream_idx].send_stream) {
    256       send_key_frame = true;
    257       break;
    258     }
    259   }
    260 
    261   int src_width = input_image.width();
    262   int src_height = input_image.height();
    263   for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
    264     // Don't encode frames in resolutions that we don't intend to send.
    265     if (!streaminfos_[stream_idx].send_stream)
    266       continue;
    267 
    268     std::vector<FrameType> stream_frame_types;
    269     if (send_key_frame) {
    270       stream_frame_types.push_back(kVideoFrameKey);
    271       streaminfos_[stream_idx].key_frame_request = false;
    272     } else {
    273       stream_frame_types.push_back(kVideoFrameDelta);
    274     }
    275 
    276     int dst_width = streaminfos_[stream_idx].width;
    277     int dst_height = streaminfos_[stream_idx].height;
    278     // If scaling isn't required, because the input resolution
    279     // matches the destination or the input image is empty (e.g.
    280     // a keyframe request for encoders with internal camera
    281     // sources), pass the image on directly. Otherwise, we'll
    282     // scale it to match what the encoder expects (below).
    283     if ((dst_width == src_width && dst_height == src_height) ||
    284         input_image.IsZeroSize()) {
    285       streaminfos_[stream_idx].encoder->Encode(input_image, codec_specific_info,
    286                                                &stream_frame_types);
    287     } else {
    288       VideoFrame dst_frame;
    289       // Making sure that destination frame is of sufficient size.
    290       // Aligning stride values based on width.
    291       dst_frame.CreateEmptyFrame(dst_width, dst_height, dst_width,
    292                                  (dst_width + 1) / 2, (dst_width + 1) / 2);
    293       libyuv::I420Scale(
    294           input_image.buffer(kYPlane), input_image.stride(kYPlane),
    295           input_image.buffer(kUPlane), input_image.stride(kUPlane),
    296           input_image.buffer(kVPlane), input_image.stride(kVPlane), src_width,
    297           src_height, dst_frame.buffer(kYPlane), dst_frame.stride(kYPlane),
    298           dst_frame.buffer(kUPlane), dst_frame.stride(kUPlane),
    299           dst_frame.buffer(kVPlane), dst_frame.stride(kVPlane), dst_width,
    300           dst_height, libyuv::kFilterBilinear);
    301       dst_frame.set_timestamp(input_image.timestamp());
    302       dst_frame.set_render_time_ms(input_image.render_time_ms());
    303       streaminfos_[stream_idx].encoder->Encode(dst_frame, codec_specific_info,
    304                                                &stream_frame_types);
    305     }
    306   }
    307 
    308   return WEBRTC_VIDEO_CODEC_OK;
    309 }
    310 
    311 int SimulcastEncoderAdapter::RegisterEncodeCompleteCallback(
    312     EncodedImageCallback* callback) {
    313   encoded_complete_callback_ = callback;
    314   return WEBRTC_VIDEO_CODEC_OK;
    315 }
    316 
    317 int SimulcastEncoderAdapter::SetChannelParameters(uint32_t packet_loss,
    318                                                   int64_t rtt) {
    319   for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
    320     streaminfos_[stream_idx].encoder->SetChannelParameters(packet_loss, rtt);
    321   }
    322   return WEBRTC_VIDEO_CODEC_OK;
    323 }
    324 
    325 int SimulcastEncoderAdapter::SetRates(uint32_t new_bitrate_kbit,
    326                                       uint32_t new_framerate) {
    327   if (!Initialized()) {
    328     return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
    329   }
    330   if (new_framerate < 1) {
    331     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
    332   }
    333   if (codec_.maxBitrate > 0 && new_bitrate_kbit > codec_.maxBitrate) {
    334     new_bitrate_kbit = codec_.maxBitrate;
    335   }
    336   if (new_bitrate_kbit < codec_.minBitrate) {
    337     new_bitrate_kbit = codec_.minBitrate;
    338   }
    339   if (codec_.numberOfSimulcastStreams > 0 &&
    340       new_bitrate_kbit < codec_.simulcastStream[0].minBitrate) {
    341     new_bitrate_kbit = codec_.simulcastStream[0].minBitrate;
    342   }
    343   codec_.maxFramerate = new_framerate;
    344 
    345   bool send_stream = true;
    346   uint32_t stream_bitrate = 0;
    347   for (size_t stream_idx = 0; stream_idx < streaminfos_.size(); ++stream_idx) {
    348     stream_bitrate = GetStreamBitrate(stream_idx, streaminfos_.size(),
    349                                       new_bitrate_kbit, &send_stream);
    350     // Need a key frame if we have not sent this stream before.
    351     if (send_stream && !streaminfos_[stream_idx].send_stream) {
    352       streaminfos_[stream_idx].key_frame_request = true;
    353     }
    354     streaminfos_[stream_idx].send_stream = send_stream;
    355 
    356     // TODO(holmer): This is a temporary hack for screensharing, where we
    357     // interpret the startBitrate as the encoder target bitrate. This is
    358     // to allow for a different max bitrate, so if the codec can't meet
    359     // the target we still allow it to overshoot up to the max before dropping
    360     // frames. This hack should be improved.
    361     if (codec_.targetBitrate > 0 &&
    362         (codec_.codecSpecific.VP8.numberOfTemporalLayers == 2 ||
    363          codec_.simulcastStream[0].numberOfTemporalLayers == 2)) {
    364       stream_bitrate = std::min(codec_.maxBitrate, stream_bitrate);
    365       // TODO(ronghuawu): Can't change max bitrate via the VideoEncoder
    366       // interface. And VP8EncoderImpl doesn't take negative framerate.
    367       // max_bitrate = std::min(codec_.maxBitrate, stream_bitrate);
    368       // new_framerate = -1;
    369     }
    370 
    371     streaminfos_[stream_idx].encoder->SetRates(stream_bitrate, new_framerate);
    372   }
    373 
    374   return WEBRTC_VIDEO_CODEC_OK;
    375 }
    376 
    377 int32_t SimulcastEncoderAdapter::Encoded(
    378     size_t stream_idx,
    379     const EncodedImage& encodedImage,
    380     const CodecSpecificInfo* codecSpecificInfo,
    381     const RTPFragmentationHeader* fragmentation) {
    382   CodecSpecificInfo stream_codec_specific = *codecSpecificInfo;
    383   CodecSpecificInfoVP8* vp8Info = &(stream_codec_specific.codecSpecific.VP8);
    384   vp8Info->simulcastIdx = stream_idx;
    385 
    386   return encoded_complete_callback_->Encoded(
    387       encodedImage, &stream_codec_specific, fragmentation);
    388 }
    389 
    390 uint32_t SimulcastEncoderAdapter::GetStreamBitrate(
    391     int stream_idx,
    392     size_t total_number_of_streams,
    393     uint32_t new_bitrate_kbit,
    394     bool* send_stream) const {
    395   if (total_number_of_streams == 1) {
    396     *send_stream = true;
    397     return new_bitrate_kbit;
    398   }
    399 
    400   // The bitrate needed to start sending this stream is given by the
    401   // minimum bitrate allowed for encoding this stream, plus the sum target
    402   // rates of all lower streams.
    403   uint32_t sum_target_lower_streams =
    404       SumStreamTargetBitrate(stream_idx, codec_);
    405   uint32_t bitrate_to_send_this_layer =
    406       codec_.simulcastStream[stream_idx].minBitrate + sum_target_lower_streams;
    407   if (new_bitrate_kbit >= bitrate_to_send_this_layer) {
    408     // We have enough bandwidth to send this stream.
    409     *send_stream = true;
    410     // Bitrate for this stream is the new bitrate (|new_bitrate_kbit|) minus the
    411     // sum target rates of the lower streams, and capped to a maximum bitrate.
    412     // The maximum cap depends on whether we send the next higher stream.
    413     // If we will be sending the next higher stream, |max_rate| is given by
    414     // current stream's |targetBitrate|, otherwise it's capped by |maxBitrate|.
    415     if (stream_idx < codec_.numberOfSimulcastStreams - 1) {
    416       unsigned int max_rate = codec_.simulcastStream[stream_idx].maxBitrate;
    417       if (new_bitrate_kbit >=
    418           SumStreamTargetBitrate(stream_idx + 1, codec_) +
    419               codec_.simulcastStream[stream_idx + 1].minBitrate) {
    420         max_rate = codec_.simulcastStream[stream_idx].targetBitrate;
    421       }
    422       return std::min(new_bitrate_kbit - sum_target_lower_streams, max_rate);
    423     } else {
    424       // For the highest stream (highest resolution), the |targetBitRate| and
    425       // |maxBitrate| are not used. Any excess bitrate (above the targets of
    426       // all lower streams) is given to this (highest resolution) stream.
    427       return new_bitrate_kbit - sum_target_lower_streams;
    428     }
    429   } else {
    430     // Not enough bitrate for this stream.
    431     // Return our max bitrate of |stream_idx| - 1, but we don't send it. We need
    432     // to keep this resolution coding in order for the multi-encoder to work.
    433     *send_stream = false;
    434     return codec_.simulcastStream[stream_idx - 1].maxBitrate;
    435   }
    436 }
    437 
    438 void SimulcastEncoderAdapter::PopulateStreamCodec(
    439     const webrtc::VideoCodec* inst,
    440     int stream_index,
    441     size_t total_number_of_streams,
    442     bool highest_resolution_stream,
    443     webrtc::VideoCodec* stream_codec,
    444     bool* send_stream) {
    445   *stream_codec = *inst;
    446 
    447   // Stream specific settings.
    448   stream_codec->codecSpecific.VP8.numberOfTemporalLayers =
    449       inst->simulcastStream[stream_index].numberOfTemporalLayers;
    450   stream_codec->numberOfSimulcastStreams = 0;
    451   stream_codec->width = inst->simulcastStream[stream_index].width;
    452   stream_codec->height = inst->simulcastStream[stream_index].height;
    453   stream_codec->maxBitrate = inst->simulcastStream[stream_index].maxBitrate;
    454   stream_codec->minBitrate = inst->simulcastStream[stream_index].minBitrate;
    455   stream_codec->qpMax = inst->simulcastStream[stream_index].qpMax;
    456   // Settings that are based on stream/resolution.
    457   if (stream_index == 0) {
    458     // Settings for lowest spatial resolutions.
    459     stream_codec->qpMax = kLowestResMaxQp;
    460   }
    461   if (!highest_resolution_stream) {
    462     // For resolutions below CIF, set the codec |complexity| parameter to
    463     // kComplexityHigher, which maps to cpu_used = -4.
    464     int pixels_per_frame = stream_codec->width * stream_codec->height;
    465     if (pixels_per_frame < 352 * 288) {
    466       stream_codec->codecSpecific.VP8.complexity = webrtc::kComplexityHigher;
    467     }
    468     // Turn off denoising for all streams but the highest resolution.
    469     stream_codec->codecSpecific.VP8.denoisingOn = false;
    470   }
    471   // TODO(ronghuawu): what to do with targetBitrate.
    472 
    473   int stream_bitrate = GetStreamBitrate(stream_index, total_number_of_streams,
    474                                         inst->startBitrate, send_stream);
    475   stream_codec->startBitrate = stream_bitrate;
    476 }
    477 
    478 bool SimulcastEncoderAdapter::Initialized() const {
    479   return !streaminfos_.empty();
    480 }
    481 
    482 void SimulcastEncoderAdapter::OnDroppedFrame() {
    483   streaminfos_[0].encoder->OnDroppedFrame();
    484 }
    485 
    486 int SimulcastEncoderAdapter::GetTargetFramerate() {
    487   return streaminfos_[0].encoder->GetTargetFramerate();
    488 }
    489 
    490 bool SimulcastEncoderAdapter::SupportsNativeHandle() const {
    491   // We should not be calling this method before streaminfos_ are configured.
    492   RTC_DCHECK(!streaminfos_.empty());
    493   // TODO(pbos): Support textures when using more than one encoder.
    494   if (streaminfos_.size() != 1)
    495     return false;
    496   return streaminfos_[0].encoder->SupportsNativeHandle();
    497 }
    498 
    499 const char* SimulcastEncoderAdapter::ImplementationName() const {
    500   // We should not be calling this method before streaminfos_ are configured.
    501   RTC_DCHECK(!streaminfos_.empty());
    502   // TODO(pbos): Support multiple implementation names for different encoders.
    503   return streaminfos_[0].encoder->ImplementationName();
    504 }
    505 
    506 }  // namespace webrtc
    507