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 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
VCMGenericEncoder(VideoEncoder & encoder,bool internalSource)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
~VCMGenericEncoder()70 VCMGenericEncoder::~VCMGenericEncoder()
71 {
72 }
73
Release()74 int32_t VCMGenericEncoder::Release()
75 {
76 _bitRate = 0;
77 _frameRate = 0;
78 _VCMencodedFrameCallback = NULL;
79 return _encoder.Release();
80 }
81
82 int32_t
InitEncode(const VideoCodec * settings,int32_t numberOfCores,uint32_t maxPayloadSize)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
Encode(const I420VideoFrame & inputFrame,const CodecSpecificInfo * codecSpecificInfo,const std::vector<FrameType> & frameTypes)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
SetChannelParameters(int32_t packetLoss,int rtt)109 VCMGenericEncoder::SetChannelParameters(int32_t packetLoss, int rtt)
110 {
111 return _encoder.SetChannelParameters(packetLoss, rtt);
112 }
113
114 int32_t
SetRates(uint32_t newBitRate,uint32_t frameRate)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
CodecConfigParameters(uint8_t * buffer,int32_t size)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
BitRate() const139 uint32_t VCMGenericEncoder::BitRate() const
140 {
141 return _bitRate;
142 }
143
FrameRate() const144 uint32_t VCMGenericEncoder::FrameRate() const
145 {
146 return _frameRate;
147 }
148
149 int32_t
SetPeriodicKeyFrames(bool enable)150 VCMGenericEncoder::SetPeriodicKeyFrames(bool enable)
151 {
152 return _encoder.SetPeriodicKeyFrames(enable);
153 }
154
RequestFrame(const std::vector<FrameType> & frame_types)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
RegisterEncodeCallback(VCMEncodedFrameCallback * VCMencodedFrameCallback)165 VCMGenericEncoder::RegisterEncodeCallback(VCMEncodedFrameCallback* VCMencodedFrameCallback)
166 {
167 _VCMencodedFrameCallback = VCMencodedFrameCallback;
168 _VCMencodedFrameCallback->SetInternalSource(_internalSource);
169 return _encoder.RegisterEncodeCompleteCallback(_VCMencodedFrameCallback);
170 }
171
172 bool
InternalSource() const173 VCMGenericEncoder::InternalSource() const
174 {
175 return _internalSource;
176 }
177
178 /***************************
179 * Callback Implementation
180 ***************************/
VCMEncodedFrameCallback(EncodedImageCallback * post_encode_callback)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
~VCMEncodedFrameCallback()197 VCMEncodedFrameCallback::~VCMEncodedFrameCallback()
198 {
199 #ifdef DEBUG_ENCODER_BIT_STREAM
200 fclose(_bitStreamAfterEncoder);
201 #endif
202 }
203
204 int32_t
SetTransportCallback(VCMPacketizationCallback * transport)205 VCMEncodedFrameCallback::SetTransportCallback(VCMPacketizationCallback* transport)
206 {
207 _sendCallback = transport;
208 return VCM_OK;
209 }
210
211 int32_t
Encoded(EncodedImage & encodedImage,const CodecSpecificInfo * codecSpecificInfo,const RTPFragmentationHeader * fragmentationHeader)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
SetMediaOpt(media_optimization::MediaOptimization * mediaOpt)267 VCMEncodedFrameCallback::SetMediaOpt(
268 media_optimization::MediaOptimization *mediaOpt)
269 {
270 _mediaOpt = mediaOpt;
271 }
272
273 } // namespace webrtc
274