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
18namespace webrtc {
19namespace {
20// Map information from info into rtp. If no relevant information is found
21// in info, rtp is set to NULL.
22void 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
58VCMGenericEncoder::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
70VCMGenericEncoder::~VCMGenericEncoder()
71{
72}
73
74int32_t VCMGenericEncoder::Release()
75{
76    _bitRate = 0;
77    _frameRate = 0;
78    _VCMencodedFrameCallback = NULL;
79    return _encoder.Release();
80}
81
82int32_t
83VCMGenericEncoder::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
98int32_t
99VCMGenericEncoder::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
108int32_t
109VCMGenericEncoder::SetChannelParameters(int32_t packetLoss, int rtt)
110{
111    return _encoder.SetChannelParameters(packetLoss, rtt);
112}
113
114int32_t
115VCMGenericEncoder::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
128int32_t
129VCMGenericEncoder::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
139uint32_t VCMGenericEncoder::BitRate() const
140{
141    return _bitRate;
142}
143
144uint32_t VCMGenericEncoder::FrameRate() const
145{
146    return _frameRate;
147}
148
149int32_t
150VCMGenericEncoder::SetPeriodicKeyFrames(bool enable)
151{
152    return _encoder.SetPeriodicKeyFrames(enable);
153}
154
155int32_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
164int32_t
165VCMGenericEncoder::RegisterEncodeCallback(VCMEncodedFrameCallback* VCMencodedFrameCallback)
166{
167   _VCMencodedFrameCallback = VCMencodedFrameCallback;
168   _VCMencodedFrameCallback->SetInternalSource(_internalSource);
169   return _encoder.RegisterEncodeCompleteCallback(_VCMencodedFrameCallback);
170}
171
172bool
173VCMGenericEncoder::InternalSource() const
174{
175    return _internalSource;
176}
177
178 /***************************
179  * Callback Implementation
180  ***************************/
181VCMEncodedFrameCallback::VCMEncodedFrameCallback(
182    EncodedImageCallback* post_encode_callback):
183_sendCallback(),
184_mediaOpt(NULL),
185_payloadType(0),
186_internalSource(false),
187post_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
197VCMEncodedFrameCallback::~VCMEncodedFrameCallback()
198{
199#ifdef DEBUG_ENCODER_BIT_STREAM
200    fclose(_bitStreamAfterEncoder);
201#endif
202}
203
204int32_t
205VCMEncodedFrameCallback::SetTransportCallback(VCMPacketizationCallback* transport)
206{
207    _sendCallback = transport;
208    return VCM_OK;
209}
210
211int32_t
212VCMEncodedFrameCallback::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
266void
267VCMEncodedFrameCallback::SetMediaOpt(
268    media_optimization::MediaOptimization *mediaOpt)
269{
270    _mediaOpt = mediaOpt;
271}
272
273}  // namespace webrtc
274