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

Side by Side Diff: extensions/renderer/api/display_source/wifi_display/wifi_display_media_manager.cc

Issue 1860083002: [chrome.displaySource][WiFi Display] Media pipeline infrastructure (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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 "extensions/renderer/api/display_source/wifi_display/wifi_display_media _manager.h" 5 #include "extensions/renderer/api/display_source/wifi_display/wifi_display_media _manager.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/rand_util.h" 8 #include "base/rand_util.h"
9 #include "base/task_runner_util.h"
9 #include "content/public/renderer/media_stream_utils.h" 10 #include "content/public/renderer/media_stream_utils.h"
11 #include "content/public/renderer/media_stream_video_sink.h"
12 #include "content/public/renderer/render_thread.h"
13 #include "content/public/renderer/video_encode_accelerator.h"
14 #include "extensions/common/mojo/wifi_display_session_service.mojom.h"
15 #include "extensions/renderer/api/display_source/wifi_display/wifi_display_eleme ntary_stream_info.h"
16 #include "extensions/renderer/api/display_source/wifi_display/wifi_display_media _pipeline.h"
17 #include "media/base/bind_to_current_loop.h"
10 18
11 namespace extensions { 19 namespace extensions {
12 20
13 namespace { 21 namespace {
14 22
15 const char kErrorNoVideoFormatData[] = 23 const char kErrorNoVideoFormatData[] =
16 "Failed to get video format data from the given MediaStreamTrack object"; 24 "Failed to get video format data from the given MediaStreamTrack object";
17 const char kErrorSinkCannotPlayVideo[] = 25 const char kErrorSinkCannotPlayVideo[] =
18 "The sink cannot play video from the given MediaStreamTrack object"; 26 "The sink cannot play video from the given MediaStreamTrack object";
19 const char kErrorSinkCannotPlayAudio[] = 27 const char kErrorSinkCannotPlayAudio[] =
20 "The sink cannot play audio from the given MediaStreamTrack object"; 28 "The sink cannot play audio from the given MediaStreamTrack object";
29 const char kErrorMediaPipelineFailure[] =
30 "Failed to initialize media pipeline for the session";
21 } // namespace 31 } // namespace
22 32
33 class WiFiDisplayVideoSink : public content::MediaStreamVideoSink {
34 public:
35 WiFiDisplayVideoSink(
36 const blink::WebMediaStreamTrack& track,
37 const content::VideoCaptureDeliverFrameCB& callback)
38 : track_(track),
39 sink_added_(false),
40 callback_(callback) {
41 }
42
43 ~WiFiDisplayVideoSink() override {
44 Stop();
45 }
46
47 void Start() {
48 DCHECK(!sink_added_);
49 sink_added_ = true;
50 // Callback is invoked on IO thread.
51 AddToVideoTrack(this, callback_, track_);
52 }
53
54 void Stop() {
55 if (sink_added_)
56 RemoveFromVideoTrack(this, track_);
57 }
58
59 private:
60 blink::WebMediaStreamTrack track_;
61 bool sink_added_;
62 content::VideoCaptureDeliverFrameCB callback_;
63 DISALLOW_COPY_AND_ASSIGN(WiFiDisplayVideoSink);
64 };
65
23 WiFiDisplayMediaManager::WiFiDisplayMediaManager( 66 WiFiDisplayMediaManager::WiFiDisplayMediaManager(
24 const blink::WebMediaStreamTrack& video_track, 67 const blink::WebMediaStreamTrack& video_track,
25 const blink::WebMediaStreamTrack& audio_track, 68 const blink::WebMediaStreamTrack& audio_track,
26 const ErrorCallback& error_callback) 69 const ErrorCallback& error_callback)
27 : video_track_(video_track), 70 : video_track_(video_track),
28 audio_track_(audio_track), 71 audio_track_(audio_track),
29 error_callback_(error_callback) { 72 player_(nullptr),
73 io_task_runner_(content::RenderThread::Get()->GetIOMessageLoopProxy()),
74 error_callback_(error_callback),
75 is_playing_(false),
76 is_initialized_(false),
77 weak_factory_(this) {
30 DCHECK(!video_track.isNull() || !audio_track.isNull()); 78 DCHECK(!video_track.isNull() || !audio_track.isNull());
31 DCHECK(!error_callback_.is_null()); 79 DCHECK(!error_callback_.is_null());
32 } 80 }
33 81
34 WiFiDisplayMediaManager::~WiFiDisplayMediaManager() { 82 WiFiDisplayMediaManager::~WiFiDisplayMediaManager() {
83 Teardown();
35 } 84 }
36 85
37 void WiFiDisplayMediaManager::Play() { 86 void WiFiDisplayMediaManager::Play() {
38 NOTIMPLEMENTED(); 87 is_playing_ = true;
88 if (!player_) {
89 base::PostTaskAndReplyWithResult(io_task_runner_.get(), FROM_HERE,
90 base::Bind(
91 &WiFiDisplayMediaPipeline::Create,
92 GetSessionType(),
93 video_encoder_parameters_,
94 optimal_audio_codec_,
95 media::BindToCurrentLoop(error_callback_)),
96 base::Bind(&WiFiDisplayMediaManager::OnPlayerCreated,
97 weak_factory_.GetWeakPtr()));
98 return;
99 }
100
101 if (!is_initialized_) {
102 return; // Waiting for initialization being completed.
103 }
104
105 if (!video_track_.isNull()) {
106 // To be called on IO thread.
107 auto on_raw_video_frame = base::Bind(
108 &WiFiDisplayMediaPipeline::InsertRawVideoFrame,
109 base::Unretained(player_));
110 video_sink_.reset(
111 new WiFiDisplayVideoSink(video_track_, on_raw_video_frame));
112 video_sink_->Start();
113 LOG(ERROR) << "video sink started";
114 }
39 } 115 }
40 116
41 void WiFiDisplayMediaManager::Teardown() { 117 void WiFiDisplayMediaManager::Teardown() {
42 NOTIMPLEMENTED(); 118 Pause();
119 if (player_) {
120 io_task_runner_->DeleteSoon(FROM_HERE, player_);
121 player_ = nullptr;
122 }
123 is_initialized_ = false;
43 } 124 }
44 125
45 void WiFiDisplayMediaManager::Pause() { 126 void WiFiDisplayMediaManager::Pause() {
46 NOTIMPLEMENTED(); 127 is_playing_ = false;
128 video_sink_.reset();
47 } 129 }
48 130
49 bool WiFiDisplayMediaManager::IsPaused() const { 131 bool WiFiDisplayMediaManager::IsPaused() const {
50 NOTIMPLEMENTED(); 132 return !is_playing_;
51 return true;
52 } 133 }
53 134
54 wds::SessionType WiFiDisplayMediaManager::GetSessionType() const { 135 wds::SessionType WiFiDisplayMediaManager::GetSessionType() const {
55 uint16_t session_type = 0; 136 uint16_t session_type = 0;
56 if (!video_track_.isNull()) 137 if (!video_track_.isNull())
57 session_type |= wds::VideoSession; 138 session_type |= wds::VideoSession;
58 139
59 if (!audio_track_.isNull()) 140 if (!audio_track_.isNull())
60 session_type |= wds::AudioSession; 141 session_type |= wds::AudioSession;
61 142
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 } 267 }
187 return false; 268 return false;
188 } 269 }
189 270
190 } // namespace 271 } // namespace
191 272
192 wds::H264VideoFormat WiFiDisplayMediaManager::GetOptimalVideoFormat() const { 273 wds::H264VideoFormat WiFiDisplayMediaManager::GetOptimalVideoFormat() const {
193 return optimal_video_format_; 274 return optimal_video_format_;
194 } 275 }
195 276
196 void WiFiDisplayMediaManager::SendIDRPicture() { 277 namespace {
197 NOTIMPLEMENTED(); 278
279 int GetBitRate(const gfx::Size& frame_size) {
280 DCHECK_GE(frame_size.height(), 360);
281 if (frame_size.height() < 720)
282 return 2500000;
283 if (frame_size.height() < 1080)
284 return 5000000;
285 return 8000000;
198 } 286 }
199 287
200 std::string WiFiDisplayMediaManager::GetSessionId() const { 288 void CreateVideoEncodeMemory(
201 return base::RandBytesAsString(8); 289 size_t size,
290 const WiFiDisplayVideoEncoder::ReceiveEncodeMemoryCallback& callback) {
291 DCHECK(content::RenderThread::Get());
292
293 scoped_ptr<base::SharedMemory> shm =
294 content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(size);
295 DCHECK(shm) << "Failed to allocate shared memory";
296 if (!shm->Map(size)) {
297 NOTREACHED() << "Map failed";
298 }
299 callback.Run(std::move(shm));
202 } 300 }
203 301
302 } // namespace
303
204 bool WiFiDisplayMediaManager::InitOptimalVideoFormat( 304 bool WiFiDisplayMediaManager::InitOptimalVideoFormat(
205 const wds::NativeVideoFormat& sink_native_format, 305 const wds::NativeVideoFormat& sink_native_format,
206 const std::vector<wds::H264VideoCodec>& sink_supported_codecs) { 306 const std::vector<wds::H264VideoCodec>& sink_supported_codecs) {
207 const media::VideoCaptureFormat* capture_format = 307 const media::VideoCaptureFormat* capture_format =
208 content::GetCurrentVideoTrackFormat(video_track_); 308 content::GetCurrentVideoTrackFormat(video_track_);
209 if (!capture_format) { 309 if (!capture_format) {
210 error_callback_.Run(kErrorNoVideoFormatData); 310 error_callback_.Run(kErrorNoVideoFormatData);
211 return false; 311 return false;
212 } 312 }
213 313
214 if (!FindOptimalFormat( 314 if (!FindOptimalFormat(
215 capture_format, sink_supported_codecs, &optimal_video_format_)) { 315 capture_format, sink_supported_codecs, &optimal_video_format_)) {
216 error_callback_.Run(kErrorSinkCannotPlayVideo); 316 error_callback_.Run(kErrorSinkCannotPlayVideo);
217 return false; 317 return false;
218 } 318 }
319 video_encoder_parameters_.frame_size = capture_format->frame_size;
320 video_encoder_parameters_.frame_rate =
321 static_cast<int>(capture_format->frame_rate);
322 video_encoder_parameters_.bit_rate = GetBitRate(capture_format->frame_size);
323 video_encoder_parameters_.profile = optimal_video_format_.profile;
324 video_encoder_parameters_.level = optimal_video_format_.level;
325 video_encoder_parameters_.create_memory_callback =
326 media::BindToCurrentLoop(base::Bind(&CreateVideoEncodeMemory));
327 video_encoder_parameters_.vea_create_callback =
328 media::BindToCurrentLoop(
329 base::Bind(&content::CreateVideoEncodeAccelerator));
219 330
220 return true; 331 return true;
221 } 332 }
222 333
223 bool WiFiDisplayMediaManager::InitOptimalAudioFormat( 334 bool WiFiDisplayMediaManager::InitOptimalAudioFormat(
224 const std::vector<wds::AudioCodec>& sink_codecs) { 335 const std::vector<wds::AudioCodec>& sink_codecs) {
225 for (const wds::AudioCodec& codec : sink_codecs) { 336 for (const wds::AudioCodec& codec : sink_codecs) {
226 // MediaStreamTrack contains LPCM audio. 337 // MediaStreamTrack contains LPCM audio.
227 if (codec.format == wds::LPCM) { 338 if (codec.format == wds::LPCM) {
228 optimal_audio_codec_ = codec; 339 optimal_audio_codec_ = codec;
229 // Picking a single mode. 340 // Picking a single mode.
230 wds::AudioModes optimal_mode; 341 wds::AudioModes optimal_mode;
231 if (codec.modes.test(wds::LPCM_44_1K_16B_2CH)) 342 if (codec.modes.test(wds::LPCM_44_1K_16B_2CH))
232 optimal_mode.set(wds::LPCM_44_1K_16B_2CH); 343 optimal_mode.set(wds::LPCM_44_1K_16B_2CH);
233 else 344 else
234 optimal_mode.set(wds::LPCM_48K_16B_2CH); 345 optimal_mode.set(wds::LPCM_48K_16B_2CH);
235 optimal_audio_codec_.modes = optimal_mode; 346 optimal_audio_codec_.modes = optimal_mode;
236 return true; 347 return true;
237 } 348 }
238 } 349 }
239 error_callback_.Run(kErrorSinkCannotPlayAudio); 350 error_callback_.Run(kErrorSinkCannotPlayAudio);
240 return false; 351 return false;
241 } 352 }
242 353
243 wds::AudioCodec WiFiDisplayMediaManager::GetOptimalAudioFormat() const { 354 wds::AudioCodec WiFiDisplayMediaManager::GetOptimalAudioFormat() const {
244 return optimal_audio_codec_; 355 return optimal_audio_codec_;
245 } 356 }
246 357
358 void WiFiDisplayMediaManager::SendIDRPicture() {
359 DCHECK(player_);
360 io_task_runner_->PostTask(FROM_HERE,
361 base::Bind(&WiFiDisplayMediaPipeline::RequestIDRPicture,
362 base::Unretained(player_)));
363 }
364
365 std::string WiFiDisplayMediaManager::GetSessionId() const {
366 return base::RandBytesAsString(8);
shalamov 2016/04/06 07:48:48 I think session id should be unique during the ses
Mikhail 2016/04/06 09:40:59 Fixed, ptal
367 }
368
369 void WiFiDisplayMediaManager::OnPlayerCreated(
370 scoped_ptr<WiFiDisplayMediaPipeline> player) {
371 DCHECK(player);
372 DCHECK(content::RenderThread::Get());
373 player_ = player.release();
374
375 auto completion_callback = base::Bind(
376 &WiFiDisplayMediaManager::OnMediaPipelineInitialized,
377 weak_factory_.GetWeakPtr());
378
379 io_task_runner_->PostTask(FROM_HERE,
380 base::Bind(&WiFiDisplayMediaPipeline::Initialize,
381 base::Unretained(player_),
382 media::BindToCurrentLoop(completion_callback)));
383 }
384
385 void WiFiDisplayMediaManager::OnMediaPipelineInitialized(bool success) {
386 DCHECK(content::RenderThread::Get());
387 is_initialized_ = success;
388
389 if (!is_initialized_) {
390 error_callback_.Run(kErrorMediaPipelineFailure);
391 return;
392 }
393
394 if (is_playing_)
395 Play();
396 }
397
398
247 } // namespace extensions 399 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698