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

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: Added 'TODO' to the DEPS file 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 }
39 } 114 }
40 115
41 void WiFiDisplayMediaManager::Teardown() { 116 void WiFiDisplayMediaManager::Teardown() {
42 NOTIMPLEMENTED(); 117 Pause();
118 if (player_) {
119 io_task_runner_->DeleteSoon(FROM_HERE, player_);
120 player_ = nullptr;
121 }
122 is_initialized_ = false;
123 session_id_.clear();
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 std::unique_ptr<base::SharedMemory> shm =
294 content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(size);
295 if (!shm || !shm->Map(size)) {
296 NOTREACHED() << "Shared memory allocation or map failed";
297 }
298 callback.Run(std::move(shm));
202 } 299 }
203 300
301 } // namespace
302
204 bool WiFiDisplayMediaManager::InitOptimalVideoFormat( 303 bool WiFiDisplayMediaManager::InitOptimalVideoFormat(
205 const wds::NativeVideoFormat& sink_native_format, 304 const wds::NativeVideoFormat& sink_native_format,
206 const std::vector<wds::H264VideoCodec>& sink_supported_codecs) { 305 const std::vector<wds::H264VideoCodec>& sink_supported_codecs) {
207 const media::VideoCaptureFormat* capture_format = 306 const media::VideoCaptureFormat* capture_format =
208 content::GetCurrentVideoTrackFormat(video_track_); 307 content::GetCurrentVideoTrackFormat(video_track_);
209 if (!capture_format) { 308 if (!capture_format) {
210 error_callback_.Run(kErrorNoVideoFormatData); 309 error_callback_.Run(kErrorNoVideoFormatData);
211 return false; 310 return false;
212 } 311 }
213 312
214 if (!FindOptimalFormat( 313 if (!FindOptimalFormat(
215 capture_format, sink_supported_codecs, &optimal_video_format_)) { 314 capture_format, sink_supported_codecs, &optimal_video_format_)) {
216 error_callback_.Run(kErrorSinkCannotPlayVideo); 315 error_callback_.Run(kErrorSinkCannotPlayVideo);
217 return false; 316 return false;
218 } 317 }
318 video_encoder_parameters_.frame_size = capture_format->frame_size;
319 video_encoder_parameters_.frame_rate =
320 static_cast<int>(capture_format->frame_rate);
321 video_encoder_parameters_.bit_rate = GetBitRate(capture_format->frame_size);
322 video_encoder_parameters_.profile = optimal_video_format_.profile;
323 video_encoder_parameters_.level = optimal_video_format_.level;
324 video_encoder_parameters_.create_memory_callback =
325 media::BindToCurrentLoop(base::Bind(&CreateVideoEncodeMemory));
326 video_encoder_parameters_.vea_create_callback =
327 media::BindToCurrentLoop(
328 base::Bind(&content::CreateVideoEncodeAccelerator));
219 329
220 return true; 330 return true;
221 } 331 }
222 332
223 bool WiFiDisplayMediaManager::InitOptimalAudioFormat( 333 bool WiFiDisplayMediaManager::InitOptimalAudioFormat(
224 const std::vector<wds::AudioCodec>& sink_codecs) { 334 const std::vector<wds::AudioCodec>& sink_codecs) {
225 for (const wds::AudioCodec& codec : sink_codecs) { 335 for (const wds::AudioCodec& codec : sink_codecs) {
226 // MediaStreamTrack contains LPCM audio. 336 // MediaStreamTrack contains LPCM audio.
227 if (codec.format == wds::LPCM) { 337 if (codec.format == wds::LPCM) {
228 optimal_audio_codec_ = codec; 338 optimal_audio_codec_ = codec;
229 // Picking a single mode. 339 // Picking a single mode.
230 wds::AudioModes optimal_mode; 340 wds::AudioModes optimal_mode;
231 if (codec.modes.test(wds::LPCM_44_1K_16B_2CH)) 341 if (codec.modes.test(wds::LPCM_44_1K_16B_2CH))
232 optimal_mode.set(wds::LPCM_44_1K_16B_2CH); 342 optimal_mode.set(wds::LPCM_44_1K_16B_2CH);
233 else 343 else
234 optimal_mode.set(wds::LPCM_48K_16B_2CH); 344 optimal_mode.set(wds::LPCM_48K_16B_2CH);
235 optimal_audio_codec_.modes = optimal_mode; 345 optimal_audio_codec_.modes = optimal_mode;
236 return true; 346 return true;
237 } 347 }
238 } 348 }
239 error_callback_.Run(kErrorSinkCannotPlayAudio); 349 error_callback_.Run(kErrorSinkCannotPlayAudio);
240 return false; 350 return false;
241 } 351 }
242 352
243 wds::AudioCodec WiFiDisplayMediaManager::GetOptimalAudioFormat() const { 353 wds::AudioCodec WiFiDisplayMediaManager::GetOptimalAudioFormat() const {
244 return optimal_audio_codec_; 354 return optimal_audio_codec_;
245 } 355 }
246 356
357 void WiFiDisplayMediaManager::SendIDRPicture() {
358 DCHECK(player_);
359 io_task_runner_->PostTask(FROM_HERE,
360 base::Bind(&WiFiDisplayMediaPipeline::RequestIDRPicture,
361 base::Unretained(player_)));
362 }
363
364 std::string WiFiDisplayMediaManager::GetSessionId() const {
365 if (session_id_.empty())
366 session_id_ = base::RandBytesAsString(8);
367 return session_id_;
368 }
369
370 void WiFiDisplayMediaManager::OnPlayerCreated(
371 std::unique_ptr<WiFiDisplayMediaPipeline> player) {
372 DCHECK(player);
373 DCHECK(content::RenderThread::Get());
374 player_ = player.release();
375
376 auto completion_callback = base::Bind(
377 &WiFiDisplayMediaManager::OnMediaPipelineInitialized,
378 weak_factory_.GetWeakPtr());
379
380 io_task_runner_->PostTask(FROM_HERE,
381 base::Bind(&WiFiDisplayMediaPipeline::Initialize,
382 base::Unretained(player_),
383 media::BindToCurrentLoop(completion_callback)));
384 }
385
386 void WiFiDisplayMediaManager::OnMediaPipelineInitialized(bool success) {
387 DCHECK(content::RenderThread::Get());
388 is_initialized_ = success;
389
390 if (!is_initialized_) {
391 error_callback_.Run(kErrorMediaPipelineFailure);
392 return;
393 }
394
395 if (is_playing_)
396 Play();
397 }
398
399
247 } // namespace extensions 400 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698