blob: a68f7339dacb7b963625189d94a429270c33d3aa [file] [log] [blame]
// Copyright 2016 Google Inc. 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_proxy.h"
#include "base/synchronization/lock.h"
#include "base/time.h"
#include "cobalt/media/base/audio_decoder_config.h"
#include "cobalt/media/base/decoder_buffer.h"
#include "cobalt/media/base/decoder_buffer_cache.h"
#include "cobalt/media/base/demuxer_stream.h"
#include "cobalt/media/base/sbplayer_set_bounds_helper.h"
#include "cobalt/media/base/video_decoder_config.h"
#include "cobalt/media/base/video_frame_provider.h"
#include "starboard/media.h"
#include "starboard/player.h"
namespace cobalt {
namespace media {
// TODO: Add switch to disable caching
class StarboardPlayer {
public:
class Host {
public:
#if !SB_HAS(PLAYER_WITH_URL)
virtual void OnNeedData(DemuxerStream::Type type) = 0;
#endif // !SB_HAS(PLAYER_WITH_URL)
virtual void OnPlayerStatus(SbPlayerState state) = 0;
#if SB_HAS(PLAYER_ERROR_MESSAGE)
virtual void OnPlayerError(SbPlayerError error,
const std::string& message) = 0;
#endif // SB_HAS(PLAYER_ERROR_MESSAGE)
protected:
~Host() {}
};
#if SB_HAS(PLAYER_WITH_URL)
typedef base::Callback<void(const char*, const unsigned char*, unsigned)>
OnEncryptedMediaInitDataEncounteredCB;
StarboardPlayer(const scoped_refptr<base::MessageLoopProxy>& message_loop,
const std::string& url, SbWindow window, Host* host,
SbPlayerSetBoundsHelper* set_bounds_helper,
bool prefer_decode_to_texture,
const OnEncryptedMediaInitDataEncounteredCB&
encrypted_media_init_data_encountered_cb,
VideoFrameProvider* const video_frame_provider);
#else // SB_HAS(PLAYER_WITH_URL)
StarboardPlayer(const scoped_refptr<base::MessageLoopProxy>& message_loop,
const AudioDecoderConfig& audio_config,
const VideoDecoderConfig& video_config, SbWindow window,
SbDrmSystem drm_system, Host* host,
SbPlayerSetBoundsHelper* set_bounds_helper,
bool prefer_decode_to_texture,
VideoFrameProvider* const video_frame_provider);
#endif // SB_HAS(PLAYER_WITH_URL)
~StarboardPlayer();
bool IsValid() const { return SbPlayerIsValid(player_); }
void UpdateVideoResolution(int frame_width, int frame_height);
void GetVideoResolution(int* frame_width, int* frame_height);
#if !SB_HAS(PLAYER_WITH_URL)
void WriteBuffer(DemuxerStream::Type type,
const scoped_refptr<DecoderBuffer>& buffer);
#endif // !SB_HAS(PLAYER_WITH_URL)
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 GetInfo(uint32* video_frames_decoded, uint32* video_frames_dropped,
base::TimeDelta* media_time, base::TimeDelta* buffer_start_time,
base::TimeDelta* buffer_length_time, int* frame_width,
int* frame_height);
#endif // SB_HAS(PLAYER_WITH_URL)
#if SB_HAS(PLAYER_WITH_URL)
base::TimeDelta GetDuration();
base::TimeDelta GetStartDate();
void SetDrmSystem(SbDrmSystem drm_system);
#endif // SB_HAS(PLAYER_WITH_URL)
void Suspend();
void Resume();
SbDecodeTarget GetCurrentSbDecodeTarget();
SbPlayerOutputMode GetSbPlayerOutputMode();
private:
enum State {
kPlaying,
kSuspended,
kResuming,
};
// This class ensures that the callbacks posted to |message_loop_| 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);
#if SB_HAS(PLAYER_ERROR_MESSAGE)
void OnPlayerError(SbPlayer player, SbPlayerError error,
const std::string& message);
#endif // SB_HAS(PLAYER_ERROR_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_;
void CreatePlayerWithUrl(const std::string& url);
#else // SB_HAS(PLAYER_WITH_URL)
void CreatePlayer();
void WriteNextBufferFromCache(DemuxerStream::Type type);
#endif // SB_HAS(PLAYER_WITH_URL)
void UpdateBounds_Locked();
void ClearDecoderBufferCache();
void OnDecoderStatus(SbPlayer player, SbMediaType type,
SbPlayerDecoderState state, int ticket);
void OnPlayerStatus(SbPlayer player, SbPlayerState state, int ticket);
#if SB_HAS(PLAYER_ERROR_MESSAGE)
void OnPlayerError(SbPlayer player, SbPlayerError error,
const std::string& message);
#endif // SB_HAS(PLAYER_ERROR_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);
#if SB_HAS(PLAYER_ERROR_MESSAGE)
static void PlayerErrorCB(SbPlayer player, void* context, SbPlayerError error,
const char* message);
#endif // SB_HAS(PLAYER_ERROR_MESSAGE)
static void DeallocateSampleCB(SbPlayer player, void* context,
const void* sample_buffer);
#if SB_HAS(PLAYER_WITH_URL)
// Returns the output mode that should be used for the URL player.
static SbPlayerOutputMode ComputeSbPlayerOutputModeWithUrl(
bool prefer_decode_to_texture);
static void EncryptedMediaInitDataEncounteredCB(
SbPlayer player, void* context, const char* init_data_type,
const unsigned char* init_data, unsigned int init_data_length);
#else // SB_HAS(PLAYER_WITH_URL)
// Returns the output mode that should be used for a video with the given
// specifications.
static SbPlayerOutputMode ComputeSbPlayerOutputMode(
SbMediaVideoCodec codec, SbDrmSystem drm_system,
bool prefer_decode_to_texture);
#endif // SB_HAS(PLAYER_WITH_URL)
// The following variables are initialized in the ctor and never changed.
std::string url_;
const scoped_refptr<base::MessageLoopProxy> message_loop_;
scoped_refptr<CallbackHelper> callback_helper_;
AudioDecoderConfig audio_config_;
VideoDecoderConfig video_config_;
const SbWindow window_;
SbDrmSystem drm_system_;
Host* const host_;
// Consider merge |SbPlayerSetBoundsHelper| into CallbackHelper.
SbPlayerSetBoundsHelper* const set_bounds_helper_;
// The following variables are only changed or accessed from the
// |message_loop_|.
int frame_width_;
int frame_height_;
DecodingBuffers decoding_buffers_;
int ticket_;
float volume_;
double playback_rate_;
bool paused_;
bool seek_pending_;
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_;
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_;
VideoFrameProvider* const video_frame_provider_;
};
} // namespace media
} // namespace cobalt
#endif // COBALT_MEDIA_BASE_STARBOARD_PLAYER_H_