• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2015 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/video_encoder.h"
12 
13 #include "webrtc/base/checks.h"
14 #include "webrtc/base/logging.h"
15 #include "webrtc/modules/video_coding/codecs/h264/include/h264.h"
16 #include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h"
17 #include "webrtc/modules/video_coding/codecs/vp9/include/vp9.h"
18 
19 namespace webrtc {
Create(VideoEncoder::EncoderType codec_type)20 VideoEncoder* VideoEncoder::Create(VideoEncoder::EncoderType codec_type) {
21   switch (codec_type) {
22     case kH264:
23       RTC_DCHECK(H264Encoder::IsSupported());
24       return H264Encoder::Create();
25     case kVp8:
26       return VP8Encoder::Create();
27     case kVp9:
28       return VP9Encoder::Create();
29     case kUnsupportedCodec:
30       RTC_NOTREACHED();
31       return nullptr;
32   }
33   RTC_NOTREACHED();
34   return nullptr;
35 }
36 
CodecToEncoderType(VideoCodecType codec_type)37 VideoEncoder::EncoderType CodecToEncoderType(VideoCodecType codec_type) {
38   switch (codec_type) {
39     case kVideoCodecH264:
40       return VideoEncoder::kH264;
41     case kVideoCodecVP8:
42       return VideoEncoder::kVp8;
43     case kVideoCodecVP9:
44       return VideoEncoder::kVp9;
45     default:
46       return VideoEncoder::kUnsupportedCodec;
47   }
48 }
49 
VideoEncoderSoftwareFallbackWrapper(VideoCodecType codec_type,webrtc::VideoEncoder * encoder)50 VideoEncoderSoftwareFallbackWrapper::VideoEncoderSoftwareFallbackWrapper(
51     VideoCodecType codec_type,
52     webrtc::VideoEncoder* encoder)
53     : rates_set_(false),
54       channel_parameters_set_(false),
55       encoder_type_(CodecToEncoderType(codec_type)),
56       encoder_(encoder),
57       callback_(nullptr) {}
58 
InitFallbackEncoder()59 bool VideoEncoderSoftwareFallbackWrapper::InitFallbackEncoder() {
60   RTC_CHECK(encoder_type_ != kUnsupportedCodec)
61       << "Encoder requesting fallback to codec not supported in software.";
62   fallback_encoder_.reset(VideoEncoder::Create(encoder_type_));
63   if (fallback_encoder_->InitEncode(&codec_settings_, number_of_cores_,
64                                     max_payload_size_) !=
65       WEBRTC_VIDEO_CODEC_OK) {
66     LOG(LS_ERROR) << "Failed to initialize software-encoder fallback.";
67     fallback_encoder_->Release();
68     fallback_encoder_.reset();
69     return false;
70   }
71   // Replay callback, rates, and channel parameters.
72   if (callback_)
73     fallback_encoder_->RegisterEncodeCompleteCallback(callback_);
74   if (rates_set_)
75     fallback_encoder_->SetRates(bitrate_, framerate_);
76   if (channel_parameters_set_)
77     fallback_encoder_->SetChannelParameters(packet_loss_, rtt_);
78 
79   fallback_implementation_name_ =
80       std::string(fallback_encoder_->ImplementationName()) +
81       " (fallback from: " + encoder_->ImplementationName() + ")";
82   // Since we're switching to the fallback encoder, Release the real encoder. It
83   // may be re-initialized via InitEncode later, and it will continue to get
84   // Set calls for rates and channel parameters in the meantime.
85   encoder_->Release();
86   return true;
87 }
88 
InitEncode(const VideoCodec * codec_settings,int32_t number_of_cores,size_t max_payload_size)89 int32_t VideoEncoderSoftwareFallbackWrapper::InitEncode(
90     const VideoCodec* codec_settings,
91     int32_t number_of_cores,
92     size_t max_payload_size) {
93   // Store settings, in case we need to dynamically switch to the fallback
94   // encoder after a failed Encode call.
95   codec_settings_ = *codec_settings;
96   number_of_cores_ = number_of_cores;
97   max_payload_size_ = max_payload_size;
98   // Clear stored rate/channel parameters.
99   rates_set_ = false;
100   channel_parameters_set_ = false;
101 
102   int32_t ret =
103       encoder_->InitEncode(codec_settings, number_of_cores, max_payload_size);
104   if (ret == WEBRTC_VIDEO_CODEC_OK || encoder_type_ == kUnsupportedCodec) {
105     if (fallback_encoder_)
106       fallback_encoder_->Release();
107     fallback_encoder_.reset();
108     if (callback_)
109       encoder_->RegisterEncodeCompleteCallback(callback_);
110     return ret;
111   }
112   // Try to instantiate software codec.
113   if (InitFallbackEncoder()) {
114     return WEBRTC_VIDEO_CODEC_OK;
115   }
116   // Software encoder failed, use original return code.
117   return ret;
118 }
119 
RegisterEncodeCompleteCallback(EncodedImageCallback * callback)120 int32_t VideoEncoderSoftwareFallbackWrapper::RegisterEncodeCompleteCallback(
121     EncodedImageCallback* callback) {
122   callback_ = callback;
123   int32_t ret = encoder_->RegisterEncodeCompleteCallback(callback);
124   if (fallback_encoder_)
125     return fallback_encoder_->RegisterEncodeCompleteCallback(callback);
126   return ret;
127 }
128 
Release()129 int32_t VideoEncoderSoftwareFallbackWrapper::Release() {
130   // If the fallback_encoder_ is non-null, it means it was created via
131   // InitFallbackEncoder which has Release()d encoder_, so we should only ever
132   // need to Release() whichever one is active.
133   if (fallback_encoder_)
134     return fallback_encoder_->Release();
135   return encoder_->Release();
136 }
137 
Encode(const VideoFrame & frame,const CodecSpecificInfo * codec_specific_info,const std::vector<FrameType> * frame_types)138 int32_t VideoEncoderSoftwareFallbackWrapper::Encode(
139     const VideoFrame& frame,
140     const CodecSpecificInfo* codec_specific_info,
141     const std::vector<FrameType>* frame_types) {
142   if (fallback_encoder_)
143     return fallback_encoder_->Encode(frame, codec_specific_info, frame_types);
144   int32_t ret = encoder_->Encode(frame, codec_specific_info, frame_types);
145   // If requested, try a software fallback.
146   if (ret == WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE && InitFallbackEncoder()) {
147     // Fallback was successful, so start using it with this frame.
148     return fallback_encoder_->Encode(frame, codec_specific_info, frame_types);
149   }
150   return ret;
151 }
152 
SetChannelParameters(uint32_t packet_loss,int64_t rtt)153 int32_t VideoEncoderSoftwareFallbackWrapper::SetChannelParameters(
154     uint32_t packet_loss,
155     int64_t rtt) {
156   channel_parameters_set_ = true;
157   packet_loss_ = packet_loss;
158   rtt_ = rtt;
159   int32_t ret = encoder_->SetChannelParameters(packet_loss, rtt);
160   if (fallback_encoder_)
161     return fallback_encoder_->SetChannelParameters(packet_loss, rtt);
162   return ret;
163 }
164 
SetRates(uint32_t bitrate,uint32_t framerate)165 int32_t VideoEncoderSoftwareFallbackWrapper::SetRates(uint32_t bitrate,
166                                                       uint32_t framerate) {
167   rates_set_ = true;
168   bitrate_ = bitrate;
169   framerate_ = framerate;
170   int32_t ret = encoder_->SetRates(bitrate, framerate);
171   if (fallback_encoder_)
172     return fallback_encoder_->SetRates(bitrate, framerate);
173   return ret;
174 }
175 
OnDroppedFrame()176 void VideoEncoderSoftwareFallbackWrapper::OnDroppedFrame() {
177   if (fallback_encoder_)
178     return fallback_encoder_->OnDroppedFrame();
179   return encoder_->OnDroppedFrame();
180 }
181 
SupportsNativeHandle() const182 bool VideoEncoderSoftwareFallbackWrapper::SupportsNativeHandle() const {
183   if (fallback_encoder_)
184     return fallback_encoder_->SupportsNativeHandle();
185   return encoder_->SupportsNativeHandle();
186 }
187 
ImplementationName() const188 const char* VideoEncoderSoftwareFallbackWrapper::ImplementationName() const {
189   if (fallback_encoder_)
190     return fallback_implementation_name_.c_str();
191   return encoder_->ImplementationName();
192 }
193 
GetTargetFramerate()194 int VideoEncoderSoftwareFallbackWrapper::GetTargetFramerate() {
195   if (fallback_encoder_)
196     return fallback_encoder_->GetTargetFramerate();
197   return encoder_->GetTargetFramerate();
198 }
199 
200 }  // namespace webrtc
201