#include "media/base/pipeline.h"
#endif
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+#include "base/command_line.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/common_types.h"
+#include "media/base/media_switches.h"
+#endif // defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+
namespace cc {
class Layer;
}
virtual bool IsGameMode() const = 0;
virtual bool IsLowLatencyMode() const = 0;
virtual bool IsVideoTextureMode() const = 0;
-#endif
+ virtual void OnLoadDeferredUntilSourceOpen() = 0;
+ content::elementary_media_stream_source::PipelineMode GetEmssPipelineMode()
+ const;
+#endif // defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
virtual void RemotePlaybackCompatibilityChanged(const WebURL&,
bool is_compatible) = 0;
~WebMediaPlayerClient() = default;
};
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+inline content::elementary_media_stream_source::PipelineMode
+WebMediaPlayerClient::GetEmssPipelineMode() const {
+ const auto demuxer_mode = ([&]() {
+ using DemuxerMode = content::elementary_media_stream_source::DemuxerMode;
+ return media::IsUpstreamArchitectureEnabled() ? DemuxerMode::kMediaStream
+ : DemuxerMode::kDataStream;
+ })();
+
+ const auto latency_mode = ([&]() {
+ using LatencyMode = content::elementary_media_stream_source::LatencyMode;
+ if (IsGameMode()) {
+ return LatencyMode::kUltraLow;
+ }
+ if (IsLowLatencyMode()) {
+ return LatencyMode::kLow;
+ }
+ return LatencyMode::kNormal;
+ })();
+
+ const auto player_mode = ([&]() {
+ using PlayerMode = content::elementary_media_stream_source::PlayerMode;
+ return IsVideoTextureMode() ? PlayerMode::kDecodeToTexture
+ : PlayerMode::kPlayer;
+ })();
+
+ return {demuxer_mode, latency_mode, player_mode};
+}
+#endif // defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+
} // namespace blink
#endif // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_MEDIA_PLAYER_CLIENT_H_
class WebString;
class WebVideoFrameSubmitter;
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+class WebElementaryMediaStreamSourceDispatcher;
+#endif // defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+
// WebMediaPlayerMS delegates calls from WebCore::MediaPlayerPrivate to
// Chrome's media player when "src" is from media stream.
//
void PaintDecodedVideoFrame(scoped_refptr<media::VideoFrame> decoded_frame);
#endif
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+ void StartLoadingEmss();
+ void OnEmssInitialized(
+ std::shared_ptr<WebElementaryMediaStreamSourceDispatcher>);
+ bool SourceHasTracks(const WebMediaPlayerSource& source);
+#endif // defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+
std::unique_ptr<MediaStreamInternalFrameWrapper> internal_frame_;
WebMediaPlayer::NetworkState network_state_;
DVLOG(2) << "parseAttribute(" << *this
<< ", kSrcAttr, old=" << params.old_value
<< ", new=" << params.new_value << ")";
+
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+ if (media_source_attachment_ &&
+ media_source_attachment_->IsElementaryMediaStreamSource()) {
+ // Contrary to WebRTC source which is set via `.srcObject` attribute, EMSS
+ // is set via `.src`. Clear fields that would be usually reset by changing
+ // `.srcObject` if EMSS was attached previously.
+ src_object_stream_descriptor_ = nullptr;
+ src_object_media_source_handle_ = nullptr;
+ }
+#endif // defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+
// A change to the src attribute can affect intrinsic size, which in turn
// requires a style recalc.
SetNeedsStyleRecalc(kLocalStyleChange,
void HTMLMediaElement::StartPlayerLoad() {
DCHECK(!web_media_player_);
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+ if (media_source_attachment_) {
+ if (auto* src_object_stream_descriptor =
+ media_source_attachment_->GetMediaStreamDescriptorIfAvailable(
+ media_source_tracer_)) {
+ src_object_stream_descriptor_ = src_object_stream_descriptor;
+ }
+ }
+#endif
+
WebMediaPlayerSource source;
if (src_object_stream_descriptor_) {
source =
media_source_attachment_->SetWebElementaryStreamSourceAndOpen(
media_source_tracer_, std::move(web_elementary_stream_source_dispatcher));
}
+
+void HTMLMediaElement::OnLoadDeferredUntilSourceOpen() {
+ media_source_attachment_->OnLoadDeferredUntilSourceOpen(
+ media_source_tracer_,
+ WTF::BindOnce(&HTMLMediaElement::FireDeferredLoadAfterSourceOpen,
+ WrapWeakPersistent(this)));
+}
+
+void HTMLMediaElement::FireDeferredLoadAfterSourceOpen() {
+ LOG(INFO) << "FireDeferredLoadAfterSourceOpen(" << *this << ")";
+
+ if (!web_media_player_ || !src_object_stream_descriptor_)
+ return;
+
+ auto source =
+ WebMediaPlayerSource(WebMediaStream(src_object_stream_descriptor_));
+ bool is_cache_disabled = false;
+ probe::IsCacheDisabled(GetDocument().GetExecutionContext(),
+ &is_cache_disabled);
+ web_media_player_->Load(GetLoadType(), source, CorsMode(), is_cache_disabled);
+}
#endif
bool HTMLMediaElement::IsInteractiveContent() const {
void ElementaryMediaStreamSourceOpened(
std::shared_ptr<WebElementaryMediaStreamSourceDispatcher>
web_elementary_stream_source_dispatcher) final;
+ void OnLoadDeferredUntilSourceOpen() final;
+ void FireDeferredLoadAfterSourceOpen();
#endif
void RemotePlaybackCompatibilityChanged(const WebURL&,
bool is_compatible) final;
class HTMLMediaElement;
class MediaSourceRegistry;
+class MediaStreamDescriptor;
class TrackBase;
class WebMediaSource;
virtual bool IsGameMode(MediaSourceTracer* tracer) const = 0;
virtual bool IsLowLatencyMode(MediaSourceTracer* tracer) const = 0;
virtual bool IsVideoTextureMode(MediaSourceTracer* tracer) const = 0;
+ virtual void OnLoadDeferredUntilSourceOpen(
+ MediaSourceTracer* tracer,
+ base::OnceClosure on_source_opened) = 0;
virtual void OnPause(MediaSourceTracer* tracer) = 0;
virtual void OnPlay(MediaSourceTracer* tracer) = 0;
virtual void OnResume(MediaSourceTracer* tracer) = 0;
virtual void UpdatePlaybackPosition(MediaSourceTracer* tracer,
double playback_position,
uint32_t session_id) = 0;
+ virtual MediaStreamDescriptor* GetMediaStreamDescriptorIfAvailable(
+ MediaSourceTracer* tracer) = 0;
#endif // defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
private:
return false;
}
+void MediaSourceAttachmentSupplement::OnLoadDeferredUntilSourceOpen(
+ MediaSourceTracer*,
+ base::OnceClosure) {}
+
void MediaSourceAttachmentSupplement::OnPause(MediaSourceTracer*) {}
void MediaSourceAttachmentSupplement::OnPlay(MediaSourceTracer*) {}
double,
uint32_t) {}
+MediaStreamDescriptor*
+MediaSourceAttachmentSupplement::GetMediaStreamDescriptorIfAvailable(
+ MediaSourceTracer*) {
+ return nullptr;
+}
+
#endif // defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
// protected
bool IsGameMode(MediaSourceTracer* tracer) const override;
bool IsLowLatencyMode(MediaSourceTracer* tracer) const override;
bool IsVideoTextureMode(MediaSourceTracer* tracer) const override;
+ void OnLoadDeferredUntilSourceOpen(
+ MediaSourceTracer* tracer,
+ base::OnceClosure on_source_opened) override;
void OnPause(MediaSourceTracer* tracer) override;
void OnPlay(MediaSourceTracer* tracer) override;
void OnResume(MediaSourceTracer* tracer) override;
void UpdatePlaybackPosition(MediaSourceTracer* tracer,
double playback_position,
uint32_t session_id) override;
+ MediaStreamDescriptor* GetMediaStreamDescriptorIfAvailable(
+ MediaSourceTracer* tracer) override;
#endif // defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
protected:
#include "third_party/blink/renderer/platform/wtf/cross_thread_copier_media.h"
#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer_dispatcher.h"
+#include "third_party/blink/renderer/platform/elementary_media_stream_source/web_elementary_media_stream_source_dispatcher.h"
+#endif // defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+
#if BUILDFLAG(IS_TIZEN)
#include "tizen/system_info.h"
#endif
return "MediaSource";
case WebMediaPlayer::kLoadTypeMediaStream:
return "MediaStream";
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+ case WebMediaPlayer::kLoadTypeSamsungElementaryMediaStreamSource:
+ return "ElementaryMediaStreamSource";
+#endif // defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
default:
return "Unknown type";
}
CorsMode /*cors_mode*/,
bool is_cache_disabled) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+ if (load_type ==
+ WebMediaPlayer::kLoadTypeSamsungElementaryMediaStreamSource &&
+ !SourceHasTracks(source)) {
+ LOG(INFO) << "Deferring load until EMSS opens...";
+ StartLoadingEmss();
+ return WebMediaPlayer::LoadTiming::kDeferred;
+ }
+#endif // defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
SendLogMessage(String::Format("%s({load_type=%s})", __func__,
LoadTypeToString(load_type)));
}
#endif
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+void WebMediaPlayerMS::StartLoadingEmss() {
+ using EmssDemuxerDispatcher =
+ ::content::elementary_media_stream_source::any_thread::DemuxerDispatcher;
+ client_->OnLoadDeferredUntilSourceOpen();
+ const auto emss_pipeline_mode = client_->GetEmssPipelineMode();
+ auto emss_demuxer_dispatcher = EmssDemuxerDispatcher::Create(
+ emss_pipeline_mode, base::SingleThreadTaskRunner::GetCurrentDefault());
+ auto [blink_source_dispatcher, any_thread_source_impl,
+ control_thread_source_impl, worker_thread_source_impl] =
+ WebElementaryMediaStreamSourceDispatcher::Create(
+ emss_pipeline_mode, base::SingleThreadTaskRunner::GetCurrentDefault(),
+ emss_demuxer_dispatcher->GetWorkerThreadTaskRunner());
+ blink_source_dispatcher->KeepDemuxerDispatcher(emss_demuxer_dispatcher);
+ emss_demuxer_dispatcher->RegisterSource(
+ std::move(any_thread_source_impl), std::move(control_thread_source_impl),
+ std::move(worker_thread_source_impl),
+ media::BindToCurrentLoop(WTF::BindOnce(
+ &WebMediaPlayerMS::OnEmssInitialized, weak_factory_.GetWeakPtr(),
+ std::move(blink_source_dispatcher))));
+}
+
+void WebMediaPlayerMS::OnEmssInitialized(
+ std::shared_ptr<WebElementaryMediaStreamSourceDispatcher>
+ web_elementary_media_stream_source_dispatcher) {
+ client_->ElementaryMediaStreamSourceOpened(
+ std::move(web_elementary_media_stream_source_dispatcher));
+}
+
+bool WebMediaPlayerMS::SourceHasTracks(const WebMediaPlayerSource& source) {
+ auto web_stream = source.GetAsMediaStream();
+ if (web_stream.IsNull())
+ return false;
+
+ MediaStreamDescriptor& descriptor = *web_stream;
+ return descriptor.VideoComponents().size() != 0 ||
+ descriptor.AudioComponents().size() != 0;
+}
+#endif // defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+
} // namespace blink
} else if (load_type_ == kLoadTypeSamsungElementaryMediaStreamSource) {
using EmssDemuxer = content::elementary_media_stream_source::any_thread::
ElementaryMediaStreamDemuxer;
- using PipelineMode = content::elementary_media_stream_source::PipelineMode;
-
- const auto demuxer_mode = ([&]() {
- using DemuxerMode = content::elementary_media_stream_source::DemuxerMode;
- return media::IsUpstreamArchitectureEnabled() ? DemuxerMode::kMediaStream
- : DemuxerMode::kDataStream;
- })();
-
- const auto latency_mode = ([&]() {
- using content::elementary_media_stream_source::LatencyMode;
- if (client_->IsGameMode()) {
- return LatencyMode::kUltraLow;
- }
- if (client_->IsLowLatencyMode()) {
- return LatencyMode::kLow;
- }
- return LatencyMode::kNormal;
- })();
-
- const auto player_mode = ([&]() {
- using content::elementary_media_stream_source::PlayerMode;
- if (client_->IsVideoTextureMode()) {
- // In Video Texture mode, we disable video hole functionality, to
- // force returning decoded frames from player instead of
- // presenting them on as screen.
- LOG(INFO) << "Disabling video hole in EMSS Video Texture mode";
- is_video_hole_ = false;
- return PlayerMode::kDecodeToTexture;
- }
- return PlayerMode::kPlayer;
- })();
+ using PlayerMode = content::elementary_media_stream_source::PlayerMode;
+
+ auto pipeline_mode = client_->GetEmssPipelineMode();
+
+ if (pipeline_mode.player_mode == PlayerMode::kDecodeToTexture) {
+ // In Video Texture mode, we disable video hole functionality, to
+ // force returning decoded frames from player instead of
+ // presenting them on as screen.
+ LOG(INFO) << "Disabling video hole in EMSS Video Texture mode";
+ is_video_hole_ = false;
+ }
auto elementary_stream_demuxer = std::make_unique<EmssDemuxer>(
- PipelineMode{demuxer_mode, latency_mode, player_mode},
+ pipeline_mode,
base::ThreadTaskRunnerHandle::Get(),
media::BindToCurrentLoop(base::BindOnce(
&WebMediaPlayerImpl::OnElementaryMediaStreamDemuxerOpened,
"mojo_shm_pool.h",
"mojom_media_type_converters.cc",
"mojom_media_type_converters.h",
+ "ms_decoding_stream.cc",
+ "ms_decoding_stream.h",
"packet.cc",
"packet.h",
"platform_demuxer_adapter.h",
return os;
}
+std::ostream& operator<<(std::ostream& os, LatencyMode latency_mode) {
+ switch (latency_mode) {
+ ENUM_VALUE_TO_OSTREAM(os, LatencyMode::kNormal);
+ ENUM_VALUE_TO_OSTREAM(os, LatencyMode::kLow);
+ ENUM_VALUE_TO_OSTREAM(os, LatencyMode::kUltraLow);
+ ENUM_DEFAULT_UNKNOWN(os, LatencyMode, latency_mode);
+ }
+ return os;
+}
+
std::ostream& operator<<(std::ostream& os, OperationResult result) {
switch (result) {
ENUM_VALUE_TO_OSTREAM(os, OperationResult::kOk);
std::ostream& operator<<(std::ostream&, DecodingMode);
std::ostream& operator<<(std::ostream&, DemuxerMode);
std::ostream& operator<<(std::ostream&, DemuxerSeekingState);
+std::ostream& operator<<(std::ostream&, LatencyMode);
std::ostream& operator<<(std::ostream&, OperationResult);
std::ostream& operator<<(std::ostream&, PlayerMode);
std::ostream& operator<<(std::ostream&, PlayerState);
public:
virtual ~Demuxer() = default;
- virtual void OnInitialConfigReadyForMediaStream(
+ // Special OnInitialConfigReady variant dedicated for media::Demuxer
+ // implementation.
+ virtual void OnInitialConfigReadyForMediaDemuxer(
MaybeAudioConfig audio_config,
MaybeVideoConfig video_config) = 0;
#include <cstddef>
#include <optional>
+#include "base/task/bind_post_task.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/thread_pool.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/common_types.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer_impl.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer_params.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/lockable_demuxer_state.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/ms_decoding_stream.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/platform_demuxer_adapter_client.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/source_impl.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/control_thread/demuxer_dispatcher_client.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/control_thread/demuxer_impl.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/control_thread/ms_decoding_stream.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/control_thread/source_impl.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/media_thread/platform_demuxer_adapter.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/data_stream_demuxer_impl.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/demuxer_dispatcher_client.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/demuxer_dispatcher_lifecycle_observer.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/media_stream_demuxer_impl.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/ms_decoding_stream.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/source_impl.h"
#include "mojo/public/cpp/bindings/remote.h"
+#include "platform/scheduler/public/thread.h"
#include "services/elementary_media_stream_source/public/cpp/logger.h"
#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/platform/scheduler/public/main_thread.h"
// generated sources:
#include "tizen_src/chromium_impl/services/elementary_media_stream_source/public/mojom/data_stream.mojom.h"
std::move(pending_data_stream_receiver)));
}
+void GetGpuFactoriesOnBlinkMainThread(
+ base::OnceCallback<void(media::GpuVideoAcceleratorFactories*)>
+ on_got_gpu_factories) {
+ auto* gpu_factories = blink::Platform::Current()->GetGpuFactories();
+ EMSS_LOG_ASSERT(gpu_factories) << "Cannot retrieve GPU Factories!";
+ std::move(on_got_gpu_factories).Run(gpu_factories);
+}
+
} // anonymous namespace
// static
DemuxerParams params(demuxer_dispatcher, pipeline_mode,
std::make_shared<LockableDemuxerState>());
- auto any_demuxer_impl = std::make_shared<any_thread::DemuxerImpl>(params);
- demuxer_dispatcher->SetClient<AnyThreadClient>(any_demuxer_impl);
- demuxer_dispatcher->SetClient<AnyThreadDemuxerAdapterClient>(
- std::move(any_demuxer_impl));
-
- auto control_demuxer_client =
- std::make_shared<control_thread::DemuxerImpl>(params);
- demuxer_dispatcher->SetClient<ControlThreadClient>(control_demuxer_client);
- demuxer_dispatcher->SetClient<ControlThreadDemuxerAdapterClient>(
- std::move(control_demuxer_client));
+ if (pipeline_mode.demuxer_mode == DemuxerMode::kMediaStream &&
+ pipeline_mode.latency_mode != LatencyMode::kNormal) {
+ SetAnyClients(demuxer_dispatcher,
+ std::make_shared<any_thread::MsDecodingStream>(params));
+ SetControlClients(
+ demuxer_dispatcher,
+ std::make_shared<control_thread::MsDecodingStream>(params));
+ } else {
+ SetAnyClients(demuxer_dispatcher,
+ std::make_shared<any_thread::DemuxerImpl>(params));
+ SetControlClients(demuxer_dispatcher,
+ std::make_shared<control_thread::DemuxerImpl>(params));
+ }
if (pipeline_mode.demuxer_mode == DemuxerMode::kDataStream) {
SetWorkerClients<worker_thread::DataStreamDemuxerImpl>(
pipeline_mode, demuxer_dispatcher,
std::move(maybe_pending_data_stream_src),
std::make_shared<worker_thread::DataStreamDemuxerImpl>(params));
- } else {
+ } else if (pipeline_mode.latency_mode == LatencyMode::kNormal) {
SetWorkerClients<worker_thread::MediaStreamDemuxerImpl>(
pipeline_mode, demuxer_dispatcher,
std::move(maybe_pending_data_stream_src),
std::make_shared<worker_thread::MediaStreamDemuxerImpl>(params));
+ } else {
+ auto worker_demuxer_impl =
+ std::make_shared<worker_thread::MsDecodingStream>(params);
+ auto weak_ms_decoding_stream =
+ std::weak_ptr<worker_thread::MsDecodingStream>{worker_demuxer_impl};
+ SetWorkerClients<worker_thread::MsDecodingStream>(
+ pipeline_mode, demuxer_dispatcher,
+ std::move(maybe_pending_data_stream_src),
+ std::move(worker_demuxer_impl));
+
+ blink::Thread::MainThread()->GetDeprecatedTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &GetGpuFactoriesOnBlinkMainThread,
+ base::BindPostTask(
+ demuxer_dispatcher->GetWorkerThreadTaskRunner(),
+ base::BindOnce(
+ [](std::weak_ptr<worker_thread::MsDecodingStream>
+ weak_ms_decoding_stream,
+ media::GpuVideoAcceleratorFactories* gpu_factories) {
+ if (auto ms_decoding_stream =
+ weak_ms_decoding_stream.lock()) {
+ ms_decoding_stream->SetGpuFactories(gpu_factories);
+ }
+ },
+ std::move(weak_ms_decoding_stream)))));
}
return demuxer_dispatcher;
SetClient(platform_demuxer_adapter);
}
+void DemuxerDispatcher::RegisterSource(
+ std::shared_ptr<any_thread::SourceImpl> any_thread_source_impl,
+ std::shared_ptr<control_thread::SourceImpl> control_thread_source_impl,
+ std::shared_ptr<worker_thread::SourceImpl> worker_thread_source_impl,
+ base::OnceClosure on_emss_initialized) {
+ RunTask(&any_thread::PlatformDemuxerAdapterClient::RegisterSource,
+ std::static_pointer_cast<any_thread::DemuxerClient>(
+ std::move(any_thread_source_impl)));
+ DispatchTask(&control_thread::PlatformDemuxerAdapterClient::RegisterSource,
+ std::static_pointer_cast<control_thread::DemuxerClient>(
+ std::move(control_thread_source_impl)));
+ DispatchTask(&worker_thread::PlatformDemuxerAdapterClient::RegisterSource,
+ std::static_pointer_cast<worker_thread::DemuxerClient>(
+ std::move(worker_thread_source_impl)),
+ std::move(on_emss_initialized));
+}
+
} // namespace any_thread
} // namespace elementary_media_stream_source
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/common_types.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/source_impl.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/demuxer_dispatcher_lifecycle_observer.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/pending_data_stream_src_interfaces.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace control_thread {
class DemuxerDispatcherClient;
class PlatformDemuxerAdapterClient;
+class SourceImpl;
} // namespace control_thread
namespace media_thread {
namespace worker_thread {
class DemuxerDispatcherClient;
class PlatformDemuxerAdapterClient;
+class SourceImpl;
} // namespace worker_thread
namespace any_thread {
SetClient<TypedMediaStreamProxy<track_type>>(std::move(stream));
}
+ void RegisterSource(std::shared_ptr<any_thread::SourceImpl>,
+ std::shared_ptr<control_thread::SourceImpl>,
+ std::shared_ptr<worker_thread::SourceImpl>,
+ base::OnceClosure on_emss_initialized);
+
scoped_refptr<base::SingleThreadTaskRunner> GetWorkerThreadTaskRunner()
const {
return worker_thread_task_runner_;
worker_thread_task_runner);
private:
+ template <typename DemuxerImplT>
+ static void SetAnyClients(
+ const std::shared_ptr<DemuxerDispatcher>& demuxer_dispatcher,
+ std::shared_ptr<DemuxerImplT>&& any_demuxer_impl) {
+ demuxer_dispatcher->SetClient<AnyThreadClient>(any_demuxer_impl);
+ demuxer_dispatcher->SetClient<AnyThreadDemuxerAdapterClient>(
+ std::move(any_demuxer_impl));
+ }
+
+ template <typename DemuxerImplT>
+ static void SetControlClients(
+ const std::shared_ptr<DemuxerDispatcher>& demuxer_dispatcher,
+ std::shared_ptr<DemuxerImplT>&& control_demuxer_impl) {
+ demuxer_dispatcher->SetClient<ControlThreadClient>(control_demuxer_impl);
+ demuxer_dispatcher->SetClient<ControlThreadDemuxerAdapterClient>(
+ std::move(control_demuxer_impl));
+ }
+
template <typename DemuxerImplT>
static void SetWorkerClients(
PipelineMode pipeline_mode,
//////////////////// Demuxer ////////////////////
-void DemuxerImpl::OnInitialConfigReadyForMediaStream(
+void DemuxerImpl::OnInitialConfigReadyForMediaDemuxer(
MaybeAudioConfig maybe_audio_conf,
MaybeVideoConfig maybe_video_conf) {
EMSS_DEBUG();
- EMSS_LOG_ASSERT(pipeline_mode_.demuxer_mode == DemuxerMode::kMediaStream)
- << "Should not be called in " << pipeline_mode_.demuxer_mode;
+ EMSS_LOG_ASSERT(pipeline_mode_.demuxer_mode == DemuxerMode::kMediaStream &&
+ pipeline_mode_.latency_mode == LatencyMode::kNormal)
+ << "Should not be called in " << pipeline_mode_.demuxer_mode << " and "
+ << pipeline_mode_.latency_mode;
auto dispatcher = dispatcher_.lock();
~DemuxerImpl() override;
// Demuxer
- void OnInitialConfigReadyForMediaStream(
+ void OnInitialConfigReadyForMediaDemuxer(
MaybeAudioConfig audio_config,
MaybeVideoConfig video_config) override;
dispatcher_->RegisterPlatformDemuxerAdapter(this);
- auto [source_dispatcher, any_thread_source_impl, control_thread_source_impl,
- worker_thread_source_impl] =
- SourceDispatcher::Create(pipeline_mode_, control_thread_task_runner_,
- dispatcher_->GetWorkerThreadTaskRunner());
-
- auto blink_source_dispatcher = std::make_shared<
- blink::WebElementaryMediaStreamSourceDispatcher>(
- control_thread_task_runner_, std::move(source_dispatcher),
- std::static_pointer_cast<blink::WebElementaryMediaStreamSourceControl>(
- control_thread_source_impl));
-
- dispatcher_->RunTask(&AnyThreadClient::RegisterSource,
- std::static_pointer_cast<any_thread::DemuxerClient>(
- any_thread_source_impl));
- dispatcher_->DispatchTask(
- &ControlThreadClient::RegisterSource,
- std::static_pointer_cast<control_thread::DemuxerClient>(
- control_thread_source_impl));
-
- // FIXME(p.balut): better not unretained...
- auto emss_initialized = media::BindToCurrentLoop(base::BindOnce(
- &ElementaryMediaStreamDemuxer::OnInitializationDone,
- base::Unretained(this), std::move(blink_source_dispatcher)));
-
- dispatcher_->DispatchTask(
- &WorkerThreadClient::RegisterSource,
- std::static_pointer_cast<worker_thread::DemuxerClient>(
- worker_thread_source_impl),
- std::move(emss_initialized));
+ auto [blink_source_dispatcher, any_thread_source_impl,
+ control_thread_source_impl, worker_thread_source_impl] =
+ blink::WebElementaryMediaStreamSourceDispatcher::Create(
+ pipeline_mode_, control_thread_task_runner_,
+ dispatcher_->GetWorkerThreadTaskRunner());
+
+ dispatcher_->RegisterSource(
+ std::move(any_thread_source_impl), std::move(control_thread_source_impl),
+ std::move(worker_thread_source_impl),
+ media::BindToCurrentLoop(base::BindOnce(
+ &ElementaryMediaStreamDemuxer::OnInitializationDone,
+ base::Unretained(this), std::move(blink_source_dispatcher))));
}
void ElementaryMediaStreamDemuxer::AbortPendingReads() {
--- /dev/null
+// Copyright (c) 2024 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.
+
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/ms_decoding_stream.h"
+
+#include <memory>
+#include <utility>
+
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/common_tools.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/common_types.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer_client.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer_dispatcher.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/media_stream_impl.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/media_thread/platform_demuxer_adapter.h"
+#include "services/elementary_media_stream_source/public/cpp/logger.h"
+
+namespace content {
+
+namespace elementary_media_stream_source {
+
+namespace any_thread {
+
+MsDecodingStream::MsDecodingStream(DemuxerParams params)
+ : pipeline_mode_(params.pipeline_mode),
+ dispatcher_(std::move(params.dispatcher)),
+ state_(std::move(params.state)) {
+ EMSS_DEBUG() << "Constructing object";
+}
+
+MsDecodingStream::~MsDecodingStream() {
+ EMSS_DEBUG() << "Destructing object";
+}
+
+//////////////////// Demuxer ////////////////////
+
+void MsDecodingStream::OnInitialConfigReadyForMediaDemuxer(
+ MaybeAudioConfig maybe_audio_conf,
+ MaybeVideoConfig maybe_video_conf) {
+ EMSS_DEBUG();
+ EMSS_LOG_ASSERT(false) << "Should not be called for MsDecodingStream";
+}
+
+//////////////////// DemuxerDispatcherClient ////////////////////
+
+blink::WebTimeRanges MsDecodingStream::GetBufferedRanges() const {
+ EMSS_LOG_ASSERT(false) << "Should not be called for MsDecodingStream";
+ return blink::WebTimeRanges();
+}
+
+bool MsDecodingStream::IsSeeking() const {
+ return false;
+}
+
+void MsDecodingStream::RegisterSessionIdChangeListeners(
+ SessionIdChangeListeners session_id_change_listeners) {
+ EMSS_LOG_ASSERT(false) << "Should not be called for MsDecodingStream";
+}
+
+//////////////////// PlatformDemuxerAdapterClient ////////////////////
+
+void MsDecodingStream::RegisterSource(std::shared_ptr<DemuxerClient> client) {
+ EMSS_DEBUG();
+
+ client->RegisterDemuxer(shared_from_this());
+}
+
+} // namespace any_thread
+
+} // namespace elementary_media_stream_source
+
+} // namespace content
--- /dev/null
+// Copyright (c) 2024 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 TIZEN_SRC_CHROMIUM_IMPL_CONTENT_RENDERER_MEDIA_TIZEN_ELEMENTARY_MEDIA_STREAM_SOURCE_ANY_THREAD_MS_DECODING_STREAM_H_
+#define TIZEN_SRC_CHROMIUM_IMPL_CONTENT_RENDERER_MEDIA_TIZEN_ELEMENTARY_MEDIA_STREAM_SOURCE_ANY_THREAD_MS_DECODING_STREAM_H_
+
+#include <memory>
+
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer_client.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer_dispatcher_client.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer_params.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/lockable_demuxer_state.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/platform_demuxer_adapter_client.h"
+#include "third_party/blink/public/platform/web_time_range.h"
+
+namespace content {
+
+namespace elementary_media_stream_source {
+
+namespace any_thread {
+
+class MsDecodingStream : public Demuxer,
+ public DemuxerDispatcherClient,
+ public PlatformDemuxerAdapterClient,
+ public std::enable_shared_from_this<MsDecodingStream> {
+ public:
+ explicit MsDecodingStream(DemuxerParams);
+ ~MsDecodingStream() override;
+
+ // Demuxer
+ void OnInitialConfigReadyForMediaDemuxer(
+ MaybeAudioConfig audio_config,
+ MaybeVideoConfig video_config) override;
+
+ // DemuxerDispatcherClient
+ blink::WebTimeRanges GetBufferedRanges() const override;
+ bool IsSeeking() const override;
+ void RegisterSessionIdChangeListeners(SessionIdChangeListeners) override;
+
+ // PlatformDemuxerAdapterClient
+ void RegisterSource(std::shared_ptr<DemuxerClient>) override;
+
+ private:
+ const PipelineMode pipeline_mode_;
+
+ std::weak_ptr<any_thread::DemuxerDispatcher> dispatcher_;
+ std::shared_ptr<LockableDemuxerState> state_;
+};
+
+} // namespace any_thread
+
+} // namespace elementary_media_stream_source
+
+} // namespace content
+
+#endif // TIZEN_SRC_CHROMIUM_IMPL_CONTENT_RENDERER_MEDIA_TIZEN_ELEMENTARY_MEDIA_STREAM_SOURCE_ANY_THREAD_MS_DECODING_STREAM_H_
if (std::holds_alternative<Packet::DataStreamPacket>(p.packet_)) {
os << std::get<Packet::DataStreamPacket>(p.packet_);
} else if (std::holds_alternative<Packet::MediaPacket>(p.packet_)) {
- const auto& buffer = std::get<Packet::MediaPacket>(p.packet_).buffer;
- if (buffer)
+ const auto& media_packet = std::get<Packet::MediaPacket>(p.packet_);
+ const auto& buffer = media_packet.buffer;
+ if (buffer) {
os << buffer->AsHumanReadableString()
<< "; session id = " << p.session_id();
- else
+ } else
os << "{ nullptr }";
} else {
NOTREACHED() << "unknown packet type";
::elementary_media_stream_source::mojom::ElementaryMediaPacketPtr;
using PacketType = ::elementary_media_stream_source::PacketType;
+ static constexpr const auto kNoCaptureTime = base::TimeTicks::Min();
+
struct MediaPacket {
scoped_refptr<media::DecoderBuffer> buffer;
uint32_t session_id;
const PipelineMode pipeline_mode_;
const scoped_refptr<base::SingleThreadTaskRunner> worker_thread_task_runner_;
- friend class ElementaryMediaStreamDemuxer;
+ friend class ::blink::WebElementaryMediaStreamSourceDispatcher;
};
} // namespace any_thread
MaybeVideoConfig video_config) {
EMSS_DEBUG();
- switch (pipeline_mode_.demuxer_mode) {
- case DemuxerMode::kDataStream:
- if (auto dispatcher = dispatcher_.lock()) {
- dispatcher->DispatchTask(&worker_thread::SourceDispatcherClient::
- OnInitialConfigReadyForDataStream,
- std::move(audio_config),
- std::move(video_config));
- }
- break;
-
- case DemuxerMode::kMediaStream:
- if (auto demuxer = demuxer_.lock()) {
- demuxer->OnInitialConfigReadyForMediaStream(std::move(audio_config),
- std::move(video_config));
- }
- break;
+ if (pipeline_mode_.demuxer_mode == DemuxerMode::kMediaStream &&
+ pipeline_mode_.latency_mode == LatencyMode::kNormal) {
+ if (auto demuxer = demuxer_.lock()) {
+ demuxer->OnInitialConfigReadyForMediaDemuxer(std::move(audio_config),
+ std::move(video_config));
+ }
+ return;
+ }
+
+ if (auto dispatcher = dispatcher_.lock()) {
+ dispatcher->DispatchTask(
+ &worker_thread::SourceDispatcherClient::OnInitialConfigReady,
+ std::move(audio_config), std::move(video_config));
}
}
"demuxer_impl.cc",
"demuxer_impl.h",
"enable_dispatcher.h",
+ "ms_decoding_stream.cc",
+ "ms_decoding_stream.h",
"platform_demuxer_adapter_client.h",
"source.h",
"source_client.h",
--- /dev/null
+// Copyright (c) 2024 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.
+
+#include "content/renderer/media/tizen/elementary_media_stream_source/control_thread/ms_decoding_stream.h"
+
+#include "content/renderer/media/tizen/elementary_media_stream_source/control_thread/demuxer_client.h"
+#include "services/elementary_media_stream_source/public/cpp/logger.h"
+
+namespace content {
+namespace elementary_media_stream_source {
+namespace control_thread {
+
+MsDecodingStream::MsDecodingStream(any_thread::DemuxerParams params)
+ : pipeline_mode_(params.pipeline_mode),
+ dispatcher_(std::move(params.dispatcher)) {
+ EMSS_DEBUG() << "Constructing object";
+}
+
+MsDecodingStream::~MsDecodingStream() {
+ EMSS_DEBUG() << "Destructing object";
+}
+
+//////////////////// Demuxer: ////////////////////
+
+void MsDecodingStream::NotifyDemuxerInitialized() {}
+
+void MsDecodingStream::OnBufferedTimeRangesChanged(
+ media::Ranges<base::TimeDelta>&&) {}
+
+void MsDecodingStream::OnDemuxerSeekDone(base::TimeDelta, uint32_t session_id) {
+}
+
+void MsDecodingStream::OnPipelineClosed() {}
+
+void MsDecodingStream::OnPipelineResuming() {}
+
+void MsDecodingStream::OnPipelineSuspended() {}
+
+void MsDecodingStream::SetDuration(base::TimeDelta) {}
+
+void MsDecodingStream::OnSessionIdChange(uint32_t session_id) {}
+
+//////////////////// DemuxerDispatcherClient: ////////////////////
+
+void MsDecodingStream::OnClosedCaptions(std::vector<uint8_t> closed_captions) {}
+
+void MsDecodingStream::OnPlayerError(BackendError,
+ std::string message,
+ base::OnceClosure on_error_reported) {}
+
+void MsDecodingStream::OnResumeComplete() {}
+
+//////////////////// PlatformDemuxerAdapterClient ////////////////////
+
+void MsDecodingStream::CancelPendingSeek(base::TimeDelta seek_time) {}
+
+void MsDecodingStream::RegisterSource(std::shared_ptr<DemuxerClient> client) {
+ EMSS_DEBUG();
+
+ client->RegisterDemuxer(shared_from_this());
+ client_ = std::move(client);
+}
+
+void MsDecodingStream::Stop() {}
+
+void MsDecodingStream::StartSeek(base::TimeDelta seek_time,
+ base::OnceClosure on_seek_done) {}
+
+void MsDecodingStream::StartWaitingForSeek(base::TimeDelta seek_time) {}
+
+} // namespace control_thread
+} // namespace elementary_media_stream_source
+} // namespace content
--- /dev/null
+// Copyright (c) 2024 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 TIZEN_SRC_CHROMIUM_IMPL_CONTENT_RENDERER_MEDIA_TIZEN_ELEMENTARY_MEDIA_STREAM_SOURCE_CONTROL_THREAD_MS_DECODING_STREAM_H_
+#define TIZEN_SRC_CHROMIUM_IMPL_CONTENT_RENDERER_MEDIA_TIZEN_ELEMENTARY_MEDIA_STREAM_SOURCE_CONTROL_THREAD_MS_DECODING_STREAM_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/functional/callback_helpers.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/time/time.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/common_types.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer_dispatcher.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer_params.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/lockable_demuxer_state.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/control_thread/demuxer.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/control_thread/demuxer_dispatcher_client.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/control_thread/platform_demuxer_adapter_client.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/control_thread/platform_demuxer_adapter_client.h"
+
+namespace content {
+namespace elementary_media_stream_source {
+namespace control_thread {
+
+class MsDecodingStream : public Demuxer,
+ public DemuxerDispatcherClient,
+ public PlatformDemuxerAdapterClient,
+ public std::enable_shared_from_this<MsDecodingStream> {
+ public:
+ explicit MsDecodingStream(any_thread::DemuxerParams);
+
+ ~MsDecodingStream() override;
+
+ // Demuxer
+ void NotifyDemuxerInitialized() override;
+ void OnBufferedTimeRangesChanged(media::Ranges<base::TimeDelta>&&) override;
+ void OnDemuxerSeekDone(base::TimeDelta, uint32_t session_id) override;
+ void OnPipelineClosed() override;
+ void OnPipelineResuming() override;
+ void OnPipelineSuspended() override;
+ void SetDuration(base::TimeDelta) override;
+ void OnSessionIdChange(uint32_t session_id) override;
+
+ // DemuxerDispatcherClient
+ void OnClosedCaptions(std::vector<uint8_t> closed_captions) override;
+ void OnPlayerError(BackendError,
+ std::string message,
+ base::OnceClosure on_error_reported) override;
+ void OnResumeComplete() override;
+
+ // PlatformDemuxerAdapterClient
+ void CancelPendingSeek(base::TimeDelta seek_time) override;
+ void RegisterSource(std::shared_ptr<DemuxerClient>) override;
+ void Stop() override;
+ void StartSeek(base::TimeDelta seek_time,
+ base::OnceClosure on_seek_done) override;
+ void StartWaitingForSeek(base::TimeDelta seek_time) override;
+
+ private:
+ const PipelineMode pipeline_mode_;
+
+ std::weak_ptr<DemuxerClient> client_;
+ std::weak_ptr<any_thread::DemuxerDispatcher> dispatcher_;
+};
+
+} // namespace control_thread
+} // namespace elementary_media_stream_source
+} // namespace content
+
+#endif // TIZEN_SRC_CHROMIUM_IMPL_CONTENT_RENDERER_MEDIA_TIZEN_ELEMENTARY_MEDIA_STREAM_SOURCE_CONTROL_THREAD_MS_DECODING_STREAM_H_
return result;
}
+void SourceImpl::SetMediaStreamAudioTrackSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsAudioSink> audio_sink) {
+ EMSS_DEBUG();
+
+ if (auto dispatcher = dispatcher_.lock())
+ dispatcher->DispatchTask(
+ &worker_thread::SourceDispatcherClient::SetMediaStreamAudioTrackSink,
+ std::move(audio_sink));
+}
+
+void SourceImpl::SetMediaStreamVideoTrackSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsVideoSink> video_sink) {
+ EMSS_DEBUG();
+
+ if (auto dispatcher = dispatcher_.lock())
+ dispatcher->DispatchTask(
+ &worker_thread::SourceDispatcherClient::SetMediaStreamVideoTrackSink,
+ std::move(video_sink));
+}
+
//////////////////// private ////////////////////
uint32_t SourceImpl::GenerateNextInputSessionId() {
void SetDuration(double) override;
OperationCallbackResult SetSourceClosed() override;
OperationCallbackResult SetSourceOpened() override;
+ void SetMediaStreamAudioTrackSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsAudioSink>) override;
+ void SetMediaStreamVideoTrackSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsVideoSink>) override;
private:
uint32_t GenerateNextInputSessionId();
elementary_media_stream_source_renderer("worker_thread") {
sources = [
"append_client.h",
+ "append_host.cc",
"append_host.h",
"audio_track_impl.cc",
"audio_track_impl.h",
"enable_dispatcher.h",
"media_stream_demuxer_impl.cc",
"media_stream_demuxer_impl.h",
+ "ms_decoding_stream.cc",
+ "ms_decoding_stream.h",
"pending_data_stream_src_interfaces.h",
"platform_demuxer_adapter_client.h",
"source.h",
--- /dev/null
+// Copyright (c) 2020 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.
+
+#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/append_host.h"
+
+#include "services/elementary_media_stream_source/public/cpp/logger.h"
+
+namespace content {
+namespace elementary_media_stream_source {
+namespace worker_thread {
+
+void AppendHost::SetAudioSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsAudioSink>) {
+ EMSS_LOG_ASSERT(false) << "Not implemented?";
+}
+
+void AppendHost::SetVideoSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsVideoSink>) {
+ EMSS_LOG_ASSERT(false) << "Not implemented?";
+}
+
+} // namespace worker_thread
+} // namespace elementary_media_stream_source
+} // namespace content
\ No newline at end of file
#include "tizen_src/chromium_impl/services/elementary_media_stream_source/public/mojom/elementary_media_packet.mojom-forward.h"
#include "tizen_src/chromium_impl/services/elementary_media_stream_source/public/mojom/video_track_config.mojom-forward.h"
+namespace blink {
+class WebElementaryMediaTrackMsAudioSink;
+class WebElementaryMediaTrackMsVideoSink;
+} // namespace blink
+
namespace content {
namespace elementary_media_stream_source {
namespace worker_thread {
virtual void OnReadConfig(AudioTrackConfigPtr) = 0;
virtual void OnReadConfig(VideoTrackConfigPtr) = 0;
virtual void OnReadMediaPackets(TrackType, std::vector<Packet>) = 0;
+ virtual void SetAudioSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsAudioSink>);
+ virtual void SetVideoSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsVideoSink>);
protected:
AppendHost() = default;
std::move(buffered_time_ranges));
}
-void DataStreamDemuxerImpl::OnInitialConfigReadyForDataStream(
+void DataStreamDemuxerImpl::OnInitialConfigReady(
const MaybeAudioConfig& audio_config,
const MaybeVideoConfig& video_config) {
EMSS_DEBUG();
// Demuxer
std::shared_ptr<AppendHost> GetAppendHost(TrackType) override;
void OnBufferedTimeRangesChanged(media::Ranges<base::TimeDelta>&&) override;
- void OnInitialConfigReadyForDataStream(const MaybeAudioConfig&,
- const MaybeVideoConfig&) override;
+ void OnInitialConfigReady(const MaybeAudioConfig&,
+ const MaybeVideoConfig&) override;
void SetAppendClient(TrackType, std::shared_ptr<AppendClient>) override;
void SetVideoTextureClient(std::shared_ptr<VideoTextureClient>) override;
virtual std::shared_ptr<AppendHost> GetAppendHost(TrackType) = 0;
virtual void OnBufferedTimeRangesChanged(
media::Ranges<base::TimeDelta>&&) = 0;
- virtual void OnInitialConfigReadyForDataStream(const MaybeAudioConfig&,
- const MaybeVideoConfig&) = 0;
+ virtual void OnInitialConfigReady(const MaybeAudioConfig&,
+ const MaybeVideoConfig&) = 0;
virtual void SetAppendClient(TrackType, std::shared_ptr<AppendClient>) = 0;
virtual void SetVideoTextureClient(std::shared_ptr<VideoTextureClient>) = 0;
std::move(buffered_time_ranges));
}
-void MediaStreamDemuxerImpl::OnInitialConfigReadyForDataStream(
- const MaybeAudioConfig&,
- const MaybeVideoConfig&) {
+void MediaStreamDemuxerImpl::OnInitialConfigReady(const MaybeAudioConfig&,
+ const MaybeVideoConfig&) {
EMSS_LOG_ASSERT(pipeline_mode_.demuxer_mode == DemuxerMode::kDataStream)
<< "Should not be called in " << pipeline_mode_.demuxer_mode;
}
// Demuxer
std::shared_ptr<AppendHost> GetAppendHost(TrackType) override;
void OnBufferedTimeRangesChanged(media::Ranges<base::TimeDelta>&&) override;
- void OnInitialConfigReadyForDataStream(const MaybeAudioConfig&,
- const MaybeVideoConfig&) override;
+ void OnInitialConfigReady(const MaybeAudioConfig&,
+ const MaybeVideoConfig&) override;
void SetAppendClient(TrackType, std::shared_ptr<AppendClient>) override;
void SetVideoTextureClient(std::shared_ptr<VideoTextureClient>) override;
--- /dev/null
+// Copyright (c) 2024 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.
+
+#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/ms_decoding_stream.h"
+
+#include "base/functional/callback_helpers.h"
+#include "base/task/sequenced_task_runner.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/control_thread/demuxer_dispatcher_client.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/demuxer_client.h"
+#include "media/base/bind_to_current_loop.h"
+#include "media/base/media_util.h"
+#include "media/video/gpu_video_accelerator_factories.h"
+#include "services/elementary_media_stream_source/public/cpp/logger.h"
+#include "services/elementary_media_stream_source/public/cpp/mojom_type_exports.h"
+#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/platform/elementary_media_stream_source/web_elementary_media_track_ms_audio_sink.h"
+#include "third_party/blink/renderer/platform/elementary_media_stream_source/web_elementary_media_track_ms_video_sink.h"
+
+namespace media {
+
+#define ENUM_VALUE_TO_OSTREAM(os, enum_value) \
+ case (enum_value): \
+ os << (#enum_value); \
+ break
+
+std::ostream& operator<<(std::ostream& os, WaitingReason value) {
+ switch (value) {
+ ENUM_VALUE_TO_OSTREAM(os, WaitingReason::kNoCdm);
+ ENUM_VALUE_TO_OSTREAM(os, WaitingReason::kNoDecryptionKey);
+ ENUM_VALUE_TO_OSTREAM(os, WaitingReason::kDecoderStateLost);
+ }
+ return os;
+}
+
+} // namespace media
+
+namespace content {
+namespace elementary_media_stream_source {
+namespace worker_thread {
+
+namespace {
+
+void OnRequestOverlayInfo(bool decoder_requires_restart_for_overlay,
+ media::ProvideOverlayInfoCB overlay_info_cb) {
+ // Android overlays are not supported.
+ if (overlay_info_cb)
+ std::move(overlay_info_cb).Run(media::OverlayInfo());
+}
+
+} // anonymous namespace
+
+//////////////////////// MsDecodingStream::VideoStream: ////////////////////////
+
+class MsDecodingStream::VideoStream {
+ public:
+ VideoStream(
+ MsDecodingStream* parent,
+ media::MediaLog* media_log,
+ std::shared_ptr<blink::WebElementaryMediaTrackMsVideoSink> video_sink);
+ ~VideoStream();
+
+ void DecodeFrames(std::vector<Packet> frames);
+ void SetGpuFactories(media::GpuVideoAcceleratorFactories* gpu_factories);
+ void StartInitializingVideoDecoder(const media::VideoDecoderConfig&);
+
+ private:
+ static std::unique_ptr<media::VideoDecoder>
+ CreateVideoDecoderOnGpuFactoriesThread(
+ media::GpuVideoAcceleratorFactories* gpu_factories,
+ media::MediaLog* media_log);
+ void OnVideoDecoderCreated(std::unique_ptr<media::VideoDecoder>);
+ void OnVideoDecoderInitialized(std::unique_ptr<media::VideoDecoder>,
+ media::DecoderStatus);
+ void OnVideoDecoderWaiting(media::WaitingReason);
+
+ bool HasDecodingSlots() const;
+ void TryProcessPendingVideoDecodes();
+ void EnqueueVideoFrameForDecoding(scoped_refptr<media::DecoderBuffer>);
+ void DoDecodeVideoFrame(scoped_refptr<media::DecoderBuffer>);
+ void OnDecodeVideoFrameDone(media::DecoderStatus);
+ void OnVideoFrameDecoded(scoped_refptr<media::VideoFrame>);
+
+ MsDecodingStream* parent_;
+ media::MediaLog* media_log_;
+
+ std::optional<media::VideoDecoderConfig> video_config_;
+ std::unique_ptr<media::VideoDecoder> video_decoder_;
+ std::shared_ptr<blink::WebElementaryMediaTrackMsVideoSink> video_sink_;
+ int32_t ongoing_decodes_{0};
+ std::queue<scoped_refptr<media::DecoderBuffer>> pending_decodes_;
+
+ media::GpuVideoAcceleratorFactories* gpu_factories_{nullptr};
+ base::OnceClosure on_got_gpu_factories_;
+
+ base::WeakPtrFactory<VideoStream> weak_ptr_factory_;
+}; // class MsDecodingStream::VideoStream
+
+MsDecodingStream::VideoStream::VideoStream(
+ MsDecodingStream* parent,
+ media::MediaLog* media_log,
+ std::shared_ptr<blink::WebElementaryMediaTrackMsVideoSink> video_sink)
+ : parent_(parent),
+ media_log_(media_log),
+ video_sink_(std::move(video_sink)),
+ weak_ptr_factory_(this) {
+ EMSS_DEBUG() << "Constructing object";
+}
+
+MsDecodingStream::VideoStream::~VideoStream() {
+ EMSS_DEBUG() << "Destructingg object";
+}
+
+void MsDecodingStream::VideoStream::DecodeFrames(std::vector<Packet> frames) {
+ EMSS_VERBOSE() << frames.size();
+
+ for (auto& frame : frames) {
+ auto media_packet = frame.leak_media_packet();
+ EnqueueVideoFrameForDecoding(std::move(media_packet.buffer));
+ }
+ if (!pending_decodes_.empty())
+ TryProcessPendingVideoDecodes();
+}
+
+void MsDecodingStream::VideoStream::SetGpuFactories(
+ media::GpuVideoAcceleratorFactories* gpu_factories) {
+ EMSS_DEBUG() << gpu_factories;
+
+ gpu_factories_ = gpu_factories;
+
+ if (on_got_gpu_factories_)
+ std::move(on_got_gpu_factories_).Run();
+}
+
+void MsDecodingStream::VideoStream::StartInitializingVideoDecoder(
+ const media::VideoDecoderConfig& video_conf) {
+ EMSS_LOG(INFO) << video_conf.AsHumanReadableString();
+
+ if (!gpu_factories_) {
+ EMSS_LOG(INFO) << "Waiting for GPU Factories to become available...";
+ on_got_gpu_factories_ = base::BindOnce(
+ &MsDecodingStream::VideoStream::StartInitializingVideoDecoder,
+ weak_ptr_factory_.GetWeakPtr(), video_conf);
+ return;
+ }
+
+ if (!gpu_factories_->IsDecoderSupportKnown()) {
+ EMSS_LOG(INFO)
+ << "Waiting for GPU Factories to establish supported decoders...";
+ gpu_factories_->NotifyDecoderSupportKnown(base::BindOnce(
+ &MsDecodingStream::VideoStream::StartInitializingVideoDecoder,
+ weak_ptr_factory_.GetWeakPtr(), video_conf));
+ return;
+ }
+
+ if (gpu_factories_->IsDecoderConfigSupportedOrUnknown(video_conf) !=
+ media::GpuVideoAcceleratorFactories::Supported::kTrue) {
+ EMSS_LOG(ERROR) << "Video config not supported?";
+ parent_->EmitError(BackendError::kConfigError, "Config not supported");
+ return;
+ }
+
+ video_config_ = video_conf;
+ gpu_factories_->GetTaskRunner()->PostTaskAndReplyWithResult(
+ FROM_HERE,
+ base::BindOnce(&MsDecodingStream::VideoStream::
+ CreateVideoDecoderOnGpuFactoriesThread,
+ gpu_factories_, media_log_),
+ base::BindOnce(&MsDecodingStream::VideoStream::OnVideoDecoderCreated,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+// static
+std::unique_ptr<media::VideoDecoder>
+MsDecodingStream::VideoStream::CreateVideoDecoderOnGpuFactoriesThread(
+ media::GpuVideoAcceleratorFactories* gpu_factories,
+ media::MediaLog* media_log) {
+ EMSS_DEBUG_NO_INSTANCE();
+ return gpu_factories->CreateVideoDecoder(
+ media_log, base::BindRepeating(&OnRequestOverlayInfo));
+}
+
+void MsDecodingStream::VideoStream::OnVideoDecoderCreated(
+ std::unique_ptr<media::VideoDecoder> video_decoder) {
+ EMSS_DEBUG();
+
+ auto* decoder_ptr = video_decoder.get();
+ decoder_ptr->Initialize(
+ *video_config_, /* low_delay */ true, /* cdm_context */ nullptr,
+ base::BindOnce(&MsDecodingStream::VideoStream::OnVideoDecoderInitialized,
+ weak_ptr_factory_.GetWeakPtr(), std::move(video_decoder)),
+ base::BindRepeating(&MsDecodingStream::VideoStream::OnVideoFrameDecoded,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::BindRepeating(&MsDecodingStream::VideoStream::OnVideoDecoderWaiting,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void MsDecodingStream::VideoStream::OnVideoDecoderInitialized(
+ std::unique_ptr<media::VideoDecoder> video_decoder,
+ media::DecoderStatus status) {
+ EMSS_DEBUG();
+
+ if (!status.is_ok()) {
+ const auto error_msg =
+ std::string{"Failed to initialize video decoder: "} + status.message();
+ EMSS_LOG(ERROR) << error_msg;
+ parent_->EmitError(BackendError::kPipelineError, error_msg);
+ return;
+ }
+
+ video_decoder_ = std::move(video_decoder);
+
+ TryProcessPendingVideoDecodes();
+}
+
+void MsDecodingStream::VideoStream::OnVideoDecoderWaiting(
+ media::WaitingReason reason) {
+ EMSS_LOG(WARNING) << "Decoder is waiting: " << reason;
+}
+
+bool MsDecodingStream::VideoStream::HasDecodingSlots() const {
+ return video_decoder_ &&
+ ongoing_decodes_ < video_decoder_->GetMaxDecodeRequests();
+}
+
+void MsDecodingStream::VideoStream::TryProcessPendingVideoDecodes() {
+ EMSS_DEBUG() << "pending decodes = " << pending_decodes_.size()
+ << ", ongoing decodes = " << ongoing_decodes_;
+ while (!pending_decodes_.empty() && HasDecodingSlots()) {
+ auto frame = std::move(pending_decodes_.front());
+ pending_decodes_.pop();
+ DoDecodeVideoFrame(std::move(frame));
+ }
+}
+
+void MsDecodingStream::VideoStream::EnqueueVideoFrameForDecoding(
+ scoped_refptr<media::DecoderBuffer> frame) {
+ if (pending_decodes_.empty() && HasDecodingSlots()) {
+ // This is the default code path. We expect frames in low latency to be
+ // immediately after they arrive when playback progresses normally. Frames
+ // should leave decoder before all decoding slots are taken.
+ DoDecodeVideoFrame(std::move(frame));
+ return;
+ }
+
+ EMSS_DEBUG();
+ pending_decodes_.push(std::move(frame));
+}
+
+void MsDecodingStream::VideoStream::DoDecodeVideoFrame(
+ scoped_refptr<media::DecoderBuffer> frame) {
+ EMSS_DEBUG() << frame->AsHumanReadableString();
+
+ ++ongoing_decodes_;
+ video_decoder_->Decode(
+ std::move(frame),
+ base::BindOnce(&MsDecodingStream::VideoStream::OnDecodeVideoFrameDone,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void MsDecodingStream::VideoStream::OnDecodeVideoFrameDone(
+ media::DecoderStatus status) {
+ EMSS_VERBOSE();
+
+ --ongoing_decodes_;
+
+ if (!status.is_ok()) {
+ const auto error_msg =
+ std::string{"Video decoding error: "} + status.message();
+ EMSS_LOG(ERROR) << error_msg;
+ parent_->EmitError(BackendError::kPipelineError, error_msg);
+ return;
+ }
+
+ if (!pending_decodes_.empty())
+ TryProcessPendingVideoDecodes();
+}
+
+void MsDecodingStream::VideoStream::OnVideoFrameDecoded(
+ scoped_refptr<media::VideoFrame> frame) {
+ EMSS_VERBOSE() << frame->AsHumanReadableString();
+
+ video_sink_->AppendPacket(std::move(frame));
+}
+
+////////////////////////////// MsDecodingStream: ///////////////////////////////
+
+MsDecodingStream::MsDecodingStream(any_thread::DemuxerParams params)
+ : dispatcher_(std::move(params.dispatcher)),
+ // FIXME(p.balut): provide actual media log
+ media_log_(std::make_unique<media::NullMediaLog>()) {
+ EMSS_DEBUG() << "Constructing object";
+}
+
+MsDecodingStream::~MsDecodingStream() {
+ EMSS_DEBUG() << "Destructing object";
+}
+
+void MsDecodingStream::SetGpuFactories(
+ media::GpuVideoAcceleratorFactories* gpu_factories) {
+ EMSS_DEBUG() << gpu_factories;
+
+ gpu_factories_ = gpu_factories;
+
+ if (video_stream_)
+ video_stream_->SetGpuFactories(gpu_factories);
+}
+
+void MsDecodingStream::SetAudioSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsAudioSink>) {
+ EMSS_DEBUG();
+ EmitError(BackendError::kConfigError, "Audio support not implemented yet.");
+}
+
+void MsDecodingStream::SetVideoSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsVideoSink> video_sink) {
+ EMSS_DEBUG();
+
+ video_stream_ = std::make_unique<VideoStream>(this, media_log_.get(),
+ std::move(video_sink));
+
+ if (gpu_factories_)
+ video_stream_->SetGpuFactories(gpu_factories_);
+}
+
+//////////////////// Demuxer: ////////////////////
+
+std::shared_ptr<AppendHost> MsDecodingStream::GetAppendHost(TrackType) {
+ EMSS_VERBOSE();
+
+ return shared_from_this();
+}
+
+void MsDecodingStream::OnBufferedTimeRangesChanged(
+ media::Ranges<base::TimeDelta>&&) {}
+
+void MsDecodingStream::OnInitialConfigReady(
+ const MaybeAudioConfig& maybe_audio_conf,
+ const MaybeVideoConfig& maybe_video_conf) {
+ if (maybe_video_conf) {
+ EMSS_LOG_ASSERT(!!video_stream_) << "Video decoding stream should've been "
+ "set by now if video track is present";
+ video_stream_->StartInitializingVideoDecoder(
+ *std::get<std::unique_ptr<media::VideoDecoderConfig>>(
+ *maybe_video_conf));
+ }
+}
+
+void MsDecodingStream::SetAppendClient(TrackType,
+ std::shared_ptr<AppendClient>) {
+ EMSS_DEBUG();
+}
+
+void MsDecodingStream::SetVideoTextureClient(
+ std::shared_ptr<VideoTextureClient>) {
+ EMSS_LOG(ERROR) << "FIXME(p.balut): Not implemented!";
+ EmitError(BackendError::kUnknownError, "Not implemented");
+}
+
+//////////////////// DemuxerDispatcherClient: ////////////////////
+
+void MsDecodingStream::OnPipelineResuming() {}
+
+void MsDecodingStream::OnPipelineSuspended() {}
+
+void MsDecodingStream::OnReadRequested(TrackType) {}
+
+void MsDecodingStream::OnSeekDone(base::TimeDelta new_time,
+ uint32_t session_id) {}
+
+void MsDecodingStream::OnSessionIdChange(uint32_t session_id) {}
+
+//////////////////// AppendHost: ////////////////////
+
+void MsDecodingStream::NotifyFramerateSet(
+ const media::StreamFramerate::Framerate& framerate) {}
+
+void MsDecodingStream::OnReadConfig(AudioTrackConfigPtr) {}
+
+void MsDecodingStream::OnReadConfig(VideoTrackConfigPtr) {}
+
+void MsDecodingStream::OnReadMediaPackets(TrackType type,
+ std::vector<Packet> frames) {
+ EMSS_DEBUG() << "Got " << frames.size() << " " << type << " frames";
+
+ switch (type) {
+ case TrackType::kAudio:
+ break;
+ case TrackType::kVideo:
+ EMSS_LOG_ASSERT(!!video_stream_)
+ << "Video decoding stream should've been set by now if video track "
+ "is present";
+ video_stream_->DecodeFrames(std::move(frames));
+ break;
+ }
+}
+
+//////////////////// own private methods: ////////////////////
+
+void MsDecodingStream::EmitError(BackendError backend_error,
+ const std::string& message) {
+ EMSS_LOG(ERROR) << "error: " << backend_error << " message: '" << message
+ << "'";
+
+ if (auto demuxer_dispatcher = dispatcher_.lock()) {
+ demuxer_dispatcher->DispatchTask(
+ &control_thread::DemuxerDispatcherClient::OnPlayerError, backend_error,
+ std::string{message}, base::DoNothing());
+ }
+}
+
+// PlatformDemuxerAdapterClient:
+void MsDecodingStream::RegisterSource(std::shared_ptr<DemuxerClient> client,
+ base::OnceClosure on_source_registered) {
+ EMSS_DEBUG();
+
+ client->RegisterDemuxer(shared_from_this());
+
+ std::move(on_source_registered).Run();
+}
+
+} // namespace worker_thread
+} // namespace elementary_media_stream_source
+} // namespace content
--- /dev/null
+// Copyright (c) 2024 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.
+
+#include <queue>
+
+#include "base/functional/callback_forward.h"
+#include "base/memory/weak_ptr.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer_dispatcher.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer_params.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/append_host.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/demuxer.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/demuxer_dispatcher_client.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/platform_demuxer_adapter_client.h"
+#include "media/base/media_log.h"
+#include "media/base/video_decoder.h"
+#include "media/video/gpu_video_accelerator_factories.h"
+
+namespace blink {
+class WebElementaryMediaTrackMsAudioSink;
+class WebElementaryMediaTrackMsVideoSink;
+} // namespace blink
+
+namespace media {
+class GpuVideoAcceleratorFactories;
+}
+
+namespace content {
+namespace elementary_media_stream_source {
+namespace worker_thread {
+
+// AppendHost used when EMSS acts as source for media streams.
+//
+// Contrary to modes that use demuxer (DataStream or media::Demuxer), this class
+// wraps sinks that transfer data back to blink:: realm, where it is consumed by
+// media streams implementation (WebPlatformMediaStreamSource derivatives).
+class MsDecodingStream : public Demuxer,
+ public DemuxerDispatcherClient,
+ public AppendHost,
+ public PlatformDemuxerAdapterClient,
+ public std::enable_shared_from_this<MsDecodingStream> {
+ public:
+ explicit MsDecodingStream(any_thread::DemuxerParams params);
+ ~MsDecodingStream() override;
+
+ void SetGpuFactories(media::GpuVideoAcceleratorFactories* gpu_factories);
+
+ // Demuxer:
+ std::shared_ptr<AppendHost> GetAppendHost(TrackType) override;
+ void OnBufferedTimeRangesChanged(media::Ranges<base::TimeDelta>&&) override;
+ void OnInitialConfigReady(const MaybeAudioConfig&,
+ const MaybeVideoConfig&) override;
+ void SetAppendClient(TrackType, std::shared_ptr<AppendClient>) override;
+ void SetVideoTextureClient(std::shared_ptr<VideoTextureClient>) override;
+
+ // DemuxerDispatcherClient:
+ void OnPipelineResuming() override;
+ void OnPipelineSuspended() override;
+ void OnReadRequested(TrackType) override;
+ void OnSeekDone(base::TimeDelta new_time, uint32_t session_id) override;
+ void OnSessionIdChange(uint32_t session_id) override;
+
+ // AppendHost:
+ void NotifyFramerateSet(
+ const media::StreamFramerate::Framerate& framerate) override;
+ void OnReadConfig(AudioTrackConfigPtr) override;
+ void OnReadConfig(VideoTrackConfigPtr) override;
+ void OnReadMediaPackets(TrackType, std::vector<Packet>) override;
+ void SetAudioSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsAudioSink>) override;
+ void SetVideoSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsVideoSink>) override;
+
+ // PlatformDemuxerAdapterClient:
+ void RegisterSource(std::shared_ptr<DemuxerClient>,
+ base::OnceClosure on_source_registered) override;
+
+ private:
+ using BackendError = ::elementary_media_stream_source::mojom::BackendError;
+
+ class VideoStream;
+
+ void EmitError(BackendError backend_error, const std::string& message);
+
+ std::unique_ptr<VideoStream> video_stream_;
+
+ std::weak_ptr<any_thread::DemuxerDispatcher> dispatcher_;
+ media::GpuVideoAcceleratorFactories* gpu_factories_{nullptr};
+ std::unique_ptr<media::MediaLog> media_log_;
+};
+
+} // namespace worker_thread
+} // namespace elementary_media_stream_source
+} // namespace content
#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/common_types.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/enable_dispatcher.h"
+namespace blink {
+class WebElementaryMediaTrackMsAudioSink;
+class WebElementaryMediaTrackMsVideoSink;
+} // namespace blink
+
namespace content {
namespace elementary_media_stream_source {
virtual ~SourceDispatcherClient() = default;
virtual void BufferedRangesChanged() const = 0;
- virtual void OnInitialConfigReadyForDataStream(MaybeAudioConfig,
- MaybeVideoConfig) = 0;
+ virtual void OnInitialConfigReady(MaybeAudioConfig, MaybeVideoConfig) = 0;
virtual void RegisterClient(std::shared_ptr<SourceClient>) = 0;
+ virtual void SetMediaStreamAudioTrackSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsAudioSink>) = 0;
+ virtual void SetMediaStreamVideoTrackSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsVideoSink>) = 0;
protected:
SourceDispatcherClient() = default;
#include "base/time/time.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/common_tools.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/common_types.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/append_host.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/demuxer.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/source_client.h"
#include "services/elementary_media_stream_source/public/cpp/logger.h"
//////////////////// SourceDispatcherClient ////////////////////
-void SourceImpl::OnInitialConfigReadyForDataStream(
- MaybeAudioConfig audio_config,
- MaybeVideoConfig video_config) {
+void SourceImpl::OnInitialConfigReady(MaybeAudioConfig audio_config,
+ MaybeVideoConfig video_config) {
EMSS_DEBUG();
- EMSS_LOG_ASSERT(pipeline_mode_.demuxer_mode == DemuxerMode::kDataStream)
- << "Should not be called in " << pipeline_mode_.demuxer_mode;
+ EMSS_LOG_ASSERT(pipeline_mode_.demuxer_mode != DemuxerMode::kMediaStream ||
+ pipeline_mode_.latency_mode != LatencyMode::kNormal)
+ << "Should not be called in " << pipeline_mode_.demuxer_mode << " and "
+ << pipeline_mode_.latency_mode;
if (auto demuxer = demuxer_.lock()) {
- demuxer->OnInitialConfigReadyForDataStream(audio_config, video_config);
+ demuxer->OnInitialConfigReady(audio_config, video_config);
}
}
}
}
+void SourceImpl::SetMediaStreamAudioTrackSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsAudioSink> audio_sink) {
+ EMSS_DEBUG();
+ if (auto demuxer = demuxer_.lock()) {
+ demuxer->GetAppendHost(TrackType::kAudio)
+ ->SetAudioSink(std::move(audio_sink));
+ }
+}
+
+void SourceImpl::SetMediaStreamVideoTrackSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsVideoSink> video_sink) {
+ EMSS_DEBUG();
+ if (auto demuxer = demuxer_.lock()) {
+ demuxer->GetAppendHost(TrackType::kVideo)
+ ->SetVideoSink(std::move(video_sink));
+ }
+}
+
} // namespace worker_thread
} // namespace elementary_media_stream_source
void BufferedRangesChanged() const override;
// SourceDispatcherClient
- void OnInitialConfigReadyForDataStream(MaybeAudioConfig,
- MaybeVideoConfig) override;
+ void OnInitialConfigReady(MaybeAudioConfig, MaybeVideoConfig) override;
void RegisterClient(std::shared_ptr<SourceClient>) override;
+ void SetMediaStreamAudioTrackSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsAudioSink>) override;
+ void SetMediaStreamVideoTrackSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsVideoSink>) override;
private:
+ const PipelineMode pipeline_mode_;
+
std::array<std::weak_ptr<SourceClient>, (+TrackType::kMaxValue + 1)> clients_;
std::weak_ptr<Demuxer> demuxer_;
- const PipelineMode pipeline_mode_;
std::shared_ptr<any_thread::LockableSourceState> state_;
};
#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/enable_dispatcher.h"
#include "media/base/decryptor.h"
+namespace blink {
+class WebElementaryMediaTrackMsAudioSink;
+class WebElementaryMediaTrackMsVideoSink;
+} // namespace blink
+
namespace content {
namespace elementary_media_stream_source {
(override));
MOCK_METHOD(void,
- OnInitialConfigReadyForDataStream,
+ OnInitialConfigReady,
(const MaybeAudioConfig&, const MaybeVideoConfig&),
(override));
MOCK_METHOD(void,
class MockSourceDispatcherClient : public SourceDispatcherClient {
public:
- MOCK_CONST_METHOD0(BufferedRangesChanged, void());
- MOCK_METHOD2(OnInitialConfigReadyForDataStream,
- void(MaybeAudioConfig, MaybeVideoConfig));
- MOCK_METHOD1(RegisterClient, void(std::shared_ptr<SourceClient>));
+ MOCK_METHOD(void, BufferedRangesChanged, (), (const override));
+ MOCK_METHOD(void,
+ OnInitialConfigReady,
+ (MaybeAudioConfig, MaybeVideoConfig),
+ (override));
+ MOCK_METHOD(void,
+ RegisterClient,
+ (std::shared_ptr<SourceClient>),
+ (override));
+ MOCK_METHOD(void,
+ SetMediaStreamAudioTrackSink,
+ (std::shared_ptr<blink::WebElementaryMediaTrackMsAudioSink>),
+ (override));
+ MOCK_METHOD(void,
+ SetMediaStreamVideoTrackSink,
+ (std::shared_ptr<blink::WebElementaryMediaTrackMsVideoSink>),
+ (override));
};
} // namespace worker_thread
std::static_pointer_cast<DemuxerClient>(demuxer_client_mock),
std::move(emss_initialized_));
FlushForTesting();
- CallMethod(demuxer_,
- &DataStreamDemuxerImpl::OnInitialConfigReadyForDataStream,
+ CallMethod(demuxer_, &DataStreamDemuxerImpl::OnInitialConfigReady,
MaybeAudioConfig{},
std::make_tuple(std::make_unique<media::VideoDecoderConfig>(),
DecodingMode::kHardware));
"elementary_media_track_seek_event.h",
"elementary_media_track_session_id_changed_event.cc",
"elementary_media_track_session_id_changed_event.h",
+ "ms_audio_track_source.cc",
+ "ms_audio_track_source.h",
+ "ms_video_track_source.cc",
+ "ms_video_track_source.h",
"same_thread_elementary_media_stream_source_attachment.cc",
"same_thread_elementary_media_stream_source_attachment.h",
"side_thread_elementary_media_track.cc",
#include "media/base/audio_decoder_config.h"
#include "media/base/media_track.h"
#include "media/base/video_decoder_config.h"
+#include "platform/mediastream/media_stream_component.h"
#include "services/elementary_media_stream_source/public/cpp/logger.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/platform/bindings/exception_code.h"
#include "third_party/blink/renderer/platform/bindings/exception_messages.h"
#include "third_party/blink/renderer/platform/elementary_media_stream_source/web_elementary_media_track_dispatcher.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_descriptor.h"
// autogenerated headers
#include "third_party/blink/renderer/bindings/modules/v8/v8_elementary_audio_stream_track_config.h"
auto result = web_elementary_media_stream_source_dispatcher_->RunTask(
&WebElementaryMediaStreamSourceControl::SetSourceOpened);
+ if (load_deferred_until_source_open_cb_) {
+ EMSS_LOG(INFO) << "Triggering deferred web media player load...";
+ main_js_task_runner_->PostTask(
+ FROM_HERE, std::move(load_deferred_until_source_open_cb_));
+ }
+
main_js_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
return rendering_mode_ == RenderingModeVideoTextureKeyword();
}
+void ElementaryMediaStreamSource::OnLoadDeferredUntilSourceOpen(
+ base::OnceClosure on_source_opened) {
+ EMSS_DEBUG();
+
+ load_deferred_until_source_open_cb_ = std::move(on_source_opened);
+}
+
void ElementaryMediaStreamSource::OnPause() {
EMSS_DEBUG();
playback_position, session_id);
}
+MediaStreamDescriptor*
+ElementaryMediaStreamSource::GetMediaStreamDescriptorIfAvailable() {
+ EMSS_DEBUG();
+
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ const bool enable_ttvd =
+ command_line.HasSwitch(switches::kEnableUpstreamArchitecture);
+ if (!enable_ttvd || !IsLowLatencyMode()) {
+ EMSS_DEBUG() << "Not available!";
+ return nullptr;
+ }
+
+ if (media_stream_descriptor_)
+ return media_stream_descriptor_;
+
+ media_stream_descriptor_ = MakeGarbageCollected<MediaStreamDescriptor>(
+ MediaStreamComponentVector{}, MediaStreamComponentVector{});
+ return media_stream_descriptor_;
+}
+
//////////////// EventTarget interface ////////////////
ExecutionContext* ElementaryMediaStreamSource::GetExecutionContext() const {
visitor->Trace(emss_tracer_);
visitor->Trace(open_resolver_);
visitor->Trace(video_tracks_);
+ visitor->Trace(media_stream_descriptor_);
EventTargetWithInlineData::Trace(visitor);
ExecutionContextLifecycleObserver::Trace(visitor);
}
Detach();
}
+//////////////// Media Stream support: ////////////////
+
+void ElementaryMediaStreamSource::SetMediaStreamAudioTrackSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsAudioSink> audio_sink) {
+ EMSS_DEBUG();
+ web_elementary_media_stream_source_dispatcher_->RunTask(
+ &WebElementaryMediaStreamSourceControl::SetMediaStreamAudioTrackSink,
+ std::move(audio_sink));
+}
+
+void ElementaryMediaStreamSource::SetMediaStreamVideoTrackSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsVideoSink> video_sink) {
+ EMSS_DEBUG();
+ web_elementary_media_stream_source_dispatcher_->RunTask(
+ &WebElementaryMediaStreamSourceControl::SetMediaStreamVideoTrackSink,
+ std::move(video_sink));
+}
+
/////////////////////////////////// private ////////////////////////////////////
ElementaryMediaStreamSource::ElementaryMediaStreamSource(
// Garbage-collector managed:
close_resolver_(nullptr),
emss_tracer_(nullptr),
- open_resolver_(nullptr) {
+ open_resolver_(nullptr),
+ media_stream_descriptor_(nullptr) {
EMSS_LOG(INFO) << "Constructing object, EMSS version = "
<< ElementaryMediaStreamSourceVersion::GetApiVersion() << ", "
<< latency_mode_ << ", " << rendering_mode_;
std::move(web_elementary_video_track_dispatcher), this,
active_decoding_mode);
video_tracks_.push_back(video_track);
+ if (media_stream_descriptor_) {
+ media_stream_descriptor_->AddComponent(
+ video_track->GetMediaStreamComponent());
+ }
return video_track;
}
bool IsGameMode() const;
bool IsLowLatencyMode() const;
bool IsVideoTextureMode() const;
+ void OnLoadDeferredUntilSourceOpen(base::OnceClosure on_source_opened);
void OnPause();
void OnPlay();
void OnResume();
WebTimeRanges BufferedInternal() const;
WebTimeRanges SeekableInternal() const;
void UpdatePlaybackPosition(double playback_position, uint32_t session_id);
+ MediaStreamDescriptor* GetMediaStreamDescriptorIfAvailable();
// EventTarget interface
ExecutionContext* GetExecutionContext() const override;
void SetPlayerOpenedPending() override;
void Stop() override;
+ // Media Stream support:
+ void SetMediaStreamAudioTrackSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsAudioSink>);
+ void SetMediaStreamVideoTrackSink(
+ std::shared_ptr<blink::WebElementaryMediaTrackMsVideoSink>);
+
private:
ElementaryMediaTrack* addAudioTrackCommon(
const ElementaryAudioStreamTrackConfig*,
scoped_refptr<ElementaryMediaStreamSourceAttachment> emss_attachment_;
bool is_suspended_;
double last_known_playback_position_;
+ base::OnceClosure load_deferred_until_source_open_cb_;
const scoped_refptr<base::SingleThreadTaskRunner> main_js_task_runner_;
ReadyState ready_state_;
uint32_t session_id_;
Member<ScriptPromiseResolver> open_resolver_;
HeapVector<Member<ElementaryMediaTrack>> video_tracks_;
+ // Media streams integration (used only when EMSS works with
+ // webmediaplayer_ms):
+ WeakMember<MediaStreamDescriptor> media_stream_descriptor_;
+
friend std::ostream& operator<<(std::ostream& os, ReadyState seeking_status);
};
{kBaseEmss, true, 1},
{kVideoTexture, !IsUsingTTvd(), 2},
{kSoftwareDecoding, true, 3},
- {kConstructWithModes, !IsUsingTTvd(), 4},
+ {kConstructWithModes, true, 4},
{kLowLatencyVideoTexture, !IsUsingTTvd(), 4},
- {kUltraLowLatency, !IsUsingTTvd(), 5},
+ {kUltraLowLatency, true, 5},
{kConfigValidation, true, 6},
{kBackendError, true, 7},
}};
#include "media/base/video_codecs.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_types.h"
+#include "modules/elementary_media_stream_source/ms_audio_track_source.h"
+#include "modules/elementary_media_stream_source/ms_video_track_source.h"
+#include "modules/mediastream/media_stream_video_track.h"
#include "platform/bindings/exception_code.h"
+#include "platform/heap/garbage_collected.h"
+#include "platform/mediastream/media_stream_audio_track.h"
+#include "platform/mediastream/media_stream_component_impl.h"
#include "services/elementary_media_stream_source/public/cpp/codec_capabilities.h"
#include "services/elementary_media_stream_source/public/cpp/logger.h"
#include "services/elementary_media_stream_source/public/cpp/mojom_type_exports.h"
// layers.
constexpr const auto kSyncAppendTimeoutMs = base::Milliseconds(2000);
+int32_t GetNextMsTrackUniqueId() {
+ static std::atomic<int32_t> unique_id = 0;
+ return unique_id.fetch_add(1);
+}
+
+String MakeMsTrackId(int32_t unique_id, ElementaryMediaTrack::TrackType type) {
+ std::ostringstream oss;
+ oss << (type == ElementaryMediaTrack::TrackType::kVideo ? "video" : "audio")
+ << "-elementary-track-" << unique_id;
+ const auto id_str = oss.str();
+ return {id_str.c_str(), id_str.size()};
+}
+
+std::tuple<MediaStreamComponent*,
+ std::shared_ptr<WebElementaryMediaTrackMsAudioSink>>
+CreateMsAudioComponent() {
+ const auto unique_id = GetNextMsTrackUniqueId();
+ const auto id =
+ MakeMsTrackId(unique_id, ElementaryMediaTrack::TrackType::kAudio);
+ auto track_source =
+ std::make_unique<MsAudioTrackSource>(base::ThreadTaskRunnerHandle::Get());
+ auto track = std::make_unique<MediaStreamAudioTrack>(
+ /* is_local_track */ false);
+ auto sink = track_source->GetAudioSink();
+ return {MakeGarbageCollected<MediaStreamComponentImpl>(
+ id,
+ MakeGarbageCollected<MediaStreamSource>(
+ id, MediaStreamSource::kTypeAudio, id, /* remote */ true,
+ std::move(track_source)),
+ std::move(track)),
+ std::move(sink)};
+}
+
+std::tuple<MediaStreamComponent*,
+ std::shared_ptr<WebElementaryMediaTrackMsVideoSink>>
+CreateMsVideoComponent() {
+ const auto unique_id = GetNextMsTrackUniqueId();
+ const auto id =
+ MakeMsTrackId(unique_id, ElementaryMediaTrack::TrackType::kVideo);
+ auto track_source =
+ std::make_unique<MsVideoTrackSource>(base::ThreadTaskRunnerHandle::Get());
+ auto track = std::make_unique<MediaStreamVideoTrack>(
+ track_source.get(), MediaStreamVideoSource::ConstraintsOnceCallback(),
+ true);
+ auto sink = track_source->GetVideoSink();
+ return {MakeGarbageCollected<MediaStreamComponentImpl>(
+ id,
+ MakeGarbageCollected<MediaStreamSource>(
+ id, MediaStreamSource::kTypeVideo, id, /* remote */ true,
+ std::move(track_source)),
+ std::move(track)),
+ std::move(sink)};
+}
+
media::EncryptionScheme EncryptionModeAsEnum(
const WTF::String& encryption_mode) {
EMSS_VERBOSE_NO_INSTANCE();
// Garbage-collector managed:
get_picture_resolver_(nullptr),
source_(source),
- video_texture_(nullptr) {
+ video_texture_(nullptr),
+ ms_component_(nullptr) {
EMSS_DEBUG_TYPED() << "Constructing object";
EMSS_LOG_ASSERT(source_);
visitor->Trace(get_picture_resolver_);
visitor->Trace(source_);
visitor->Trace(video_texture_);
+ visitor->Trace(ms_component_);
EventTargetWithInlineData::Trace(visitor);
ActiveScriptWrappable<ElementaryMediaTrack>::Trace(visitor);
ExecutionContextLifecycleObserver::Trace(visitor);
video_size, // natural_size
video_extra_data,
EncryptionScheme::kUnencrypted};
+ video_decoder_config.set_is_rtc(emss_latency_mode !=
+ EmssLatencyMode::kNormal);
+#if defined(TIZEN_TV_UPSTREAM_MULTIMEDIA)
+ video_decoder_config.set_is_game_mode(emss_latency_mode ==
+ EmssLatencyMode::kUltraLow);
+#endif // defined(TIZEN_TV_UPSTREAM_MULTIMEDIA)
#if BUILDFLAG(IS_TIZEN_TV)
int framerate_num = static_cast<int>(config->framerateNum());
&WebElementaryMediaTrackControl::GetHighestBufferedPresentationTimestamp);
}
+MediaStreamComponent* ElementaryMediaTrack::GetMediaStreamComponent() {
+ if (ms_component_)
+ return ms_component_;
+
+ if (!web_elementary_media_track_dispatcher_) {
+ return nullptr;
+ }
+
+ if (Type() == TrackType::kVideo) {
+ auto [component, video_sink] = CreateMsVideoComponent();
+ if (source_)
+ source_->SetMediaStreamVideoTrackSink(std::move(video_sink));
+ return ms_component_ = component;
+ }
+
+ auto [component, audio_sink] = CreateMsAudioComponent();
+ if (source_)
+ source_->SetMediaStreamAudioTrackSink(std::move(audio_sink));
+ return ms_component_ = component;
+}
+
bool ElementaryMediaTrack::IsEnabled() const {
EMSS_DEBUG_TYPED();
#include "third_party/blink/renderer/modules/elementary_media_stream_source/elementary_media_print_helpers.h"
#include "third_party/blink/renderer/platform/bindings/exception_code.h"
#include "third_party/blink/renderer/platform/elementary_media_stream_source/web_elementary_media_packet_metadata.h"
+#include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
#include "third_party/blink/renderer/platform/elementary_media_stream_source/web_elementary_media_track_control.h"
#include "third_party/blink/renderer/platform/elementary_media_stream_source/web_elementary_media_track_dispatcher.h"
#include "third_party/blink/renderer/platform/elementary_media_stream_source/web_elementary_media_track_operations.h"
public:
using DecodingMode = WebElementaryMediaTrackOperations::DecodingMode;
using PlayerMode = WebElementaryMediaTrackOperations::PlayerMode;
+ using TrackType = WebElementaryMediaTrackControl::TrackType;
enum class ConfigVerificationResult {
kConfigSupported,
const AtomicString& rendering_mode);
double GetHighestBufferedPresentationTimestamp() const;
+ MediaStreamComponent* GetMediaStreamComponent();
bool IsEnabled() const;
+ TrackType Type() const;
+
// content::WebElementaryMediaTrackControl::
// WebElementaryMediaTrackControlClient
void OnSeek(base::TimeDelta seek_to) override;
private:
using OperationResult = WebElementaryMediaTrackOperations::OperationResult;
- using TrackType = WebElementaryMediaTrackControl::TrackType;
struct SyncAppendData {
base::Lock append_lock;
OperationResult SyncAppendWaitWhileLocked(bool* is_call_finished)
EXCLUSIVE_LOCKS_REQUIRED(sync_append_data_->append_lock);
- TrackType Type() const;
-
void UpdateFramerateAndVideoConfigurationIfNeeded(
const WebElementaryMediaPacketMetadata&);
WeakMember<ElementaryMediaStreamSource> source_;
Member<WebGLTexture> video_texture_;
+ // Media streams integration (used only when EMSS works with
+ // webmediaplayer_ms):
+ Member<MediaStreamComponent> ms_component_;
+
friend class SideThreadElementaryMediaTrack;
};
--- /dev/null
+// Copyright (c) 2024 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.
+
+#include "tizen_src/chromium_impl/third_party/blink/renderer/modules/elementary_media_stream_source/ms_audio_track_source.h"
+
+#include "services/elementary_media_stream_source/public/cpp/logger.h"
+
+namespace blink {
+
+class MsAudioTrackSource::SinkImpl : public WebElementaryMediaTrackMsAudioSink {
+ public:
+ SinkImpl() = default;
+ ~SinkImpl() override = default;
+}; // class MsAudioTrackSource::SinkImpl
+
+MsAudioTrackSource::MsAudioTrackSource(
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
+ : MediaStreamAudioSource(std::move(main_task_runner),
+ /* is_local_source */ false) {
+ EMSS_DEBUG() << "Constructing object";
+}
+
+MsAudioTrackSource::~MsAudioTrackSource() {
+ EMSS_DEBUG() << "Destructing object";
+}
+
+std::shared_ptr<WebElementaryMediaTrackMsAudioSink>
+MsAudioTrackSource::GetAudioSink() {
+ return sink_impl_;
+}
+
+} // namespace blink
--- /dev/null
+// Copyright (c) 2024 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 TIZEN_SRC_CHROMIUM_IMPL_THIRD_PARTY_BLINK_RENDERER_MODULES_ELEMENTARY_MEDIA_STREAM_SOURCE_MS_AUDIO_TRACK_SOURCE_H_
+#define TIZEN_SRC_CHROMIUM_IMPL_THIRD_PARTY_BLINK_RENDERER_MODULES_ELEMENTARY_MEDIA_STREAM_SOURCE_MS_AUDIO_TRACK_SOURCE_H_
+
+#include "third_party/blink/renderer/platform/mediastream/media_stream_audio_source.h"
+
+#include "third_party/blink/renderer/platform/elementary_media_stream_source/web_elementary_media_track_ms_audio_sink.h"
+
+namespace blink {
+
+class MsAudioTrackSource : public MediaStreamAudioSource {
+ public:
+ explicit MsAudioTrackSource(
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
+ ~MsAudioTrackSource() override;
+
+ std::shared_ptr<WebElementaryMediaTrackMsAudioSink> GetAudioSink();
+
+ private:
+ class SinkImpl;
+
+ std::shared_ptr<SinkImpl> sink_impl_;
+};
+
+} // namespace blink
+
+#endif // TIZEN_SRC_CHROMIUM_IMPL_THIRD_PARTY_BLINK_RENDERER_MODULES_ELEMENTARY_MEDIA_STREAM_SOURCE_MS_VIDEO_TRACK_SOURCE_H_
--- /dev/null
+// Copyright (c) 2024 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.
+
+#include "third_party/blink/renderer/modules/elementary_media_stream_source/ms_video_track_source.h"
+
+#include "base/time/time.h"
+#include "services/elementary_media_stream_source/public/cpp/logger.h"
+
+namespace blink {
+
+class MsVideoTrackSource::SinkImpl : public WebElementaryMediaTrackMsVideoSink {
+ public:
+ explicit SinkImpl(base::SingleThreadTaskRunner* frame_delivery_task_runner)
+ : frame_delivery_task_runner_(frame_delivery_task_runner) {}
+
+ ~SinkImpl() override = default;
+
+ void Start(VideoCaptureDeliverFrameCB frame_cb,
+ EncodedVideoFrameCB encoded_frame_cb,
+ VideoCaptureCropVersionCB crop_version_cb) {
+ EMSS_DEBUG();
+ frame_cb_ = std::move(frame_cb);
+ encoded_frame_cb_ = std::move(encoded_frame_cb);
+ crop_version_cb_ = std::move(crop_version_cb);
+ }
+
+ // WebElementaryMediaTrackMsVideoSink:
+
+ void AppendPacket(scoped_refptr<media::VideoFrame> frame) override {
+ EMSS_VERBOSE() << "Transferring frame to frame delivery thread: "
+ << frame->timestamp();
+ frame_delivery_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(
+ [](VideoCaptureDeliverFrameCB frame_cb,
+ scoped_refptr<media::VideoFrame> frame) {
+ EMSS_VERBOSE_NO_INSTANCE()
+ << "Delivering frame: " << frame->timestamp();
+ auto capture_time = base::TimeTicks::Now();
+ frame_cb.Run(std::move(frame), {}, capture_time);
+ },
+ frame_cb_, std::move(frame)));
+ }
+
+ private:
+ base::SingleThreadTaskRunner* frame_delivery_task_runner_;
+
+ VideoCaptureDeliverFrameCB frame_cb_;
+ EncodedVideoFrameCB encoded_frame_cb_;
+ VideoCaptureCropVersionCB crop_version_cb_;
+}; // class MsVideoTrackSource::SinkImpl
+
+//////////////////// own public methods: ////////////////////
+
+MsVideoTrackSource::MsVideoTrackSource(
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
+ : MediaStreamVideoSource(std::move(main_task_runner)),
+ sink_impl_(std::make_shared<SinkImpl>(io_task_runner())),
+ weak_factory_(this) {
+ EMSS_DEBUG() << "Constructing object";
+}
+
+MsVideoTrackSource::~MsVideoTrackSource() {
+ EMSS_DEBUG() << "Destructing object";
+}
+
+std::shared_ptr<WebElementaryMediaTrackMsVideoSink>
+MsVideoTrackSource::GetVideoSink() {
+ return sink_impl_;
+}
+
+//////////////////// MediaStreamVideoSource: ////////////////////
+
+base::WeakPtr<MediaStreamVideoSource> MsVideoTrackSource::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
+void MsVideoTrackSource::StartSourceImpl(
+ VideoCaptureDeliverFrameCB frame_callback,
+ EncodedVideoFrameCB encoded_frame_callback,
+ VideoCaptureCropVersionCB crop_version_callback) {
+ EMSS_DEBUG();
+ sink_impl_->Start(std::move(frame_callback),
+ std::move(encoded_frame_callback),
+ std::move(crop_version_callback));
+ OnStartDone(mojom::MediaStreamRequestResult::OK);
+}
+
+void MsVideoTrackSource::StopSourceImpl() {
+ EMSS_DEBUG();
+}
+
+} // namespace blink
--- /dev/null
+// Copyright (c) 2024 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 TIZEN_SRC_CHROMIUM_IMPL_THIRD_PARTY_BLINK_RENDERER_MODULES_ELEMENTARY_MEDIA_STREAM_SOURCE_MS_VIDEO_TRACK_SOURCE_H_
+#define TIZEN_SRC_CHROMIUM_IMPL_THIRD_PARTY_BLINK_RENDERER_MODULES_ELEMENTARY_MEDIA_STREAM_SOURCE_MS_VIDEO_TRACK_SOURCE_H_
+
+#include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.h"
+
+#include "third_party/blink/renderer/platform/elementary_media_stream_source/web_elementary_media_track_ms_video_sink.h"
+
+namespace blink {
+
+class MsVideoTrackSource : public MediaStreamVideoSource {
+ public:
+ explicit MsVideoTrackSource(scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
+ ~MsVideoTrackSource() override;
+
+ std::shared_ptr<WebElementaryMediaTrackMsVideoSink> GetVideoSink();
+
+ // MediaStreamVideoSource:
+ base::WeakPtr<MediaStreamVideoSource> GetWeakPtr() override;
+ void StartSourceImpl(
+ VideoCaptureDeliverFrameCB frame_callback,
+ EncodedVideoFrameCB encoded_frame_callback,
+ VideoCaptureCropVersionCB crop_version_callback) override;
+ void StopSourceImpl() override;
+
+ private:
+ class SinkImpl;
+
+ std::shared_ptr<SinkImpl> sink_impl_;
+
+ base::WeakPtrFactory<MediaStreamVideoSource> weak_factory_;
+};
+
+} // namespace blink
+
+#endif // TIZEN_SRC_CHROMIUM_IMPL_THIRD_PARTY_BLINK_RENDERER_MODULES_ELEMENTARY_MEDIA_STREAM_SOURCE_MS_VIDEO_TRACK_SOURCE_H_
GetSource(tracer)->OnPause();
}
+void SameThreadElementaryMediaStreamSourceAttachment::
+ OnLoadDeferredUntilSourceOpen(MediaSourceTracer* tracer,
+ base::OnceClosure on_source_opened) {
+ EMSS_DEBUG();
+
+ GetSource(tracer)->OnLoadDeferredUntilSourceOpen(std::move(on_source_opened));
+}
+
void SameThreadElementaryMediaStreamSourceAttachment::OnPlay(
blink::MediaSourceTracer* tracer) {
EMSS_DEBUG();
GetSource(tracer)->UpdatePlaybackPosition(playback_position, session_id);
}
+MediaStreamDescriptor* SameThreadElementaryMediaStreamSourceAttachment::
+ GetMediaStreamDescriptorIfAvailable(MediaSourceTracer* tracer) {
+ return GetSource(tracer)->GetMediaStreamDescriptorIfAvailable();
+}
+
// ElementaryMediaStreamSourceAttachment interface:
void SameThreadElementaryMediaStreamSourceAttachment::OnDurationChanged(
bool IsVideoTextureMode(MediaSourceTracer* tracer) const override;
+ void OnLoadDeferredUntilSourceOpen(
+ MediaSourceTracer* tracer,
+ base::OnceClosure on_source_opened) override;
+
void OnPause(MediaSourceTracer* tracer) override;
void OnPlay(MediaSourceTracer* tracer) override;
double playback_position,
uint32_t session_id) override;
+ MediaStreamDescriptor* GetMediaStreamDescriptorIfAvailable(
+ MediaSourceTracer* tracer) override;
+
// ElementaryMediaStreamSourceAttachment interface:
void OnDurationChanged(MediaSourceTracer* tracer,
"web_elementary_media_track_control.h",
"web_elementary_media_track_dispatcher.cc",
"web_elementary_media_track_dispatcher.h",
+ "web_elementary_media_track_ms_audio_sink.h",
+ "web_elementary_media_track_ms_video_sink.h",
"web_elementary_media_track_operations.h",
]
}
virtual void SetDuration(double) = 0;
virtual OperationCallbackResult SetSourceClosed() = 0;
virtual OperationCallbackResult SetSourceOpened() = 0;
+ virtual void SetMediaStreamAudioTrackSink(
+ std::shared_ptr<WebElementaryMediaTrackMsAudioSink>) = 0;
+ virtual void SetMediaStreamVideoTrackSink(
+ std::shared_ptr<WebElementaryMediaTrackMsVideoSink>) = 0;
protected:
WebElementaryMediaStreamSourceControl() = default;
#include "third_party/blink/renderer/platform/elementary_media_stream_source/web_elementary_media_stream_source_dispatcher.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/control_thread/source_impl.h"
#include "services/elementary_media_stream_source/public/cpp/logger.h"
namespace blink {
+// static
+WebElementaryMediaStreamSourceDispatcher::CreationTuple
+WebElementaryMediaStreamSourceDispatcher::Create(
+ PipelineMode pipeline_mode,
+ scoped_refptr<base::SingleThreadTaskRunner> control_thread_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> worker_thread_task_runner) {
+ auto [source_dispatcher, any_thread_source_impl, control_thread_source_impl,
+ worker_thread_source_impl] =
+ SourceDispatcher::Create(pipeline_mode, control_thread_task_runner,
+ worker_thread_task_runner);
+
+ auto blink_source_dispatcher = std::make_shared<
+ blink::WebElementaryMediaStreamSourceDispatcher>(
+ control_thread_task_runner, std::move(source_dispatcher),
+ std::static_pointer_cast<blink::WebElementaryMediaStreamSourceControl>(
+ control_thread_source_impl));
+
+ return std::make_tuple(std::move(blink_source_dispatcher),
+ std::move(any_thread_source_impl),
+ std::move(control_thread_source_impl),
+ std::move(worker_thread_source_impl));
+}
+
WebElementaryMediaStreamSourceDispatcher::
WebElementaryMediaStreamSourceDispatcher(
scoped_refptr<base::SingleThreadTaskRunner> control_thread_task_runner,
#include "base/memory/scoped_refptr.h"
#include "base/task/single_thread_task_runner.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/common_types.h"
+#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer_dispatcher.h"
#include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/source_dispatcher.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/tizen/stream_framerate.h"
public:
using DecodingMode = WebElementaryMediaTrackOperations::DecodingMode;
+ using PipelineMode = content::elementary_media_stream_source::PipelineMode;
+ using DemuxerDispatcher =
+ content::elementary_media_stream_source::any_thread::DemuxerDispatcher;
using SourceDispatcher =
content::elementary_media_stream_source::any_thread::SourceDispatcher;
using TrackDispatcher =
content::elementary_media_stream_source::any_thread::TrackDispatcher;
+ using AnySourceImpl =
+ content::elementary_media_stream_source::any_thread::SourceImpl;
+ using ControlSourceImpl =
+ content::elementary_media_stream_source::control_thread::SourceImpl;
+ using WorkerSourceImpl =
+ content::elementary_media_stream_source::worker_thread::SourceImpl;
+
+ using CreationTuple =
+ std::tuple<std::shared_ptr<WebElementaryMediaStreamSourceDispatcher>,
+ std::shared_ptr<AnySourceImpl>,
+ std::shared_ptr<ControlSourceImpl>,
+ std::shared_ptr<WorkerSourceImpl>>;
+
+ static CreationTuple Create(
+ PipelineMode pipeline_mode,
+ scoped_refptr<base::SingleThreadTaskRunner> control_thread_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> worker_thread_task_runner);
+
WebElementaryMediaStreamSourceDispatcher(
scoped_refptr<base::SingleThreadTaskRunner> control_thread_task_runner,
std::shared_ptr<SourceDispatcher> source_dispatcher,
std::shared_ptr<WebElementaryMediaStreamSourceControl> client);
-
~WebElementaryMediaStreamSourceDispatcher() override;
std::shared_ptr<WebElementaryMediaTrackDispatcher> CreateAudioTrackDispatcher(
std::move(track_control), std::move(track_operations));
}
+ void KeepDemuxerDispatcher(
+ std::shared_ptr<DemuxerDispatcher> maybe_demuxer_dispatcher) {
+ maybe_demuxer_dispatcher_ = std::move(maybe_demuxer_dispatcher);
+ }
+
private:
std::tuple<std::shared_ptr<WebElementaryMediaStreamSourceControl>> clients_;
std::shared_ptr<SourceDispatcher> source_dispatcher_;
+
+ // DemuxerDispatcher will be owned only by media::Demuxer implementation if
+ // available. If not available, WebElementaryMediaStreamSourceDispatcher will
+ // hold DemuxerDispatcher alive although it won't use it directly.
+ std::shared_ptr<DemuxerDispatcher> maybe_demuxer_dispatcher_;
};
} // namespace blink
#include "media/base/video_frame.h"
#include "third_party/blink/renderer/platform/elementary_media_stream_source/web_elementary_media_enable_control_dispatcher.h"
#include "third_party/blink/renderer/platform/elementary_media_stream_source/web_elementary_media_packet_metadata.h"
+#include "third_party/blink/renderer/platform/elementary_media_stream_source/web_elementary_media_track_ms_audio_sink.h"
+#include "third_party/blink/renderer/platform/elementary_media_stream_source/web_elementary_media_track_ms_video_sink.h"
namespace blink {
--- /dev/null
+// Copyright (c) 2024 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 TIZEN_SRC_CHROMIUM_IMPL_THIRD_PARTY_BLINK_PUBLIC_PLATFORM_TIZEN_ELEMENTARY_MEDIA_STREAM_SOURCE_WEB_ELEMENTARY_MEDIA_TRACK_MS_AUDIO_SINK_H_
+#define TIZEN_SRC_CHROMIUM_IMPL_THIRD_PARTY_BLINK_PUBLIC_PLATFORM_TIZEN_ELEMENTARY_MEDIA_STREAM_SOURCE_WEB_ELEMENTARY_MEDIA_TRACK_MS_AUDIO_SINK_H_
+
+namespace blink {
+
+class WebElementaryMediaTrackMsAudioSink {
+ public:
+ WebElementaryMediaTrackMsAudioSink() = default;
+ virtual ~WebElementaryMediaTrackMsAudioSink() = default;
+};
+
+} // namespace blink
+
+#endif // TIZEN_SRC_CHROMIUM_IMPL_THIRD_PARTY_BLINK_PUBLIC_PLATFORM_TIZEN_ELEMENTARY_MEDIA_STREAM_SOURCE_WEB_ELEMENTARY_MEDIA_TRACK_MS_AUDIO_SINK_H_
\ No newline at end of file
--- /dev/null
+// Copyright (c) 2024 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 TIZEN_SRC_CHROMIUM_IMPL_THIRD_PARTY_BLINK_PUBLIC_PLATFORM_TIZEN_ELEMENTARY_MEDIA_STREAM_SOURCE_WEB_ELEMENTARY_MEDIA_TRACK_MS_VIDEO_SINK_H_
+#define TIZEN_SRC_CHROMIUM_IMPL_THIRD_PARTY_BLINK_PUBLIC_PLATFORM_TIZEN_ELEMENTARY_MEDIA_STREAM_SOURCE_WEB_ELEMENTARY_MEDIA_TRACK_MS_VIDEO_SINK_H_
+
+#include "media/base/video_frame.h"
+
+namespace blink {
+
+class WebElementaryMediaTrackMsVideoSink {
+ public:
+ WebElementaryMediaTrackMsVideoSink() = default;
+ virtual ~WebElementaryMediaTrackMsVideoSink() = default;
+
+ virtual void AppendPacket(scoped_refptr<media::VideoFrame>) = 0;
+};
+
+} // namespace blink
+
+#endif // TIZEN_SRC_CHROMIUM_IMPL_THIRD_PARTY_BLINK_PUBLIC_PLATFORM_TIZEN_ELEMENTARY_MEDIA_STREAM_SOURCE_WEB_ELEMENTARY_MEDIA_TRACK_MS_VIDEO_SINK_H_
\ No newline at end of file