kOk,
kAborted,
kConfigChanged,
+#if defined(TIZEN_MULTIMEDIA)
+ kNeedBuffer,
+#endif
kError,
kStatusMax = kError,
};
// Return early without calling |read_cb_| since we don't have
// any data to return yet.
DVLOG(2) << __func__ << ": returning kNeedBuffer, type " << type_;
+#if defined(TIZEN_MULTIMEDIA)
+ status = DemuxerStream::kNeedBuffer;
+ buffer = nullptr;
+ break;
+#else
return;
+#endif
case SourceBufferStreamStatus::kEndOfStream:
status = DemuxerStream::kOk;
buffer = StreamParserBuffer::CreateEOSBuffer();
return;
}
+#if defined(TIZEN_MULTIMEDIA)
+ if (status == Status::kNeedBuffer) {
+ LOG(INFO) << __func__ << ": kNeedBuffer!";
+ std::move(callback).Run(Status::kNeedBuffer, mojom::DecoderBufferPtr(),
+ audio_config, video_config);
+ return;
+ }
+#endif
+
if (status == Status::kAborted) {
std::move(callback).Run(Status::kAborted, mojom::DecoderBufferPtr(),
audio_config, video_config);
return;
}
+#if defined(TIZEN_MULTIMEDIA)
+ if (status == kNeedBuffer) {
+ std::move(read_cb_).Run(kNeedBuffer, nullptr);
+ return;
+ }
+#endif
+
DCHECK_EQ(status, kOk);
mojo_decoder_buffer_reader_->ReadDecoderBuffer(
std::move(buffer), base::BindOnce(&MojoDemuxerStreamAdapter::OnBufferRead,
bool WebMediaPlayerImpl::IsEnded() const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
+#if defined(TIZEN_MULTIMEDIA)
+ return (ended_ || (CurrentTime() >= Duration()));
+#else
return ended_;
+#endif
}
WebMediaPlayer::NetworkState WebMediaPlayerImpl::GetNetworkState() const {
--- /dev/null
+// Copyright (c) 2022 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STATIC_MAP_H
+#define BASE_STATIC_MAP_H
+
+#include <type_traits>
+#include <unordered_map>
+
+// |StaticMap| is a map which resemebles std::unordered_map (ie. has no element
+// order) but can inline values for given keys for fast access. Because
+// everything is calculated at compile time this has a drawback of using only
+// types which match non-type template parameter for a key type.
+// This can be especially useful for enumeration types where you know you will
+// need to frequently access values for some predefined keys but need some sort
+// of fallback in other cases.
+//
+// Template of declaration of |StaticMap| should contain |KeyType| and
+// |ValueType| (duh) then a |StaticKeys| with template containing KeyType and
+// then values of keys storage you want to inline, then optionally a
+// |DynamicMapType| which will be used when key is not present in static part of
+// the map, this defaults to std::unordered_map. For |DynamicMapType| you can
+// also use |UseDefaultValue| which will return the same value (by const&) for
+// any key. Example declarations:
+//
+// StaticMap<SomeEnumT, size_t, StaticKeys<SomeEnumT, SomeEnumT::Important,
+// SomeEnumT::EquallyImportant>>
+// - this defines a map from SomeEnumT to size_t, with SomeEnumT::Important and
+// SomeEnumT::EquallyImportant inlined. Both map values are default initialized
+// and as a fallback std::unordered_map<SomeEnumT, size_t> is used.
+// StaticMap<OtherEnumT, Clazz*, StaticKeys<OtherEnumT, OtherEnumT::Quick>,
+// UseDefaultValue<Clazz*>>
+// - this map will map OtherEnumT to Clazz*, but only allows modification of
+// OtherEnumT::Quick key. Other return nullptr.
+//
+// You can access elements of the map by using operator[], which will behave
+// like normal operator[] when using std::unordered_map fallback; this means no
+// const version. To access inlined elements in const context you can use
+// get<key>(), which will check if key is indeed stored inlined.
+// The fun thing is, with |UseDefaultValue| you get const version of operator[]
+// so you can use it anywhere.
+// To check whether element is present use count().
+//
+// TODO: iterators and other map interfaces.
+
+namespace base {
+
+// Scroll down for |StaticMap| implementation here are utilities
+
+// |DoesTemplateContain| is a type trait (i.e. it defines static boolean member
+// |value|), checking, if the first value template argument is also among the
+// rest of the template parameter pack. This is used as a helper in
+// |IsTemplateSet| type trait to guarantee the static map keys are unique.
+template <class T, T... Tail>
+struct DoesTemplateContain;
+
+template <class T, T Value>
+struct DoesTemplateContain<T, Value> : std::false_type {};
+
+template <class T, T Value, T Head>
+struct DoesTemplateContain<T, Value, Head>
+ : std::integral_constant<bool, Value == Head> {};
+
+template <class T, T Value, T Head, T... Tail>
+struct DoesTemplateContain<T, Value, Head, Tail...>
+ : std::integral_constant<
+ bool,
+ DoesTemplateContain<T, Value, Head>::value ||
+ DoesTemplateContain<T, Value, Tail...>::value> {};
+
+static_assert(!DoesTemplateContain<int, 1>::value, "Test failed");
+static_assert(DoesTemplateContain<int, 1, 1>::value, "Test failed");
+static_assert(!DoesTemplateContain<int, 2, 1>::value, "Test failed");
+static_assert(DoesTemplateContain<int, 1, 1, 1, 1, 1, 1>::value, "Test failed");
+static_assert(DoesTemplateContain<int, 1, 2, 2, 2, 2, 1>::value, "Test failed");
+
+// |IsTemplateSet| is a type trait checking, if the value parameter pack set
+// consists of unique values, that is, it can be used as a set of unique keys in
+// static map. As such, it is used in |StaticKeys| class.
+template <class T, T... Tail>
+struct IsTemplateSet;
+
+template <class T>
+struct IsTemplateSet<T> : std::true_type {};
+
+template <class T, T Head, T... Tail>
+struct IsTemplateSet<T, Head, Tail...>
+ : std::integral_constant<bool,
+ !DoesTemplateContain<T, Head, Tail...>::value &&
+ IsTemplateSet<T, Tail...>::value> {};
+
+static_assert(IsTemplateSet<int>::value, "Test failed");
+static_assert(IsTemplateSet<int, 2>::value, "Test failed");
+static_assert(IsTemplateSet<int, 2, 1>::value, "Test failed");
+static_assert(!IsTemplateSet<int, 1, 1>::value, "Test failed");
+static_assert(!IsTemplateSet<int, 1, 1, 1, 1, 1, 1>::value, "Test failed");
+static_assert(IsTemplateSet<int, 1, 2, 3, 4, 5, 6>::value, "Test failed");
+static_assert(!IsTemplateSet<int, 1, 2, 3, 4, 5, 1>::value, "Test failed");
+
+// Here is |StaticMap| implementation
+
+// |StaticKeys| are used for defining key values which storage should be
+// inlined. |StaticKeys| checks whether provided keys are not duplicated.
+template <class T, T... Values>
+struct StaticKeys {
+ static_assert(IsTemplateSet<T, Values...>::value, "Keys are duplicated!");
+ using KeyType = T;
+};
+
+template <class T>
+struct StaticKeys<T> {
+ // TODO: Make this fail, why use static map without static values...
+ // Right now it will fail in DynamicMap specialization.
+ // static_assert(!std::is_same<T,T>::value, "Static keys are empty");
+};
+
+template <class T>
+struct UseDefaultValue {
+ constexpr UseDefaultValue() : value() {}
+
+ template <class... Args>
+ explicit UseDefaultValue(Args&&... args)
+ : value(std::forward<Args>(args)...) {}
+
+ template <class KeyType>
+ const T& operator[](KeyType) const {
+ return value;
+ }
+
+ private:
+ const T value;
+};
+
+template <class K, class V>
+using DefaultDynamicMap = std::unordered_map<K, V>;
+
+// This is only to fail if StaticKeys were not used
+template <class KeyType,
+ class ValueType,
+ class StaticKeysT,
+ class DynamicMapType = DefaultDynamicMap<KeyType, ValueType>,
+ KeyType... keys>
+class StaticMap {
+ static_assert(std::is_same<StaticKeysT, StaticKeys<KeyType, keys...>>::value,
+ "You didn't use StaticKeys to pass compile time keys or the "
+ "type of it's values does not match KeyType");
+};
+
+// |DynamicMapType| version which uses this type for a fallback in case when key
+// is not inlined
+template <class KeyType, class ValueType, class DynamicMapType>
+class StaticMap<KeyType, ValueType, StaticKeys<KeyType>, DynamicMapType> {
+ public:
+ constexpr StaticMap() = default;
+ StaticMap(const StaticMap&) = default;
+ StaticMap(StaticMap&&) = default;
+ ~StaticMap() = default;
+
+ StaticMap& operator=(const StaticMap&) = default;
+ StaticMap& operator=(StaticMap&&) = default;
+
+ template <class... Args>
+ explicit StaticMap(Args&&... rest) : map_(std::forward<Args>(rest)...) {}
+
+ // This will should always fail, because DynamicMap won't provide keys at
+ // compile time
+ template <KeyType V>
+ ValueType& get() {
+ static_assert(!std::is_same<KeyType, decltype(V)>::value,
+ "There is no such compile time Key!");
+ }
+
+ template <KeyType V>
+ constexpr const ValueType& get() const {
+ static_assert(!std::is_same<KeyType, decltype(V)>::value,
+ "There is no such compile time Key!");
+ }
+
+ // Below functions will only exist if map_ defines matching operator[]
+ // This ugly monster is used to disable it for const DynamicMapType when this
+ // is not const
+ template <class U = DynamicMapType>
+ auto operator[](KeyType key) -> typename std::enable_if<
+ std::is_same<decltype(std::declval<U>()[key]), ValueType&>::value,
+ ValueType&>::type {
+ return map_[key];
+ }
+
+ template <class U = DynamicMapType>
+ auto operator[](KeyType key) const -> decltype(std::declval<const U>()[key]) {
+ static_assert(std::is_same<decltype(std::declval<const U>()[key]),
+ const ValueType&>::value,
+ "DynamicMapType::operator[] must return ValueType& or const "
+ "ValueType&");
+ return map_[key];
+ }
+
+ private:
+ DynamicMapType map_;
+};
+
+// Contains storage for given inlined key value and otherwise delegates to map_,
+// which could be again this or |DynamicMapType| version.
+template <class KeyType,
+ class ValueType,
+ class DynamicMapType,
+ KeyType key_value_,
+ KeyType... rest_of_keys_>
+class StaticMap<KeyType,
+ ValueType,
+ StaticKeys<KeyType, key_value_, rest_of_keys_...>,
+ DynamicMapType> {
+ // Make sure keys set is ok
+ static const StaticKeys<KeyType, key_value_, rest_of_keys_...> static_keys;
+
+ using InnerMapType = StaticMap<KeyType,
+ ValueType,
+ StaticKeys<KeyType, rest_of_keys_...>,
+ DynamicMapType>;
+
+ public:
+ using size_type = size_t;
+
+ constexpr StaticMap() : value_() {}
+ StaticMap(const StaticMap&) = default;
+ StaticMap(StaticMap&&) = default;
+ ~StaticMap() = default;
+
+ StaticMap& operator=(const StaticMap&) = default;
+ StaticMap& operator=(StaticMap&&) = default;
+
+ template <class T, class... Args>
+ explicit StaticMap(T&& arg, Args&&... rest)
+ : value_(std::forward<T>(arg)), map_(std::forward<Args>(rest)...) {}
+
+ // Compile time conditional on key value
+ template <KeyType V>
+ auto get() -> typename std::enable_if<V == key_value_, ValueType&>::type {
+ return value_;
+ }
+
+ template <KeyType V>
+ auto get() -> typename std::enable_if<V != key_value_, ValueType&>::type {
+ return map_.template get<V>();
+ }
+
+ template <KeyType V>
+ constexpr auto get() const ->
+ typename std::enable_if<V == key_value_, const ValueType&>::type {
+ return value_;
+ }
+
+ template <KeyType V>
+ constexpr auto get() const ->
+ typename std::enable_if<V != key_value_, const ValueType&>::type {
+ return map_.template get<V>();
+ }
+
+ // Below functions will only exist if map_ defines matching operator[]
+ template <class U = InnerMapType>
+ auto operator[](KeyType key) -> decltype(std::declval<U>()[key]) {
+ if (key == key_value_)
+ return value_;
+ return map_[key];
+ }
+
+ template <class U = InnerMapType>
+ auto operator[](KeyType key) const -> decltype(std::declval<const U>()[key]) {
+ if (key == key_value_)
+ return value_;
+ return map_[key];
+ }
+
+ // This is to mimic std::unordered_map and std::map interfaces
+ size_type count(KeyType key) const {
+ return key == key_value_ ? 1 : map_.count();
+ }
+
+ private:
+ ValueType value_;
+ InnerMapType map_;
+};
+
+} // namespace base
+#endif // BASE_STATIC_MAP_H
#include "tizen_src/chromium_impl/media/filters/media_player_esplusplayer.h"
namespace content {
-namespace {
-const float kDefaultVolume = 1.0;
-}
class TizenRendererImpl::RendererClientInternal final
: public media::RendererClient {
: state_(STATE_UNINITIALIZED),
task_runner_(task_runner),
sink_(sink),
- volume_(1.0),
- renderer_extension_receiver_(this),
- playback_rate_(0.0) {
+ renderer_extension_receiver_(this) {
// TODO(dalecurtis): Remove once experiments for http://crbug.com/470940 are
// complete.
int threshold_ms = 0;
weak_factory_.InvalidateWeakPtrs();
- // TODO
- if (init_cb_)
- ;
- else if (flush_cb_)
- ;
+ media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()->Release();
if (web_contents_observer_)
web_contents_observer_->RemoveMediaPlayerRenderer(this);
}
init_cb_ = std::move(init_cb);
media_resource_ = media_resource;
- if (!media::MediaPlayerESPlusPlayer::GetEsppPlayer()->Initialize(sink_)) {
+ if (!media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()
+ ->CreatePlayer()) {
std::move(init_cb_).Run(media::PIPELINE_ERROR_INITIALIZATION_FAILED);
return;
}
- std::move(init_cb_).Run(media::PIPELINE_OK);
-
// TODO: return unsupported error for CDM.
- state_ = STATE_INITIALIZING;
- media::MediaPlayerESPlusPlayer::GetEsppPlayer()->SetTaskRunner(
+ std::move(init_cb_).Run(media::PIPELINE_OK);
+ media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()->SetTaskRunner(
task_runner_.get());
- SetStreamInfo();
}
void TizenRendererImpl::SetStreamInfo() {
if (audio_stream_) {
audio_renderer_client_ = std::make_unique<RendererClientInternal>(
media::DemuxerStream::AUDIO, this);
- media::MediaPlayerESPlusPlayer::GetEsppPlayer()->SetStreamInfo(
+ media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()->SetStreamInfo(
media::DemuxerStream::AUDIO, audio_stream_,
audio_renderer_client_.get());
}
if (video_stream_) {
video_renderer_client_ = std::make_unique<RendererClientInternal>(
media::DemuxerStream::VIDEO, this);
- media::MediaPlayerESPlusPlayer::GetEsppPlayer()->SetStreamInfo(
+ media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()->SetStreamInfo(
media::DemuxerStream::VIDEO, video_stream_,
video_renderer_client_.get());
#if defined(TIZEN_TBM_SUPPORT)
- media::MediaPlayerESPlusPlayer::GetEsppPlayer()->SetFrameAvailableCallback(
- base::BindRepeating(&TizenRendererImpl::OnNewTbmFrameAvailable,
- base::Unretained(this)));
+ media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()
+ ->SetFrameAvailableCallback(
+ base::BindRepeating(&TizenRendererImpl::OnNewTbmFrameAvailable,
+ base::Unretained(this)));
#else
- media::MediaPlayerESPlusPlayer::GetEsppPlayer()->SetFrameAvailableCallback(
- base::BindRepeating(&TizenRendererImpl::OnNewFrameAvailable,
- base::Unretained(this)));
+ media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()
+ ->SetFrameAvailableCallback(base::BindRepeating(
+ &TizenRendererImpl::OnNewFrameAvailable, base::Unretained(this)));
#endif
}
}
flush_cb_ = std::move(flush_cb);
state_ = STATE_FLUSHING;
- media::MediaPlayerESPlusPlayer::GetEsppPlayer()->Flush(std::move(flush_cb));
+ media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()->Flush(
+ std::move(flush_cb));
}
void TizenRendererImpl::Seek(base::TimeDelta time) {
LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
<< " time : " << time.InMicroseconds();
- media::MediaPlayerESPlusPlayer::GetEsppPlayer()->Seek(time);
+ media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()->Seek(time);
}
void TizenRendererImpl::StartPlayingFrom(base::TimeDelta time) {
TRACE_EVENT1("media", "TizenRendererImpl::StartPlayingFrom", "time_us",
time.InMicroseconds());
+ if (!media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()
+ ->IsInitialized())
+ media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()->Initialize(
+ sink_);
+
+ if (!media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()
+ ->IsPrepared()) {
+ SetStreamInfo();
+ SetPlayerVolume();
+ media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()->Prepare();
+ }
+
+ state_ = STATE_INITIALIZING;
+ media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()->Seek(time);
state_ = STATE_PLAYING;
- media::MediaPlayerESPlusPlayer::GetEsppPlayer()->Prepare();
- media::MediaPlayerESPlusPlayer::GetEsppPlayer()->Seek(time);
}
void TizenRendererImpl::SetPlaybackRate(double playback_rate) {
- LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__ << "("
- << playback_rate << ")";
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__ << " "
+ << playback_rate << "/ " << playback_rate_;
DCHECK(task_runner_->BelongsToCurrentThread());
TRACE_EVENT1("media", "TizenRendererImpl::SetPlaybackRate", "rate",
playback_rate);
playback_rate_ = playback_rate;
// TODO: Random error is observed on TM1.
- // MediaPlayerESPlusPlayer::GetEsppPlayer()->SetRate(playback_rate_);
+ // MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()->SetRate(playback_rate_);
if (playback_rate > 0)
- media::MediaPlayerESPlusPlayer::GetEsppPlayer()->Play();
+ media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()->Play();
else
- media::MediaPlayerESPlusPlayer::GetEsppPlayer()->Pause();
+ media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()->Pause();
}
void TizenRendererImpl::SetVolume(float volume) {
return;
volume_ = volume;
- media::MediaPlayerESPlusPlayer::GetEsppPlayer()->SetVolume(volume);
+ SetPlayerVolume();
+}
+
+void TizenRendererImpl::SetPlayerVolume() const {
+ media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()->SetVolume(
+ volume_);
}
base::TimeDelta TizenRendererImpl::GetMediaTime() {
- return media::MediaPlayerESPlusPlayer::GetEsppPlayer()->GetCurrentTime();
+ return media::MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer()
+ ->GetCurrentTime();
}
void TizenRendererImpl::OnSelectedVideoTracksChanged(
}
void TizenRendererImpl::OnRendererEnded() {
+ playback_rate_ = 0.0;
client_->OnEnded();
}
void TizenRendererImpl::OnError(media::PipelineStatus error) {
+ playback_rate_ = 0.0;
state_ = STATE_ERROR;
client_->OnError(error);
}
private:
class RendererClientInternal;
+ const float kDefaultVolume = 1.0;
enum State {
STATE_UNINITIALIZED,
};
void SetStreamInfo();
+ void SetPlayerVolume() const;
void OnRendererEnded();
void OnError(media::PipelineStatus error);
void OnStatisticsUpdate(const media::PipelineStatistics& stats);
media::DemuxerStream* audio_stream_;
media::DemuxerStream* video_stream_;
- double volume_ = 0.0;
- double playback_rate_ = 0;
+ double volume_ = kDefaultVolume;
+ double playback_rate_ = 0.0;
// The time to start playback from after starting/seeking has completed.
base::TimeDelta start_time_;
media::BufferingState video_buffering_state_;
// Whether we've received the audio/video ended events.
- bool media_ended_;
- bool web_contents_muted_;
+ bool media_ended_ = false;
+ bool web_contents_muted_ = false;
mojo::Receiver<MediaPlayerRendererExtension> renderer_extension_receiver_;
raw_ptr<content::MediaPlayerRendererWebContentsObserver>
web_contents_observer_;
virtual void SetEos(DemuxerStream::Type) = 0;
virtual void UpdateBufferedSize(DemuxerStream::Type, espp_buffer_size_t) = 0;
virtual void ResetBufferStatus() = 0;
+ virtual void ResetBufferStatusCallbacks(esplusplayer_handle) = 0;
virtual int SetMediaStreamStatusCallback(
esplusplayer_handle,
esplusplayer_stream_type stream_type) = 0;
<< GetBuffer(DemuxerStream::VIDEO).buffer_percent << "%"
<< "\tAUDIO: " << GetBuffer(DemuxerStream::AUDIO).buffer_percent
<< "%";
-
+#if defined(OS_TIZEN_TV_PRODUCT)
+ // The buffer is controlled in time domain, however we want to stop
+ // pushing data in case of size overflow as well
+ buffer.has_size_overflow = (buffer_status == kBufferOverflow);
+ if (buffer.has_size_overflow == false)
+ return;
+#endif
CallbackIfNeed(type, buffer_status);
}
}
}
+void BufferObserverImpl::ResetBufferStatusCallbacks(
+ esplusplayer_handle player) {
+ esplusplayer_set_buffer_byte_status_cb(player, nullptr, this);
+ esplusplayer_set_buffer_time_status_cb(player, nullptr, this);
+ buffering_callback_.Reset();
+}
+
int BufferObserverImpl::SetBufferStatusCallbacks(
esplusplayer_handle player,
esplusplayer_stream_type type,
}
// FIXME: TM1 is giving wrong time size for pipeline.
-#if 0
+#if defined(OS_TIZEN_TV_PRODUCT)
if ((ret = esplusplayer_set_buffer_time_status_cb(
player, callbacks.time_status_cb, this)) !=
ESPLUSPLAYER_ERROR_TYPE_NONE) {
// |handler| will be invoked from player's thread.
void SetBufferingCallback(const BufferingCallback&) final;
+ void ResetBufferStatusCallbacks(esplusplayer_handle player) final;
void SetEos(DemuxerStream::Type) final;
void UpdateBufferedSize(DemuxerStream::Type, espp_buffer_size_t) final;
void ResetBufferStatus() final;
return PIPELINE_ERROR_DECODE;
}
+gfx::Size GetMaxCodecResolution(esplusplayer_video_mime_type mime_type) {
+ switch (mime_type) {
+ case ESPLUSPLAYER_VIDEO_MIME_TYPE_AV1:
+ return {k8KVideoMaxWidth, k8KVideoMaxHeight};
+ case ESPLUSPLAYER_VIDEO_MIME_TYPE_VP8:
+ return {kFHDVideoMaxWidth, kFHDVideoMaxHeight};
+ case ESPLUSPLAYER_VIDEO_MIME_TYPE_VP9:
+ case ESPLUSPLAYER_VIDEO_MIME_TYPE_HEVC:
+ return {k8KVideoMaxWidth, k8KVideoMaxHeight};
+ case ESPLUSPLAYER_VIDEO_MIME_TYPE_H264:
+ return {kFHDVideoMaxWidth, kFHDVideoMaxHeight};
+ default:
+ // for all kind of codecs.
+ return {kFHDVideoMaxWidth, kFHDVideoMaxHeight};
+ }
+}
+
} // namespace media
#include "media/base/pipeline_status.h"
#include "media/base/video_codecs.h"
#include "tizen_src/chromium_impl/media/filters/esplusplayer_buffer_observer.h"
+#include "ui/gfx/geometry/size.h"
namespace media {
const int kFHDVideoMaxHeight = 1080;
const int k4KVideoMaxWidth = 3840;
const int k4KVideoMaxHeight = 2160;
+const int k8KVideoMaxWidth = 7680;
+const int k8KVideoMaxHeight = 4320;
const int kMaxFramerate = 60;
const int kBuffingLimit = 5; // Seconds
PipelineStatus GetPipelineError(const esplusplayer_error_type error);
+gfx::Size GetMaxCodecResolution(esplusplayer_video_mime_type mime_type);
+
} // namespace media
#endif // MEDIA_FILTERS_ESPP_PLAYER_UTIL_H_
#include "third_party/libyuv/include/libyuv/convert.h"
namespace media {
+using player_buffer_size_t = unsigned long long;
+
+// Limit of platform player's total (audio and video) buffer size in bytes
+const media::player_buffer_size_t kPlayerTotalBufferSize = 64 * 1024 * 1024;
+// Limit of platform player's audio buffer in bytes
+const media::player_buffer_size_t kPlayerAudioBufferSize = 768 * 1024;
espp_buffer_size_t GetMaxAudioBufferSize() {
- // Assume MPEG-1 Audio Layer III 320kbit/s audio.
- return 320 * 1000 / 8 * kBuffingLimit;
+ return kPlayerAudioBufferSize;
}
espp_buffer_size_t GetMaxVideoBufferSize(gfx::Size size) {
- const int fps = 60; // Asume max.
-
- // Reference of buffer size estimation:
- // http://stackoverflow.com/questions/5024114/suggested-compression-ratio-with-h-264
- return static_cast<espp_buffer_size_t>(size.width()) * size.height() * fps *
- 2 * 7 / 100 / 8 * kBuffingLimit;
+ return kPlayerTotalBufferSize - kPlayerAudioBufferSize;
}
void ReadyToPrepareCallback(const esplusplayer_stream_type stream_type,
}
// static
-MediaPlayerESPlusPlayer* MediaPlayerESPlusPlayer::GetEsppPlayer() {
+MediaPlayerESPlusPlayer* MediaPlayerESPlusPlayer::GetMediaPlayerESPlusPlayer() {
return base::Singleton<MediaPlayerESPlusPlayer>::get();
}
esplayer_ = nullptr;
}
-bool MediaPlayerESPlusPlayer::Initialize(VideoRendererSink* sink) {
- if (esplayer_) {
- LOG(INFO) << "esplus player exists!";
- sink_ = sink;
+bool MediaPlayerESPlusPlayer::CreatePlayer() {
+ if (esplayer_)
return true;
- }
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
esplayer_ = esplusplayer_create();
if (!esplayer_) {
LOG(ERROR) << "Cannot create esplus player!";
return false;
}
+ last_frames_.get<DemuxerStream::AUDIO>().first = media::kNoTimestamp;
+ last_frames_.get<DemuxerStream::AUDIO>().second = media::kNoTimestamp;
+ last_frames_.get<DemuxerStream::VIDEO>().first = media::kNoTimestamp;
+ last_frames_.get<DemuxerStream::VIDEO>().second = media::kNoTimestamp;
+
+ buffer_observer_.reset(BufferObserver::CreateBufferObserver());
+
+ return true;
+}
+
+void MediaPlayerESPlusPlayer::Initialize(VideoRendererSink* sink) {
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
esplusplayer_set_ready_to_prepare_cb(esplayer_, &ReadyToPrepareCallback,
this);
esplusplayer_set_prepare_async_done_cb(esplayer_, &PrepareCompleteCallback,
esplusplayer_set_resource_conflicted_cb(esplayer_, &ResourceConflictCallback,
this);
esplusplayer_set_error_cb(esplayer_, &ErrorCallback, this);
+ buffer_observer_->SetBufferingCallback(
+ base::BindRepeating(&MediaPlayerESPlusPlayer::OnBufferingStatusChanged,
+ weak_factory_.GetWeakPtr()));
int error = esplusplayer_open(esplayer_);
if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
LOG(ERROR) << "esplusplayer_open failed. error #"
<< esplusplayer_get_error_string(
static_cast<esplusplayer_error_type>(error));
- return false;
+ return;
}
LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
<< " state:" << GetString(GetPlayerState());
- error = esplusplayer_set_video_frame_buffer_type(
- esplayer_, ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_COPY);
+
+ esplusplayer_decoded_video_frame_buffer_type video_frame_buffer_type =
+ ESPLUSPLAYER_DECODED_VIDEO_FRAME_BUFFER_TYPE_COPY;
+
+ error = esplusplayer_set_video_frame_buffer_type(esplayer_,
+ video_frame_buffer_type);
if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
LOG(ERROR) << "esplusplayer_set_video_frame_buffer_type failed. error #"
<< esplusplayer_get_error_string(
static_cast<esplusplayer_error_type>(error));
- return false;
+ return;
}
sink_ = sink;
- buffer_observer_.reset(BufferObserver::CreateBufferObserver());
- buffer_observer_->SetBufferingCallback(
- base::BindRepeating(&MediaPlayerESPlusPlayer::OnBufferingStatusChanged,
- weak_factory_.GetWeakPtr()));
- return true;
+}
+
+bool MediaPlayerESPlusPlayer::IsInitialized() {
+ return (GetPlayerState() >= ESPLUSPLAYER_STATE_IDLE);
}
void MediaPlayerESPlusPlayer::SetTaskRunner(
}
void MediaPlayerESPlusPlayer::Prepare() {
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+ if (is_prepared_ || is_preparing_)
+ return;
+
if (GetPlayerState() != ESPLUSPLAYER_STATE_IDLE) {
LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
<< " Prepare called on invalid state : "
->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
return;
}
+ is_preparing_ = true;
+}
+
+bool MediaPlayerESPlusPlayer::IsPrepared() {
+ return (GetPlayerState() >= ESPLUSPLAYER_STATE_READY);
+}
+
+void MediaPlayerESPlusPlayer::Release() {
+ if (!esplayer_)
+ return;
+
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+ SetIsEos(DemuxerStream::AUDIO, false);
+ SetShouldFeed(DemuxerStream::AUDIO, false);
+ SetIsValid(DemuxerStream::AUDIO, false);
+ SetReadRequested(DemuxerStream::AUDIO, false);
+
+ SetIsEos(DemuxerStream::VIDEO, false);
+ SetShouldFeed(DemuxerStream::VIDEO, false);
+ SetIsValid(DemuxerStream::VIDEO, false);
+ SetReadRequested(DemuxerStream::VIDEO, false);
+
+ esplusplayer_set_ready_to_prepare_cb(esplayer_, nullptr, this);
+ esplusplayer_set_prepare_async_done_cb(esplayer_, nullptr, this);
+ esplusplayer_set_eos_cb(esplayer_, nullptr, this);
+ esplusplayer_set_media_packet_video_decoded_cb(esplayer_, nullptr, this);
+ esplusplayer_set_flush_done_cb(esplayer_, nullptr, this);
+ esplusplayer_set_ready_to_seek_cb(esplayer_, nullptr, this);
+ esplusplayer_set_seek_done_cb(esplayer_, nullptr, this);
+ esplusplayer_set_resource_conflicted_cb(esplayer_, nullptr, this);
+ esplusplayer_set_error_cb(esplayer_, nullptr, this);
buffer_observer_->ResetBufferStatus();
+ buffer_observer_->ResetBufferStatusCallbacks(esplayer_);
+
+ volume_ = 1.0;
+ playback_rate_ = 0.0;
+ is_prepared_ = false;
+ is_preparing_ = false;
+ is_paused_ = true;
+ is_buffering_ = false;
+ current_position_ = base::TimeDelta();
+ is_flushing_ = false;
+ is_seeking_ = false;
+ seek_position_ = base::TimeDelta();
+ pending_seek_ = false;
+ pending_seek_position_ = base::TimeDelta();
+ should_set_playback_rate_ = false;
+
+ GetBufferQueue(DemuxerStream::VIDEO).clear();
+ GetBufferQueue(DemuxerStream::AUDIO).clear();
+ data_cb_.Reset();
+ sink_ = nullptr;
+
+ if (GetPlayerState() == ESPLUSPLAYER_STATE_NONE) {
+ LOG(ERROR) << "(" << static_cast<void*>(this) << ") " << __func__
+ << " Release called on invalid state : "
+ << GetString(GetPlayerState());
+ return;
+ }
+
+ esplusplayer_close(esplayer_);
}
void MediaPlayerESPlusPlayer::Play() {
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
int error = ESPLUSPLAYER_ERROR_TYPE_NONE;
esplusplayer_state state = GetPlayerState();
}
void MediaPlayerESPlusPlayer::Pause(bool is_media_related_action) {
+ if (is_paused_) {
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
+ << " already paused";
+ return;
+ }
+
if (!is_media_related_action)
is_paused_ = true;
}
void MediaPlayerESPlusPlayer::SetRate(double rate) {
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__ << " : "
+ << rate;
if (playback_rate_ == rate)
return;
}
void MediaPlayerESPlusPlayer::Seek(base::TimeDelta time) {
- if (GetCurrentTime() == time)
+ // Ignore seek to 0 during initialization.
+ if (GetPlayerState() < ESPLUSPLAYER_STATE_READY && time.InSecondsF() == 00) {
+ LOG(INFO) << __func__ << " Ignore seek to 0 during initialization.";
return;
+ }
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__ << " :"
+ << time;
if (GetPlayerState() < ESPLUSPLAYER_STATE_READY || !is_prepared_ ||
is_seeking_) {
LOG(INFO) << "Add to pending seek ("
return;
}
+ last_frames_.get<DemuxerStream::AUDIO>().first = media::kNoTimestamp;
+ last_frames_.get<DemuxerStream::VIDEO>().first = media::kNoTimestamp;
+
+ UpdateBufferedDtsDifference();
+
+ SetShouldFeed(DemuxerStream::AUDIO, false);
+ SetShouldFeed(DemuxerStream::VIDEO, false);
+ GetBufferQueue(DemuxerStream::VIDEO).clear();
+ GetBufferQueue(DemuxerStream::AUDIO).clear();
+ buffer_observer_->ResetBufferStatus();
+
LOG(INFO) << __func__ << " : " << time;
int error = esplusplayer_seek(esplayer_, time.InMilliseconds());
if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
}
is_seeking_ = true;
- pending_seek_ = false;
seek_position_ = time;
+ pending_seek_ = false;
pending_seek_position_ = base::TimeDelta();
}
void MediaPlayerESPlusPlayer::Flush(base::OnceClosure flush_cb) {
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+ last_frames_.get<DemuxerStream::AUDIO>().first = media::kNoTimestamp;
+ last_frames_.get<DemuxerStream::VIDEO>().first = media::kNoTimestamp;
+
+ UpdateBufferedDtsDifference();
+
NOTIMPLEMENTED();
std::move(flush_cb).Run();
}
void MediaPlayerESPlusPlayer::SetVolume(double volume) {
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__ << " :"
+ << volume;
volume_ = volume;
if (GetPlayerState() == ESPLUSPLAYER_STATE_NONE)
return;
}
base::TimeDelta MediaPlayerESPlusPlayer::GetCurrentTime() {
- if (GetPlayerState() < ESPLUSPLAYER_STATE_PLAYING)
- return base::TimeDelta();
+ if (pending_seek_)
+ return pending_seek_position_;
if (is_seeking_)
return seek_position_;
+ // Seek can be called before PLAY / PAUSE. Return last known time.
+ if (GetPlayerState() < ESPLUSPLAYER_STATE_PLAYING)
+ return current_position_;
+
uint64_t time = 0; // In milliseconds.
int error = esplusplayer_get_playing_time(esplayer_, &time);
if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
return base::TimeDelta();
}
- return base::Milliseconds(time);
+ current_position_ = base::Milliseconds(time);
+ return current_position_;
}
esplusplayer_state MediaPlayerESPlusPlayer::GetPlayerState() {
- return esplusplayer_get_state(esplayer_);
+ return (esplayer_ ? esplusplayer_get_state(esplayer_)
+ : ESPLUSPLAYER_STATE_NONE);
}
void MediaPlayerESPlusPlayer::InitializeStreamConfig(DemuxerStream::Type type) {
+ LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
DemuxerStream* stream = GetDemuxerStream(type);
CHECK(stream);
audio_stream_info.codec_data = NULL;
}
- int error =
- esplusplayer_set_audio_stream_info(esplayer_, &audio_stream_info);
- if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
- LOG(ERROR) << "esplusplayer_set_audio_stream_info failed. error code "
- << error;
- GetRendererClient(type)->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
- return;
+ int error;
+ if (!IsValid(type)) {
+ error = esplusplayer_set_audio_stream_info(esplayer_, &audio_stream_info);
+ if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
+ LOG(ERROR) << "esplusplayer_set_audio_stream_info failed. error code "
+ << error;
+ GetRendererClient(type)->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
+ return;
+ }
+ buffer_observer_->SetMediaStreamStatusCallback(
+ esplayer_, ESPLUSPLAYER_STREAM_TYPE_AUDIO);
}
espp_buffer_size_t max_buffer_size = GetMaxAudioBufferSize();
- buffer_observer_->SetMediaStreamStatusCallback(
- esplayer_, ESPLUSPLAYER_STREAM_TYPE_AUDIO);
buffer_observer_->SetBufferSize(type, max_buffer_size);
-
+ LOG(INFO) << "Audio Max buffer size " << max_buffer_size;
error = esplusplayer_set_buffer_size(
esplayer_, ESPLUSPLAYER_BUFFER_AUDIO_MAX_BYTE_SIZE, max_buffer_size);
if (error != ESPLUSPLAYER_ERROR_TYPE_NONE)
} else {
video_stream_info.codec_data = NULL;
}
-
- video_stream_info.max_width = k4KVideoMaxWidth;
- video_stream_info.max_height = k4KVideoMaxHeight;
-
- int error =
- esplusplayer_set_video_stream_info(esplayer_, &video_stream_info);
- if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
- LOG(ERROR) << "esplusplayer_set_video_stream_info failed. error code "
- << error;
- GetRendererClient(type)->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
- return;
+ auto max_resolution = GetMaxCodecResolution(video_stream_info.mime_type);
+
+ video_stream_info.max_width = max_resolution.width();
+ video_stream_info.max_height = max_resolution.height();
+
+ int error;
+ if (!IsValid(type)) {
+ error = esplusplayer_set_video_stream_info(esplayer_, &video_stream_info);
+ if (error != ESPLUSPLAYER_ERROR_TYPE_NONE) {
+ LOG(ERROR) << "esplusplayer_set_video_stream_info failed. error code "
+ << error;
+ GetRendererClient(type)->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
+ return;
+ }
+ buffer_observer_->SetMediaStreamStatusCallback(
+ esplayer_, ESPLUSPLAYER_STREAM_TYPE_VIDEO);
}
espp_buffer_size_t max_buffer_size =
GetMaxVideoBufferSize(video_config.coded_size());
- buffer_observer_->SetMediaStreamStatusCallback(
- esplayer_, ESPLUSPLAYER_STREAM_TYPE_VIDEO);
buffer_observer_->SetBufferSize(type, max_buffer_size);
+ LOG(INFO) << "Video Max buffer size " << max_buffer_size;
error = esplusplayer_set_buffer_size(
esplayer_, ESPLUSPLAYER_BUFFER_VIDEO_MAX_BYTE_SIZE, max_buffer_size);
if (error != ESPLUSPLAYER_ERROR_TYPE_NONE)
}
void MediaPlayerESPlusPlayer::ReadBuffer(DemuxerStream::Type type) {
- // TODO: Check and read from Queue.
+ if (!ReadFromBufferQueue(type))
+ return;
+
+ // Avoid unnecessary or redundant read requests.
if (!ShouldFeed(type) || ReadRequested(type))
return;
case DemuxerStream::kError:
GetBufferQueue(type).clear();
break;
+ case DemuxerStream::kNeedBuffer:
+ break;
case DemuxerStream::kConfigChanged:
// Clear pending buffer of older config
GetBufferQueue(type).clear();
InitializeStreamConfig(type);
break;
case DemuxerStream::kOk: {
- if (buffer.get()->end_of_stream()) {
- SubmitEosPacket(type);
- return;
- }
-
- SubmitEsPacket(type, std::move(buffer));
+ GetBufferQueue(type).push_back(buffer);
break;
}
}
ReadBuffer(type);
}
-void MediaPlayerESPlusPlayer::SubmitEosPacket(DemuxerStream::Type type) {
+bool MediaPlayerESPlusPlayer::ReadFromBufferQueue(DemuxerStream::Type type) {
+ if (!GetBufferQueue(type).size())
+ return true;
+
+ esplusplayer_submit_status status = ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS;
+ scoped_refptr<DecoderBuffer> buffer = GetBufferQueue(type).front();
+ if (buffer.get()->end_of_stream())
+ status = SubmitEosPacket(type);
+ else
+ status = SubmitEsPacket(type, buffer);
+
+ if (status == ESPLUSPLAYER_SUBMIT_STATUS_NOT_PREPARED ||
+ status == ESPLUSPLAYER_SUBMIT_STATUS_OUT_OF_MEMORY ||
+ status == ESPLUSPLAYER_SUBMIT_STATUS_FULL) {
+ return false;
+ }
+
+ UpdateBufferedDtsDifference();
+ GetBufferQueue(type).pop_front();
+ return true;
+}
+
+esplusplayer_submit_status MediaPlayerESPlusPlayer::SubmitEosPacket(
+ DemuxerStream::Type type) {
if (IsEos(type))
- return;
+ return ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS;
- esplusplayer_submit_status ret = esplusplayer_submit_eos_packet(
+ last_frames_[type].first = base::TimeDelta::Max();
+
+ esplusplayer_submit_status status = esplusplayer_submit_eos_packet(
esplayer_, GetESPlusPlayerStreamType(type));
- if (ret != ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS) {
+ if (status != ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS) {
LOG(ERROR) << "Submit Eos (" << DemuxerStream::GetTypeName(type)
- << ") Packet failed, ret:" << ret;
- return;
+ << ") Packet failed, ret:" << GetString(status);
+ return status;
}
-
buffer_observer_->SetEos(type);
SetIsEos(type, true);
+ return status;
}
-void MediaPlayerESPlusPlayer::SubmitEsPacket(
+esplusplayer_submit_status MediaPlayerESPlusPlayer::SubmitEsPacket(
DemuxerStream::Type type,
scoped_refptr<DecoderBuffer> buffer) {
esplusplayer_es_packet packet;
// This filed only set when PushMediaPacket
packet.matroska_color_info = nullptr;
- esplusplayer_submit_status ret =
+ esplusplayer_submit_status status =
esplusplayer_submit_packet(esplayer_, &packet);
- if (ret != ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS) {
- if (ret == ESPLUSPLAYER_SUBMIT_STATUS_FULL ||
- ret == ESPLUSPLAYER_SUBMIT_STATUS_OUT_OF_MEMORY ||
- ret == ESPLUSPLAYER_SUBMIT_STATUS_NOT_PREPARED) {
- GetBufferQueue(type).push_back(buffer);
- }
-
+ if (status != ESPLUSPLAYER_SUBMIT_STATUS_SUCCESS) {
LOG(WARNING) << "submit " << DemuxerStream::GetTypeName(type)
- << " packet : " << GetString(ret);
+ << " packet : " << GetString(status);
+ }
+
+ last_frames_[type].first = base::Milliseconds(packet.pts);
+ last_frames_[type].second = base::Milliseconds(packet.duration);
+ return status;
+}
+
+void MediaPlayerESPlusPlayer::UpdateBufferedDtsDifference() {
+ const auto& audio_ts = last_frames_.get<DemuxerStream::AUDIO>().first;
+ const auto& video_ts = last_frames_.get<DemuxerStream::VIDEO>().first;
+
+ if ((audio_ts != media::kNoTimestamp) && (video_ts != media::kNoTimestamp) &&
+ (audio_ts != base::TimeDelta::Max()) &&
+ (video_ts != base::TimeDelta::Max())) {
+ const auto av_diff = (audio_ts - video_ts).InMilliseconds();
+ buffer_observer_->SetAudioVideoDtsDifference(av_diff);
+ } else {
+ buffer_observer_->SetAudioVideoDtsDifference(0);
}
}
SetShouldFeed(type, true);
ReadBuffer(type);
break;
-
case kBufferMaxThreshold:
case kBufferOverflow:
case kBufferEos:
GetRendererClient(type)->OnBufferingStateChange(BUFFERING_HAVE_NOTHING,
DEMUXER_UNDERFLOW);
} else if (status == kBufferMaxThreshold || status == kBufferOverflow ||
- status == kBufferAhead) {
+ status == kBufferAhead || status == kBufferEos) {
GetRendererClient(type)->OnBufferingStateChange(
BUFFERING_HAVE_ENOUGH, BUFFERING_CHANGE_REASON_UNKNOWN);
}
}
LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
+ << " is_paused_ : " << is_paused_
<< " seek_position : " << seek_position_
<< " pending_seek_ : " << pending_seek_
<< " pending_seek_position_ : " << pending_seek_position_;
is_prepared_ = true;
if (pending_seek_) {
Seek(pending_seek_position_);
- pending_seek_position_ = base::TimeDelta();
+ } else if (!is_paused_) {
+ Play();
}
}
GetRendererClient(DemuxerStream::VIDEO)->OnEnded();
else if (IsValid(DemuxerStream::AUDIO))
GetRendererClient(DemuxerStream::AUDIO)->OnEnded();
+ Release();
}
void MediaPlayerESPlusPlayer::OnFrameReady(
<< " : " << seek_time;
SetShouldFeed(GetDemuxerStreamType(stream_type), true);
- SetReadRequested(GetDemuxerStreamType(stream_type), false);
+ SetIsEos(GetDemuxerStreamType(stream_type), false);
ReadBuffer(GetDemuxerStreamType(stream_type));
}
LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__
<< " is_paused:" << is_paused_;
+
+ current_position_ = seek_position_;
is_seeking_ = false;
+ seek_position_ = base::TimeDelta();
if (pending_seek_) {
Seek(pending_seek_position_);
pending_seek_position_ = base::TimeDelta();
GetRendererClient(DemuxerStream::VIDEO)->OnError(GetPipelineError(error));
else if (IsValid(DemuxerStream::AUDIO))
GetRendererClient(DemuxerStream::AUDIO)->OnError(GetPipelineError(error));
+ Release();
}
MediaPlayerESPlusPlayer::ElementryStream&
GetElementryStream(type).renderer_client_ = client;
}
-base::circular_deque<scoped_refptr<DecoderBuffer>>
-MediaPlayerESPlusPlayer::GetBufferQueue(DemuxerStream::Type type) {
+Queue& MediaPlayerESPlusPlayer::GetBufferQueue(DemuxerStream::Type type) {
return GetElementryStream(type).pending_buffers_;
}
const DataRequestCB& datacb) {
data_cb_ = datacb;
}
+
} // namespace media
#include "base/time/time.h"
#include "media/base/demuxer_stream.h"
#include "media/base/video_renderer_sink.h"
+#include "tizen_src/chromium_impl/base/tizen/static_map.h"
#include "tizen_src/chromium_impl/media/filters/esplusplayer_buffer_observer.h"
#include "tizen_src/chromium_impl/media/filters/esplusplayer_util.h"
class DemuxerStream;
class RendererClient;
+using Queue = base::circular_deque<scoped_refptr<DecoderBuffer>>;
+
// This class handles media source extensions for CAPI port.
class MEDIA_EXPORT MediaPlayerESPlusPlayer {
public:
- static MediaPlayerESPlusPlayer* GetEsppPlayer();
+ static MediaPlayerESPlusPlayer* GetMediaPlayerESPlusPlayer();
using DataRequestCB =
base::RepeatingCallback<void(uint32_t,
base::TimeDelta,
uint32_t,
uint32_t)>;
- bool Initialize(VideoRendererSink* sink);
+ bool CreatePlayer();
+ void Initialize(VideoRendererSink* sink);
+ bool IsInitialized();
void Prepare();
+ bool IsPrepared();
+ void Release();
+
void SetTaskRunner(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
void SetStreamInfo(DemuxerStream::Type type,
void OnBufferReady(DemuxerStream::Type type,
DemuxerStream::Status status,
scoped_refptr<DecoderBuffer> buffer);
- void SubmitEosPacket(DemuxerStream::Type type);
- void SubmitEsPacket(DemuxerStream::Type type,
- scoped_refptr<DecoderBuffer> buffer);
+ bool ReadFromBufferQueue(DemuxerStream::Type type);
+ esplusplayer_submit_status SubmitEosPacket(DemuxerStream::Type type);
+ esplusplayer_submit_status SubmitEsPacket(
+ DemuxerStream::Type type,
+ scoped_refptr<DecoderBuffer> buffer);
+ void UpdateBufferedDtsDifference();
ElementryStream& GetElementryStream(DemuxerStream::Type type);
const ElementryStream& GetElementryStream(DemuxerStream::Type type) const;
void SetDemuxerStream(DemuxerStream::Type type, DemuxerStream* stream);
RendererClient* GetRendererClient(DemuxerStream::Type type) const;
void SetRendererClient(DemuxerStream::Type type, RendererClient* client);
- base::circular_deque<scoped_refptr<DecoderBuffer>> GetBufferQueue(
- DemuxerStream::Type type);
+ Queue& GetBufferQueue(DemuxerStream::Type type);
esplusplayer_handle esplayer_ = nullptr;
+ // first -> pts, second -> duration
+ base::StaticMap<DemuxerStream::Type,
+ std::pair<base::TimeDelta, base::TimeDelta>,
+ base::StaticKeys<DemuxerStream::Type,
+ DemuxerStream::AUDIO,
+ DemuxerStream::VIDEO>>
+ last_frames_;
double volume_ = 1.0;
bool playback_rate_ = 0.0;
bool is_prepared_ = false;
+ bool is_preparing_ = false;
bool is_paused_ = true;
bool is_buffering_ = false;
+ base::TimeDelta current_position_;
bool is_flushing_ = false;
bool is_seeking_ = false;