1 /* 2 * Copyright (c) 2012 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/engine_configurations.h" 12 #include "webrtc/modules/video_coding/main/source/encoded_frame.h" 13 #include "webrtc/modules/video_coding/main/source/generic_encoder.h" 14 #include "webrtc/modules/video_coding/main/source/media_optimization.h" 15 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" 16 #include "webrtc/system_wrappers/interface/logging.h" 17 18 namespace webrtc { 19 namespace { 20 // Map information from info into rtp. If no relevant information is found 21 // in info, rtp is set to NULL. 22 void CopyCodecSpecific(const CodecSpecificInfo* info, RTPVideoHeader** rtp) { 23 if (!info) { 24 *rtp = NULL; 25 return; 26 } 27 switch (info->codecType) { 28 case kVideoCodecVP8: { 29 (*rtp)->codec = kRtpVideoVp8; 30 (*rtp)->codecHeader.VP8.InitRTPVideoHeaderVP8(); 31 (*rtp)->codecHeader.VP8.pictureId = info->codecSpecific.VP8.pictureId; 32 (*rtp)->codecHeader.VP8.nonReference = 33 info->codecSpecific.VP8.nonReference; 34 (*rtp)->codecHeader.VP8.temporalIdx = info->codecSpecific.VP8.temporalIdx; 35 (*rtp)->codecHeader.VP8.layerSync = info->codecSpecific.VP8.layerSync; 36 (*rtp)->codecHeader.VP8.tl0PicIdx = info->codecSpecific.VP8.tl0PicIdx; 37 (*rtp)->codecHeader.VP8.keyIdx = info->codecSpecific.VP8.keyIdx; 38 (*rtp)->simulcastIdx = info->codecSpecific.VP8.simulcastIdx; 39 return; 40 } 41 case kVideoCodecH264: 42 (*rtp)->codec = kRtpVideoH264; 43 return; 44 case kVideoCodecGeneric: 45 (*rtp)->codec = kRtpVideoGeneric; 46 (*rtp)->simulcastIdx = info->codecSpecific.generic.simulcast_idx; 47 return; 48 default: 49 // No codec specific info. Change RTP header pointer to NULL. 50 *rtp = NULL; 51 return; 52 } 53 } 54 } // namespace 55 56 //#define DEBUG_ENCODER_BIT_STREAM 57 58 VCMGenericEncoder::VCMGenericEncoder(VideoEncoder& encoder, bool internalSource /*= false*/) 59 : 60 _encoder(encoder), 61 _codecType(kVideoCodecUnknown), 62 _VCMencodedFrameCallback(NULL), 63 _bitRate(0), 64 _frameRate(0), 65 _internalSource(internalSource) 66 { 67 } 68 69 70 VCMGenericEncoder::~VCMGenericEncoder() 71 { 72 } 73 74 int32_t VCMGenericEncoder::Release() 75 { 76 _bitRate = 0; 77 _frameRate = 0; 78 _VCMencodedFrameCallback = NULL; 79 return _encoder.Release(); 80 } 81 82 int32_t 83 VCMGenericEncoder::InitEncode(const VideoCodec* settings, 84 int32_t numberOfCores, 85 uint32_t maxPayloadSize) 86 { 87 _bitRate = settings->startBitrate * 1000; 88 _frameRate = settings->maxFramerate; 89 _codecType = settings->codecType; 90 if (_encoder.InitEncode(settings, numberOfCores, maxPayloadSize) != 0) { 91 LOG(LS_ERROR) << "Failed to initialize the encoder associated with " 92 "payload name: " << settings->plName; 93 return -1; 94 } 95 return 0; 96 } 97 98 int32_t 99 VCMGenericEncoder::Encode(const I420VideoFrame& inputFrame, 100 const CodecSpecificInfo* codecSpecificInfo, 101 const std::vector<FrameType>& frameTypes) { 102 std::vector<VideoFrameType> video_frame_types(frameTypes.size(), 103 kDeltaFrame); 104 VCMEncodedFrame::ConvertFrameTypes(frameTypes, &video_frame_types); 105 return _encoder.Encode(inputFrame, codecSpecificInfo, &video_frame_types); 106 } 107 108 int32_t 109 VCMGenericEncoder::SetChannelParameters(int32_t packetLoss, int rtt) 110 { 111 return _encoder.SetChannelParameters(packetLoss, rtt); 112 } 113 114 int32_t 115 VCMGenericEncoder::SetRates(uint32_t newBitRate, uint32_t frameRate) 116 { 117 uint32_t target_bitrate_kbps = (newBitRate + 500) / 1000; 118 int32_t ret = _encoder.SetRates(target_bitrate_kbps, frameRate); 119 if (ret < 0) 120 { 121 return ret; 122 } 123 _bitRate = newBitRate; 124 _frameRate = frameRate; 125 return VCM_OK; 126 } 127 128 int32_t 129 VCMGenericEncoder::CodecConfigParameters(uint8_t* buffer, int32_t size) 130 { 131 int32_t ret = _encoder.CodecConfigParameters(buffer, size); 132 if (ret < 0) 133 { 134 return ret; 135 } 136 return ret; 137 } 138 139 uint32_t VCMGenericEncoder::BitRate() const 140 { 141 return _bitRate; 142 } 143 144 uint32_t VCMGenericEncoder::FrameRate() const 145 { 146 return _frameRate; 147 } 148 149 int32_t 150 VCMGenericEncoder::SetPeriodicKeyFrames(bool enable) 151 { 152 return _encoder.SetPeriodicKeyFrames(enable); 153 } 154 155 int32_t VCMGenericEncoder::RequestFrame( 156 const std::vector<FrameType>& frame_types) { 157 I420VideoFrame image; 158 std::vector<VideoFrameType> video_frame_types(frame_types.size(), 159 kDeltaFrame); 160 VCMEncodedFrame::ConvertFrameTypes(frame_types, &video_frame_types); 161 return _encoder.Encode(image, NULL, &video_frame_types); 162 } 163 164 int32_t 165 VCMGenericEncoder::RegisterEncodeCallback(VCMEncodedFrameCallback* VCMencodedFrameCallback) 166 { 167 _VCMencodedFrameCallback = VCMencodedFrameCallback; 168 _VCMencodedFrameCallback->SetInternalSource(_internalSource); 169 return _encoder.RegisterEncodeCompleteCallback(_VCMencodedFrameCallback); 170 } 171 172 bool 173 VCMGenericEncoder::InternalSource() const 174 { 175 return _internalSource; 176 } 177 178 /*************************** 179 * Callback Implementation 180 ***************************/ 181 VCMEncodedFrameCallback::VCMEncodedFrameCallback( 182 EncodedImageCallback* post_encode_callback): 183 _sendCallback(), 184 _mediaOpt(NULL), 185 _payloadType(0), 186 _internalSource(false), 187 post_encode_callback_(post_encode_callback) 188 #ifdef DEBUG_ENCODER_BIT_STREAM 189 , _bitStreamAfterEncoder(NULL) 190 #endif 191 { 192 #ifdef DEBUG_ENCODER_BIT_STREAM 193 _bitStreamAfterEncoder = fopen("encoderBitStream.bit", "wb"); 194 #endif 195 } 196 197 VCMEncodedFrameCallback::~VCMEncodedFrameCallback() 198 { 199 #ifdef DEBUG_ENCODER_BIT_STREAM 200 fclose(_bitStreamAfterEncoder); 201 #endif 202 } 203 204 int32_t 205 VCMEncodedFrameCallback::SetTransportCallback(VCMPacketizationCallback* transport) 206 { 207 _sendCallback = transport; 208 return VCM_OK; 209 } 210 211 int32_t 212 VCMEncodedFrameCallback::Encoded( 213 EncodedImage &encodedImage, 214 const CodecSpecificInfo* codecSpecificInfo, 215 const RTPFragmentationHeader* fragmentationHeader) 216 { 217 post_encode_callback_->Encoded(encodedImage); 218 219 FrameType frameType = VCMEncodedFrame::ConvertFrameType(encodedImage._frameType); 220 221 uint32_t encodedBytes = 0; 222 if (_sendCallback != NULL) 223 { 224 encodedBytes = encodedImage._length; 225 226 #ifdef DEBUG_ENCODER_BIT_STREAM 227 if (_bitStreamAfterEncoder != NULL) 228 { 229 fwrite(encodedImage._buffer, 1, encodedImage._length, _bitStreamAfterEncoder); 230 } 231 #endif 232 233 RTPVideoHeader rtpVideoHeader; 234 RTPVideoHeader* rtpVideoHeaderPtr = &rtpVideoHeader; 235 CopyCodecSpecific(codecSpecificInfo, &rtpVideoHeaderPtr); 236 237 int32_t callbackReturn = _sendCallback->SendData( 238 frameType, 239 _payloadType, 240 encodedImage._timeStamp, 241 encodedImage.capture_time_ms_, 242 encodedImage._buffer, 243 encodedBytes, 244 *fragmentationHeader, 245 rtpVideoHeaderPtr); 246 if (callbackReturn < 0) 247 { 248 return callbackReturn; 249 } 250 } 251 else 252 { 253 return VCM_UNINITIALIZED; 254 } 255 if (_mediaOpt != NULL) { 256 _mediaOpt->UpdateWithEncodedData(encodedBytes, encodedImage._timeStamp, 257 frameType); 258 if (_internalSource) 259 { 260 return _mediaOpt->DropFrame(); // Signal to encoder to drop next frame 261 } 262 } 263 return VCM_OK; 264 } 265 266 void 267 VCMEncodedFrameCallback::SetMediaOpt( 268 media_optimization::MediaOptimization *mediaOpt) 269 { 270 _mediaOpt = mediaOpt; 271 } 272 273 } // namespace webrtc 274