blob: 1e75888faf9954ec4ca0dd985c39cbaf40320bcc [file] [log] [blame]
// Copyright 2016 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef COBALT_MEDIA_BASE_STARBOARD_PLAYER_H_
#define COBALT_MEDIA_BASE_STARBOARD_PLAYER_H_
#include <map>
#include <string>
#include <utility>
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/synchronization/lock.h"
#include "base/time/time.h"
#include "cobalt/media/base/decode_target_provider.h"
#include "cobalt/media/base/decoder_buffer_cache.h"
#include "cobalt/media/base/sbplayer_set_bounds_helper.h"
#include "starboard/media.h"
#include "starboard/player.h"
#include "third_party/chromium/media/base/audio_decoder_config.h"
#include "third_party/chromium/media/base/decoder_buffer.h"
#include "third_party/chromium/media/base/demuxer_stream.h"
#include "third_party/chromium/media/base/video_decoder_config.h"
#include "third_party/chromium/media/cobalt/ui/gfx/geometry/rect.h"
#if SB_HAS(PLAYER_WITH_URL)
#include SB_URL_PLAYER_INCLUDE_PATH
#endif // SB_HAS(PLAYER_WITH_URL)
namespace cobalt {
namespace media {
// TODO: Add switch to disable caching
class StarboardPlayer {
typedef ::media::AudioDecoderConfig AudioDecoderConfig;
typedef ::media::DecoderBuffer DecoderBuffer;
typedef ::media::DemuxerStream DemuxerStream;
typedef ::media::VideoDecoderConfig VideoDecoderConfig;
public:
class Host {
public:
virtual void OnNeedData(DemuxerStream::Type type) = 0;
virtual void OnPlayerStatus(SbPlayerState state) = 0;
virtual void OnPlayerError(SbPlayerError error,
const std::string& message) = 0;
protected:
~Host() {}
};
// Call to get the SbDecodeTargetGraphicsContextProvider for SbPlayerCreate().
typedef base::Callback<SbDecodeTargetGraphicsContextProvider*()>
GetDecodeTargetGraphicsContextProviderFunc;
#if SB_HAS(PLAYER_WITH_URL)
typedef base::Callback<void(const char*, const unsigned char*, unsigned)>
OnEncryptedMediaInitDataEncounteredCB;
// Create a StarboardPlayer with url-based player.
StarboardPlayer(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
const std::string& url, SbWindow window, Host* host,
SbPlayerSetBoundsHelper* set_bounds_helper,
bool allow_resume_after_suspend, bool prefer_decode_to_texture,
const OnEncryptedMediaInitDataEncounteredCB&
encrypted_media_init_data_encountered_cb,
DecodeTargetProvider* const decode_target_provider);
#endif // SB_HAS(PLAYER_WITH_URL)
// Create a StarboardPlayer with normal player
StarboardPlayer(
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
const GetDecodeTargetGraphicsContextProviderFunc&
get_decode_target_graphics_context_provider_func,
const AudioDecoderConfig& audio_config,
const std::string& audio_mime_type,
const VideoDecoderConfig& video_config,
const std::string& video_mime_type, SbWindow window,
SbDrmSystem drm_system, Host* host,
SbPlayerSetBoundsHelper* set_bounds_helper,
bool allow_resume_after_suspend, bool prefer_decode_to_texture,
DecodeTargetProvider* const decode_target_provider,
const std::string& max_video_capabilities);
~StarboardPlayer();
bool IsValid() const { return SbPlayerIsValid(player_); }
void UpdateAudioConfig(const AudioDecoderConfig& audio_config,
const std::string& mime_type);
void UpdateVideoConfig(const VideoDecoderConfig& video_config,
const std::string& mime_type);
void WriteBuffer(DemuxerStream::Type type,
const scoped_refptr<DecoderBuffer>& buffer);
void SetBounds(int z_index, const gfx::Rect& rect);
void PrepareForSeek();
void Seek(base::TimeDelta time);
void SetVolume(float volume);
void SetPlaybackRate(double playback_rate);
void GetInfo(uint32* video_frames_decoded, uint32* video_frames_dropped,
base::TimeDelta* media_time);
#if SB_HAS(PLAYER_WITH_URL)
void GetUrlPlayerBufferedTimeRanges(base::TimeDelta* buffer_start_time,
base::TimeDelta* buffer_length_time);
void GetVideoResolution(int* frame_width, int* frame_height);
base::TimeDelta GetDuration();
base::TimeDelta GetStartDate();
void SetDrmSystem(SbDrmSystem drm_system);
#endif // SB_HAS(PLAYER_WITH_URL)
void Suspend();
// TODO: This is temporary for supporting background media playback.
// Need to be removed with media refactor.
void Resume(SbWindow window);
// These functions help the pipeline report an error message on a player
// creation error. TryToSetPlayerCreationErrorMessage() will set
// |player_creation_error_message_| and return true when called while
// |is_creating_player_| is true, else it will do nothing and return false.
bool TryToSetPlayerCreationErrorMessage(const std::string& message);
std::string GetPlayerCreationErrorMessage() const {
return player_creation_error_message_;
}
SbDecodeTarget GetCurrentSbDecodeTarget();
SbPlayerOutputMode GetSbPlayerOutputMode();
void RecordSetDrmSystemReadyTime(SbTimeMonotonic timestamp) {
set_drm_system_ready_cb_time_ = timestamp;
}
private:
enum State {
kPlaying,
kSuspended,
kResuming,
};
// This class ensures that the callbacks posted to |task_runner_| are ignored
// automatically once StarboardPlayer is destroyed.
class CallbackHelper : public base::RefCountedThreadSafe<CallbackHelper> {
public:
explicit CallbackHelper(StarboardPlayer* player);
void ClearDecoderBufferCache();
void OnDecoderStatus(SbPlayer player, SbMediaType type,
SbPlayerDecoderState state, int ticket);
void OnPlayerStatus(SbPlayer player, SbPlayerState state, int ticket);
void OnPlayerError(SbPlayer player, SbPlayerError error,
const std::string& message);
void OnDeallocateSample(const void* sample_buffer);
void ResetPlayer();
private:
base::Lock lock_;
StarboardPlayer* player_;
};
static const int64 kClearDecoderCacheIntervalInMilliseconds = 1000;
// A map from raw data pointer returned by DecoderBuffer::GetData() to the
// DecoderBuffer and a reference count. The reference count indicates how
// many instances of the DecoderBuffer is currently being decoded in the
// pipeline.
typedef std::map<const void*, std::pair<scoped_refptr<DecoderBuffer>, int>>
DecodingBuffers;
#if SB_HAS(PLAYER_WITH_URL)
OnEncryptedMediaInitDataEncounteredCB
on_encrypted_media_init_data_encountered_cb_;
static void EncryptedMediaInitDataEncounteredCB(
SbPlayer player, void* context, const char* init_data_type,
const unsigned char* init_data, unsigned int init_data_length);
void CreateUrlPlayer(const std::string& url);
#endif // SB_HAS(PLAYER_WITH_URL)
void CreatePlayer();
void WriteNextBufferFromCache(DemuxerStream::Type type);
void WriteBufferInternal(DemuxerStream::Type type,
const scoped_refptr<DecoderBuffer>& buffer);
void GetInfo_Locked(uint32* video_frames_decoded,
uint32* video_frames_dropped,
base::TimeDelta* media_time);
void UpdateBounds_Locked();
void ClearDecoderBufferCache();
void OnDecoderStatus(SbPlayer player, SbMediaType type,
SbPlayerDecoderState state, int ticket);
void OnPlayerStatus(SbPlayer player, SbPlayerState state, int ticket);
void OnPlayerError(SbPlayer player, SbPlayerError error,
const std::string& message);
void OnDeallocateSample(const void* sample_buffer);
static void DecoderStatusCB(SbPlayer player, void* context, SbMediaType type,
SbPlayerDecoderState state, int ticket);
static void PlayerStatusCB(SbPlayer player, void* context,
SbPlayerState state, int ticket);
static void PlayerErrorCB(SbPlayer player, void* context, SbPlayerError error,
const char* message);
static void DeallocateSampleCB(SbPlayer player, void* context,
const void* sample_buffer);
#if SB_HAS(PLAYER_WITH_URL)
static SbPlayerOutputMode ComputeSbUrlPlayerOutputMode(
bool prefer_decode_to_texture);
#endif // SB_HAS(PLAYER_WITH_URL)
// Returns the output mode that should be used for a video with the given
// specifications.
SbPlayerOutputMode ComputeSbPlayerOutputMode(
bool prefer_decode_to_texture) const;
void LogStartupLatency() const;
// The following variables are initialized in the ctor and never changed.
#if SB_HAS(PLAYER_WITH_URL)
std::string url_;
#endif // SB_HAS(PLAYER_WITH_URL)
const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
const GetDecodeTargetGraphicsContextProviderFunc
get_decode_target_graphics_context_provider_func_;
scoped_refptr<CallbackHelper> callback_helper_;
SbWindow window_;
SbDrmSystem drm_system_ = kSbDrmSystemInvalid;
Host* const host_;
// Consider merge |SbPlayerSetBoundsHelper| into CallbackHelper.
SbPlayerSetBoundsHelper* const set_bounds_helper_;
const bool allow_resume_after_suspend_;
// The following variables are only changed or accessed from the
// |task_runner_|.
AudioDecoderConfig audio_config_;
VideoDecoderConfig video_config_;
SbMediaAudioSampleInfo audio_sample_info_ = {};
SbMediaVideoSampleInfo video_sample_info_ = {};
DecodingBuffers decoding_buffers_;
int ticket_ = SB_PLAYER_INITIAL_TICKET;
float volume_ = 1.0f;
double playback_rate_ = 0.0;
bool seek_pending_ = false;
DecoderBufferCache decoder_buffer_cache_;
// The following variables can be accessed from GetInfo(), which can be called
// from any threads. So some of their usages have to be guarded by |lock_|.
base::Lock lock_;
// Stores the |z_index| and |rect| parameters of the latest SetBounds() call.
base::Optional<int> set_bounds_z_index_;
base::Optional<gfx::Rect> set_bounds_rect_;
State state_ = kPlaying;
SbPlayer player_;
uint32 cached_video_frames_decoded_;
uint32 cached_video_frames_dropped_;
base::TimeDelta preroll_timestamp_;
// Keep track of the output mode we are supposed to output to.
SbPlayerOutputMode output_mode_;
DecodeTargetProvider* const decode_target_provider_;
// Keep copies of the mime type strings instead of using the ones in the
// DemuxerStreams to ensure that the strings are always valid.
std::string audio_mime_type_;
std::string video_mime_type_;
// A string of video maximum capabilities.
std::string max_video_capabilities_;
// Keep track of errors during player creation.
bool is_creating_player_ = false;
std::string player_creation_error_message_;
// Variables related to tracking player startup latencies.
SbTimeMonotonic set_drm_system_ready_cb_time_ = -1;
SbTimeMonotonic player_creation_time_ = 0;
SbTimeMonotonic sb_player_state_initialized_time_ = 0;
SbTimeMonotonic sb_player_state_prerolling_time_ = 0;
SbTimeMonotonic first_audio_sample_time_ = 0;
SbTimeMonotonic first_video_sample_time_ = 0;
SbTimeMonotonic sb_player_state_presenting_time_ = 0;
#if SB_HAS(PLAYER_WITH_URL)
const bool is_url_based_;
#endif // SB_HAS(PLAYER_WITH_URL)
};
} // namespace media
} // namespace cobalt
#endif // COBALT_MEDIA_BASE_STARBOARD_PLAYER_H_