[MM]EME implementation using EncryptedMediaPlayerSupport.
[platform/framework/web/chromium-efl.git] / tizen_src / impl / content / renderer / media / tizen / media_source_delegate_tizen.cc
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.
4
5 #include "content/renderer/media/tizen/media_source_delegate_tizen.h"
6
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"
16
17 namespace content {
18
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));
23 }
24
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),
38       audio_stream_(NULL),
39       video_stream_(NULL),
40       seek_time_(media::kNoTimestamp()),
41       pending_seek_(false),
42       is_seeking_(false),
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_);
53 }
54
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_);
62 }
63
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;
77
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_),
84       false));
85
86   media_task_runner_->PostTask(FROM_HERE,
87       base::Bind(&MediaSourceDelegateTizen::InitializeDemuxer,
88           base::Unretained(this)));
89 }
90
91 void MediaSourceDelegateTizen::InitializeDemuxer() {
92   DCHECK(media_task_runner_->BelongsToCurrentThread());
93   demuxer_client_->AddDelegate(demuxer_client_id_, this);
94   chunk_demuxer_->Initialize(
95       this,
96       base::Bind(&MediaSourceDelegateTizen::OnDemuxerInitDone,
97           media_weak_factory_.GetWeakPtr()),
98       false);
99 }
100
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()) {
106     return;
107   }
108   need_key_cb_.Run(type, init_data);
109 }
110
111 void MediaSourceDelegateTizen::OnDemuxerOpened() {
112   DCHECK(main_loop_->BelongsToCurrentThread());
113   if (media_source_opened_cb_.is_null())
114     return;
115   media_source_opened_cb_.Run(new media::WebMediaSourceImpl(
116       chunk_demuxer_.get(), base::Bind(&LogMediaSourceError, media_log_)));
117 }
118
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));
123 }
124
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);
131     return;
132   }
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();
138     return;
139   }
140   if (video_stream_ && video_stream_->video_decoder_config().is_encrypted() &&
141       !set_decryptor_ready_cb_.is_null()) {
142     InitVideoDecryptingDemuxerStream();
143     return;
144   }
145   // Notify demuxer ready when both streams are not encrypted.
146   is_demuxer_ready_ = true;
147   NotifyDemuxerReady();
148 }
149
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_));
154
155   audio_decrypting_demuxer_stream_->Initialize(
156       audio_stream_,
157       base::Bind(&MediaSourceDelegateTizen::OnAudioDecryptingDemuxerStreamInitDone,
158                  media_weak_factory_.GetWeakPtr()));
159 }
160
161 void MediaSourceDelegateTizen::InitVideoDecryptingDemuxerStream() {
162   DCHECK(media_task_runner_->BelongsToCurrentThread());
163
164   video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
165       media_task_runner_, set_decryptor_ready_cb_));
166
167   video_decrypting_demuxer_stream_->Initialize(
168       video_stream_,
169       base::Bind(&MediaSourceDelegateTizen::OnVideoDecryptingDemuxerStreamInitDone,
170                  media_weak_factory_.GetWeakPtr()));
171 }
172
173
174 void MediaSourceDelegateTizen::OnAudioDecryptingDemuxerStreamInitDone(
175   media::PipelineStatus status) {
176   DCHECK(media_task_runner_->BelongsToCurrentThread());
177   DCHECK(chunk_demuxer_);
178
179   if (status != media::PIPELINE_OK)
180     audio_decrypting_demuxer_stream_.reset();
181   else
182     audio_stream_ = audio_decrypting_demuxer_stream_.get();
183
184   if (video_stream_ && video_stream_->video_decoder_config().is_encrypted()) {
185     InitVideoDecryptingDemuxerStream();
186     return;
187   }
188
189   // Try to notify demuxer ready when audio DDS initialization finished and
190   // video is not encrypted.
191   is_demuxer_ready_ = true;
192   NotifyDemuxerReady();
193 }
194
195 void MediaSourceDelegateTizen::OnVideoDecryptingDemuxerStreamInitDone(
196   media::PipelineStatus status) {
197   DCHECK(media_task_runner_->BelongsToCurrentThread());
198   DCHECK(chunk_demuxer_);
199
200   if (status != media::PIPELINE_OK)
201     video_decrypting_demuxer_stream_.reset();
202   else
203     video_stream_ = video_decrypting_demuxer_stream_.get();
204
205   // Try to notify demuxer ready when video DDS initialization finished.
206   is_demuxer_ready_ = true;
207   NotifyDemuxerReady();
208 }
209
210 void MediaSourceDelegateTizen::NotifyDemuxerReady() {
211   DCHECK(media_task_runner_->BelongsToCurrentThread());
212   DCHECK(is_demuxer_ready_);
213
214   scoped_ptr<media::DemuxerConfigs> configs(new media::DemuxerConfigs());
215   if (audio_stream_) {
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());
225   }
226   if (video_stream_) {
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());
234   }
235   if (demuxer_client_) {
236     demuxer_client_->DemuxerReady(demuxer_client_id_, *configs);
237   }
238 }
239
240 void MediaSourceDelegateTizen::OnReadFromDemuxer(
241     media::DemuxerStream::Type type) {
242   DCHECK(media_task_runner_->BelongsToCurrentThread());
243
244   if (is_seeking_)
245     return;
246
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));
253   }
254
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));
261   }
262 }
263
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_;
268
269   if (!chunk_demuxer_) {
270     DCHECK(!demuxer_client_);
271     return;
272   }
273
274   duration_change_cb_.Reset();
275   update_network_state_cb_.Reset();
276   media_source_opened_cb_.Reset();
277
278   main_weak_factory_.InvalidateWeakPtrs();
279   DCHECK(!main_weak_factory_.HasWeakPtrs());
280
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(
286       FROM_HERE,
287       base::Bind(&MediaSourceDelegateTizen::StopDemuxer,
288       base::Unretained(this),
289       stop_cb));
290 }
291
292 void MediaSourceDelegateTizen::StopDemuxer(const base::Closure& stop_cb) {
293   DCHECK(media_task_runner_->BelongsToCurrentThread());
294   DCHECK(chunk_demuxer_);
295
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();
302
303   media_weak_factory_.InvalidateWeakPtrs();
304   DCHECK(!media_weak_factory_.HasWeakPtrs());
305
306   chunk_demuxer_->Stop();
307   chunk_demuxer_.reset();
308
309   stop_cb.Run();
310 }
311
312 void MediaSourceDelegateTizen::OnMediaConfigRequest() {
313   NotifyDemuxerReady();
314 }
315
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()));
322 }
323
324 void MediaSourceDelegateTizen::OnBufferReady(
325     media::DemuxerStream::Type type,
326     media::DemuxerStream::Status status,
327     const scoped_refptr<media::DecoderBuffer>& buffer) {
328
329   scoped_ptr<media::DemuxedBufferMetaData> meta_data(
330       new media::DemuxedBufferMetaData());
331   meta_data->status = status;
332   meta_data->type = type;
333
334   if (type == media::DemuxerStream::AUDIO)
335     is_audio_read_fired_ = false;
336   if (type == media::DemuxerStream::VIDEO)
337     is_video_read_fired_ = false;
338
339   switch (status) {
340     case media::DemuxerStream::kAborted:
341       LOG (ERROR) << "[RENDER] : DemuxerStream::kAborted";
342       break;
343
344     case media::DemuxerStream::kConfigChanged:
345       VLOG(1) << "[RENDER] : DemuxerStream::kConfigChanged";
346       NotifyDemuxerReady();
347       break;
348
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;
353           break;
354         }
355         shared_memory_size_ = buffer.get()->data_size();
356         if (!shared_memory_.CreateAndMapAnonymous(shared_memory_size_)) {
357           LOG (ERROR) << "Shared Memory creation failed.";
358           return;
359         }
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();
364           return;
365         }
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);
374         }
375         shared_memory_.Close();
376         return;
377       break;
378     default:
379       NOTREACHED();
380   }
381
382   if (demuxer_client_)
383     demuxer_client_->BufferMetaDataAck(demuxer_client_id_, *meta_data);
384 }
385
386 void MediaSourceDelegateTizen::StartWaitingForSeek(
387     const base::TimeDelta& seek_time) {
388   DCHECK(main_loop_->BelongsToCurrentThread());
389
390   if (!chunk_demuxer_)
391     return;
392   // Called from |webmediaplayertizen| only.
393   is_demuxer_seek_done_ = false;
394   seeking_pending_seek_ = false;
395   is_seeking_ = true;
396   chunk_demuxer_->StartWaitingForSeek(seek_time);
397 }
398
399 void MediaSourceDelegateTizen::CancelPendingSeek(
400     const base::TimeDelta& seek_time) {
401   DCHECK(main_loop_->BelongsToCurrentThread());
402   if (!chunk_demuxer_)
403     return;
404   is_seeking_ = true;
405   pending_seek_ = true;
406   pending_seek_time_ = seek_time;
407
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.
411     //
412     // This block will handle when |gstreamer| is seeking and new seek came in
413     // between.
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);
419     return;
420   }
421
422   chunk_demuxer_->CancelPendingSeek(seek_time);
423 }
424
425 void MediaSourceDelegateTizen::StartSeek(
426     const base::TimeDelta& seek_time,
427     bool is_seeking_pending_seek) {
428   DCHECK(media_task_runner_->BelongsToCurrentThread());
429
430   VLOG(1)<< "MediaSourceDelegateTizen::" << __FUNCTION__
431           << " : " << seek_time.InSecondsF();
432   if (!chunk_demuxer_)
433     return;
434   is_seeking_ = true;
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";
440     return;
441   }
442   seek_time_ = seek_time;
443   SeekInternal(seek_time);
444 }
445
446 void MediaSourceDelegateTizen::OnDemuxerSeekDone(
447     media::PipelineStatus status) {
448   DCHECK(media_task_runner_->BelongsToCurrentThread());
449   if (status != media::PIPELINE_OK) {
450     OnDemuxerError(status);
451     return;
452   }
453   if (pending_seek_) {
454     pending_seek_ = false;
455     StartSeek(pending_seek_time_, true);
456     seek_time_ = pending_seek_time_;
457   } else {
458     VLOG(1) << "Actual time that Gstreamer seeks : "
459             << seek_time_.InMilliseconds();
460     seeking_pending_seek_ = false;
461     is_seeking_ = false;
462     is_demuxer_seek_done_ = true;
463     demuxer_client_->DemuxerSeekDone(demuxer_client_id_, seek_time_);
464   }
465   ResetAudioDecryptingDemuxerStream();
466 }
467
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()));
474     return;
475   }
476   ResetVideoDecryptingDemuxerStream();
477 }
478
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()));
485     return;
486   }
487   FinishResettingDecryptingDemuxerStreams();
488 }
489
490 void MediaSourceDelegateTizen::FinishResettingDecryptingDemuxerStreams() {
491   DCHECK(media_task_runner_->BelongsToCurrentThread());
492   DCHECK(is_seeking_);
493   is_seeking_ = false;
494   demuxer_client_->DemuxerSeekDone(demuxer_client_id_, seek_time_);
495 }
496
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));
502 }
503
504 void MediaSourceDelegateTizen::OnDurationChanged(
505     const base::TimeDelta& duration) {
506   DCHECK(main_loop_->BelongsToCurrentThread());
507   if (demuxer_client_)
508     demuxer_client_->DurationChanged(demuxer_client_id_, duration);
509
510   if (!duration_change_cb_.is_null())
511     duration_change_cb_.Run(duration.InSecondsF());
512 }
513
514 }  // namespace content