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

Side by Side Diff: remoting/protocol/webrtc_video_renderer_adapter.cc

Issue 2200273003: Enable video stats reporting when using WebRTC (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: TODO Created 4 years, 4 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "remoting/protocol/webrtc_video_renderer_adapter.h" 5 #include "remoting/protocol/webrtc_video_renderer_adapter.h"
6 6
7 #include <memory> 7 #include <memory>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/callback.h" 11 #include "base/callback.h"
12 #include "base/location.h" 12 #include "base/location.h"
13 #include "base/memory/ptr_util.h" 13 #include "base/memory/ptr_util.h"
14 #include "base/single_thread_task_runner.h" 14 #include "base/single_thread_task_runner.h"
15 #include "base/task_runner_util.h" 15 #include "base/task_runner_util.h"
16 #include "base/threading/thread_task_runner_handle.h" 16 #include "base/threading/thread_task_runner_handle.h"
17 #include "base/threading/worker_pool.h" 17 #include "base/threading/worker_pool.h"
18 #include "remoting/protocol/client_video_stats_dispatcher.h"
18 #include "remoting/protocol/frame_consumer.h" 19 #include "remoting/protocol/frame_consumer.h"
19 #include "remoting/protocol/frame_stats.h" 20 #include "remoting/protocol/frame_stats.h"
20 #include "remoting/protocol/video_renderer.h" 21 #include "remoting/protocol/video_renderer.h"
21 #include "third_party/libyuv/include/libyuv/convert_argb.h" 22 #include "remoting/protocol/webrtc_transport.h"
22 #include "third_party/libyuv/include/libyuv/convert_from.h" 23 #include "third_party/libyuv/include/libyuv/convert_from.h"
23 #include "third_party/libyuv/include/libyuv/video_common.h"
24 #include "third_party/webrtc/media/base/videoframe.h" 24 #include "third_party/webrtc/media/base/videoframe.h"
25 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" 25 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
26 26
27 namespace remoting { 27 namespace remoting {
28 namespace protocol { 28 namespace protocol {
29 29
30 namespace { 30 namespace {
31 31
32 std::unique_ptr<webrtc::DesktopFrame> ConvertYuvToRgb( 32 std::unique_ptr<webrtc::DesktopFrame> ConvertYuvToRgb(
33 scoped_refptr<webrtc::VideoFrameBuffer> yuv_frame, 33 scoped_refptr<webrtc::VideoFrameBuffer> yuv_frame,
(...skipping 11 matching lines...) Expand all
45 yuv_frame->width(), yuv_frame->height()); 45 yuv_frame->width(), yuv_frame->height());
46 46
47 rgb_frame->mutable_updated_region()->AddRect( 47 rgb_frame->mutable_updated_region()->AddRect(
48 webrtc::DesktopRect::MakeSize(rgb_frame->size())); 48 webrtc::DesktopRect::MakeSize(rgb_frame->size()));
49 return rgb_frame; 49 return rgb_frame;
50 } 50 }
51 51
52 } // namespace 52 } // namespace
53 53
54 WebrtcVideoRendererAdapter::WebrtcVideoRendererAdapter( 54 WebrtcVideoRendererAdapter::WebrtcVideoRendererAdapter(
55 scoped_refptr<webrtc::MediaStreamInterface> media_stream, 55 const std::string& label,
56 VideoRenderer* video_renderer) 56 VideoRenderer* video_renderer)
57 : media_stream_(std::move(media_stream)), 57 : label_(label),
58 video_renderer_(video_renderer), 58 video_renderer_(video_renderer),
59 task_runner_(base::ThreadTaskRunnerHandle::Get()), 59 task_runner_(base::ThreadTaskRunnerHandle::Get()),
60 weak_factory_(this) { 60 weak_factory_(this) {}
61
62 WebrtcVideoRendererAdapter::~WebrtcVideoRendererAdapter() {
63 DCHECK(task_runner_->BelongsToCurrentThread());
64
65 webrtc::VideoTrackVector video_tracks = media_stream_->GetVideoTracks();
66 DCHECK(!video_tracks.empty());
67 video_tracks[0]->RemoveSink(this);
68 }
69
70 void WebrtcVideoRendererAdapter::SetMediaStream(
71 scoped_refptr<webrtc::MediaStreamInterface> media_stream) {
72 DCHECK_EQ(media_stream->label(), label());
73
74 media_stream_ = std::move(media_stream);
Irfan 2016/08/09 17:00:37 std::move on scoped_refptr is unclear to me. What
Sergey Ulanov 2016/08/10 18:07:44 It generates slightly more optimal code compared t
75
61 webrtc::VideoTrackVector video_tracks = media_stream_->GetVideoTracks(); 76 webrtc::VideoTrackVector video_tracks = media_stream_->GetVideoTracks();
62 if (video_tracks.empty()) { 77 if (video_tracks.empty()) {
63 LOG(ERROR) << "Received media stream with no video tracks."; 78 LOG(ERROR) << "Received media stream with no video tracks.";
64 return; 79 return;
65 } 80 }
66 81
67 if (video_tracks.size() > 1U) { 82 if (video_tracks.size() > 1U) {
68 LOG(WARNING) << "Received media stream with multiple video tracks."; 83 LOG(WARNING) << "Received media stream with multiple video tracks.";
69 } 84 }
70 85
71 video_tracks[0]->AddOrUpdateSink(this, rtc::VideoSinkWants()); 86 video_tracks[0]->AddOrUpdateSink(this, rtc::VideoSinkWants());
72 } 87 }
73 88
74 WebrtcVideoRendererAdapter::~WebrtcVideoRendererAdapter() { 89 void WebrtcVideoRendererAdapter::SetVideoStatsChannel(
75 DCHECK(task_runner_->BelongsToCurrentThread()); 90 std::unique_ptr<MessagePipe> message_pipe) {
76 91 // Expect that the host also creates video_stats data channel.
77 webrtc::VideoTrackVector video_tracks = media_stream_->GetVideoTracks(); 92 video_stats_dispatcher_.reset(new ClientVideoStatsDispatcher(label_, this));
78 DCHECK(!video_tracks.empty()); 93 video_stats_dispatcher_->Init(std::move(message_pipe), this);
79 video_tracks[0]->RemoveSink(this);
80 } 94 }
81 95
82 void WebrtcVideoRendererAdapter::OnFrame(const cricket::VideoFrame& frame) { 96 void WebrtcVideoRendererAdapter::OnFrame(const cricket::VideoFrame& frame) {
83 if (static_cast<uint64_t>(frame.timestamp_us()) >= rtc::TimeMicros()) { 97 if (static_cast<uint64_t>(frame.timestamp_us()) >= rtc::TimeMicros()) {
84 // The host sets playout delay to 0, so all incoming frames are expected to 98 // The host sets playout delay to 0, so all incoming frames are expected to
85 // be rendered as so as they are received. 99 // be rendered as so as they are received.
86 LOG(WARNING) << "Received frame with playout delay greater than 0."; 100 LOG(WARNING) << "Received frame with playout delay greater than 0.";
87 } 101 }
88 102
103 task_runner_->PostTask(
104 FROM_HERE,
105 base::Bind(&WebrtcVideoRendererAdapter::HandleFrameOnMainThread,
106 weak_factory_.GetWeakPtr(), frame.transport_frame_id(),
107 base::TimeTicks::Now(),
108 scoped_refptr<webrtc::VideoFrameBuffer>(
109 frame.video_frame_buffer().get())));
110 }
111
112 void WebrtcVideoRendererAdapter::OnVideoFrameStats(
Irfan 2016/08/09 17:00:37 It is not entirely clear how the logic here in OnV
Sergey Ulanov 2016/08/10 18:07:44 Added some comments to make the logic here easier
113 uint32_t frame_id,
114 const HostFrameStats& host_stats) {
115 DCHECK(task_runner_->BelongsToCurrentThread());
116
117 while (!client_stats_queue_.empty() &&
118 client_stats_queue_.front().first != frame_id) {
119 client_stats_queue_.pop_front();
120 }
121
122 if (client_stats_queue_.empty()) {
123 host_stats_queue_.push_back(std::make_pair(frame_id, host_stats));
124 return;
125 }
126
127 // The correspond frame has been received. Report stats for it.
128 FrameStats frame_stats;
129 frame_stats.client_stats = client_stats_queue_.front().second;
130 frame_stats.host_stats = host_stats;
131 client_stats_queue_.pop_front();
132 video_renderer_->GetFrameStatsConsumer()->OnVideoFrameStats(frame_stats);
133 }
134
135 void WebrtcVideoRendererAdapter::OnChannelInitialized(
136 ChannelDispatcherBase* channel_dispatcher) {}
137 void WebrtcVideoRendererAdapter::OnChannelClosed(
138 ChannelDispatcherBase* channel_dispatcher) {}
139
140 void WebrtcVideoRendererAdapter::HandleFrameOnMainThread(
141 uint32_t frame_id,
142 base::TimeTicks time_received,
143 scoped_refptr<webrtc::VideoFrameBuffer> frame) {
144 DCHECK(task_runner_->BelongsToCurrentThread());
145
89 std::unique_ptr<ClientFrameStats> stats(new ClientFrameStats()); 146 std::unique_ptr<ClientFrameStats> stats(new ClientFrameStats());
90 // TODO(sergeyu): |time_received| is not reported correctly here because the 147 // TODO(sergeyu): |time_received| is not reported correctly here because the
91 // frame is already decoded at this point. 148 // frame is already decoded at this point.
92 stats->time_received = base::TimeTicks::Now(); 149 stats->time_received = time_received;
93
94 task_runner_->PostTask(
95 FROM_HERE,
96 base::Bind(&WebrtcVideoRendererAdapter::HandleFrameOnMainThread,
97 weak_factory_.GetWeakPtr(), base::Passed(&stats),
98 scoped_refptr<webrtc::VideoFrameBuffer>(
99 frame.video_frame_buffer().get())));
100 }
101
102 void WebrtcVideoRendererAdapter::HandleFrameOnMainThread(
103 std::unique_ptr<ClientFrameStats> stats,
104 scoped_refptr<webrtc::VideoFrameBuffer> frame) {
105 DCHECK(task_runner_->BelongsToCurrentThread());
106 150
107 std::unique_ptr<webrtc::DesktopFrame> rgb_frame = 151 std::unique_ptr<webrtc::DesktopFrame> rgb_frame =
108 video_renderer_->GetFrameConsumer()->AllocateFrame( 152 video_renderer_->GetFrameConsumer()->AllocateFrame(
109 webrtc::DesktopSize(frame->width(), frame->height())); 153 webrtc::DesktopSize(frame->width(), frame->height()));
110 154
111 base::PostTaskAndReplyWithResult( 155 base::PostTaskAndReplyWithResult(
112 base::WorkerPool::GetTaskRunner(false).get(), FROM_HERE, 156 base::WorkerPool::GetTaskRunner(false).get(), FROM_HERE,
113 base::Bind(&ConvertYuvToRgb, base::Passed(&frame), 157 base::Bind(&ConvertYuvToRgb, base::Passed(&frame),
114 base::Passed(&rgb_frame), 158 base::Passed(&rgb_frame),
115 video_renderer_->GetFrameConsumer()->GetPixelFormat()), 159 video_renderer_->GetFrameConsumer()->GetPixelFormat()),
116 base::Bind(&WebrtcVideoRendererAdapter::DrawFrame, 160 base::Bind(&WebrtcVideoRendererAdapter::DrawFrame,
117 weak_factory_.GetWeakPtr(), base::Passed(&stats))); 161 weak_factory_.GetWeakPtr(), frame_id, base::Passed(&stats)));
118 } 162 }
119 163
120 void WebrtcVideoRendererAdapter::DrawFrame( 164 void WebrtcVideoRendererAdapter::DrawFrame(
165 uint32_t frame_id,
121 std::unique_ptr<ClientFrameStats> stats, 166 std::unique_ptr<ClientFrameStats> stats,
122 std::unique_ptr<webrtc::DesktopFrame> frame) { 167 std::unique_ptr<webrtc::DesktopFrame> frame) {
123 DCHECK(task_runner_->BelongsToCurrentThread()); 168 DCHECK(task_runner_->BelongsToCurrentThread());
124 stats->time_decoded = base::TimeTicks::Now(); 169 stats->time_decoded = base::TimeTicks::Now();
125 video_renderer_->GetFrameConsumer()->DrawFrame( 170 video_renderer_->GetFrameConsumer()->DrawFrame(
126 std::move(frame), 171 std::move(frame),
127 base::Bind(&WebrtcVideoRendererAdapter::FrameRendered, 172 base::Bind(&WebrtcVideoRendererAdapter::FrameRendered,
128 weak_factory_.GetWeakPtr(), base::Passed(&stats))); 173 weak_factory_.GetWeakPtr(), frame_id, base::Passed(&stats)));
129 } 174 }
130 175
131 void WebrtcVideoRendererAdapter::FrameRendered( 176 void WebrtcVideoRendererAdapter::FrameRendered(
132 std::unique_ptr<ClientFrameStats> stats) { 177 uint32_t frame_id,
133 // TODO(sergeyu): Report stats here 178 std::unique_ptr<ClientFrameStats> client_stats) {
179 DCHECK(task_runner_->BelongsToCurrentThread());
180
181 client_stats->time_rendered = base::TimeTicks::Now();
182
183 while (!host_stats_queue_.empty() &&
184 host_stats_queue_.front().first != frame_id) {
185 host_stats_queue_.pop_front();
186 }
187
188 if (host_stats_queue_.empty()) {
189 // Keep the stats object when the video_stats channel is connected.
190 if (video_stats_dispatcher_ && video_stats_dispatcher_->is_connected())
191 client_stats_queue_.push_back(std::make_pair(frame_id, *client_stats));
192 return;
193 }
194
195 // We have HostFrameStats for the frame, so we can report stats for it.
196 FrameStats frame_stats;
197 frame_stats.host_stats = host_stats_queue_.front().second;
198 frame_stats.client_stats = *client_stats;
199 host_stats_queue_.pop_front();
200 video_renderer_->GetFrameStatsConsumer()->OnVideoFrameStats(frame_stats);
134 } 201 }
135 202
136 } // namespace protocol 203 } // namespace protocol
137 } // namespace remoting 204 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698