blob: 9561c8323ae8964a0d8eaf15a403382b19838a85 [file] [log] [blame]
Ben Murdocheb525c52013-07-10 11:40:50 +01001// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/renderer/media/rtc_encoding_video_capturer.h"
6
7#include "base/logging.h"
8#include "media/base/encoded_bitstream_buffer.h"
9
10namespace content {
11
Ben Murdocha3f7b4e2013-07-24 10:36:34 +010012namespace {
13
14static const unsigned int kMaxBitrateKbps = 50 * 1000;
15
16} // namespace
17
Ben Murdocheb525c52013-07-10 11:40:50 +010018// Client of EncodedVideoSource. This object is created and owned by the
19// RtcEncodingVideoCapturer.
20class RtcEncodingVideoCapturer::EncodedVideoSourceClient :
21 public media::EncodedVideoSource::Client {
22 public:
23 EncodedVideoSourceClient(
24 media::EncodedVideoSource* encoded_video_source,
25 media::VideoEncodingParameters params,
26 webrtc::VideoCodecType rtc_codec_type);
27 virtual ~EncodedVideoSourceClient();
28
29 // media::EncodedVideoSource::Client implementation.
30 virtual void OnOpened(
31 const media::VideoEncodingParameters& params) OVERRIDE;
32 virtual void OnClosed() OVERRIDE;
33 virtual void OnBufferReady(
34 scoped_refptr<const media::EncodedBitstreamBuffer> buffer) OVERRIDE;
35 virtual void OnConfigChanged(
36 const media::RuntimeVideoEncodingParameters& params) OVERRIDE;
37
38 // Getters and setters for bitstream properties.
39 media::RuntimeVideoEncodingParameters runtime_params() const;
40 void set_round_trip_time(base::TimeDelta round_trip_time);
41 void set_callback(webrtc::EncodedImageCallback* callback);
42
Ben Murdocha3f7b4e2013-07-24 10:36:34 +010043 // Sets target bitrate and framerate.
44 void SetRates(uint32_t target_bitrate, uint32_t frame_rate);
45
46 // Requests key frame.
47 void RequestKeyFrame();
48
Ben Murdocheb525c52013-07-10 11:40:50 +010049 private:
50 // Convert buffer to webrtc types and invoke encode complete callback.
51 void ReportEncodedFrame(
52 scoped_refptr<const media::EncodedBitstreamBuffer> buffer);
53
54 media::VideoEncodingParameters params_;
55 webrtc::VideoCodecType rtc_codec_type_;
56 bool finished_;
57
58 base::Time time_base_;
59 base::TimeDelta round_trip_time_;
60 media::EncodedVideoSource* encoded_video_source_;
61 webrtc::EncodedImageCallback* callback_;
62
63 DISALLOW_COPY_AND_ASSIGN(EncodedVideoSourceClient);
64};
65
66RtcEncodingVideoCapturer::EncodedVideoSourceClient::EncodedVideoSourceClient(
67 media::EncodedVideoSource* encoded_video_source,
68 media::VideoEncodingParameters params,
69 webrtc::VideoCodecType rtc_codec_type)
70 : params_(params),
71 rtc_codec_type_(rtc_codec_type),
72 finished_(false),
73 encoded_video_source_(encoded_video_source),
74 callback_(NULL) {
75 DCHECK(encoded_video_source_);
76 encoded_video_source_->OpenBitstream(this, params);
77}
78
79RtcEncodingVideoCapturer::EncodedVideoSourceClient::
80 ~EncodedVideoSourceClient() {
81 if (!finished_)
82 encoded_video_source_->CloseBitstream();
83}
84
85media::RuntimeVideoEncodingParameters
86 RtcEncodingVideoCapturer::EncodedVideoSourceClient::runtime_params() const {
87 return params_.runtime_params;
88}
89
90void RtcEncodingVideoCapturer::EncodedVideoSourceClient::set_round_trip_time(
91 base::TimeDelta round_trip_time) {
92 round_trip_time_ = round_trip_time;
93}
94
95void RtcEncodingVideoCapturer::EncodedVideoSourceClient::set_callback(
96 webrtc::EncodedImageCallback* callback) {
97 DCHECK(!callback_);
98 callback_ = callback;
99}
100
101void RtcEncodingVideoCapturer::EncodedVideoSourceClient::OnOpened(
102 const media::VideoEncodingParameters& params) {
103 params_ = params;
104}
105
106void RtcEncodingVideoCapturer::EncodedVideoSourceClient::OnClosed() {
107 finished_ = true;
108}
109
110void RtcEncodingVideoCapturer::EncodedVideoSourceClient::OnBufferReady(
111 scoped_refptr<const media::EncodedBitstreamBuffer> buffer) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100112 DCHECK(!finished_ && buffer.get());
Ben Murdocheb525c52013-07-10 11:40:50 +0100113
114 // First buffer constitutes the origin of the time for this bitstream context.
115 if (time_base_.is_null())
116 time_base_ = buffer->metadata().timestamp;
117
118 ReportEncodedFrame(buffer);
119 encoded_video_source_->ReturnBitstreamBuffer(buffer);
120}
121
122void RtcEncodingVideoCapturer::EncodedVideoSourceClient::OnConfigChanged(
123 const media::RuntimeVideoEncodingParameters& params) {
124 params_.runtime_params = params;
125}
126
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100127void RtcEncodingVideoCapturer::EncodedVideoSourceClient::SetRates(
128 uint32_t target_bitrate, uint32_t frame_rate) {
129 params_.runtime_params.target_bitrate = target_bitrate;
130 params_.runtime_params.frames_per_second = frame_rate;
131 encoded_video_source_->TrySetBitstreamConfig(params_.runtime_params);
132}
133
134void RtcEncodingVideoCapturer::EncodedVideoSourceClient::RequestKeyFrame() {
135 encoded_video_source_->RequestKeyFrame();
136}
137
Ben Murdocheb525c52013-07-10 11:40:50 +0100138void RtcEncodingVideoCapturer::EncodedVideoSourceClient::ReportEncodedFrame(
139 scoped_refptr<const media::EncodedBitstreamBuffer> buffer) {
140 if (!callback_)
141 return;
142
143 webrtc::EncodedImage image;
144 webrtc::CodecSpecificInfo codecInfo;
145 webrtc::RTPFragmentationHeader fragHeader;
146
147 // TODO(hshi): remove this const_cast. Unfortunately webrtc::EncodedImage
148 // defines member |_buffer| of type uint8_t* even though webrtc never modifies
149 // the buffer contents.
150 image._buffer = const_cast<uint8_t*>(buffer->buffer());
151 image._length = buffer->size();
152 image._size = image._length;
153
154 const media::BufferEncodingMetadata& metadata = buffer->metadata();
155 base::TimeDelta capture_time = metadata.timestamp - time_base_;
156 image.capture_time_ms_ = capture_time.InMilliseconds();
157 // Convert capture time to 90 kHz RTP timestamp.
158 image._timeStamp = (capture_time * 90000).InSeconds();
159 if (metadata.key_frame) {
160 image._frameType = webrtc::kKeyFrame;
161 } else {
162 image._frameType = webrtc::kDeltaFrame;
163 }
164 image._completeFrame = true;
165 image._encodedWidth = params_.resolution.width();
166 image._encodedHeight = params_.resolution.height();
167
168 // TODO(hshi): generate codec specific info for VP8.
169 codecInfo.codecType = rtc_codec_type_;
170
171 // Generate header containing a single fragmentation.
172 fragHeader.VerifyAndAllocateFragmentationHeader(1);
173 fragHeader.fragmentationOffset[0] = 0;
174 fragHeader.fragmentationLength[0] = buffer->size();
175 fragHeader.fragmentationPlType[0] = 0;
176 fragHeader.fragmentationTimeDiff[0] = 0;
177
178 callback_->Encoded(image, &codecInfo, &fragHeader);
179}
180
181// RtcEncodingVideoCapturer
182RtcEncodingVideoCapturer::RtcEncodingVideoCapturer(
183 media::EncodedVideoSource* encoded_video_source,
184 webrtc::VideoCodecType codec_type)
185 : encoded_video_source_(encoded_video_source),
186 rtc_codec_type_(codec_type) {
187}
188
189RtcEncodingVideoCapturer::~RtcEncodingVideoCapturer() {
190}
191
192int32_t RtcEncodingVideoCapturer::InitEncode(
193 const webrtc::VideoCodec* codecSettings,
194 int32_t numberOfCores,
195 uint32_t maxPayloadSize) {
196 DCHECK(!encoded_video_source_client_);
197 if (codecSettings->codecType != rtc_codec_type_)
198 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100199 if (codecSettings->startBitrate > kMaxBitrateKbps ||
200 codecSettings->maxBitrate > kMaxBitrateKbps)
201 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
Ben Murdocheb525c52013-07-10 11:40:50 +0100202
203 // Convert |codecSettings| to |params|.
204 media::VideoEncodingParameters params;
205 params.codec_name = codecSettings->plName;
206 params.resolution = gfx::Size(codecSettings->width, codecSettings->height);
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100207 params.runtime_params.target_bitrate = codecSettings->startBitrate * 1000;
208 params.runtime_params.max_bitrate = codecSettings->maxBitrate * 1000;
Ben Murdocheb525c52013-07-10 11:40:50 +0100209 params.runtime_params.frames_per_second = codecSettings->maxFramerate;
210 encoded_video_source_client_.reset(new EncodedVideoSourceClient(
211 encoded_video_source_, params, rtc_codec_type_));
212 return WEBRTC_VIDEO_CODEC_OK;
213}
214
215int32_t RtcEncodingVideoCapturer::Encode(
216 const webrtc::I420VideoFrame& /* inputImage */,
217 const webrtc::CodecSpecificInfo* codecSpecificInfo,
218 const std::vector<webrtc::VideoFrameType>* frame_types) {
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100219 if (frame_types && !frame_types->empty()) {
220 webrtc::VideoFrameType type = frame_types->front();
221 if (type == webrtc::kKeyFrame)
222 encoded_video_source_client_->RequestKeyFrame();
223 }
Ben Murdocheb525c52013-07-10 11:40:50 +0100224 return WEBRTC_VIDEO_CODEC_OK;
225}
226
227int32_t RtcEncodingVideoCapturer::RegisterEncodeCompleteCallback(
228 webrtc::EncodedImageCallback* callback) {
229 DCHECK(encoded_video_source_client_);
230 encoded_video_source_client_->set_callback(callback);
231 return WEBRTC_VIDEO_CODEC_OK;
232}
233
234int32_t RtcEncodingVideoCapturer::Release() {
235 DCHECK(encoded_video_source_client_);
236 encoded_video_source_client_.reset(NULL);
237 return WEBRTC_VIDEO_CODEC_OK;
238}
239
240int32_t RtcEncodingVideoCapturer::SetChannelParameters(
241 uint32_t /* packetLoss */,
242 int rtt_in_ms) {
243 if (!encoded_video_source_client_)
244 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
245 encoded_video_source_client_->set_round_trip_time(
246 base::TimeDelta::FromMilliseconds(rtt_in_ms));
247 return WEBRTC_VIDEO_CODEC_OK;
248}
249
250int32_t RtcEncodingVideoCapturer::SetRates(uint32_t newBitRate,
251 uint32_t frameRate) {
252 if (!encoded_video_source_client_)
253 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
Ben Murdocha3f7b4e2013-07-24 10:36:34 +0100254 if (newBitRate > kMaxBitrateKbps)
255 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
256 encoded_video_source_client_->SetRates(newBitRate * 1000, frameRate);
Ben Murdocheb525c52013-07-10 11:40:50 +0100257 return WEBRTC_VIDEO_CODEC_OK;
258}
259
260} // namespace content