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 "media/base/efl/media_source_player_gstreamer.h"
7 #include <gst/app/gstappsink.h>
8 #include <gst/app/gstappsrc.h>
9 #include <gst/video/video.h>
10 #include <gst/video/videooverlay.h>
12 #include "base/process/process.h"
13 #include "media/base/efl/media_player_manager_efl.h"
14 #include "media/base/efl/media_player_util_efl.h"
18 // Pipeline element name
19 const char* kPipelineName = "gst_pipeline";
21 // Update duration every 100ms.
22 const int kDurationUpdateInterval = 100;
24 // For smooth playback, seeking will be done to I-Frame + kSixteenMilliSeconds
25 // Reason to choose kSixteenMilliSeconds is duration of each video frame at
26 // 60 fps video will be ~16 milliseconds.
27 const int64 kSixteenMilliSeconds = 16000000;
28 const int kMaxBufPercent = 100;
30 const int kBytesPerMegabyte = 1048576;
32 const char* h264elements[] = {
34 #if defined(TIZEN_MULTIMEDIA_USE_HW_CODEC)
41 const char* aacelements[] = {
43 #if defined(TIZEN_MULTIMEDIA_USE_HW_CODEC)
44 "omx_aacdec", "autoaudiosink",
46 "avdec_aac", "autoaudiosink"
50 const char* mp3elements[] = {
56 const AudioCodecGstElementsMapping AudioMapping[] = {
57 {media::kCodecAAC, aacelements},
58 {media::kCodecMP3, mp3elements},
59 {media::kUnknownAudioCodec, NULL}
62 const VideoCodecGstElementsMapping VideoMapping[] = {
63 {media::kCodecH264, h264elements},
64 {media::kUnknownVideoCodec, NULL}
67 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
68 // Generating Unique integer for given height / width.
69 int GetUniqueKey(int x, int y) {
70 return ((x << 16) | y);
78 static GstBusSyncReply GstPipelineMessageCB(
82 MediaSourcePlayerGstreamer* player =
83 static_cast<MediaSourcePlayerGstreamer*>(user_data);
84 if (!player || player->IsPlayerDestructing())
87 player->HandleMessage(message);
88 gst_message_unref(message);
92 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
93 static Eina_Bool NotifyDamageUpdatedCB(
97 MediaSourcePlayerGstreamer* player =
98 static_cast<MediaSourcePlayerGstreamer*>(user_data);
99 if (!player || player->IsPlayerDestructing())
100 return ECORE_CALLBACK_PASS_ON;
101 player->PlatformSurfaceUpdated();
102 return ECORE_CALLBACK_PASS_ON;
105 #if defined(OS_TIZEN_TV)
106 static int GetPixmapIdCB(void* user_data) {
107 MediaSourcePlayerGstreamer* player =
108 static_cast<MediaSourcePlayerGstreamer*>(user_data);
109 return player->GetSurfaceID();
114 static void OnGstStartVideoFeedCB(
118 MediaSourcePlayerGstreamer* player =
119 static_cast<MediaSourcePlayerGstreamer*>(user_data);
120 if (!player || player->IsPlayerDestructing())
122 player->OnReadDemuxedData(media::DemuxerStream::VIDEO);
126 static void OnGstStopVideoFeedCB(GstAppSrc* pipeline, void* user_data) {
127 MediaSourcePlayerGstreamer* player =
128 static_cast<MediaSourcePlayerGstreamer*>(user_data);
129 if (!player || player->IsPlayerDestructing())
131 player->OnStopDemuxedData(media::DemuxerStream::VIDEO);
134 static gboolean OnGstSeekVideoFeedCB(
139 MediaSourcePlayerGstreamer* player =
140 static_cast<MediaSourcePlayerGstreamer*>(user_data);
141 if (!player || player->IsPlayerDestructing())
143 player->UpdateVideoSeekOffset(offset);
147 static GstFlowReturn OnGstAppsinkPreroll(
149 gpointer user_data) {
150 MediaSourcePlayerGstreamer* player =
151 static_cast<MediaSourcePlayerGstreamer*>(user_data);
152 if (!player || player->IsPlayerDestructing())
153 return GST_FLOW_ERROR;
154 player->GetFrameDetails();
158 static GstFlowReturn OnGstAppsinkBuffer(GstAppSink* sink, gpointer user_data) {
159 MediaSourcePlayerGstreamer* player =
160 static_cast<MediaSourcePlayerGstreamer*>(user_data);
161 if (!player || player->IsPlayerDestructing())
162 return GST_FLOW_ERROR;
163 player->OnNewFrameAvailable(player->PullSample());
167 gboolean OnGstSeekAudioFeedCB(
171 MediaSourcePlayerGstreamer* player =
172 static_cast<MediaSourcePlayerGstreamer*>(user_data);
173 if (!player || player->IsPlayerDestructing())
175 player->UpdateAudioSeekOffset(offset);
179 static void OnGstStartAudioFeedCB(
183 MediaSourcePlayerGstreamer* player =
184 static_cast<MediaSourcePlayerGstreamer*>(user_data);
185 if (!player || player->IsPlayerDestructing())
187 player->OnReadDemuxedData(media::DemuxerStream::AUDIO);
190 static void OnGstStopAudioFeedCB(GstAppSrc* pipeline, void* user_data) {
191 MediaSourcePlayerGstreamer* player =
192 static_cast<MediaSourcePlayerGstreamer*>(user_data);
193 if (!player || player->IsPlayerDestructing())
195 player->OnStopDemuxedData(media::DemuxerStream::AUDIO);
198 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
199 static void OnVideoSinkCapsChangedCB(
201 GParamSpec* gparamspec,
203 MediaSourcePlayerGstreamer* player =
204 static_cast<MediaSourcePlayerGstreamer*>(user_data);
205 if (!player || player->IsPlayerDestructing())
207 player->OnVideoConfigsChanged();
211 MediaSourcePlayerGstreamer::MediaSourcePlayerGstreamer(
213 scoped_ptr<DemuxerEfl> demuxer,
214 MediaPlayerManager* manager)
215 : MediaPlayerEfl(player_id, manager),
216 demuxer_(demuxer.Pass()),
217 task_runner_(base::ThreadTaskRunnerHandle::Get()),
220 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
224 m_damage_handler_(0),
226 is_xwindow_handle_set_(false),
234 should_feed_audio_(true),
235 should_feed_video_(false),
242 is_paused_due_underflow_(false),
246 is_demuxer_seeking_(false),
249 is_download_finished_(false),
250 is_end_reached_(false),
251 error_occured_(false),
252 raw_video_frame_size_(0),
253 video_seek_offset_(0),
254 audio_seek_offset_(0),
255 is_seeking_iframe_(false) {
256 demuxer_->Initialize(this);
257 audio_buffer_queue_.clear();
258 video_buffer_queue_.clear();
259 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
260 efl_pixmaps_map_.clear();
264 void MediaSourcePlayerGstreamer::Destroy() {
265 if (IsPlayerDestructing())
270 task_runner_->DeleteSoon(FROM_HERE, this);
273 void MediaSourcePlayerGstreamer::Play() {
274 if (!pipeline_ || error_occured_)
276 if (play_rate_ == 0.0) {
280 #if defined(OS_TIZEN_MOBILE)
281 WakeUpDisplayAndAcquireDisplayLock();
284 gst_element_set_state(pipeline_, GST_STATE_PLAYING);
285 StartCurrentTimeUpdateTimer();
287 is_paused_due_underflow_ = false;
290 void MediaSourcePlayerGstreamer::Pause(bool is_media_related_action) {
291 if (!pipeline_ || error_occured_)
294 gst_element_set_state(pipeline_, GST_STATE_PAUSED);
295 StopCurrentTimeUpdateTimer();
296 if (!is_media_related_action) {
297 #if defined(OS_TIZEN_MOBILE)
298 ReleaseDisplayLock();
300 is_paused_due_underflow_ = false;
305 void MediaSourcePlayerGstreamer::SetRate(double rate) {
306 if (play_rate_ == rate)
314 // If rate was zero and requested rate is non-zero, change the paused state
315 if (play_rate_ == 0.0 && rate != 0.0) {
317 StartCurrentTimeUpdateTimer();
322 RequestPlayerSeek(GetCurrentTime());
325 void MediaSourcePlayerGstreamer::RequestPlayerSeek(double seekTime) {
326 if (is_demuxer_seeking_)
328 GstState state = GST_STATE_VOID_PENDING;
329 gst_element_get_state(pipeline_, &state, NULL, 250 * GST_NSECOND);
330 is_demuxer_seeking_ = true;
331 if (state == GST_STATE_PLAYING)
333 manager()->OnRequestSeek(GetPlayerId(), seekTime);
336 void MediaSourcePlayerGstreamer::Seek(const double time) {
337 GstState state = GST_STATE_VOID_PENDING;
338 gst_element_get_state(pipeline_, &state, NULL, 250 * GST_NSECOND);
340 is_seeking_iframe_ = false;
341 is_demuxer_seeking_ = true;
342 if (state == GST_STATE_PLAYING)
345 // Input to |FromMicroseconds| is |int64|. Additional multiplication
346 // is done to avoid data loss.
347 base::TimeDelta seek_time = base::TimeDelta::FromMicroseconds(
348 static_cast<int64>(time * base::Time::kMicrosecondsPerSecond));
349 demuxer_->RequestDemuxerSeek(seek_time);
352 void MediaSourcePlayerGstreamer::SeekInternal(const GstClockTime position) {
353 if (!pipeline_ || error_occured_)
356 GstClockTime startTime = 0, endTime = position;
358 is_demuxer_seeking_ = false;
360 if (play_rate_ > 0) {
361 startTime = position;
362 endTime = GST_CLOCK_TIME_NONE;
365 UpdateSeekState(true);
366 audio_buffer_queue_.clear();
367 video_buffer_queue_.clear();
368 if (!gst_element_seek(pipeline_, play_rate_, GST_FORMAT_TIME,
369 static_cast<GstSeekFlags>(GST_SEEK_FLAG_FLUSH |
370 GST_SEEK_FLAG_ACCURATE),
371 GST_SEEK_TYPE_SET, startTime, GST_SEEK_TYPE_SET,
373 LOG(ERROR) << "Seek to " << position << " failed";
374 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
378 double MediaSourcePlayerGstreamer::GetCurrentTime() {
379 if (!pipeline_ || error_occured_)
382 gint64 current_time = 0;
383 GstFormat format = GST_FORMAT_TIME;
384 gst_element_query_position(pipeline_, format, ¤t_time);
385 return ConvertNanoSecondsToSeconds(current_time);
388 void MediaSourcePlayerGstreamer::Release() {
389 DCHECK(IsPlayerDestructing());
391 StopCurrentTimeUpdateTimer();
392 audio_buffer_queue_.clear();
393 video_buffer_queue_.clear();
396 GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline_));
398 g_signal_handlers_disconnect_by_func(
400 reinterpret_cast<gpointer>(GstPipelineMessageCB),
402 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
403 gst_object_unref(bus);
406 gst_element_set_state(pipeline_, GST_STATE_NULL);
407 gst_object_unref(pipeline_);
411 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
412 UnregisterDamageHandler();
413 efl_pixmaps_map_.clear();
417 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
418 void MediaSourcePlayerGstreamer::UnregisterDamageHandler() {
420 ecore_x_damage_free(m_damage_);
423 if (m_damage_handler_) {
424 ecore_event_handler_del(m_damage_handler_);
425 m_damage_handler_ = 0;
430 void MediaSourcePlayerGstreamer::SetVolume(double volume) {
432 g_object_set(G_OBJECT(audio_volume_), "volume", volume, NULL);
435 void MediaSourcePlayerGstreamer::OnDemuxerConfigsAvailable(
436 const DemuxerConfigs& configs) {
437 if (IsPlayerDestructing())
441 GstElement* video_parse = NULL;
442 GstElement* video_decoder = NULL;
445 GstElement* audio_decoder = NULL;
446 GstElement* audio_parse = NULL;
447 GstElement* audio_convert = NULL;
448 GstElement* audio_resampler = NULL;
449 GstElement* audio_sink = NULL;
451 if ((configs.video_codec == kUnknownVideoCodec ||
452 configs.video_codec != kCodecH264) &&
453 (configs.audio_codec == kUnknownAudioCodec ||
454 (configs.audio_codec != kCodecAAC &&
455 configs.audio_codec != kCodecMP3))) {
456 LOG(ERROR) << "Audio and Video codecs not supported for MediaSource";
457 HandleError(MediaPlayerEfl::NetworkStateFormatError);
461 width_ = configs.video_size.width();
462 height_ = configs.video_size.height();
464 if (pipeline_ != NULL)
467 if (!gst_is_initialized())
468 gst_init_check(NULL, NULL, 0);
470 if (!gst_is_initialized()) {
471 LOG(ERROR) << "Unable to initialize GST";
472 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
476 pipeline_ = gst_pipeline_new(kPipelineName);
478 LOG(ERROR) << "Unable to Create |Pipeline|";
479 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
483 for (int i = 0; VideoMapping[i].codec != kUnknownVideoCodec; i++) {
484 if (configs.video_codec == VideoMapping[i].codec) {
485 media_type_ |= MEDIA_VIDEO_MASK;
486 video_appsrc_ = gst_element_factory_make("appsrc", "video-source");
487 if (video_appsrc_ && !gst_bin_add(GST_BIN(pipeline_), video_appsrc_)) {
488 gst_object_unref(video_appsrc_);
489 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
492 video_parse = gst_element_factory_make(VideoMapping[i].elements[0],
494 if (video_parse && !gst_bin_add(GST_BIN(pipeline_), video_parse)) {
495 gst_object_unref(video_parse);
496 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
499 video_queue_ = gst_element_factory_make("queue2", "video-queue");
500 if (video_queue_ && !gst_bin_add(GST_BIN(pipeline_), video_queue_)) {
501 gst_object_unref(video_queue_);
502 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
505 video_decoder = gst_element_factory_make(VideoMapping[i].elements[1],
507 if (video_decoder && !gst_bin_add(GST_BIN(pipeline_), video_decoder)) {
508 gst_object_unref(video_decoder);
509 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
512 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
513 PrepareForVideoSink();
516 PrepareForVideoFrame();
518 if (video_sink_ && !gst_bin_add(GST_BIN(pipeline_), video_sink_)) {
519 gst_object_unref(video_sink_);
520 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
524 g_object_set(GST_OBJECT(video_appsrc_), "format", GST_FORMAT_TIME,
526 g_object_set(GST_OBJECT(video_appsrc_), "stream-type",
527 GST_APP_STREAM_TYPE_SEEKABLE, NULL);
528 g_object_set(GST_OBJECT(video_appsrc_), "do-timestamp", false, NULL);
530 // Will make the queue to send GST_MESSAGE_BUFFERING
531 g_object_set(G_OBJECT(video_queue_), "use-buffering", true, NULL);
533 // Why |video_queue_| is placed after |video_appsrc_|?
534 // For understanding puprose consider http://tinyurl.com/qos-iron url.
535 // For 1080p resolution of the video in above url, each decoded frame
536 // is of size 2304000 bytes ~ 2.19 MB. If video_queue_ is placed before
537 // |video_sink_| then queue will buffer decoded frames, so to buffer
538 // two second worth of data queue will require 2304000*24(fps)*2 ~ 96MB
539 // of queue size. This property can't be set for pixmap backed playback
540 // as frame size won't be available for pixmap backed |video_sink|. And
541 // this size varies from video to video.
543 // But if |video_queue_| is placed after |video_appsrc_|, queue will
544 // buffer encoded data. For the same video of 1080p, maximum encoded
545 // frame is of 115398byte ~ 0.110052109 MB. So for 2 sec data, queue
546 // need to buffer 5308308bytes in queue ~ 5MB, this can be set
547 // dynamically. Refer |OnDemuxerDataAvailable| for setting queue size.
549 if (!gst_element_link_many(video_appsrc_, video_queue_, video_parse,
550 video_decoder, video_sink_, NULL)) {
551 LOG(ERROR) << "Video pipeline couldn't be created / linked";
552 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
556 GstAppSrcCallbacks video_callbacks = {
557 OnGstStartVideoFeedCB,
558 OnGstStopVideoFeedCB,
559 OnGstSeekVideoFeedCB,
562 gst_app_src_set_callbacks(GST_APP_SRC(video_appsrc_), &video_callbacks,
568 for (int i = 0; AudioMapping[i].codec != kUnknownAudioCodec; i++) {
569 if (configs.audio_codec == AudioMapping[i].codec) {
570 media_type_ |= MEDIA_AUDIO_MASK;
571 audio_appsrc_ = gst_element_factory_make("appsrc", "audio-source");
572 if (audio_appsrc_ && !gst_bin_add(GST_BIN(pipeline_), audio_appsrc_)) {
573 gst_object_unref(audio_appsrc_);
574 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
578 audio_queue_ = gst_element_factory_make("queue2", "audio-queue");
579 if (audio_queue_ && !gst_bin_add(GST_BIN(pipeline_), audio_queue_)) {
580 gst_object_unref(audio_queue_);
581 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
585 audio_parse = gst_element_factory_make(AudioMapping[i].elements[0],
587 if (audio_parse && !gst_bin_add(GST_BIN(pipeline_), audio_parse)) {
588 gst_object_unref(audio_parse);
589 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
593 audio_decoder = gst_element_factory_make(AudioMapping[i].elements[1],
595 if (audio_decoder && !gst_bin_add(GST_BIN(pipeline_), audio_decoder)) {
596 gst_object_unref(audio_decoder);
597 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
601 audio_convert = gst_element_factory_make("audioconvert",
603 if (audio_convert && !gst_bin_add(GST_BIN(pipeline_), audio_convert)) {
604 gst_object_unref(audio_convert);
605 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
609 audio_resampler = gst_element_factory_make("audioresample",
611 if (audio_resampler &&
612 !gst_bin_add(GST_BIN(pipeline_), audio_resampler)) {
613 gst_object_unref(audio_resampler);
614 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
618 audio_volume_ = gst_element_factory_make("volume", "volume");
619 if (audio_volume_ && !gst_bin_add(GST_BIN(pipeline_), audio_volume_)) {
620 gst_object_unref(audio_volume_);
621 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
625 audio_sink = gst_element_factory_make(AudioMapping[i].elements[2],
627 if (audio_sink && !gst_bin_add(GST_BIN(pipeline_), audio_sink)) {
628 gst_object_unref(audio_sink);
629 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
633 g_object_set(GST_OBJECT(audio_appsrc_), "format", GST_FORMAT_TIME,
635 g_object_set(GST_OBJECT(audio_appsrc_), "stream-type",
636 GST_APP_STREAM_TYPE_SEEKABLE, NULL);
637 g_object_set(GST_OBJECT(audio_appsrc_), "do-timestamp", false, NULL);
638 g_object_set(G_OBJECT(audio_queue_), "use-buffering", true, NULL);
639 g_object_set(G_OBJECT(audio_volume_), "mute", false, NULL);
641 if (!gst_element_link_many(audio_appsrc_, audio_queue_, audio_parse,
642 audio_decoder, audio_convert,
643 audio_resampler, audio_volume_,
645 LOG(ERROR) << "Not all elements of audio pipeline could be linked";
646 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
649 GstAppSrcCallbacks audio_callbacks = {
650 OnGstStartAudioFeedCB,
651 OnGstStopAudioFeedCB,
652 OnGstSeekAudioFeedCB,
654 gst_app_src_set_callbacks(GST_APP_SRC(audio_appsrc_),
655 &audio_callbacks, this, NULL);
660 GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline_));
662 LOG(ERROR) << "GStreamer bus creation failed";
663 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
666 gst_bus_set_sync_handler(
668 static_cast<GstBusSyncHandler>(GstPipelineMessageCB),
671 gst_object_unref(bus);
673 manager()->OnMediaDataChange(GetPlayerId(), video_format_, height_,
674 width_, media_type_);
675 manager()->OnReadyStateChange(GetPlayerId(),
676 MediaPlayerEfl::ReadyStateHaveMetadata);
678 if (gst_element_set_state(pipeline_, GST_STATE_PAUSED) ==
679 GST_STATE_CHANGE_FAILURE) {
680 LOG(ERROR) << "GStreamer state change failed";
684 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
685 void MediaSourcePlayerGstreamer::PrepareForVideoSink() {
686 video_sink_ = gst_element_factory_make("xvimagesink", "sink");
687 DCHECK(video_sink_ != NULL) << "Failed to initialize xvimagesink.";
688 if (video_sink_ != NULL) {
689 GstPad* video_sink_pad = gst_element_get_static_pad(video_sink_, "sink");
690 if (!video_sink_pad) {
691 LOG(ERROR) << "GStreamer sink could not be obtained";
692 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
695 g_signal_connect(video_sink_pad, "notify::caps",
696 G_CALLBACK(OnVideoSinkCapsChangedCB), this);
697 gst_object_unref(video_sink_pad);
702 void MediaSourcePlayerGstreamer::PrepareForVideoFrame() {
703 is_xwindow_handle_set_ = true;
704 video_sink_ = gst_element_factory_make("appsink", "sink");
705 GstAppSinkCallbacks callbacks = {
709 gst_app_sink_set_callbacks(GST_APP_SINK(video_sink_),
710 &callbacks, this, NULL);
711 g_object_set(G_OBJECT(video_sink_), "max-buffers",
712 static_cast<guint>(1), NULL);
715 void MediaSourcePlayerGstreamer::ReadDemuxedData(
716 media::DemuxerStream::Type type) {
717 if (IsPlayerDestructing())
720 if (type == media::DemuxerStream::AUDIO) {
721 should_feed_audio_ = true;
722 } else if (type == media::DemuxerStream::VIDEO) {
723 should_feed_video_ = true;
725 LOG(ERROR) << "Unknown Media Type";
728 demuxer_->RequestDemuxerData(type);
731 void MediaSourcePlayerGstreamer::OnReadDemuxedData(
732 media::DemuxerStream::Type type) {
733 if (IsPlayerDestructing()) {
734 LOG(ERROR) << "GST is deinitializing. Just return";
737 task_runner_->PostTask(
738 FROM_HERE, base::Bind(&MediaSourcePlayerGstreamer::ReadDemuxedData,
739 base::Unretained(this),
743 void MediaSourcePlayerGstreamer::OnStopDemuxedData(
744 media::DemuxerStream::Type type) {
745 if (type == media::DemuxerStream::AUDIO)
746 should_feed_audio_ = false;
747 else if (type == media::DemuxerStream::VIDEO)
748 should_feed_video_ = false;
750 LOG(ERROR) << "Unknown media stream!";
753 void MediaSourcePlayerGstreamer::OnDemuxerDataAvailable(
754 base::SharedMemoryHandle foreign_memory_handle,
755 const media::DemuxedBufferMetaData& meta_data) {
756 if (!pipeline_ || error_occured_) {
757 LOG(ERROR) << "Pipeline_ null or error occured";
760 if (meta_data.status != media::DemuxerStream::kOk ||
761 meta_data.end_of_stream)
762 BufferMetaDataAvailable(meta_data);
763 if (meta_data.size <= 0) {
764 LOG(ERROR) << "ERROR : Size of shared memory is Zero";
768 int64 metadata_timestamp_in_ms = meta_data.timestamp.InMicroseconds() * 1000;
769 if (is_seeking_ && !is_seeking_iframe_) {
770 if (meta_data.type == media::DemuxerStream::VIDEO) {
771 is_seeking_iframe_ = true;
772 if (video_seek_offset_ >
773 static_cast<guint64>(metadata_timestamp_in_ms)) {
774 int64 time = metadata_timestamp_in_ms + kSixteenMilliSeconds;
775 RequestPlayerSeek(ConvertNanoSecondsToSeconds(time));
778 } else if (meta_data.type == media::DemuxerStream::AUDIO) {
779 if (audio_seek_offset_ >
780 static_cast<guint64>(metadata_timestamp_in_ms))
785 ReadFromQueueIfAny(meta_data.type);
786 if (meta_data.type == media::DemuxerStream::VIDEO) {
787 if (meta_data.size != raw_video_frame_size_) {
788 // Dynamically Changing Video Queue Size for Smooth Playback.
789 // The default queue size limits are 100 buffers, 2MB of data,
790 // or two seconds worth of data, whichever is reached first.
791 // Adjust queue to contain two seconds worth of data for smooth playback.
792 // So need to adjust number of buffers (max-size-buffers >= 2*fps) and
793 // maximum size of queue (max-size-bytes >= 2*fps*meta_data.size).
795 // 1000000 micro seconds = 1 second.
796 // 2097152 bytes = 2 MB.
797 int no_frames_per_two_second , queue_size_for_two_sec;
798 raw_video_frame_size_ = meta_data.size;
799 no_frames_per_two_second = 2 * (1000000 /
800 (meta_data.time_duration.InMicroseconds()));
801 queue_size_for_two_sec =
802 raw_video_frame_size_ * no_frames_per_two_second;
803 if (no_frames_per_two_second > 100) {
804 g_object_set(G_OBJECT(video_queue_), "max-size-buffers",
805 static_cast<guint>(no_frames_per_two_second), NULL);
807 if (queue_size_for_two_sec > 2 * kBytesPerMegabyte) {
808 g_object_set(G_OBJECT(video_queue_), "max-size-bytes",
809 static_cast<guint>(queue_size_for_two_sec), NULL);
813 if (meta_data.type == media::DemuxerStream::AUDIO && !should_feed_audio_) {
814 // Why store the DecoderBuffer? we have requested for buffer
815 // from demuxer but gstreamer asked to stop. So need to save
816 // this buffer and use it on next |need_data| call.
817 SaveDecoderBuffer(foreign_memory_handle, meta_data);
820 if (meta_data.type == media::DemuxerStream::VIDEO && !should_feed_video_) {
821 SaveDecoderBuffer(foreign_memory_handle, meta_data);
825 // Wrapping each frame and deleting shared memory using callback
826 // will not work as possibility of Gstreamer retaining frames (such as
827 // 'i' frames) is high. In that case shared memory will crash. So, we
828 // copy frames and release shared memory right away.
830 base::SharedMemory shared_memory(foreign_memory_handle, false);
831 if (!shared_memory.Map(meta_data.size)) {
832 LOG(ERROR) << "Failed to map shared memory of size " << meta_data.size;
835 gint size = meta_data.size;
836 GstFlowReturn ret = GST_FLOW_OK;
837 GstBuffer* buffer = gst_buffer_new_allocate(NULL, size, NULL);
838 gst_buffer_fill(buffer, 0, shared_memory.memory(), size);
840 GST_BUFFER_TIMESTAMP(buffer) =
841 static_cast<guint64>(metadata_timestamp_in_ms);
842 GST_BUFFER_DURATION(buffer) =
843 static_cast<guint64>(meta_data.time_duration.InMicroseconds() * 1000);
845 if (meta_data.type == media::DemuxerStream::AUDIO)
846 ret = gst_app_src_push_buffer(GST_APP_SRC(audio_appsrc_),
848 else if (meta_data.type == media::DemuxerStream::VIDEO)
849 ret = gst_app_src_push_buffer(GST_APP_SRC(video_appsrc_),
852 // gst_app_src_push_buffer() takes ownership of the buffer.
853 // Hence no need to unref buffer.
854 if (ret != GST_FLOW_OK) {
855 LOG(ERROR) << "Gstreamer appsrc push failed : " << ret;
859 if (meta_data.type == media::DemuxerStream::AUDIO && should_feed_audio_)
860 OnReadDemuxedData(media::DemuxerStream::AUDIO);
861 else if (meta_data.type == media::DemuxerStream::VIDEO && should_feed_video_)
862 OnReadDemuxedData(media::DemuxerStream::VIDEO);
866 void MediaSourcePlayerGstreamer::BufferMetaDataAvailable(
867 const media::DemuxedBufferMetaData& meta_data) {
868 if (!pipeline_ || error_occured_) {
869 LOG(ERROR) << "Pipeline_ null or error occured";
873 switch (meta_data.status) {
874 case media::DemuxerStream::kAborted:
875 if (meta_data.type == media::DemuxerStream::AUDIO && should_feed_audio_)
876 OnReadDemuxedData(media::DemuxerStream::AUDIO);
877 else if (meta_data.type == media::DemuxerStream::VIDEO &&
879 OnReadDemuxedData(media::DemuxerStream::VIDEO);
882 case media::DemuxerStream::kConfigChanged:
883 if (meta_data.type == media::DemuxerStream::AUDIO && should_feed_audio_)
884 OnReadDemuxedData(media::DemuxerStream::AUDIO);
885 else if (meta_data.type == media::DemuxerStream::VIDEO &&
887 OnReadDemuxedData(media::DemuxerStream::VIDEO);
890 case media::DemuxerStream::kOk:
891 if (meta_data.end_of_stream) {
892 ReadFromQueueIfAny(meta_data.type);
893 LOG(ERROR) <<"[BROWSER] : DemuxerStream::kOk but |end_of_stream|";
894 if (meta_data.type == media::DemuxerStream::AUDIO)
895 gst_app_src_end_of_stream(GST_APP_SRC(audio_appsrc_));
896 if (meta_data.type == media::DemuxerStream::VIDEO)
897 gst_app_src_end_of_stream(GST_APP_SRC(video_appsrc_));
908 void MediaSourcePlayerGstreamer::ReadFromQueueIfAny(
909 DemuxerStream::Type type) {
910 if (!pipeline_ || error_occured_) {
911 LOG(ERROR) << "Pipeline_ null or error occured";
915 if (type == media::DemuxerStream::AUDIO) {
916 if (audio_buffer_queue_.empty() || !should_feed_audio_)
920 if (type == media::DemuxerStream::VIDEO) {
921 if (video_buffer_queue_.empty() || !should_feed_video_)
925 scoped_refptr<DecoderBuffer> decoder_buffer;
926 if (type == media::DemuxerStream::AUDIO) {
927 decoder_buffer = audio_buffer_queue_.front();
928 audio_buffer_queue_.pop_front();
930 decoder_buffer = video_buffer_queue_.front();
931 video_buffer_queue_.pop_front();
934 // Wrapping each frame and deleting shared memory using callback
935 // will not work as possibility of Gstreamer retaining frames (such as
936 // 'i' frames) is high. In that case shared memory will crash. So, we
937 // copy frames and release shared memory right away.
940 gint size = decoder_buffer.get()->data_size();
941 GstBuffer* buffer = gst_buffer_new_allocate(NULL, size, NULL);
945 gst_buffer_fill(buffer, 0, decoder_buffer.get()->writable_data(), size);
947 GST_BUFFER_TIMESTAMP(buffer) =
948 static_cast<guint64>(decoder_buffer.get()->timestamp().InMicroseconds() *
950 GST_BUFFER_DURATION(buffer) =
951 static_cast<guint64>(decoder_buffer.get()->duration().InMicroseconds() *
954 if (type == media::DemuxerStream::AUDIO)
955 ret = gst_app_src_push_buffer(GST_APP_SRC(audio_appsrc_), buffer);
957 ret = gst_app_src_push_buffer(GST_APP_SRC(video_appsrc_), buffer);
958 if (ret != GST_FLOW_OK)
961 // Empty the Buffer before reading the new buffer from render process.
962 ReadFromQueueIfAny(type);
966 void MediaSourcePlayerGstreamer::SaveDecoderBuffer(
967 base::SharedMemoryHandle foreign_memory_handle,
968 const media::DemuxedBufferMetaData& meta_data) {
969 if (!pipeline_ || error_occured_) {
970 LOG(ERROR) << "Pipeline_ null or error occured";
974 base::SharedMemory shared_memory(foreign_memory_handle, false);
975 if (!shared_memory.Map(meta_data.size)) {
976 LOG(ERROR) << "Failed to map shared memory of size " << meta_data.size;
979 scoped_refptr<DecoderBuffer> buffer;
980 buffer = DecoderBuffer::CopyFrom(static_cast<const uint8*> (
981 shared_memory.memory()), meta_data.size);
984 LOG(ERROR) << "DecoderBuffer::CopyFrom failed";
988 buffer->set_timestamp(meta_data.timestamp);
989 buffer->set_duration(meta_data.time_duration);
991 if (meta_data.type == media::DemuxerStream::AUDIO)
992 audio_buffer_queue_.push_back(buffer);
994 video_buffer_queue_.push_back(buffer);
997 void MediaSourcePlayerGstreamer::GetFrameDetails() {
998 if (!pipeline_ || error_occured_)
1001 GstState state = GST_STATE_VOID_PENDING;
1002 GstState pending = GST_STATE_VOID_PENDING;
1003 gst_element_get_state(pipeline_, &state, &pending, 250 * GST_NSECOND);
1005 // Get details only after prerolling.
1006 if (pending >= GST_STATE_PAUSED)
1007 task_runner_->PostTask(
1009 base::Bind(&MediaSourcePlayerGstreamer::OnGetFrameDetails,
1010 base::Unretained(this)));
1013 void MediaSourcePlayerGstreamer::OnGetFrameDetails() {
1014 if (!pipeline_ || IsPlayerDestructing() || error_occured_)
1017 GstSample* sample = gst_app_sink_pull_preroll(GST_APP_SINK(video_sink_));
1021 if (!GetGstVideoBufferMetaData(sample, &width_,
1022 &height_, &video_format_)) {
1023 gst_sample_unref(sample);
1027 gst_sample_unref(sample);
1029 if (video_format_ == GST_VIDEO_SN12)
1030 sn12_bufsize_ = GetSN12BufferSize(width_, height_);
1032 manager()->OnMediaDataChange(GetPlayerId(), video_format_, height_,
1033 width_, media_type_);
1036 GstSample* MediaSourcePlayerGstreamer::PullSample() {
1037 return gst_app_sink_pull_sample(GST_APP_SINK(video_sink_));
1040 void MediaSourcePlayerGstreamer::OnNewFrameAvailable(GstSample* sample) {
1044 if (!pipeline_ || error_occured_) {
1045 gst_sample_unref(sample);
1050 GstBuffer* buffer = gst_sample_get_buffer(sample);
1051 if (!gst_buffer_map(buffer, &map, GST_MAP_READ)) {
1052 LOG(ERROR) << "Sample contains invalid or no info!";
1056 if (!width_ || !height_)
1060 if (!GetGstVideoBufferMetaData(sample, &width,
1062 gst_sample_unref(sample);
1066 if (width != width_ || height != height_) {
1069 manager()->OnMediaDataChange(GetPlayerId(), video_format_, height_,
1070 width_, media_type_);
1072 base::SharedMemory shared_memory;
1073 uint32 shared_memory_size = 0;
1074 base::SharedMemoryHandle foreign_memory_handle;
1076 base::TimeDelta timestamp =
1077 base::TimeDelta::FromMicroseconds(
1078 GST_BUFFER_TIMESTAMP(buffer) /
1079 base::Time::kNanosecondsPerMicrosecond);
1081 if (video_format_ == GST_VIDEO_SN12)
1082 shared_memory_size = (sn12_bufsize_);
1084 shared_memory_size = (map.size);
1086 if (!shared_memory.CreateAndMapAnonymous(shared_memory_size)) {
1087 LOG(ERROR) << "Shared Memory creation failed.";
1088 gst_buffer_unmap(buffer, &map);
1089 gst_sample_unref(sample);
1093 if (!shared_memory.ShareToProcess(base::Process::Current().Handle(),
1094 &foreign_memory_handle)) {
1095 LOG(ERROR) << "Shared Memory handle could not be obtained";
1096 gst_buffer_unmap(buffer, &map);
1097 gst_sample_unref(sample);
1101 memcpy(shared_memory.memory(), map.data, shared_memory_size);
1102 manager()->OnNewFrameAvailable(
1103 GetPlayerId(), foreign_memory_handle, shared_memory_size, timestamp);
1105 gst_buffer_unmap(buffer, &map);
1106 gst_sample_unref(sample);
1109 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
1110 void MediaSourcePlayerGstreamer::XWindowIdPrepared(GstMessage* message) {
1111 const GstStructure* structure = gst_message_get_structure(message);
1113 gst_structure_get_int(structure, "video-width", &width_);
1114 gst_structure_get_int(structure, "video-height", &height_);
1116 manager()->OnMediaDataChange(GetPlayerId(), video_format_, height_,
1117 width_, media_type_);
1120 void MediaSourcePlayerGstreamer::PlatformSurfaceUpdated() {
1121 gint64 current_time = 0;
1122 GstFormat format = GST_FORMAT_TIME;
1123 gst_element_query_position(pipeline_, format, ¤t_time);
1124 base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds(
1125 current_time / base::Time::kNanosecondsPerMicrosecond);
1126 manager()->OnPlatformSurfaceUpdated(GetPlayerId(), pixmap_id_, timestamp);
1129 int MediaSourcePlayerGstreamer::GetSurfaceID() const {
1133 void MediaSourcePlayerGstreamer::SetPixmap() {
1134 #if defined(OS_TIZEN_TV)
1135 // Using below statements on mobile to set pixmap was causing two issue.
1136 // 1. Video size was different than the required one whenever configaration
1138 // 2. Sometime black screen was appearing, while video was playing.
1139 // Hence for mobile keeping implementation which uses
1140 // |gst_x_overlay_set_window_handle|to sep Pixmap.
1141 g_object_set(video_sink_, "pixmap-id-callback", GetPixmapIdCB, NULL);
1142 g_object_set(video_sink_, "pixmap-id-callback-userdata", this, NULL);
1144 gst_x_overlay_set_window_handle(GST_X_OVERLAY(video_sink_), pixmap_id_);
1146 m_damage_ = ecore_x_damage_new(pixmap_id_,
1147 ECORE_X_DAMAGE_REPORT_RAW_RECTANGLES);
1148 m_damage_handler_ = ecore_event_handler_add(ECORE_X_EVENT_DAMAGE_NOTIFY,
1149 NotifyDamageUpdatedCB, this);
1150 g_object_set(video_sink_, "rotate", 0, NULL);
1151 is_xwindow_handle_set_ = true;
1154 void MediaSourcePlayerGstreamer::OnVideoConfigsChanged() {
1155 if (!pipeline_ || error_occured_)
1157 task_runner_->PostTask(
1159 base::Bind(&MediaSourcePlayerGstreamer::VideoConfigsChanged,
1160 base::Unretained(this)));
1163 void MediaSourcePlayerGstreamer::VideoConfigsChanged() {
1164 if (!pipeline_ || IsPlayerDestructing() || error_occured_)
1167 GstPad* video_sink_pad = gst_element_get_static_pad(video_sink_, "sink");
1168 GstCaps* caps = gst_pad_get_current_caps(GST_PAD(video_sink_pad));
1170 LOG(ERROR) << "Cannot get CAPS!";
1171 gst_object_unref(video_sink_pad);
1176 gst_video_info_init(&info);
1177 if (!gst_video_info_from_caps(&info, caps)) {
1178 LOG(ERROR) << "Cannot get information from CAPS!";
1179 gst_caps_unref(caps);
1180 gst_object_unref(video_sink_pad);
1184 if ((width_ != info.width) || (height_ != info.height)) {
1185 LOG(ERROR) << "Demuxer Video Configs and Gstreamer Video Configs doesn't"
1186 <<" match.From Demuxer : width : " << width_
1187 << " and height :" << height_
1188 << " | From Gstreamer width : " << info.width
1189 << " and Height : " << info.height;
1190 width_ = info.width;
1191 height_ = info.height;
1192 UnregisterDamageHandler();
1195 manager()->OnMediaDataChange(
1196 GetPlayerId(), video_format_, height_, width_, media_type_);
1198 gst_caps_unref(caps);
1199 gst_object_unref(video_sink_pad);
1202 void MediaSourcePlayerGstreamer::CreatePixmap() {
1203 bool is_create_new = efl_pixmaps_map_.empty();
1204 int int_wh = GetUniqueKey(width_, height_);
1206 if (!is_create_new) {
1207 EflPixmapMap::iterator it = efl_pixmaps_map_.find(int_wh);
1208 if (it != efl_pixmaps_map_.end()) {
1209 is_create_new = false;
1210 efl_pixmap_ = it->second;
1211 pixmap_id_ = efl_pixmap_->GetId();
1213 is_create_new = true;
1217 if (is_create_new) {
1218 efl_pixmap_ = gfx::EflPixmap::Create(gfx::EflPixmap::SURFACE,
1219 gfx::Size(width_, height_));
1220 if (!efl_pixmap_.get()) {
1221 LOG(ERROR) << "gfx::EflPixmap::Create() failed to create Pixmap";
1224 pixmap_id_ = efl_pixmap_->GetId();
1225 efl_pixmaps_map_[int_wh] = efl_pixmap_;
1230 void MediaSourcePlayerGstreamer::OnDemuxerDurationChanged(
1231 base::TimeDelta duration) {
1232 duration_ = duration.InSecondsF();
1235 void MediaSourcePlayerGstreamer::OnDemuxerSeekDone(
1236 const base::TimeDelta& actual_browser_seek_time) {
1237 SeekInternal(ConvertToGstClockTime(actual_browser_seek_time.InSecondsF()));
1240 bool MediaSourcePlayerGstreamer::HasVideo() {
1241 return media_type_ & MEDIA_VIDEO_MASK;
1244 bool MediaSourcePlayerGstreamer::HasAudio() {
1245 return media_type_ & MEDIA_AUDIO_MASK;
1248 void MediaSourcePlayerGstreamer::OnCurrentTimeUpdateTimerFired() {
1249 manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime());
1252 void MediaSourcePlayerGstreamer::StartCurrentTimeUpdateTimer() {
1253 if (!current_time_update_timer_.IsRunning()) {
1254 current_time_update_timer_.Start(
1256 base::TimeDelta::FromMilliseconds(kDurationUpdateInterval),
1258 &MediaSourcePlayerGstreamer::OnCurrentTimeUpdateTimerFired);
1262 void MediaSourcePlayerGstreamer::StopCurrentTimeUpdateTimer() {
1263 if (current_time_update_timer_.IsRunning())
1264 current_time_update_timer_.Stop();
1267 void MediaSourcePlayerGstreamer::HandleMessage(GstMessage* message) {
1268 if (!pipeline_ || error_occured_)
1271 switch (GST_MESSAGE_TYPE(message)) {
1272 case GST_MESSAGE_ERROR: {
1273 GError* error = NULL;
1274 MediaPlayerEfl::NetworkState network_state_error =
1275 MediaPlayerEfl::NetworkStateEmpty;
1276 gst_message_parse_error(message, &error, NULL);
1277 if (error->code == GST_STREAM_ERROR_CODEC_NOT_FOUND ||
1278 error->code == GST_STREAM_ERROR_WRONG_TYPE ||
1279 error->code == GST_STREAM_ERROR_FAILED ||
1280 error->code == GST_RESOURCE_ERROR_NOT_FOUND) {
1281 network_state_error = MediaPlayerEfl::NetworkStateFormatError;
1282 } else if (error->domain == GST_RESOURCE_ERROR) {
1283 network_state_error = MediaPlayerEfl::NetworkStateNetworkError;
1285 network_state_error = MediaPlayerEfl::NetworkStateDecodeError;
1288 LOG(ERROR) << "Error Message : " << error->message << " Recieved From : "
1289 << GST_MESSAGE_SRC_NAME(message)
1290 << ", and Blink Error Code = " << network_state_error;
1291 g_error_free(error);
1292 HandleError(network_state_error);
1295 case GST_MESSAGE_EOS:
1296 task_runner_->PostTask(FROM_HERE, base::Bind(
1297 &MediaSourcePlayerGstreamer::OnPlaybackComplete,
1298 base::Unretained(this)));
1300 case GST_MESSAGE_ASYNC_DONE:
1302 is_seeking_iframe_ = false;
1303 task_runner_->PostTask(
1305 base::Bind(&MediaSourcePlayerGstreamer::UpdateSeekState,
1306 base::Unretained(this),
1309 // Initiate play for internal seeks.
1311 task_runner_->PostTask(FROM_HERE,
1312 base::Bind(&MediaSourcePlayerGstreamer::Play,
1313 base::Unretained(this)));
1315 manager()->OnTimeUpdate(GetPlayerId(), GetCurrentTime());
1316 task_runner_->PostTask(
1318 base::Bind(&MediaSourcePlayerGstreamer::OnTimeChanged,
1319 base::Unretained(this)));
1322 case GST_MESSAGE_STATE_CHANGED:
1323 if (strcmp(kPipelineName, GST_MESSAGE_SRC_NAME(message)))
1325 task_runner_->PostTask(
1327 base::Bind(&MediaSourcePlayerGstreamer::OnUpdateStates,
1328 base::Unretained(this)));
1330 case GST_MESSAGE_BUFFERING: {
1332 gst_message_parse_buffering(message, &buffered);
1334 if (audio_queue_ && GST_MESSAGE_SRC(message) ==
1335 GST_OBJECT(audio_queue_))
1336 audio_buffered_ = buffered;
1337 else if (video_queue_ && GST_MESSAGE_SRC(message) ==
1338 GST_OBJECT(video_queue_))
1339 video_buffered_ = buffered;
1342 task_runner_->PostTask(
1344 base::Bind(&MediaSourcePlayerGstreamer::HandleBufferingMessage,
1345 base::Unretained(this)));
1349 case GST_MESSAGE_ELEMENT:
1350 #if defined(TIZEN_MULTIMEDIA_PIXMAP_SUPPORT)
1351 if (!IsXWindowHandleSet() &&
1352 gst_is_video_overlay_prepare_window_handle_message(message)) {
1353 XWindowIdPrepared(message);
1362 void MediaSourcePlayerGstreamer::OnUpdateStates() {
1363 DCHECK(task_runner_->BelongsToCurrentThread());
1364 if (!pipeline_ || IsPlayerDestructing() || error_occured_)
1367 GstState state = GST_STATE_VOID_PENDING;
1368 GstState pending = GST_STATE_VOID_PENDING;
1369 GstStateChangeReturn ret = gst_element_get_state(
1370 pipeline_, &state, &pending, 250 * GST_NSECOND);
1373 case GST_STATE_CHANGE_SUCCESS:
1375 case GST_STATE_PAUSED:
1376 manager()->OnReadyStateChange(
1378 MediaPlayerEfl::ReadyStateHaveEnoughData);
1384 case GST_STATE_CHANGE_FAILURE:
1385 LOG(ERROR) << "Failure: State: "
1386 << gst_element_state_get_name(state)
1388 << gst_element_state_get_name(pending);
1389 HandleError(MediaPlayerEfl::NetworkStateDecodeError);
1391 case GST_STATE_CHANGE_NO_PREROLL:
1397 void MediaSourcePlayerGstreamer::HandleBufferingMessage() {
1398 if (IsPlayerDestructing())
1400 if (!is_paused_due_underflow_ &&
1401 ((HasAudio() && audio_buffered_ < kMaxBufPercent) ||
1402 (HasVideo() && video_buffered_ < kMaxBufPercent))) {
1403 is_paused_due_underflow_ = true;
1405 manager()->OnReadyStateChange(
1407 MediaPlayerEfl::ReadyStateHaveCurrentData);
1408 manager()->OnNetworkStateChange(
1410 MediaPlayerEfl::NetworkStateLoading);
1411 } else if (is_paused_due_underflow_ &&
1412 (!HasAudio() || audio_buffered_ == kMaxBufPercent) &&
1413 (!HasVideo() || video_buffered_ == kMaxBufPercent)) {
1414 is_paused_due_underflow_ = false;
1416 manager()->OnReadyStateChange(
1418 MediaPlayerEfl::ReadyStateHaveEnoughData);
1419 manager()->OnNetworkStateChange(
1421 MediaPlayerEfl::NetworkStateLoaded);
1425 void MediaSourcePlayerGstreamer::OnPlaybackComplete() {
1426 // GStreamer pipeline EOS time and media duration doesnt match.
1427 double time = GetCurrentTime() != duration_ ? duration_ : GetCurrentTime();
1428 is_end_reached_ = true;
1429 is_download_finished_ = false;
1430 StopCurrentTimeUpdateTimer();
1431 manager()->OnTimeUpdate(GetPlayerId(), time);
1432 manager()->OnTimeChanged(GetPlayerId());
1433 #if defined(OS_TIZEN_MOBILE)
1434 ReleaseDisplayLock();
1438 void MediaSourcePlayerGstreamer::UpdateSeekState(bool state) {
1439 manager()->OnSeekStateChange(GetPlayerId(), state);
1440 is_seeking_ = state;
1443 void MediaSourcePlayerGstreamer::OnTimeChanged() {
1444 DCHECK(task_runner_->BelongsToCurrentThread());
1445 manager()->OnTimeChanged(GetPlayerId());
1448 void MediaSourcePlayerGstreamer::HandleError(
1449 media::MediaPlayerEfl::NetworkState state) {
1450 error_occured_ = true;
1451 manager()->OnNetworkStateChange(GetPlayerId(), state);
1452 #if defined(OS_TIZEN_MOBILE)
1453 ReleaseDisplayLock();
1457 } // namespace media