OLD | NEW |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |