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