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

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

Issue 2009643002: Motown: Implement MediaTimelineController and use it. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Sync Created 4 years, 7 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 "mojo/services/media/common/cpp/timeline.h"
8 #include "services/media/factory_service/media_player_impl.h" 8 #include "services/media/factory_service/media_player_impl.h"
9 #include "services/media/framework/parts/reader.h" 9 #include "services/media/framework/parts/reader.h"
10 #include "services/media/framework/util/callback_joiner.h" 10 #include "services/media/framework/util/callback_joiner.h"
(...skipping 13 matching lines...) Expand all
24 MediaPlayerImpl::MediaPlayerImpl(InterfaceHandle<SeekingReader> reader, 24 MediaPlayerImpl::MediaPlayerImpl(InterfaceHandle<SeekingReader> reader,
25 InterfaceRequest<MediaPlayer> request, 25 InterfaceRequest<MediaPlayer> request,
26 MediaFactoryService* owner) 26 MediaFactoryService* owner)
27 : MediaFactoryService::Product<MediaPlayer>(this, request.Pass(), owner) { 27 : MediaFactoryService::Product<MediaPlayer>(this, request.Pass(), owner) {
28 DCHECK(reader); 28 DCHECK(reader);
29 29
30 status_publisher_.SetCallbackRunner([this](const GetStatusCallback& callback, 30 status_publisher_.SetCallbackRunner([this](const GetStatusCallback& callback,
31 uint64_t version) { 31 uint64_t version) {
32 MediaPlayerStatusPtr status = MediaPlayerStatus::New(); 32 MediaPlayerStatusPtr status = MediaPlayerStatus::New();
33 status->timeline_transform = TimelineTransform::From(timeline_function_); 33 status->timeline_transform = TimelineTransform::From(timeline_function_);
34 status->end_of_stream = AllSinksAtEndOfStream(); 34 status->end_of_stream = end_of_stream_;
35 status->metadata = metadata_.Clone(); 35 status->metadata = metadata_.Clone();
36 callback.Run(version, status.Pass()); 36 callback.Run(version, status.Pass());
37 }); 37 });
38 38
39 state_ = State::kWaiting; 39 state_ = State::kWaiting;
40 40
41 ConnectToService(app()->shell(), "mojo:media_factory", GetProxy(&factory_)); 41 ConnectToService(app()->shell(), "mojo:media_factory", GetProxy(&factory_));
42 42
43 factory_->CreateDemux(reader.Pass(), GetProxy(&demux_)); 43 factory_->CreateDemux(reader.Pass(), GetProxy(&demux_));
44 HandleDemuxMetadataUpdates();
44 45
45 HandleDemuxMetadataUpdates(); 46 factory_->CreateTimelineController(GetProxy(&timeline_controller_));
47 timeline_controller_->GetControlSite(GetProxy(&timeline_control_site_));
48 timeline_control_site_->GetTimelineConsumer(GetProxy(&timeline_consumer_));
49 HandleTimelineControlSiteStatusUpdates();
46 50
47 demux_->Describe([this](mojo::Array<MediaTypePtr> stream_types) { 51 demux_->Describe([this](mojo::Array<MediaTypePtr> stream_types) {
48 // Populate streams_ and enable the streams we want. 52 // Populate streams_ and enable the streams we want.
49 std::shared_ptr<CallbackJoiner> callback_joiner = CallbackJoiner::Create(); 53 std::shared_ptr<CallbackJoiner> callback_joiner = CallbackJoiner::Create();
50 54
51 for (MediaTypePtr& stream_type : stream_types) { 55 for (MediaTypePtr& stream_type : stream_types) {
52 streams_.push_back(std::unique_ptr<Stream>( 56 streams_.push_back(std::unique_ptr<Stream>(new Stream()));
53 new Stream(streams_.size(), stream_type.Pass())));
54 Stream& stream = *streams_.back(); 57 Stream& stream = *streams_.back();
55 switch (stream.media_type_->medium) { 58 switch (stream_type->medium) {
56 case MediaTypeMedium::AUDIO: 59 case MediaTypeMedium::AUDIO:
57 stream.enabled_ = true; 60 PrepareStream(&stream, streams_.size() - 1, stream_type,
58 PrepareStream(&stream, "mojo:audio_server", 61 "mojo:audio_server", callback_joiner->NewCallback());
59 callback_joiner->NewCallback());
60 break; 62 break;
61 case MediaTypeMedium::VIDEO: 63 case MediaTypeMedium::VIDEO:
62 stream.enabled_ = true;
63 // TODO(dalesat): Send video somewhere. 64 // TODO(dalesat): Send video somewhere.
64 PrepareStream(&stream, "nowhere", callback_joiner->NewCallback()); 65 PrepareStream(&stream, streams_.size() - 1, stream_type, "nowhere",
66 callback_joiner->NewCallback());
65 break; 67 break;
66 // TODO(dalesat): Enable other stream types. 68 // TODO(dalesat): Enable other stream types.
67 default: 69 default:
68 break; 70 break;
69 } 71 }
70 } 72 }
71 73
72 callback_joiner->WhenJoined([this]() { 74 callback_joiner->WhenJoined([this]() {
73 // The enabled streams are prepared. 75 // The enabled streams are prepared.
74 factory_.reset(); 76 factory_.reset();
75 state_ = State::kPaused; 77 state_ = State::kPaused;
76 Update(); 78 Update();
77 }); 79 });
78 }); 80 });
79 } 81 }
80 82
81 MediaPlayerImpl::~MediaPlayerImpl() {} 83 MediaPlayerImpl::~MediaPlayerImpl() {}
82 84
83 void MediaPlayerImpl::Update() { 85 void MediaPlayerImpl::Update() {
84 while (true) { 86 while (true) {
85 switch (state_) { 87 switch (state_) {
86 case State::kPaused: 88 case State::kPaused:
87 if (target_position_ != kUnspecifiedTime) { 89 if (target_position_ != kUnspecifiedTime) {
88 WhenPausedAndSeeking(); 90 WhenPausedAndSeeking();
89 break; 91 break;
90 } 92 }
91 93
92 if (target_state_ == State::kPlaying) { 94 if (target_state_ == State::kPlaying) {
93 if (!flushed_) { 95 if (!flushed_) {
94 SetSinkTimelineTransforms(1, 1); 96 SetTimelineTransform(1, 1);
95 state_ = State::kWaiting; 97 state_ = State::kWaiting;
96 break; 98 break;
97 } 99 }
98 100
99 flushed_ = false; 101 flushed_ = false;
100 state_ = State::kWaiting; 102 state_ = State::kWaiting;
101 demux_->Prime([this]() { 103 demux_->Prime([this]() {
102 SetSinkTimelineTransforms(1, 1); 104 SetTimelineTransform(1, 1);
103 state_ = State::kWaiting; 105 state_ = State::kWaiting;
104 Update(); 106 Update();
105 }); 107 });
106 } 108 }
107 return; 109 return;
108 110
109 case State::kPlaying: 111 case State::kPlaying:
110 if (target_position_ != kUnspecifiedTime || 112 if (target_position_ != kUnspecifiedTime ||
111 target_state_ == State::kPaused) { 113 target_state_ == State::kPaused) {
112 SetSinkTimelineTransforms(1, 0); 114 SetTimelineTransform(1, 0);
113 state_ = State::kWaiting; 115 state_ = State::kWaiting;
114 break; 116 break;
115 } 117 }
116 118
117 if (AllSinksAtEndOfStream()) { 119 if (end_of_stream_) {
118 target_state_ = State::kPaused; 120 target_state_ = State::kPaused;
119 state_ = State::kPaused; 121 state_ = State::kPaused;
120 break; 122 break;
121 } 123 }
122 return; 124 return;
123 125
124 case State::kWaiting: 126 case State::kWaiting:
125 return; 127 return;
126 } 128 }
127 } 129 }
(...skipping 15 matching lines...) Expand all
143 state_ = State::kWaiting; 145 state_ = State::kWaiting;
144 DCHECK(target_position_ != kUnspecifiedTime); 146 DCHECK(target_position_ != kUnspecifiedTime);
145 demux_->Seek(target_position_, [this]() { 147 demux_->Seek(target_position_, [this]() {
146 transform_subject_time_ = target_position_; 148 transform_subject_time_ = target_position_;
147 target_position_ = kUnspecifiedTime; 149 target_position_ = kUnspecifiedTime;
148 state_ = State::kPaused; 150 state_ = State::kPaused;
149 Update(); 151 Update();
150 }); 152 });
151 } 153 }
152 154
153 void MediaPlayerImpl::SetSinkTimelineTransforms(uint32_t reference_delta, 155 void MediaPlayerImpl::SetTimelineTransform(uint32_t reference_delta,
154 uint32_t subject_delta) { 156 uint32_t subject_delta) {
155 SetSinkTimelineTransforms( 157 timeline_consumer_->SetTimelineTransform(
156 transform_subject_time_, reference_delta, subject_delta, 158 transform_subject_time_, reference_delta, subject_delta,
157 Timeline::local_now() + kMinimumLeadTime, kUnspecifiedTime); 159 Timeline::local_now() + kMinimumLeadTime, kUnspecifiedTime,
158 } 160 [this, subject_delta](bool completed) {
161 RCHECK(state_ == State::kWaiting);
159 162
160 void MediaPlayerImpl::SetSinkTimelineTransforms( 163 if (subject_delta == 0) {
161 int64_t subject_time, 164 state_ = State::kPaused;
162 uint32_t reference_delta, 165 } else {
163 uint32_t subject_delta, 166 state_ = State::kPlaying;
164 int64_t effective_reference_time, 167 }
165 int64_t effective_subject_time) {
166 std::shared_ptr<CallbackJoiner> callback_joiner = CallbackJoiner::Create();
167 168
168 for (auto& stream : streams_) { 169 Update();
169 if (stream->enabled_) { 170 });
170 DCHECK(stream->timeline_consumer_);
171 callback_joiner->Spawn();
172 stream->timeline_consumer_->SetTimelineTransform(
173 subject_time, reference_delta, subject_delta,
174 effective_reference_time, effective_subject_time,
175 [this, callback_joiner](bool completed) {
176 callback_joiner->Complete();
177 });
178 }
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 });
194 }
195
196 bool MediaPlayerImpl::AllSinksAtEndOfStream() {
197 int result = false;
198
199 for (auto& stream : streams_) {
200 if (stream->enabled_) {
201 result = stream->end_of_stream_;
202 if (!result) {
203 break;
204 }
205 }
206 }
207
208 return result;
209 } 171 }
210 172
211 void MediaPlayerImpl::GetStatus(uint64_t version_last_seen, 173 void MediaPlayerImpl::GetStatus(uint64_t version_last_seen,
212 const GetStatusCallback& callback) { 174 const GetStatusCallback& callback) {
213 status_publisher_.Get(version_last_seen, callback); 175 status_publisher_.Get(version_last_seen, callback);
214 } 176 }
215 177
216 void MediaPlayerImpl::Play() { 178 void MediaPlayerImpl::Play() {
217 target_state_ = State::kPlaying; 179 target_state_ = State::kPlaying;
218 Update(); 180 Update();
219 } 181 }
220 182
221 void MediaPlayerImpl::Pause() { 183 void MediaPlayerImpl::Pause() {
222 target_state_ = State::kPaused; 184 target_state_ = State::kPaused;
223 Update(); 185 Update();
224 } 186 }
225 187
226 void MediaPlayerImpl::Seek(int64_t position) { 188 void MediaPlayerImpl::Seek(int64_t position) {
227 target_position_ = position; 189 target_position_ = position;
228 Update(); 190 Update();
229 } 191 }
230 192
231 void MediaPlayerImpl::PrepareStream(Stream* stream, 193 void MediaPlayerImpl::PrepareStream(Stream* stream,
194 size_t index,
195 const MediaTypePtr& input_media_type,
232 const String& url, 196 const String& url,
233 const std::function<void()>& callback) { 197 const std::function<void()>& callback) {
234 DCHECK(factory_); 198 DCHECK(factory_);
235 199
236 demux_->GetProducer(stream->index_, GetProxy(&stream->encoded_producer_)); 200 demux_->GetProducer(index, GetProxy(&stream->encoded_producer_));
237 201
238 if (stream->media_type_->encoding != MediaType::kAudioEncodingLpcm && 202 if (input_media_type->encoding != MediaType::kAudioEncodingLpcm &&
239 stream->media_type_->encoding != MediaType::kVideoEncodingUncompressed) { 203 input_media_type->encoding != MediaType::kVideoEncodingUncompressed) {
240 std::shared_ptr<CallbackJoiner> callback_joiner = CallbackJoiner::Create(); 204 std::shared_ptr<CallbackJoiner> callback_joiner = CallbackJoiner::Create();
241 205
242 // Compressed media. Insert a decoder in front of the sink. The sink would 206 // Compressed media. Insert a decoder in front of the sink. The sink would
243 // add its own internal decoder, but we want to test the decoder. 207 // add its own internal decoder, but we want to test the decoder.
244 factory_->CreateDecoder(stream->media_type_.Clone(), 208 factory_->CreateDecoder(input_media_type.Clone(),
245 GetProxy(&stream->decoder_)); 209 GetProxy(&stream->decoder_));
246 210
247 MediaConsumerPtr decoder_consumer; 211 MediaConsumerPtr decoder_consumer;
248 stream->decoder_->GetConsumer(GetProxy(&decoder_consumer)); 212 stream->decoder_->GetConsumer(GetProxy(&decoder_consumer));
249 213
250 callback_joiner->Spawn(); 214 callback_joiner->Spawn();
251 stream->encoded_producer_->Connect(decoder_consumer.Pass(), 215 stream->encoded_producer_->Connect(decoder_consumer.Pass(),
252 [stream, callback_joiner]() { 216 [stream, callback_joiner]() {
253 stream->encoded_producer_.reset(); 217 stream->encoded_producer_.reset();
254 callback_joiner->Complete(); 218 callback_joiner->Complete();
255 }); 219 });
256 220
257 callback_joiner->Spawn(); 221 callback_joiner->Spawn();
258 stream->decoder_->GetOutputType( 222 stream->decoder_->GetOutputType(
259 [this, stream, url, callback_joiner](MediaTypePtr output_type) { 223 [this, stream, url, callback_joiner](MediaTypePtr output_type) {
260 stream->decoder_->GetProducer(GetProxy(&stream->decoded_producer_)); 224 stream->decoder_->GetProducer(GetProxy(&stream->decoded_producer_));
261 CreateSink(stream, output_type, url, callback_joiner->NewCallback()); 225 CreateSink(stream, output_type, url, callback_joiner->NewCallback());
262 callback_joiner->Complete(); 226 callback_joiner->Complete();
263 }); 227 });
264 228
265 callback_joiner->WhenJoined(callback); 229 callback_joiner->WhenJoined(callback);
266 } else { 230 } else {
267 // Uncompressed media. Connect the demux stream directly to the sink. This 231 // Uncompressed media. Connect the demux stream directly to the sink. This
268 // would work for compressed media as well (the sink would decode), but we 232 // would work for compressed media as well (the sink would decode), but we
269 // want to test the decoder. 233 // want to test the decoder.
270 stream->decoded_producer_ = stream->encoded_producer_.Pass(); 234 stream->decoded_producer_ = stream->encoded_producer_.Pass();
271 CreateSink(stream, stream->media_type_, url, callback); 235 CreateSink(stream, input_media_type, url, callback);
272 } 236 }
273 } 237 }
274 238
275 void MediaPlayerImpl::CreateSink(Stream* stream, 239 void MediaPlayerImpl::CreateSink(Stream* stream,
276 const MediaTypePtr& input_media_type, 240 const MediaTypePtr& input_media_type,
277 const String& url, 241 const String& url,
278 const std::function<void()>& callback) { 242 const std::function<void()>& callback) {
279 DCHECK(input_media_type); 243 DCHECK(input_media_type);
280 DCHECK(stream->decoded_producer_); 244 DCHECK(stream->decoded_producer_);
281 DCHECK(factory_); 245 DCHECK(factory_);
282 246
283 factory_->CreateSink(url, input_media_type.Clone(), GetProxy(&stream->sink_)); 247 factory_->CreateSink(url, input_media_type.Clone(), GetProxy(&stream->sink_));
284 stream->sink_->GetTimelineControlSite(
285 GetProxy(&stream->timeline_control_site_));
286 248
287 HandleTimelineControlSiteStatusUpdates(stream); 249 MediaTimelineControlSitePtr timeline_control_site;
250 stream->sink_->GetTimelineControlSite(GetProxy(&timeline_control_site));
288 251
289 stream->timeline_control_site_->GetTimelineConsumer( 252 timeline_controller_->AddControlSite(timeline_control_site.Pass());
290 GetProxy(&stream->timeline_consumer_));
291 253
292 MediaConsumerPtr consumer; 254 MediaConsumerPtr consumer;
293 stream->sink_->GetConsumer(GetProxy(&consumer)); 255 stream->sink_->GetConsumer(GetProxy(&consumer));
294 256
295 stream->decoded_producer_->Connect(consumer.Pass(), 257 stream->decoded_producer_->Connect(consumer.Pass(),
296 [this, callback, stream]() { 258 [this, callback, stream]() {
297 stream->decoded_producer_.reset(); 259 stream->decoded_producer_.reset();
298 callback(); 260 callback();
299 }); 261 });
300 } 262 }
301 263
302 void MediaPlayerImpl::HandleDemuxMetadataUpdates(uint64_t version, 264 void MediaPlayerImpl::HandleDemuxMetadataUpdates(uint64_t version,
303 MediaMetadataPtr metadata) { 265 MediaMetadataPtr metadata) {
304 if (metadata) { 266 if (metadata) {
305 metadata_ = metadata.Pass(); 267 metadata_ = metadata.Pass();
306 status_publisher_.SendUpdates(); 268 status_publisher_.SendUpdates();
307 } 269 }
308 270
309 demux_->GetMetadata(version, 271 demux_->GetMetadata(version,
310 [this](uint64_t version, MediaMetadataPtr metadata) { 272 [this](uint64_t version, MediaMetadataPtr metadata) {
311 HandleDemuxMetadataUpdates(version, metadata.Pass()); 273 HandleDemuxMetadataUpdates(version, metadata.Pass());
312 }); 274 });
313 } 275 }
314 276
315 void MediaPlayerImpl::HandleTimelineControlSiteStatusUpdates( 277 void MediaPlayerImpl::HandleTimelineControlSiteStatusUpdates(
316 Stream* stream,
317 uint64_t version, 278 uint64_t version,
318 MediaTimelineControlSiteStatusPtr status) { 279 MediaTimelineControlSiteStatusPtr status) {
319 if (status) { 280 if (status) {
320 // TODO(dalesat): Why does one sink determine timeline_function_?
321 timeline_function_ = status->timeline_transform.To<TimelineFunction>(); 281 timeline_function_ = status->timeline_transform.To<TimelineFunction>();
322 stream->end_of_stream_ = status->end_of_stream; 282 end_of_stream_ = status->end_of_stream;
323 status_publisher_.SendUpdates(); 283 status_publisher_.SendUpdates();
324 Update(); 284 Update();
325 } 285 }
326 286
327 stream->timeline_control_site_->GetStatus( 287 timeline_control_site_->GetStatus(
328 version, [this, stream](uint64_t version, 288 version,
329 MediaTimelineControlSiteStatusPtr status) { 289 [this](uint64_t version, MediaTimelineControlSiteStatusPtr status) {
330 HandleTimelineControlSiteStatusUpdates(stream, version, status.Pass()); 290 HandleTimelineControlSiteStatusUpdates(version, status.Pass());
331 }); 291 });
332 } 292 }
333 293
334 MediaPlayerImpl::Stream::Stream(size_t index, MediaTypePtr media_type) 294 MediaPlayerImpl::Stream::Stream() {}
335 : index_(index), media_type_(media_type.Pass()) {}
336 295
337 MediaPlayerImpl::Stream::~Stream() {} 296 MediaPlayerImpl::Stream::~Stream() {}
338 297
339 } // namespace media 298 } // namespace media
340 } // namespace mojo 299 } // namespace mojo
OLDNEW
« no previous file with comments | « services/media/factory_service/media_player_impl.h ('k') | services/media/factory_service/media_timeline_controller_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698