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

Side by Side Diff: services/media/factory_service/media_player_impl.cc

Issue 2006093004: Motown: Convert MediaSink to expose MediaTimelineControlSite (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 4 years, 6 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 "base/logging.h" 5 #include "base/logging.h"
6 #include "mojo/public/cpp/application/connect.h" 6 #include "mojo/public/cpp/application/connect.h"
7 #include "mojo/services/media/common/cpp/timeline.h"
7 #include "services/media/factory_service/media_player_impl.h" 8 #include "services/media/factory_service/media_player_impl.h"
8 #include "services/media/framework/parts/reader.h" 9 #include "services/media/framework/parts/reader.h"
9 #include "services/media/framework/util/callback_joiner.h" 10 #include "services/media/framework/util/callback_joiner.h"
10 11
11 namespace mojo { 12 namespace mojo {
12 namespace media { 13 namespace media {
13 14
14 // static 15 // static
15 std::shared_ptr<MediaPlayerImpl> MediaPlayerImpl::Create( 16 std::shared_ptr<MediaPlayerImpl> MediaPlayerImpl::Create(
16 InterfaceHandle<SeekingReader> reader, 17 InterfaceHandle<SeekingReader> reader,
17 InterfaceRequest<MediaPlayer> request, 18 InterfaceRequest<MediaPlayer> request,
18 MediaFactoryService* owner) { 19 MediaFactoryService* owner) {
19 return std::shared_ptr<MediaPlayerImpl>( 20 return std::shared_ptr<MediaPlayerImpl>(
20 new MediaPlayerImpl(reader.Pass(), request.Pass(), owner)); 21 new MediaPlayerImpl(reader.Pass(), request.Pass(), owner));
21 } 22 }
22 23
23 MediaPlayerImpl::MediaPlayerImpl(InterfaceHandle<SeekingReader> reader, 24 MediaPlayerImpl::MediaPlayerImpl(InterfaceHandle<SeekingReader> reader,
24 InterfaceRequest<MediaPlayer> request, 25 InterfaceRequest<MediaPlayer> request,
25 MediaFactoryService* owner) 26 MediaFactoryService* owner)
26 : MediaFactoryService::Product<MediaPlayer>(this, request.Pass(), owner) { 27 : MediaFactoryService::Product<MediaPlayer>(this, request.Pass(), owner) {
27 DCHECK(reader); 28 DCHECK(reader);
28 29
29 status_publisher_.SetCallbackRunner( 30 status_publisher_.SetCallbackRunner([this](const GetStatusCallback& callback,
30 [this](const GetStatusCallback& callback, uint64_t version) { 31 uint64_t version) {
31 MediaPlayerStatusPtr status = MediaPlayerStatus::New(); 32 MediaPlayerStatusPtr status = MediaPlayerStatus::New();
32 status->state = reported_media_state_; 33 status->timeline_transform = TimelineTransform::From(timeline_function_);
33 status->timeline_transform = transform_.Clone(); 34 status->end_of_stream = AllSinksAtEndOfStream();
34 status->metadata = metadata_.Clone(); 35 status->metadata = metadata_.Clone();
35 callback.Run(version, status.Pass()); 36 callback.Run(version, status.Pass());
36 }); 37 });
37 38
38 state_ = State::kWaiting; 39 state_ = State::kWaiting;
39 40
40 ConnectToService(app()->shell(), "mojo:media_factory", GetProxy(&factory_)); 41 ConnectToService(app()->shell(), "mojo:media_factory", GetProxy(&factory_));
41 42
42 factory_->CreateDemux(reader.Pass(), GetProxy(&demux_)); 43 factory_->CreateDemux(reader.Pass(), GetProxy(&demux_));
43 44
44 HandleDemuxMetadataUpdates(); 45 HandleDemuxMetadataUpdates();
45 46
46 demux_->Describe([this](mojo::Array<MediaTypePtr> stream_types) { 47 demux_->Describe([this](mojo::Array<MediaTypePtr> stream_types) {
(...skipping 17 matching lines...) Expand all
64 break; 65 break;
65 // TODO(dalesat): Enable other stream types. 66 // TODO(dalesat): Enable other stream types.
66 default: 67 default:
67 break; 68 break;
68 } 69 }
69 } 70 }
70 71
71 callback_joiner->WhenJoined([this]() { 72 callback_joiner->WhenJoined([this]() {
72 // The enabled streams are prepared. 73 // The enabled streams are prepared.
73 factory_.reset(); 74 factory_.reset();
74 SetReportedMediaState(MediaState::PAUSED);
75 state_ = State::kPaused; 75 state_ = State::kPaused;
76 Update(); 76 Update();
77 }); 77 });
78 }); 78 });
79 } 79 }
80 80
81 MediaPlayerImpl::~MediaPlayerImpl() {} 81 MediaPlayerImpl::~MediaPlayerImpl() {}
82 82
83 void MediaPlayerImpl::Update() { 83 void MediaPlayerImpl::Update() {
84 while (true) { 84 while (true) {
85 switch (state_) { 85 switch (state_) {
86 case State::kPaused: 86 case State::kPaused:
87 if (target_position_ != kNotSeeking) { 87 if (target_position_ != kUnspecifiedTime) {
88 WhenPausedAndSeeking(); 88 WhenPausedAndSeeking();
89 break; 89 break;
90 } 90 }
91 91
92 if (target_state_ == MediaState::PLAYING) { 92 if (target_state_ == State::kPlaying) {
93 if (!flushed_) { 93 if (!flushed_) {
94 ChangeSinkStates(MediaState::PLAYING); 94 SetSinkTimelineTransforms(1, 1);
95 state_ = State::kWaitingForSinksToPlay; 95 state_ = State::kWaiting;
96 break; 96 break;
97 } 97 }
98 98
99 flushed_ = false; 99 flushed_ = false;
100 state_ = State::kWaiting; 100 state_ = State::kWaiting;
101 demux_->Prime([this]() { 101 demux_->Prime([this]() {
102 ChangeSinkStates(MediaState::PLAYING); 102 SetSinkTimelineTransforms(1, 1);
103 state_ = State::kWaitingForSinksToPlay; 103 state_ = State::kWaiting;
104 Update(); 104 Update();
105 }); 105 });
106 } 106 }
107 return; 107 return;
108 108
109 case State::kWaitingForSinksToPlay:
110 if (AllSinksAre(SinkState::kPlayingOrEnded)) {
111 state_ = State::kPlaying;
112 if (target_state_ == MediaState::PLAYING) {
113 SetReportedMediaState(MediaState::PLAYING);
114 }
115 }
116 return;
117
118 case State::kPlaying: 109 case State::kPlaying:
119 if (target_position_ != kNotSeeking || 110 if (target_position_ != kUnspecifiedTime ||
120 target_state_ == MediaState::PAUSED) { 111 target_state_ == State::kPaused) {
121 ChangeSinkStates(MediaState::PAUSED); 112 SetSinkTimelineTransforms(1, 0);
122 state_ = State::kWaitingForSinksToPause; 113 state_ = State::kWaiting;
123 break; 114 break;
124 } 115 }
125 116
126 if (AllSinksAre(SinkState::kEnded)) { 117 if (AllSinksAtEndOfStream()) {
127 target_state_ = MediaState::ENDED; 118 target_state_ = State::kPaused;
128 SetReportedMediaState(MediaState::ENDED);
129 state_ = State::kPaused; 119 state_ = State::kPaused;
130 break; 120 break;
131 } 121 }
132 return;
133
134 case State::kWaitingForSinksToPause:
135 if (AllSinksAre(SinkState::kPausedOrEnded)) {
136 if (target_state_ == MediaState::PAUSED) {
137 if (AllSinksAre(SinkState::kEnded)) {
138 SetReportedMediaState(MediaState::ENDED);
139 } else {
140 SetReportedMediaState(MediaState::PAUSED);
141 }
142 }
143
144 state_ = State::kPaused;
145 break;
146 }
147 return; 122 return;
148 123
149 case State::kWaiting: 124 case State::kWaiting:
150 return; 125 return;
151 } 126 }
152 } 127 }
153 } 128 }
154 129
155 void MediaPlayerImpl::WhenPausedAndSeeking() { 130 void MediaPlayerImpl::WhenPausedAndSeeking() {
156 if (!flushed_) { 131 if (!flushed_) {
157 state_ = State::kWaiting; 132 state_ = State::kWaiting;
158 demux_->Flush([this]() { 133 demux_->Flush([this]() {
159 flushed_ = true; 134 flushed_ = true;
160 WhenFlushedAndSeeking(); 135 WhenFlushedAndSeeking();
161 }); 136 });
162 } else { 137 } else {
163 WhenFlushedAndSeeking(); 138 WhenFlushedAndSeeking();
164 } 139 }
165 } 140 }
166 141
167 void MediaPlayerImpl::WhenFlushedAndSeeking() { 142 void MediaPlayerImpl::WhenFlushedAndSeeking() {
168 state_ = State::kWaiting; 143 state_ = State::kWaiting;
169 DCHECK(target_position_ != kNotSeeking); 144 DCHECK(target_position_ != kUnspecifiedTime);
170 demux_->Seek(target_position_, [this]() { 145 demux_->Seek(target_position_, [this]() {
171 target_position_ = kNotSeeking; 146 transform_subject_time_ = target_position_;
147 target_position_ = kUnspecifiedTime;
172 state_ = State::kPaused; 148 state_ = State::kPaused;
173 Update(); 149 Update();
174 }); 150 });
175 } 151 }
176 152
177 void MediaPlayerImpl::ChangeSinkStates(MediaState media_state) { 153 void MediaPlayerImpl::SetSinkTimelineTransforms(uint32_t reference_delta,
154 uint32_t subject_delta) {
155 SetSinkTimelineTransforms(
156 transform_subject_time_, reference_delta, subject_delta,
157 Timeline::local_now() + kMinimumLeadTime, kUnspecifiedTime);
158 }
159
160 void MediaPlayerImpl::SetSinkTimelineTransforms(
161 int64_t subject_time,
162 uint32_t reference_delta,
163 uint32_t subject_delta,
164 int64_t effective_reference_time,
165 int64_t effective_subject_time) {
166 std::shared_ptr<CallbackJoiner> callback_joiner = CallbackJoiner::Create();
167
178 for (auto& stream : streams_) { 168 for (auto& stream : streams_) {
179 if (stream->enabled_) { 169 if (stream->enabled_) {
180 if (media_state == MediaState::PAUSED) { 170 DCHECK(stream->timeline_consumer_);
181 stream->sink_->Pause(); 171 callback_joiner->Spawn();
182 } else { 172 stream->timeline_consumer_->SetTimelineTransform(
183 stream->sink_->Play(); 173 subject_time, reference_delta, subject_delta,
184 } 174 effective_reference_time, effective_subject_time,
175 [this, callback_joiner](bool completed) {
176 callback_joiner->Complete();
177 });
185 } 178 }
186 } 179 }
180
181 transform_subject_time_ = kUnspecifiedTime;
182
183 callback_joiner->WhenJoined([this, subject_delta]() {
184 RCHECK(state_ == State::kWaiting);
185
186 if (subject_delta == 0) {
187 state_ = State::kPaused;
188 } else {
189 state_ = State::kPlaying;
190 }
191
192 Update();
193 });
187 } 194 }
188 195
189 bool MediaPlayerImpl::AllSinksAre(SinkState sink_state) { 196 bool MediaPlayerImpl::AllSinksAtEndOfStream() {
197 int result = false;
198
190 for (auto& stream : streams_) { 199 for (auto& stream : streams_) {
191 if (stream->enabled_) { 200 if (stream->enabled_) {
192 switch (sink_state) { 201 result = stream->end_of_stream_;
193 case SinkState::kPaused: 202 if (!result) {
194 if (stream->state_ != MediaState::PAUSED) { 203 break;
195 return false;
196 }
197 break;
198 case SinkState::kPlaying:
199 if (stream->state_ != MediaState::PLAYING) {
200 return false;
201 }
202 break;
203 case SinkState::kEnded:
204 if (stream->state_ != MediaState::ENDED) {
205 return false;
206 }
207 break;
208 case SinkState::kPausedOrEnded:
209 if (stream->state_ != MediaState::PAUSED &&
210 stream->state_ != MediaState::ENDED) {
211 return false;
212 }
213 break;
214 case SinkState::kPlayingOrEnded:
215 if (stream->state_ != MediaState::PLAYING &&
216 stream->state_ != MediaState::ENDED) {
217 return false;
218 }
219 break;
220 } 204 }
221 } 205 }
222 } 206 }
223 207
224 return true; 208 return result;
225 }
226
227 void MediaPlayerImpl::SetReportedMediaState(MediaState media_state) {
228 if (reported_media_state_ != media_state) {
229 reported_media_state_ = media_state;
230 status_publisher_.SendUpdates();
231 }
232 } 209 }
233 210
234 void MediaPlayerImpl::GetStatus(uint64_t version_last_seen, 211 void MediaPlayerImpl::GetStatus(uint64_t version_last_seen,
235 const GetStatusCallback& callback) { 212 const GetStatusCallback& callback) {
236 status_publisher_.Get(version_last_seen, callback); 213 status_publisher_.Get(version_last_seen, callback);
237 } 214 }
238 215
239 void MediaPlayerImpl::Play() { 216 void MediaPlayerImpl::Play() {
240 target_state_ = MediaState::PLAYING; 217 target_state_ = State::kPlaying;
241 Update(); 218 Update();
242 } 219 }
243 220
244 void MediaPlayerImpl::Pause() { 221 void MediaPlayerImpl::Pause() {
245 target_state_ = MediaState::PAUSED; 222 target_state_ = State::kPaused;
246 Update(); 223 Update();
247 } 224 }
248 225
249 void MediaPlayerImpl::Seek(int64_t position) { 226 void MediaPlayerImpl::Seek(int64_t position) {
250 target_position_ = position; 227 target_position_ = position;
251 Update(); 228 Update();
252 } 229 }
253 230
254 void MediaPlayerImpl::PrepareStream(Stream* stream, 231 void MediaPlayerImpl::PrepareStream(Stream* stream,
255 const String& url, 232 const String& url,
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 274
298 void MediaPlayerImpl::CreateSink(Stream* stream, 275 void MediaPlayerImpl::CreateSink(Stream* stream,
299 const MediaTypePtr& input_media_type, 276 const MediaTypePtr& input_media_type,
300 const String& url, 277 const String& url,
301 const std::function<void()>& callback) { 278 const std::function<void()>& callback) {
302 DCHECK(input_media_type); 279 DCHECK(input_media_type);
303 DCHECK(stream->decoded_producer_); 280 DCHECK(stream->decoded_producer_);
304 DCHECK(factory_); 281 DCHECK(factory_);
305 282
306 factory_->CreateSink(url, input_media_type.Clone(), GetProxy(&stream->sink_)); 283 factory_->CreateSink(url, input_media_type.Clone(), GetProxy(&stream->sink_));
284 stream->sink_->GetTimelineControlSite(
285 GetProxy(&stream->timeline_control_site_));
286
287 HandleTimelineControlSiteStatusUpdates(stream);
288
289 stream->timeline_control_site_->GetTimelineConsumer(
290 GetProxy(&stream->timeline_consumer_));
307 291
308 MediaConsumerPtr consumer; 292 MediaConsumerPtr consumer;
309 stream->sink_->GetConsumer(GetProxy(&consumer)); 293 stream->sink_->GetConsumer(GetProxy(&consumer));
310 294
311 stream->decoded_producer_->Connect( 295 stream->decoded_producer_->Connect(consumer.Pass(),
312 consumer.Pass(), [this, callback, stream]() { 296 [this, callback, stream]() {
313 stream->decoded_producer_.reset(); 297 stream->decoded_producer_.reset();
314 298 callback();
315 DCHECK(stream->state_ == MediaState::UNPREPARED); 299 });
316 DCHECK(reported_media_state_ == MediaState::UNPREPARED ||
317 reported_media_state_ == MediaState::FAULT);
318
319 stream->state_ = MediaState::PAUSED;
320
321 HandleSinkStatusUpdates(stream);
322
323 callback();
324 });
325 } 300 }
326 301
327 void MediaPlayerImpl::HandleDemuxMetadataUpdates(uint64_t version, 302 void MediaPlayerImpl::HandleDemuxMetadataUpdates(uint64_t version,
328 MediaMetadataPtr metadata) { 303 MediaMetadataPtr metadata) {
329 if (metadata) { 304 if (metadata) {
330 metadata_ = metadata.Pass(); 305 metadata_ = metadata.Pass();
331 status_publisher_.SendUpdates(); 306 status_publisher_.SendUpdates();
332 } 307 }
333 308
334 demux_->GetMetadata(version, 309 demux_->GetMetadata(version,
335 [this](uint64_t version, MediaMetadataPtr metadata) { 310 [this](uint64_t version, MediaMetadataPtr metadata) {
336 HandleDemuxMetadataUpdates(version, metadata.Pass()); 311 HandleDemuxMetadataUpdates(version, metadata.Pass());
337 }); 312 });
338 } 313 }
339 314
340 void MediaPlayerImpl::HandleSinkStatusUpdates(Stream* stream, 315 void MediaPlayerImpl::HandleTimelineControlSiteStatusUpdates(
341 uint64_t version, 316 Stream* stream,
342 MediaSinkStatusPtr status) { 317 uint64_t version,
343 if (status && status->state > MediaState::UNPREPARED) { 318 MediaTimelineControlSiteStatusPtr status) {
344 // We transition to PAUSED when Connect completes. 319 if (status) {
345 DCHECK(stream->state_ > MediaState::UNPREPARED); 320 // TODO(dalesat): Why does one sink determine timeline_function_?
346 stream->state_ = status->state; 321 timeline_function_ = status->timeline_transform.To<TimelineFunction>();
347 transform_ = status->timeline_transform.Pass(); 322 stream->end_of_stream_ = status->end_of_stream;
348 status_publisher_.SendUpdates(); 323 status_publisher_.SendUpdates();
349 Update(); 324 Update();
350 } 325 }
351 326
352 stream->sink_->GetStatus( 327 stream->timeline_control_site_->GetStatus(
353 version, [this, stream](uint64_t version, MediaSinkStatusPtr status) { 328 version, [this, stream](uint64_t version,
354 HandleSinkStatusUpdates(stream, version, status.Pass()); 329 MediaTimelineControlSiteStatusPtr status) {
330 HandleTimelineControlSiteStatusUpdates(stream, version, status.Pass());
355 }); 331 });
356 } 332 }
357 333
358 MediaPlayerImpl::Stream::Stream(size_t index, MediaTypePtr media_type) 334 MediaPlayerImpl::Stream::Stream(size_t index, MediaTypePtr media_type)
359 : index_(index), media_type_(media_type.Pass()) {} 335 : index_(index), media_type_(media_type.Pass()) {}
360 336
361 MediaPlayerImpl::Stream::~Stream() {} 337 MediaPlayerImpl::Stream::~Stream() {}
362 338
363 } // namespace media 339 } // namespace media
364 } // namespace mojo 340 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698