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

Side by Side Diff: chrome/renderer/media/cast_rtp_stream.cc

Issue 1849003002: Add video frame refresh to MediaStream and VideoCapture stacks. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 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
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/renderer/media/cast_rtp_stream.h" 5 #include "chrome/renderer/media/cast_rtp_stream.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <algorithm> 8 #include <algorithm>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
12 #include "base/callback_helpers.h" 13 #include "base/callback_helpers.h"
13 #include "base/command_line.h" 14 #include "base/command_line.h"
14 #include "base/logging.h" 15 #include "base/logging.h"
15 #include "base/macros.h" 16 #include "base/macros.h"
17 #include "base/memory/ref_counted.h"
16 #include "base/memory/weak_ptr.h" 18 #include "base/memory/weak_ptr.h"
17 #include "base/strings/stringprintf.h" 19 #include "base/strings/stringprintf.h"
18 #include "base/sys_info.h" 20 #include "base/sys_info.h"
21 #include "base/thread_task_runner_handle.h"
22 #include "base/timer/timer.h"
19 #include "base/trace_event/trace_event.h" 23 #include "base/trace_event/trace_event.h"
20 #include "chrome/common/chrome_switches.h" 24 #include "chrome/common/chrome_switches.h"
21 #include "chrome/renderer/media/cast_session.h" 25 #include "chrome/renderer/media/cast_session.h"
22 #include "chrome/renderer/media/cast_udp_transport.h" 26 #include "chrome/renderer/media/cast_udp_transport.h"
23 #include "content/public/renderer/media_stream_audio_sink.h" 27 #include "content/public/renderer/media_stream_audio_sink.h"
24 #include "content/public/renderer/media_stream_video_sink.h" 28 #include "content/public/renderer/media_stream_video_sink.h"
25 #include "content/public/renderer/render_thread.h" 29 #include "content/public/renderer/render_thread.h"
26 #include "content/public/renderer/video_encode_accelerator.h" 30 #include "content/public/renderer/video_encode_accelerator.h"
27 #include "media/audio/audio_parameters.h" 31 #include "media/audio/audio_parameters.h"
28 #include "media/base/audio_bus.h" 32 #include "media/base/audio_bus.h"
(...skipping 13 matching lines...) Expand all
42 46
43 namespace { 47 namespace {
44 48
45 const char kCodecNameOpus[] = "OPUS"; 49 const char kCodecNameOpus[] = "OPUS";
46 const char kCodecNameVp8[] = "VP8"; 50 const char kCodecNameVp8[] = "VP8";
47 const char kCodecNameH264[] = "H264"; 51 const char kCodecNameH264[] = "H264";
48 52
49 // To convert from kilobits per second to bits to per second. 53 // To convert from kilobits per second to bits to per second.
50 const int kBitrateMultiplier = 1000; 54 const int kBitrateMultiplier = 1000;
51 55
56 // The maximum number of milliseconds that should elapse since the last video
57 // frame was received from the video source, before requesting refresh frames.
58 const int kRefreshIntervalMilliseconds = 250;
59
60 // The maximum number of refresh video frames to request/receive. After this
61 // limit (60 * 250ms = 15 seconds), refresh frame requests will stop being made.
62 const int kMaxConsecutiveRefreshFrames = 60;
63
52 CastRtpPayloadParams DefaultOpusPayload() { 64 CastRtpPayloadParams DefaultOpusPayload() {
53 CastRtpPayloadParams payload; 65 CastRtpPayloadParams payload;
54 payload.payload_type = media::cast::kDefaultRtpAudioPayloadType; 66 payload.payload_type = media::cast::kDefaultRtpAudioPayloadType;
55 payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs; 67 payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs;
56 payload.ssrc = 1; 68 payload.ssrc = 1;
57 payload.feedback_ssrc = 2; 69 payload.feedback_ssrc = 2;
58 payload.clock_rate = media::cast::kDefaultAudioSamplingRate; 70 payload.clock_rate = media::cast::kDefaultAudioSamplingRate;
59 // The value is 0 which means VBR. 71 // The value is 0 which means VBR.
60 payload.min_bitrate = payload.max_bitrate = 72 payload.min_bitrate = payload.max_bitrate =
61 media::cast::kDefaultAudioEncoderBitrate; 73 media::cast::kDefaultAudioEncoderBitrate;
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 if (!config->use_external_encoder) 306 if (!config->use_external_encoder)
295 config->number_of_encode_threads = NumberOfEncodeThreads(); 307 config->number_of_encode_threads = NumberOfEncodeThreads();
296 config->aes_key = params.payload.aes_key; 308 config->aes_key = params.payload.aes_key;
297 config->aes_iv_mask = params.payload.aes_iv_mask; 309 config->aes_iv_mask = params.payload.aes_iv_mask;
298 return true; 310 return true;
299 } 311 }
300 312
301 } // namespace 313 } // namespace
302 314
303 // This class receives MediaStreamTrack events and video frames from a 315 // This class receives MediaStreamTrack events and video frames from a
304 // MediaStreamTrack. 316 // MediaStreamVideoTrack. It also includes a timer to request refresh frames
317 // when the capturer halts (e.g., a screen capturer stops delivering frames
318 // because the screen is not being updated). When a halt is detected, refresh
319 // frames will be requested at regular intervals for a short period of time.
320 // This provides the video encoder, downstream, several copies of the last frame
321 // so that it may clear up lossy encoding artifacts.
305 // 322 //
306 // Threading: Video frames are received on the IO thread and then 323 // Threading: Video frames are received on the IO thread and then
307 // forwarded to media::cast::VideoFrameInput through a static method. 324 // forwarded to media::cast::VideoFrameInput. The inner class, Deliverer,
308 // Member variables of this class are only accessed on the render thread. 325 // handles this. Otherwise, all methods and member variables of the outer class
326 // must only be accessed on the render thread.
309 class CastVideoSink : public base::SupportsWeakPtr<CastVideoSink>, 327 class CastVideoSink : public base::SupportsWeakPtr<CastVideoSink>,
310 public content::MediaStreamVideoSink { 328 public content::MediaStreamVideoSink {
311 public: 329 public:
312 // |track| provides data for this sink. 330 // |track| provides data for this sink.
313 // |error_callback| is called if video formats don't match. 331 // |error_callback| is called if video formats don't match.
314 CastVideoSink(const blink::WebMediaStreamTrack& track, 332 CastVideoSink(const blink::WebMediaStreamTrack& track,
315 const CastRtpStream::ErrorCallback& error_callback) 333 const CastRtpStream::ErrorCallback& error_callback)
316 : track_(track), 334 : track_(track), deliverer_(new Deliverer(error_callback)),
317 sink_added_(false), 335 consecutive_refresh_count_(0),
318 error_callback_(error_callback) {} 336 expecting_a_refresh_frame_(false) {}
319 337
320 ~CastVideoSink() override { 338 ~CastVideoSink() override {
321 if (sink_added_) 339 MediaStreamVideoSink::DisconnectFromTrack();
322 RemoveFromVideoTrack(this, track_);
323 }
324
325 // This static method is used to forward video frames to |frame_input|.
326 static void OnVideoFrame(
327 // These parameters are already bound when callback is created.
328 const CastRtpStream::ErrorCallback& error_callback,
329 const scoped_refptr<media::cast::VideoFrameInput> frame_input,
330 // These parameters are passed for each frame.
331 const scoped_refptr<media::VideoFrame>& video_frame,
332 base::TimeTicks estimated_capture_time) {
333 const base::TimeTicks timestamp = estimated_capture_time.is_null()
334 ? base::TimeTicks::Now()
335 : estimated_capture_time;
336
337 if (!(video_frame->format() == media::PIXEL_FORMAT_I420 ||
338 video_frame->format() == media::PIXEL_FORMAT_YV12 ||
339 video_frame->format() == media::PIXEL_FORMAT_YV12A)) {
340 NOTREACHED();
341 return;
342 }
343 scoped_refptr<media::VideoFrame> frame = video_frame;
344 // Drop alpha channel since we do not support it yet.
345 if (frame->format() == media::PIXEL_FORMAT_YV12A)
346 frame = media::WrapAsI420VideoFrame(video_frame);
347
348 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
349 TRACE_EVENT_INSTANT2(
350 "cast_perf_test", "MediaStreamVideoSink::OnVideoFrame",
351 TRACE_EVENT_SCOPE_THREAD,
352 "timestamp", timestamp.ToInternalValue(),
353 "time_delta", frame->timestamp().ToInternalValue());
354 frame_input->InsertRawVideoFrame(frame, timestamp);
355 } 340 }
356 341
357 // Attach this sink to a video track represented by |track_|. 342 // Attach this sink to a video track represented by |track_|.
358 // Data received from the track will be submitted to |frame_input|. 343 // Data received from the track will be submitted to |frame_input|.
359 void AddToTrack( 344 void AddToTrack(
360 const scoped_refptr<media::cast::VideoFrameInput>& frame_input) { 345 const scoped_refptr<media::cast::VideoFrameInput>& frame_input) {
361 DCHECK(!sink_added_); 346 DCHECK(deliverer_);
362 sink_added_ = true; 347 deliverer_->WillConnectToTrack(AsWeakPtr(), frame_input);
363 AddToVideoTrack( 348 refresh_timer_.Start(
364 this, 349 FROM_HERE,
365 base::Bind( 350 base::TimeDelta::FromMilliseconds(kRefreshIntervalMilliseconds),
366 &CastVideoSink::OnVideoFrame, 351 base::Bind(&CastVideoSink::OnRefreshTimerFired,
367 error_callback_, 352 base::Unretained(this)));
368 frame_input), 353 MediaStreamVideoSink::ConnectToTrack(track_,
369 track_); 354 base::Bind(&Deliverer::OnVideoFrame,
355 deliverer_));
370 } 356 }
371 357
372 private: 358 private:
373 blink::WebMediaStreamTrack track_; 359 class Deliverer : public base::RefCountedThreadSafe<Deliverer> {
374 bool sink_added_; 360 public:
375 CastRtpStream::ErrorCallback error_callback_; 361 explicit Deliverer(const CastRtpStream::ErrorCallback& error_callback)
362 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
363 error_callback_(error_callback) {}
364
365 void WillConnectToTrack(
366 base::WeakPtr<CastVideoSink> sink,
367 scoped_refptr<media::cast::VideoFrameInput> frame_input) {
368 DCHECK(main_task_runner_->RunsTasksOnCurrentThread());
369 sink_ = sink;
370 frame_input_ = std::move(frame_input);
371 }
372
373 void OnVideoFrame(const scoped_refptr<media::VideoFrame>& video_frame,
374 base::TimeTicks estimated_capture_time) {
375 main_task_runner_->PostTask(
376 FROM_HERE, base::Bind(&CastVideoSink::DidReceiveFrame, sink_));
377
378 const base::TimeTicks timestamp = estimated_capture_time.is_null()
379 ? base::TimeTicks::Now()
380 : estimated_capture_time;
381
382 if (!(video_frame->format() == media::PIXEL_FORMAT_I420 ||
383 video_frame->format() == media::PIXEL_FORMAT_YV12 ||
384 video_frame->format() == media::PIXEL_FORMAT_YV12A)) {
385 error_callback_.Run("Incompatible video frame format.");
386 return;
387 }
388 scoped_refptr<media::VideoFrame> frame = video_frame;
389 // Drop alpha channel since we do not support it yet.
390 if (frame->format() == media::PIXEL_FORMAT_YV12A)
391 frame = media::WrapAsI420VideoFrame(video_frame);
392
393 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
394 TRACE_EVENT_INSTANT2(
395 "cast_perf_test", "MediaStreamVideoSink::OnVideoFrame",
396 TRACE_EVENT_SCOPE_THREAD,
397 "timestamp", timestamp.ToInternalValue(),
398 "time_delta", frame->timestamp().ToInternalValue());
399 frame_input_->InsertRawVideoFrame(frame, timestamp);
400 }
401
402 private:
403 friend class base::RefCountedThreadSafe<Deliverer>;
404 ~Deliverer() {}
405
406 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
407 const CastRtpStream::ErrorCallback error_callback_;
408
409 // These are set on the main thread after construction, and before the first
410 // call to OnVideoFrame() on the IO thread. |sink_| may be passed around on
411 // any thread, but must only be dereferenced on the main renderer thread.
412 base::WeakPtr<CastVideoSink> sink_;
413 scoped_refptr<media::cast::VideoFrameInput> frame_input_;
414
415 DISALLOW_COPY_AND_ASSIGN(Deliverer);
416 };
417
418 private:
419 void OnRefreshTimerFired() {
420 ++consecutive_refresh_count_;
421 if (consecutive_refresh_count_ >= kMaxConsecutiveRefreshFrames)
422 refresh_timer_.Stop(); // Stop timer until receiving a non-refresh frame.
423
424 DVLOG(1) << "CastVideoSink is requesting another refresh frame "
425 "(consecutive count=" << consecutive_refresh_count_ << ").";
426 expecting_a_refresh_frame_ = true;
427 MediaStreamVideoSink::RequestRefreshFrame();
428 }
429
430 void DidReceiveFrame() {
431 if (expecting_a_refresh_frame_) {
432 // There is uncertainty as to whether the video frame was in response to a
433 // refresh request. However, if it was not, more video frames will soon
434 // follow, and before the refresh timer can fire again. Thus, the
435 // behavior resulting from this logic will be correct.
436 expecting_a_refresh_frame_ = false;
437 } else {
438 consecutive_refresh_count_ = 0;
439 // The following re-starts the timer, scheduling it to fire at
440 // kRefreshIntervalMilliseconds from now.
441 refresh_timer_.Reset();
442 }
443 }
444
445 const blink::WebMediaStreamTrack track_;
446 const scoped_refptr<Deliverer> deliverer_;
447
448 // Requests refresh frames at a constant rate while the source is paused, up
449 // to a consecutive maximum.
450 base::RepeatingTimer refresh_timer_;
451
452 // Counter for the number of consecutive "refresh frames" received.
xjz 2016/04/01 19:10:04 nit: s/received/requested.
miu 2016/04/01 23:24:27 Done. Good catch.
453 int consecutive_refresh_count_;
454
455 // Set to true when a request for a refresh frame has been made. This is
456 // cleared once the next frame is received.
457 bool expecting_a_refresh_frame_;
376 458
377 DISALLOW_COPY_AND_ASSIGN(CastVideoSink); 459 DISALLOW_COPY_AND_ASSIGN(CastVideoSink);
378 }; 460 };
379 461
380 // Receives audio data from a MediaStreamTrack. Data is submitted to 462 // Receives audio data from a MediaStreamTrack. Data is submitted to
381 // media::cast::FrameInput. 463 // media::cast::FrameInput.
382 // 464 //
383 // Threading: Audio frames are received on the real-time audio thread. 465 // Threading: Audio frames are received on the real-time audio thread.
384 // Note that RemoveFromAudioTrack() is synchronous and we have 466 // Note that RemoveFromAudioTrack() is synchronous and we have
385 // gurantee that there will be no more audio data after calling it. 467 // gurantee that there will be no more audio data after calling it.
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
648 DCHECK(content::RenderThread::Get()); 730 DCHECK(content::RenderThread::Get());
649 DVLOG(1) << "CastRtpStream::DidEncounterError(" << message << ") = " 731 DVLOG(1) << "CastRtpStream::DidEncounterError(" << message << ") = "
650 << (IsAudio() ? "audio" : "video"); 732 << (IsAudio() ? "audio" : "video");
651 // Save the WeakPtr first because the error callback might delete this object. 733 // Save the WeakPtr first because the error callback might delete this object.
652 base::WeakPtr<CastRtpStream> ptr = weak_factory_.GetWeakPtr(); 734 base::WeakPtr<CastRtpStream> ptr = weak_factory_.GetWeakPtr();
653 error_callback_.Run(message); 735 error_callback_.Run(message);
654 base::ThreadTaskRunnerHandle::Get()->PostTask( 736 base::ThreadTaskRunnerHandle::Get()->PostTask(
655 FROM_HERE, 737 FROM_HERE,
656 base::Bind(&CastRtpStream::Stop, ptr)); 738 base::Bind(&CastRtpStream::Stop, ptr));
657 } 739 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698