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

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: Addressed nick's PS3 comments (moving non-observer impl out of MSVideoSink interface). 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
« no previous file with comments | « no previous file | content/browser/renderer_host/media/video_capture_host.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
28 #include "content/public/renderer/media_stream_utils.h"
24 #include "content/public/renderer/media_stream_video_sink.h" 29 #include "content/public/renderer/media_stream_video_sink.h"
25 #include "content/public/renderer/render_thread.h" 30 #include "content/public/renderer/render_thread.h"
26 #include "content/public/renderer/video_encode_accelerator.h" 31 #include "content/public/renderer/video_encode_accelerator.h"
27 #include "media/audio/audio_parameters.h" 32 #include "media/audio/audio_parameters.h"
28 #include "media/base/audio_bus.h" 33 #include "media/base/audio_bus.h"
29 #include "media/base/audio_converter.h" 34 #include "media/base/audio_converter.h"
30 #include "media/base/bind_to_current_loop.h" 35 #include "media/base/bind_to_current_loop.h"
31 #include "media/base/limits.h" 36 #include "media/base/limits.h"
32 #include "media/base/video_frame.h" 37 #include "media/base/video_frame.h"
33 #include "media/base/video_util.h" 38 #include "media/base/video_util.h"
34 #include "media/cast/cast_config.h" 39 #include "media/cast/cast_config.h"
35 #include "media/cast/cast_sender.h" 40 #include "media/cast/cast_sender.h"
36 #include "media/cast/net/cast_transport_config.h" 41 #include "media/cast/net/cast_transport_config.h"
37 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" 42 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
38 #include "ui/gfx/geometry/size.h" 43 #include "ui/gfx/geometry/size.h"
39 44
40 using media::cast::AudioSenderConfig; 45 using media::cast::AudioSenderConfig;
41 using media::cast::VideoSenderConfig; 46 using media::cast::VideoSenderConfig;
42 47
43 namespace { 48 namespace {
44 49
45 const char kCodecNameOpus[] = "OPUS"; 50 const char kCodecNameOpus[] = "OPUS";
46 const char kCodecNameVp8[] = "VP8"; 51 const char kCodecNameVp8[] = "VP8";
47 const char kCodecNameH264[] = "H264"; 52 const char kCodecNameH264[] = "H264";
48 53
49 // To convert from kilobits per second to bits to per second. 54 // To convert from kilobits per second to bits to per second.
50 const int kBitrateMultiplier = 1000; 55 const int kBitrateMultiplier = 1000;
51 56
57 // The maximum number of milliseconds that should elapse since the last video
58 // frame was received from the video source, before requesting refresh frames.
59 const int kRefreshIntervalMilliseconds = 250;
60
61 // The maximum number of refresh video frames to request/receive. After this
62 // limit (60 * 250ms = 15 seconds), refresh frame requests will stop being made.
63 const int kMaxConsecutiveRefreshFrames = 60;
64
52 CastRtpPayloadParams DefaultOpusPayload() { 65 CastRtpPayloadParams DefaultOpusPayload() {
53 CastRtpPayloadParams payload; 66 CastRtpPayloadParams payload;
54 payload.payload_type = media::cast::kDefaultRtpAudioPayloadType; 67 payload.payload_type = media::cast::kDefaultRtpAudioPayloadType;
55 payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs; 68 payload.max_latency_ms = media::cast::kDefaultRtpMaxDelayMs;
56 payload.ssrc = 1; 69 payload.ssrc = 1;
57 payload.feedback_ssrc = 2; 70 payload.feedback_ssrc = 2;
58 payload.clock_rate = media::cast::kDefaultAudioSamplingRate; 71 payload.clock_rate = media::cast::kDefaultAudioSamplingRate;
59 // The value is 0 which means VBR. 72 // The value is 0 which means VBR.
60 payload.min_bitrate = payload.max_bitrate = 73 payload.min_bitrate = payload.max_bitrate =
61 media::cast::kDefaultAudioEncoderBitrate; 74 media::cast::kDefaultAudioEncoderBitrate;
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 if (!config->use_external_encoder) 307 if (!config->use_external_encoder)
295 config->number_of_encode_threads = NumberOfEncodeThreads(); 308 config->number_of_encode_threads = NumberOfEncodeThreads();
296 config->aes_key = params.payload.aes_key; 309 config->aes_key = params.payload.aes_key;
297 config->aes_iv_mask = params.payload.aes_iv_mask; 310 config->aes_iv_mask = params.payload.aes_iv_mask;
298 return true; 311 return true;
299 } 312 }
300 313
301 } // namespace 314 } // namespace
302 315
303 // This class receives MediaStreamTrack events and video frames from a 316 // This class receives MediaStreamTrack events and video frames from a
304 // MediaStreamTrack. 317 // MediaStreamVideoTrack. It also includes a timer to request refresh frames
318 // when the capturer halts (e.g., a screen capturer stops delivering frames
319 // because the screen is not being updated). When a halt is detected, refresh
320 // frames will be requested at regular intervals for a short period of time.
321 // This provides the video encoder, downstream, several copies of the last frame
322 // so that it may clear up lossy encoding artifacts.
305 // 323 //
306 // Threading: Video frames are received on the IO thread and then 324 // Threading: Video frames are received on the IO thread and then
307 // forwarded to media::cast::VideoFrameInput through a static method. 325 // forwarded to media::cast::VideoFrameInput. The inner class, Deliverer,
308 // Member variables of this class are only accessed on the render thread. 326 // handles this. Otherwise, all methods and member variables of the outer class
327 // must only be accessed on the render thread.
309 class CastVideoSink : public base::SupportsWeakPtr<CastVideoSink>, 328 class CastVideoSink : public base::SupportsWeakPtr<CastVideoSink>,
310 public content::MediaStreamVideoSink { 329 public content::MediaStreamVideoSink {
311 public: 330 public:
312 // |track| provides data for this sink. 331 // |track| provides data for this sink.
313 // |error_callback| is called if video formats don't match. 332 // |error_callback| is called if video formats don't match.
314 CastVideoSink(const blink::WebMediaStreamTrack& track, 333 CastVideoSink(const blink::WebMediaStreamTrack& track,
315 const CastRtpStream::ErrorCallback& error_callback) 334 const CastRtpStream::ErrorCallback& error_callback)
316 : track_(track), 335 : track_(track), deliverer_(new Deliverer(error_callback)),
317 sink_added_(false), 336 consecutive_refresh_count_(0),
318 error_callback_(error_callback) {} 337 expecting_a_refresh_frame_(false) {}
319 338
320 ~CastVideoSink() override { 339 ~CastVideoSink() override {
321 if (sink_added_) 340 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 } 341 }
356 342
357 // Attach this sink to a video track represented by |track_|. 343 // Attach this sink to a video track represented by |track_|.
358 // Data received from the track will be submitted to |frame_input|. 344 // Data received from the track will be submitted to |frame_input|.
359 void AddToTrack( 345 void AddToTrack(
360 const scoped_refptr<media::cast::VideoFrameInput>& frame_input) { 346 const scoped_refptr<media::cast::VideoFrameInput>& frame_input) {
361 DCHECK(!sink_added_); 347 DCHECK(deliverer_);
362 sink_added_ = true; 348 deliverer_->WillConnectToTrack(AsWeakPtr(), frame_input);
363 AddToVideoTrack( 349 refresh_timer_.Start(
364 this, 350 FROM_HERE,
365 base::Bind( 351 base::TimeDelta::FromMilliseconds(kRefreshIntervalMilliseconds),
366 &CastVideoSink::OnVideoFrame, 352 base::Bind(&CastVideoSink::OnRefreshTimerFired,
367 error_callback_, 353 base::Unretained(this)));
368 frame_input), 354 MediaStreamVideoSink::ConnectToTrack(track_,
369 track_); 355 base::Bind(&Deliverer::OnVideoFrame,
356 deliverer_));
370 } 357 }
371 358
372 private: 359 private:
373 blink::WebMediaStreamTrack track_; 360 class Deliverer : public base::RefCountedThreadSafe<Deliverer> {
374 bool sink_added_; 361 public:
375 CastRtpStream::ErrorCallback error_callback_; 362 explicit Deliverer(const CastRtpStream::ErrorCallback& error_callback)
363 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
364 error_callback_(error_callback) {}
365
366 void WillConnectToTrack(
367 base::WeakPtr<CastVideoSink> sink,
368 scoped_refptr<media::cast::VideoFrameInput> frame_input) {
369 DCHECK(main_task_runner_->RunsTasksOnCurrentThread());
370 sink_ = sink;
371 frame_input_ = std::move(frame_input);
372 }
373
374 void OnVideoFrame(const scoped_refptr<media::VideoFrame>& video_frame,
375 base::TimeTicks estimated_capture_time) {
376 main_task_runner_->PostTask(
377 FROM_HERE, base::Bind(&CastVideoSink::DidReceiveFrame, sink_));
378
379 const base::TimeTicks timestamp = estimated_capture_time.is_null()
380 ? base::TimeTicks::Now()
381 : estimated_capture_time;
382
383 if (!(video_frame->format() == media::PIXEL_FORMAT_I420 ||
384 video_frame->format() == media::PIXEL_FORMAT_YV12 ||
385 video_frame->format() == media::PIXEL_FORMAT_YV12A)) {
386 error_callback_.Run("Incompatible video frame format.");
387 return;
388 }
389 scoped_refptr<media::VideoFrame> frame = video_frame;
390 // Drop alpha channel since we do not support it yet.
391 if (frame->format() == media::PIXEL_FORMAT_YV12A)
392 frame = media::WrapAsI420VideoFrame(video_frame);
393
394 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
395 TRACE_EVENT_INSTANT2(
396 "cast_perf_test", "MediaStreamVideoSink::OnVideoFrame",
397 TRACE_EVENT_SCOPE_THREAD,
398 "timestamp", timestamp.ToInternalValue(),
399 "time_delta", frame->timestamp().ToInternalValue());
400 frame_input_->InsertRawVideoFrame(frame, timestamp);
401 }
402
403 private:
404 friend class base::RefCountedThreadSafe<Deliverer>;
405 ~Deliverer() {}
406
407 const scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
408 const CastRtpStream::ErrorCallback error_callback_;
409
410 // These are set on the main thread after construction, and before the first
411 // call to OnVideoFrame() on the IO thread. |sink_| may be passed around on
412 // any thread, but must only be dereferenced on the main renderer thread.
413 base::WeakPtr<CastVideoSink> sink_;
414 scoped_refptr<media::cast::VideoFrameInput> frame_input_;
415
416 DISALLOW_COPY_AND_ASSIGN(Deliverer);
417 };
418
419 private:
420 void OnRefreshTimerFired() {
421 ++consecutive_refresh_count_;
422 if (consecutive_refresh_count_ >= kMaxConsecutiveRefreshFrames)
423 refresh_timer_.Stop(); // Stop timer until receiving a non-refresh frame.
424
425 DVLOG(1) << "CastVideoSink is requesting another refresh frame "
426 "(consecutive count=" << consecutive_refresh_count_ << ").";
427 expecting_a_refresh_frame_ = true;
428 content::RequestRefreshFrameFromVideoTrack(connected_track());
429 }
430
431 void DidReceiveFrame() {
432 if (expecting_a_refresh_frame_) {
433 // There is uncertainty as to whether the video frame was in response to a
434 // refresh request. However, if it was not, more video frames will soon
435 // follow, and before the refresh timer can fire again. Thus, the
436 // behavior resulting from this logic will be correct.
437 expecting_a_refresh_frame_ = false;
438 } else {
439 consecutive_refresh_count_ = 0;
440 // The following re-starts the timer, scheduling it to fire at
441 // kRefreshIntervalMilliseconds from now.
442 refresh_timer_.Reset();
443 }
444 }
445
446 const blink::WebMediaStreamTrack track_;
447 const scoped_refptr<Deliverer> deliverer_;
448
449 // Requests refresh frames at a constant rate while the source is paused, up
450 // to a consecutive maximum.
451 base::RepeatingTimer refresh_timer_;
452
453 // Counter for the number of consecutive "refresh frames" requested.
454 int consecutive_refresh_count_;
455
456 // Set to true when a request for a refresh frame has been made. This is
457 // cleared once the next frame is received.
458 bool expecting_a_refresh_frame_;
376 459
377 DISALLOW_COPY_AND_ASSIGN(CastVideoSink); 460 DISALLOW_COPY_AND_ASSIGN(CastVideoSink);
378 }; 461 };
379 462
380 // Receives audio data from a MediaStreamTrack. Data is submitted to 463 // Receives audio data from a MediaStreamTrack. Data is submitted to
381 // media::cast::FrameInput. 464 // media::cast::FrameInput.
382 // 465 //
383 // Threading: Audio frames are received on the real-time audio thread. 466 // Threading: Audio frames are received on the real-time audio thread.
384 // Note that RemoveFromAudioTrack() is synchronous and we have 467 // Note that RemoveFromAudioTrack() is synchronous and we have
385 // gurantee that there will be no more audio data after calling it. 468 // 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()); 731 DCHECK(content::RenderThread::Get());
649 DVLOG(1) << "CastRtpStream::DidEncounterError(" << message << ") = " 732 DVLOG(1) << "CastRtpStream::DidEncounterError(" << message << ") = "
650 << (IsAudio() ? "audio" : "video"); 733 << (IsAudio() ? "audio" : "video");
651 // Save the WeakPtr first because the error callback might delete this object. 734 // Save the WeakPtr first because the error callback might delete this object.
652 base::WeakPtr<CastRtpStream> ptr = weak_factory_.GetWeakPtr(); 735 base::WeakPtr<CastRtpStream> ptr = weak_factory_.GetWeakPtr();
653 error_callback_.Run(message); 736 error_callback_.Run(message);
654 base::ThreadTaskRunnerHandle::Get()->PostTask( 737 base::ThreadTaskRunnerHandle::Get()->PostTask(
655 FROM_HERE, 738 FROM_HERE,
656 base::Bind(&CastRtpStream::Stop, ptr)); 739 base::Bind(&CastRtpStream::Stop, ptr));
657 } 740 }
OLDNEW
« no previous file with comments | « no previous file | content/browser/renderer_host/media/video_capture_host.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698