Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(500)

Side by Side Diff: media/cast/video_sender/external_video_encoder.cc

Issue 388663003: Cast: Reshuffle files under media/cast (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: missing includes Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 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 "media/cast/video_sender/external_video_encoder.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/memory/scoped_vector.h"
10 #include "base/memory/shared_memory.h"
11 #include "base/message_loop/message_loop.h"
12 #include "media/base/video_frame.h"
13 #include "media/base/video_util.h"
14 #include "media/cast/cast_defines.h"
15 #include "media/cast/logging/logging_defines.h"
16 #include "media/cast/transport/cast_transport_config.h"
17 #include "media/video/video_encode_accelerator.h"
18
19 namespace media {
20 namespace cast {
21 class LocalVideoEncodeAcceleratorClient;
22 } // namespace cast
23 } // namespace media
24
25 namespace {
26 static const size_t kOutputBufferCount = 3;
27
28 void LogFrameEncodedEvent(
29 const scoped_refptr<media::cast::CastEnvironment>& cast_environment,
30 base::TimeTicks event_time,
31 media::cast::RtpTimestamp rtp_timestamp,
32 uint32 frame_id) {
33 cast_environment->Logging()->InsertFrameEvent(
34 event_time, media::cast::FRAME_ENCODED, media::cast::VIDEO_EVENT,
35 rtp_timestamp, frame_id);
36 }
37
38 // Proxy this call to ExternalVideoEncoder on the cast main thread.
39 void ProxyCreateVideoEncodeAccelerator(
40 const scoped_refptr<media::cast::CastEnvironment>& cast_environment,
41 const base::WeakPtr<media::cast::ExternalVideoEncoder>& weak_ptr,
42 const media::cast::CreateVideoEncodeMemoryCallback&
43 create_video_encode_mem_cb,
44 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner,
45 scoped_ptr<media::VideoEncodeAccelerator> vea) {
46 cast_environment->PostTask(
47 media::cast::CastEnvironment::MAIN,
48 FROM_HERE,
49 base::Bind(
50 &media::cast::ExternalVideoEncoder::OnCreateVideoEncodeAccelerator,
51 weak_ptr,
52 create_video_encode_mem_cb,
53 encoder_task_runner,
54 base::Passed(&vea)));
55 }
56 } // namespace
57
58 namespace media {
59 namespace cast {
60
61 // Container for the associated data of a video frame being processed.
62 struct EncodedFrameReturnData {
63 EncodedFrameReturnData(base::TimeTicks c_time,
64 VideoEncoder::FrameEncodedCallback callback) {
65 capture_time = c_time;
66 frame_encoded_callback = callback;
67 }
68 base::TimeTicks capture_time;
69 VideoEncoder::FrameEncodedCallback frame_encoded_callback;
70 };
71
72 // The ExternalVideoEncoder class can be deleted directly by cast, while
73 // LocalVideoEncodeAcceleratorClient stays around long enough to properly shut
74 // down the VideoEncodeAccelerator.
75 class LocalVideoEncodeAcceleratorClient
76 : public VideoEncodeAccelerator::Client,
77 public base::RefCountedThreadSafe<LocalVideoEncodeAcceleratorClient> {
78 public:
79 LocalVideoEncodeAcceleratorClient(
80 scoped_refptr<CastEnvironment> cast_environment,
81 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner,
82 scoped_ptr<media::VideoEncodeAccelerator> vea,
83 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb,
84 const base::WeakPtr<ExternalVideoEncoder>& weak_owner)
85 : cast_environment_(cast_environment),
86 encoder_task_runner_(encoder_task_runner),
87 video_encode_accelerator_(vea.Pass()),
88 create_video_encode_memory_cb_(create_video_encode_mem_cb),
89 weak_owner_(weak_owner),
90 last_encoded_frame_id_(kStartFrameId),
91 key_frame_encountered_(false) {
92 DCHECK(encoder_task_runner_);
93 }
94
95 // Initialize the real HW encoder.
96 void Initialize(const VideoSenderConfig& video_config) {
97 DCHECK(encoder_task_runner_);
98 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
99
100 VideoCodecProfile output_profile = media::VIDEO_CODEC_PROFILE_UNKNOWN;
101 switch (video_config.codec) {
102 case transport::CODEC_VIDEO_VP8:
103 output_profile = media::VP8PROFILE_MAIN;
104 break;
105 case transport::CODEC_VIDEO_H264:
106 output_profile = media::H264PROFILE_MAIN;
107 break;
108 case transport::CODEC_VIDEO_FAKE:
109 NOTREACHED() << "Fake software video encoder cannot be external";
110 break;
111 default:
112 NOTREACHED() << "Video codec not specified or not supported";
113 break;
114 }
115 max_frame_rate_ = video_config.max_frame_rate;
116
117 if (!video_encode_accelerator_->Initialize(
118 media::VideoFrame::I420,
119 gfx::Size(video_config.width, video_config.height),
120 output_profile,
121 video_config.start_bitrate,
122 this)) {
123 NotifyError(VideoEncodeAccelerator::kInvalidArgumentError);
124 return;
125 }
126
127 // Wait until shared memory is allocated to indicate that encoder is
128 // initialized.
129 }
130
131 // Free the HW.
132 void Destroy() {
133 DCHECK(encoder_task_runner_);
134 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
135
136 video_encode_accelerator_.reset();
137 }
138
139 void SetBitRate(uint32 bit_rate) {
140 DCHECK(encoder_task_runner_);
141 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
142
143 video_encode_accelerator_->RequestEncodingParametersChange(bit_rate,
144 max_frame_rate_);
145 }
146
147 void EncodeVideoFrame(
148 const scoped_refptr<media::VideoFrame>& video_frame,
149 const base::TimeTicks& capture_time,
150 bool key_frame_requested,
151 const VideoEncoder::FrameEncodedCallback& frame_encoded_callback) {
152 DCHECK(encoder_task_runner_);
153 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
154
155 encoded_frame_data_storage_.push_back(
156 EncodedFrameReturnData(capture_time, frame_encoded_callback));
157
158 // BitstreamBufferReady will be called once the encoder is done.
159 video_encode_accelerator_->Encode(video_frame, key_frame_requested);
160 }
161
162 protected:
163 virtual void NotifyError(VideoEncodeAccelerator::Error error) OVERRIDE {
164 DCHECK(encoder_task_runner_);
165 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
166 VLOG(1) << "ExternalVideoEncoder NotifyError: " << error;
167
168 video_encode_accelerator_.reset();
169 cast_environment_->PostTask(
170 CastEnvironment::MAIN,
171 FROM_HERE,
172 base::Bind(&ExternalVideoEncoder::EncoderError, weak_owner_));
173 }
174
175 // Called to allocate the input and output buffers.
176 virtual void RequireBitstreamBuffers(unsigned int input_count,
177 const gfx::Size& input_coded_size,
178 size_t output_buffer_size) OVERRIDE {
179 DCHECK(encoder_task_runner_);
180 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
181 DCHECK(video_encode_accelerator_);
182
183 for (size_t j = 0; j < kOutputBufferCount; ++j) {
184 create_video_encode_memory_cb_.Run(
185 output_buffer_size,
186 base::Bind(&LocalVideoEncodeAcceleratorClient::OnCreateSharedMemory,
187 this));
188 }
189 }
190
191 // Encoder has encoded a frame and it's available in one of out output
192 // buffers.
193 virtual void BitstreamBufferReady(int32 bitstream_buffer_id,
194 size_t payload_size,
195 bool key_frame) OVERRIDE {
196 DCHECK(encoder_task_runner_);
197 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
198 if (bitstream_buffer_id < 0 ||
199 bitstream_buffer_id >= static_cast<int32>(output_buffers_.size())) {
200 NOTREACHED();
201 VLOG(1) << "BitstreamBufferReady(): invalid bitstream_buffer_id="
202 << bitstream_buffer_id;
203 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
204 return;
205 }
206 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id];
207 if (payload_size > output_buffer->mapped_size()) {
208 NOTREACHED();
209 VLOG(1) << "BitstreamBufferReady(): invalid payload_size = "
210 << payload_size;
211 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
212 return;
213 }
214 if (key_frame)
215 key_frame_encountered_ = true;
216 if (!key_frame_encountered_) {
217 // Do not send video until we have encountered the first key frame.
218 // Save the bitstream buffer in |stream_header_| to be sent later along
219 // with the first key frame.
220 stream_header_.append(static_cast<const char*>(output_buffer->memory()),
221 payload_size);
222 } else if (!encoded_frame_data_storage_.empty()) {
223 scoped_ptr<transport::EncodedFrame> encoded_frame(
224 new transport::EncodedFrame());
225 encoded_frame->dependency = key_frame ? transport::EncodedFrame::KEY :
226 transport::EncodedFrame::DEPENDENT;
227 encoded_frame->frame_id = ++last_encoded_frame_id_;
228 if (key_frame)
229 encoded_frame->referenced_frame_id = encoded_frame->frame_id;
230 else
231 encoded_frame->referenced_frame_id = encoded_frame->frame_id - 1;
232 encoded_frame->reference_time =
233 encoded_frame_data_storage_.front().capture_time;
234 encoded_frame->rtp_timestamp =
235 GetVideoRtpTimestamp(encoded_frame->reference_time);
236 if (!stream_header_.empty()) {
237 encoded_frame->data = stream_header_;
238 stream_header_.clear();
239 }
240 encoded_frame->data.append(
241 static_cast<const char*>(output_buffer->memory()), payload_size);
242
243 cast_environment_->PostTask(
244 CastEnvironment::MAIN,
245 FROM_HERE,
246 base::Bind(&LogFrameEncodedEvent,
247 cast_environment_,
248 cast_environment_->Clock()->NowTicks(),
249 encoded_frame->rtp_timestamp,
250 encoded_frame->frame_id));
251
252 cast_environment_->PostTask(
253 CastEnvironment::MAIN,
254 FROM_HERE,
255 base::Bind(encoded_frame_data_storage_.front().frame_encoded_callback,
256 base::Passed(&encoded_frame)));
257
258 encoded_frame_data_storage_.pop_front();
259 } else {
260 VLOG(1) << "BitstreamBufferReady(): no encoded frame data available";
261 }
262
263 // We need to re-add the output buffer to the encoder after we are done
264 // with it.
265 video_encode_accelerator_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
266 bitstream_buffer_id,
267 output_buffers_[bitstream_buffer_id]->handle(),
268 output_buffers_[bitstream_buffer_id]->mapped_size()));
269 }
270
271 private:
272 // Note: This method can be called on any thread.
273 void OnCreateSharedMemory(scoped_ptr<base::SharedMemory> memory) {
274 encoder_task_runner_->PostTask(
275 FROM_HERE,
276 base::Bind(&LocalVideoEncodeAcceleratorClient::ReceivedSharedMemory,
277 this,
278 base::Passed(&memory)));
279 }
280
281 void ReceivedSharedMemory(scoped_ptr<base::SharedMemory> memory) {
282 DCHECK(encoder_task_runner_);
283 DCHECK(encoder_task_runner_->RunsTasksOnCurrentThread());
284
285 output_buffers_.push_back(memory.release());
286
287 // Wait until all requested buffers are received.
288 if (output_buffers_.size() < kOutputBufferCount)
289 return;
290
291 // Immediately provide all output buffers to the VEA.
292 for (size_t i = 0; i < output_buffers_.size(); ++i) {
293 video_encode_accelerator_->UseOutputBitstreamBuffer(
294 media::BitstreamBuffer(static_cast<int32>(i),
295 output_buffers_[i]->handle(),
296 output_buffers_[i]->mapped_size()));
297 }
298
299 cast_environment_->PostTask(
300 CastEnvironment::MAIN,
301 FROM_HERE,
302 base::Bind(&ExternalVideoEncoder::EncoderInitialized, weak_owner_));
303 }
304
305 friend class base::RefCountedThreadSafe<LocalVideoEncodeAcceleratorClient>;
306
307 virtual ~LocalVideoEncodeAcceleratorClient() {}
308
309 const scoped_refptr<CastEnvironment> cast_environment_;
310 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner_;
311 scoped_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_;
312 const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_;
313 const base::WeakPtr<ExternalVideoEncoder> weak_owner_;
314 int max_frame_rate_;
315 uint32 last_encoded_frame_id_;
316 bool key_frame_encountered_;
317 std::string stream_header_;
318
319 // Shared memory buffers for output with the VideoAccelerator.
320 ScopedVector<base::SharedMemory> output_buffers_;
321
322 // FIFO list.
323 std::list<EncodedFrameReturnData> encoded_frame_data_storage_;
324
325 DISALLOW_COPY_AND_ASSIGN(LocalVideoEncodeAcceleratorClient);
326 };
327
328 ExternalVideoEncoder::ExternalVideoEncoder(
329 scoped_refptr<CastEnvironment> cast_environment,
330 const VideoSenderConfig& video_config,
331 const CreateVideoEncodeAcceleratorCallback& create_vea_cb,
332 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb)
333 : video_config_(video_config),
334 cast_environment_(cast_environment),
335 encoder_active_(false),
336 key_frame_requested_(false),
337 weak_factory_(this) {
338 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
339
340 create_vea_cb.Run(base::Bind(&ProxyCreateVideoEncodeAccelerator,
341 cast_environment,
342 weak_factory_.GetWeakPtr(),
343 create_video_encode_mem_cb));
344 }
345
346 ExternalVideoEncoder::~ExternalVideoEncoder() {
347 encoder_task_runner_->PostTask(
348 FROM_HERE,
349 base::Bind(&LocalVideoEncodeAcceleratorClient::Destroy,
350 video_accelerator_client_));
351 }
352
353 void ExternalVideoEncoder::EncoderInitialized() {
354 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
355 encoder_active_ = true;
356 }
357
358 void ExternalVideoEncoder::EncoderError() {
359 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
360 encoder_active_ = false;
361 }
362
363 void ExternalVideoEncoder::OnCreateVideoEncodeAccelerator(
364 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb,
365 scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner,
366 scoped_ptr<media::VideoEncodeAccelerator> vea) {
367 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
368 encoder_task_runner_ = encoder_task_runner;
369
370 video_accelerator_client_ =
371 new LocalVideoEncodeAcceleratorClient(cast_environment_,
372 encoder_task_runner,
373 vea.Pass(),
374 create_video_encode_mem_cb,
375 weak_factory_.GetWeakPtr());
376 encoder_task_runner_->PostTask(
377 FROM_HERE,
378 base::Bind(&LocalVideoEncodeAcceleratorClient::Initialize,
379 video_accelerator_client_,
380 video_config_));
381 }
382
383 bool ExternalVideoEncoder::EncodeVideoFrame(
384 const scoped_refptr<media::VideoFrame>& video_frame,
385 const base::TimeTicks& capture_time,
386 const FrameEncodedCallback& frame_encoded_callback) {
387 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
388
389 if (!encoder_active_)
390 return false;
391
392 encoder_task_runner_->PostTask(
393 FROM_HERE,
394 base::Bind(&LocalVideoEncodeAcceleratorClient::EncodeVideoFrame,
395 video_accelerator_client_,
396 video_frame,
397 capture_time,
398 key_frame_requested_,
399 frame_encoded_callback));
400
401 key_frame_requested_ = false;
402 return true;
403 }
404
405 // Inform the encoder about the new target bit rate.
406 void ExternalVideoEncoder::SetBitRate(int new_bit_rate) {
407 if (!encoder_active_) {
408 // If we receive SetBitRate() before VEA creation callback is invoked,
409 // cache the new bit rate in the encoder config and use the new settings
410 // to initialize VEA.
411 video_config_.start_bitrate = new_bit_rate;
412 return;
413 }
414
415 encoder_task_runner_->PostTask(
416 FROM_HERE,
417 base::Bind(&LocalVideoEncodeAcceleratorClient::SetBitRate,
418 video_accelerator_client_,
419 new_bit_rate));
420 }
421
422 // Inform the encoder to encode the next frame as a key frame.
423 void ExternalVideoEncoder::GenerateKeyFrame() {
424 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
425 key_frame_requested_ = true;
426 }
427
428 // Inform the encoder to only reference frames older or equal to frame_id;
429 void ExternalVideoEncoder::LatestFrameIdToReference(uint32 /*frame_id*/) {
430 // Do nothing not supported.
431 }
432
433 } // namespace cast
434 } // namespace media
OLDNEW
« no previous file with comments | « media/cast/video_sender/external_video_encoder.h ('k') | media/cast/video_sender/external_video_encoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698