1 // Copyright 2014 Samsung Electronics Inc. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/media/tizen/media_source_delegate_tizen.h"
7 #include "base/process/process.h"
8 #include "media/base/bind_to_current_loop.h"
9 #include "media/base/media_log.h"
10 #include "media/base/tizen/demuxer_stream_player_params_tizen.h"
11 #include "media/blink/webmediaplayer_util.h"
12 #include "media/blink/webmediasource_impl.h"
13 #include "media/filters/chunk_demuxer.h"
14 #include "media/filters/decrypting_demuxer_stream.h"
15 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
19 static void LogMediaSourceError(
20 const scoped_refptr<media::MediaLog>& media_log,
21 const std::string& error) {
22 media_log->AddEvent(media_log->CreateMediaSourceErrorEvent(error));
25 MediaSourceDelegateTizen::MediaSourceDelegateTizen(
26 RendererDemuxerTizen* demuxer_client,
27 int demuxer_client_id,
28 const scoped_refptr<base::SingleThreadTaskRunner>& media_task_runner,
29 media::MediaLog* media_log)
30 : main_loop_(base::MessageLoopProxy::current()),
31 main_weak_factory_(this),
32 main_weak_this_(main_weak_factory_.GetWeakPtr()),
33 media_task_runner_(media_task_runner),
34 media_weak_factory_(this),
35 demuxer_client_(demuxer_client),
36 demuxer_client_id_(demuxer_client_id),
37 media_log_(media_log),
40 seek_time_(media::kNoTimestamp()),
43 seeking_pending_seek_(false),
44 is_demuxer_seek_done_(false),
45 pending_seek_time_(media::kNoTimestamp()),
46 is_audio_read_fired_(false),
47 is_video_read_fired_(false),
48 is_demuxer_ready_(false),
49 shared_memory_size_(0) {
50 VLOG(1) << "MediaSourceDelegateTizen::" << __FUNCTION__
51 << ": Demuxer Client Id = " << demuxer_client_id_;
52 DCHECK(!chunk_demuxer_);
55 MediaSourceDelegateTizen::~MediaSourceDelegateTizen() {
56 DCHECK(main_loop_->BelongsToCurrentThread());
57 DCHECK(!chunk_demuxer_);
58 DCHECK(!audio_stream_);
59 DCHECK(!video_stream_);
60 DCHECK(!audio_decrypting_demuxer_stream_);
61 DCHECK(!video_decrypting_demuxer_stream_);
64 void MediaSourceDelegateTizen::InitializeMediaSource(
65 const MediaSourceOpenedCB& media_source_opened_cb,
66 const media::Demuxer::NeedKeyCB& need_key_cb,
67 const media::SetDecryptorReadyCB& set_decryptor_ready_cb,
68 const UpdateNetworkStateCB& update_network_state_cb,
69 const DurationChangeCB& duration_change_cb) {
70 DCHECK(main_loop_->BelongsToCurrentThread());
71 DCHECK(!media_source_opened_cb.is_null());
72 media_source_opened_cb_ = media_source_opened_cb;
73 need_key_cb_ = need_key_cb;
74 set_decryptor_ready_cb_ = set_decryptor_ready_cb;
75 update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb);
76 duration_change_cb_ = duration_change_cb;
78 chunk_demuxer_.reset(new media::ChunkDemuxer(
79 media::BindToCurrentLoop(base::Bind(
80 &MediaSourceDelegateTizen::OnDemuxerOpened, main_weak_this_)),
81 media::BindToCurrentLoop(base::Bind(
82 &MediaSourceDelegateTizen::OnNeedKey, main_weak_this_)),
83 base::Bind(&LogMediaSourceError, media_log_),
86 media_task_runner_->PostTask(FROM_HERE,
87 base::Bind(&MediaSourceDelegateTizen::InitializeDemuxer,
88 base::Unretained(this)));
91 void MediaSourceDelegateTizen::InitializeDemuxer() {
92 DCHECK(media_task_runner_->BelongsToCurrentThread());
93 demuxer_client_->AddDelegate(demuxer_client_id_, this);
94 chunk_demuxer_->Initialize(
96 base::Bind(&MediaSourceDelegateTizen::OnDemuxerInitDone,
97 media_weak_factory_.GetWeakPtr()),
101 void MediaSourceDelegateTizen::OnNeedKey(
102 const std::string& type,
103 const std::vector<uint8>& init_data) {
104 DCHECK(main_loop_->BelongsToCurrentThread());
105 if (need_key_cb_.is_null()) {
108 need_key_cb_.Run(type, init_data);
111 void MediaSourceDelegateTizen::OnDemuxerOpened() {
112 DCHECK(main_loop_->BelongsToCurrentThread());
113 if (media_source_opened_cb_.is_null())
115 media_source_opened_cb_.Run(new media::WebMediaSourceImpl(
116 chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_)));
119 void MediaSourceDelegateTizen::OnDemuxerError(
120 media::PipelineStatus status) {
121 if (status != media::PIPELINE_OK && !update_network_state_cb_.is_null())
122 update_network_state_cb_.Run(PipelineErrorToNetworkState(status));
125 void MediaSourceDelegateTizen::OnDemuxerInitDone(
126 media::PipelineStatus status) {
127 DCHECK(media_task_runner_->BelongsToCurrentThread());
128 DCHECK(chunk_demuxer_);
129 if (status != media::PIPELINE_OK) {
130 OnDemuxerError(status);
133 audio_stream_ = chunk_demuxer_->GetStream(media::DemuxerStream::AUDIO);
134 video_stream_ = chunk_demuxer_->GetStream(media::DemuxerStream::VIDEO);
135 if (audio_stream_ && audio_stream_->audio_decoder_config().is_encrypted() &&
136 !set_decryptor_ready_cb_.is_null()) {
137 InitAudioDecryptingDemuxerStream();
140 if (video_stream_ && video_stream_->video_decoder_config().is_encrypted() &&
141 !set_decryptor_ready_cb_.is_null()) {
142 InitVideoDecryptingDemuxerStream();
145 // Notify demuxer ready when both streams are not encrypted.
146 is_demuxer_ready_ = true;
147 NotifyDemuxerReady();
150 void MediaSourceDelegateTizen::InitAudioDecryptingDemuxerStream() {
151 DCHECK(media_task_runner_->BelongsToCurrentThread());
152 audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
153 media_task_runner_, set_decryptor_ready_cb_));
155 audio_decrypting_demuxer_stream_->Initialize(
157 base::Bind(&MediaSourceDelegateTizen::OnAudioDecryptingDemuxerStreamInitDone,
158 media_weak_factory_.GetWeakPtr()));
161 void MediaSourceDelegateTizen::InitVideoDecryptingDemuxerStream() {
162 DCHECK(media_task_runner_->BelongsToCurrentThread());
164 video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
165 media_task_runner_, set_decryptor_ready_cb_));
167 video_decrypting_demuxer_stream_->Initialize(
169 base::Bind(&MediaSourceDelegateTizen::OnVideoDecryptingDemuxerStreamInitDone,
170 media_weak_factory_.GetWeakPtr()));
174 void MediaSourceDelegateTizen::OnAudioDecryptingDemuxerStreamInitDone(
175 media::PipelineStatus status) {
176 DCHECK(media_task_runner_->BelongsToCurrentThread());
177 DCHECK(chunk_demuxer_);
179 if (status != media::PIPELINE_OK)
180 audio_decrypting_demuxer_stream_.reset();
182 audio_stream_ = audio_decrypting_demuxer_stream_.get();
184 if (video_stream_ && video_stream_->video_decoder_config().is_encrypted()) {
185 InitVideoDecryptingDemuxerStream();
189 // Try to notify demuxer ready when audio DDS initialization finished and
190 // video is not encrypted.
191 is_demuxer_ready_ = true;
192 NotifyDemuxerReady();
195 void MediaSourceDelegateTizen::OnVideoDecryptingDemuxerStreamInitDone(
196 media::PipelineStatus status) {
197 DCHECK(media_task_runner_->BelongsToCurrentThread());
198 DCHECK(chunk_demuxer_);
200 if (status != media::PIPELINE_OK)
201 video_decrypting_demuxer_stream_.reset();
203 video_stream_ = video_decrypting_demuxer_stream_.get();
205 // Try to notify demuxer ready when video DDS initialization finished.
206 is_demuxer_ready_ = true;
207 NotifyDemuxerReady();
210 void MediaSourceDelegateTizen::NotifyDemuxerReady() {
211 DCHECK(media_task_runner_->BelongsToCurrentThread());
212 DCHECK(is_demuxer_ready_);
214 scoped_ptr<media::DemuxerConfigs> configs(new media::DemuxerConfigs());
216 media::AudioDecoderConfig audio_config =
217 audio_stream_->audio_decoder_config();
218 configs->audio_codec = audio_config.codec();
219 configs->audio_channels =
220 media::ChannelLayoutToChannelCount(audio_config.channel_layout());
221 configs->audio_sampling_rate = audio_config.samples_per_second();
222 configs->is_audio_encrypted = audio_config.is_encrypted();
223 configs->audio_extra_data = std::vector<uint8>(audio_config.extra_data(),
224 audio_config.extra_data() + audio_config.extra_data_size());
227 media::VideoDecoderConfig video_config =
228 video_stream_->video_decoder_config();
229 configs->video_codec = video_config.codec();
230 configs->video_size = video_config.natural_size();
231 configs->is_video_encrypted = video_config.is_encrypted();
232 configs->video_extra_data = std::vector<uint8>(video_config.extra_data(),
233 video_config.extra_data() + video_config.extra_data_size());
235 if (demuxer_client_) {
236 demuxer_client_->DemuxerReady(demuxer_client_id_, *configs);
240 void MediaSourceDelegateTizen::OnReadFromDemuxer(
241 media::DemuxerStream::Type type) {
242 DCHECK(media_task_runner_->BelongsToCurrentThread());
247 if ((type == media::DemuxerStream::AUDIO) && audio_stream_
248 && !is_audio_read_fired_) {
249 is_audio_read_fired_ = true;
250 audio_stream_->Read(base::Bind(
251 &MediaSourceDelegateTizen::OnBufferReady,
252 media_weak_factory_.GetWeakPtr() , type));
255 if ((type == media::DemuxerStream::VIDEO) && video_stream_
256 && !is_video_read_fired_) {
257 is_video_read_fired_ = true;
258 video_stream_->Read(base::Bind(
259 &MediaSourceDelegateTizen::OnBufferReady,
260 media_weak_factory_.GetWeakPtr() , type));
264 void MediaSourceDelegateTizen::Stop(const base::Closure& stop_cb) {
265 DCHECK(main_loop_->BelongsToCurrentThread());
266 VLOG(1) << "MediaSourceDelegateTizen::" << __FUNCTION__
267 << ": Demuxer Client Id = " << demuxer_client_id_;
269 if (!chunk_demuxer_) {
270 DCHECK(!demuxer_client_);
274 duration_change_cb_.Reset();
275 update_network_state_cb_.Reset();
276 media_source_opened_cb_.Reset();
278 main_weak_factory_.InvalidateWeakPtrs();
279 DCHECK(!main_weak_factory_.HasWeakPtrs());
281 // 1. shutdown demuxer.
282 // 2. On media thread, call stop demuxer.
283 // 3. On callback, post message and self destory.
284 chunk_demuxer_->Shutdown();
285 media_task_runner_->PostTask(
287 base::Bind(&MediaSourceDelegateTizen::StopDemuxer,
288 base::Unretained(this),
292 void MediaSourceDelegateTizen::StopDemuxer(const base::Closure& stop_cb) {
293 DCHECK(media_task_runner_->BelongsToCurrentThread());
294 DCHECK(chunk_demuxer_);
296 demuxer_client_->RemoveDelegate(demuxer_client_id_);
297 demuxer_client_ = NULL;
298 audio_stream_ = NULL;
299 video_stream_ = NULL;
300 audio_decrypting_demuxer_stream_.reset();
301 video_decrypting_demuxer_stream_.reset();
303 media_weak_factory_.InvalidateWeakPtrs();
304 DCHECK(!media_weak_factory_.HasWeakPtrs());
306 chunk_demuxer_->Stop();
307 chunk_demuxer_.reset();
312 void MediaSourceDelegateTizen::OnMediaConfigRequest() {
313 NotifyDemuxerReady();
316 void MediaSourceDelegateTizen::SeekInternal(
317 const base::TimeDelta& seek_time) {
318 DCHECK(media_task_runner_->BelongsToCurrentThread());
319 chunk_demuxer_->Seek(seek_time, base::Bind(
320 &MediaSourceDelegateTizen::OnDemuxerSeekDone,
321 media_weak_factory_.GetWeakPtr()));
324 void MediaSourceDelegateTizen::OnBufferReady(
325 media::DemuxerStream::Type type,
326 media::DemuxerStream::Status status,
327 const scoped_refptr<media::DecoderBuffer>& buffer) {
329 scoped_ptr<media::DemuxedBufferMetaData> meta_data(
330 new media::DemuxedBufferMetaData());
331 meta_data->status = status;
332 meta_data->type = type;
334 if (type == media::DemuxerStream::AUDIO)
335 is_audio_read_fired_ = false;
336 if (type == media::DemuxerStream::VIDEO)
337 is_video_read_fired_ = false;
340 case media::DemuxerStream::kAborted:
341 LOG (ERROR) << "[RENDER] : DemuxerStream::kAborted";
344 case media::DemuxerStream::kConfigChanged:
345 VLOG(1) << "[RENDER] : DemuxerStream::kConfigChanged";
346 NotifyDemuxerReady();
349 case media::DemuxerStream::kOk:
350 if (buffer.get()->end_of_stream()) {
351 VLOG(1) << "[RENDER] : DemuxerStream::kOk but |end_of_stream|";
352 meta_data->end_of_stream = true;
355 shared_memory_size_ = buffer.get()->data_size();
356 if (!shared_memory_.CreateAndMapAnonymous(shared_memory_size_)) {
357 LOG (ERROR) << "Shared Memory creation failed.";
360 if (!shared_memory_.ShareToProcess(base::Process::Current().Handle(),
361 &foreign_memory_handle_)) {
362 LOG (ERROR) << "Shared Memory handle could not be obtained";
363 shared_memory_.Close();
366 memcpy(shared_memory_.memory(), (void*)buffer.get()->writable_data(),
367 shared_memory_size_);
368 meta_data->timestamp = buffer.get()->timestamp();
369 meta_data->time_duration = buffer.get()->duration();
370 if (demuxer_client_) {
371 meta_data->size = shared_memory_size_;
372 demuxer_client_->ReadFromDemuxerAck(
373 demuxer_client_id_, foreign_memory_handle_, *meta_data);
375 shared_memory_.Close();
383 demuxer_client_->BufferMetaDataAck(demuxer_client_id_, *meta_data);
386 void MediaSourceDelegateTizen::StartWaitingForSeek(
387 const base::TimeDelta& seek_time) {
388 DCHECK(main_loop_->BelongsToCurrentThread());
392 // Called from |webmediaplayertizen| only.
393 is_demuxer_seek_done_ = false;
394 seeking_pending_seek_ = false;
396 chunk_demuxer_->StartWaitingForSeek(seek_time);
399 void MediaSourceDelegateTizen::CancelPendingSeek(
400 const base::TimeDelta& seek_time) {
401 DCHECK(main_loop_->BelongsToCurrentThread());
405 pending_seek_ = true;
406 pending_seek_time_ = seek_time;
408 if (is_demuxer_seek_done_) {
409 // Since we already requested gstreamer to seek. And there are no pending
410 // seeks in |chunk_demuxer|. Cancelling pending seek makes no sense.
412 // This block will handle when |gstreamer| is seeking and new seek came in
414 VLOG(1) << "No need to CancelPendingSeek";
415 is_demuxer_seek_done_ = false;
416 pending_seek_ = false;
417 chunk_demuxer_->StartWaitingForSeek(seek_time);
418 StartSeek(seek_time, true);
422 chunk_demuxer_->CancelPendingSeek(seek_time);
425 void MediaSourceDelegateTizen::StartSeek(
426 const base::TimeDelta& seek_time,
427 bool is_seeking_pending_seek) {
428 DCHECK(media_task_runner_->BelongsToCurrentThread());
430 VLOG(1)<< "MediaSourceDelegateTizen::" << __FUNCTION__
431 << " : " << seek_time.InSecondsF();
435 is_demuxer_seek_done_ = false;
436 if (is_seeking_pending_seek)
437 seeking_pending_seek_ = is_seeking_pending_seek;
438 else if (seeking_pending_seek_) {
439 VLOG(1)<< "Ignoring seek request from Gstreamer";
442 seek_time_ = seek_time;
443 SeekInternal(seek_time);
446 void MediaSourceDelegateTizen::OnDemuxerSeekDone(
447 media::PipelineStatus status) {
448 DCHECK(media_task_runner_->BelongsToCurrentThread());
449 if (status != media::PIPELINE_OK) {
450 OnDemuxerError(status);
454 pending_seek_ = false;
455 StartSeek(pending_seek_time_, true);
456 seek_time_ = pending_seek_time_;
458 VLOG(1) << "Actual time that Gstreamer seeks : "
459 << seek_time_.InMilliseconds();
460 seeking_pending_seek_ = false;
462 is_demuxer_seek_done_ = true;
463 demuxer_client_->DemuxerSeekDone(demuxer_client_id_, seek_time_);
465 ResetAudioDecryptingDemuxerStream();
468 void MediaSourceDelegateTizen::ResetAudioDecryptingDemuxerStream() {
469 DCHECK(media_task_runner_->BelongsToCurrentThread());
470 if (audio_decrypting_demuxer_stream_) {
471 audio_decrypting_demuxer_stream_->Reset(
472 base::Bind(&MediaSourceDelegateTizen::ResetVideoDecryptingDemuxerStream,
473 media_weak_factory_.GetWeakPtr()));
476 ResetVideoDecryptingDemuxerStream();
479 void MediaSourceDelegateTizen::ResetVideoDecryptingDemuxerStream() {
480 DCHECK(media_task_runner_->BelongsToCurrentThread());
481 if (video_decrypting_demuxer_stream_) {
482 video_decrypting_demuxer_stream_->Reset(base::Bind(
483 &MediaSourceDelegateTizen::FinishResettingDecryptingDemuxerStreams,
484 media_weak_factory_.GetWeakPtr()));
487 FinishResettingDecryptingDemuxerStreams();
490 void MediaSourceDelegateTizen::FinishResettingDecryptingDemuxerStreams() {
491 DCHECK(media_task_runner_->BelongsToCurrentThread());
494 demuxer_client_->DemuxerSeekDone(demuxer_client_id_, seek_time_);
497 void MediaSourceDelegateTizen::SetDuration(base::TimeDelta duration) {
498 DCHECK(main_loop_->BelongsToCurrentThread());
499 main_loop_->PostTask(FROM_HERE, base::Bind(
500 &MediaSourceDelegateTizen::OnDurationChanged,
501 main_weak_this_, duration));
504 void MediaSourceDelegateTizen::OnDurationChanged(
505 const base::TimeDelta& duration) {
506 DCHECK(main_loop_->BelongsToCurrentThread());
508 demuxer_client_->DurationChanged(demuxer_client_id_, duration);
510 if (!duration_change_cb_.is_null())
511 duration_change_cb_.Run(duration.InSecondsF());
514 } // namespace content