chromium/chromecast/starboard/media/media/cast_media_starboard.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/logging.h"
#include "chromecast/public/cast_media_shlib.h"
#include "chromecast/public/media/media_capabilities_shlib.h"
#include "chromecast/public/video_plane.h"
#include "chromecast/starboard/media/media/media_pipeline_backend_starboard.h"
#include "chromecast/starboard/media/media/mime_utils.h"
#include "chromecast/starboard/media/media/starboard_api_wrapper.h"
#include "chromecast/starboard/media/media/starboard_video_plane.h"

namespace chromecast {
namespace media {
namespace {

StarboardVideoPlane* g_video_plane = nullptr;

// Returns true if starboard supports Dolby Vision playback for HEVC content
// with the given profile and level.
bool IsHEVCDolbyVisionSupported(VideoProfile profile, int level) {
  // A leak is intentional here, since starboard_api has static storage
  // duration.
  static StarboardApiWrapper* const starboard_api =
      GetStarboardApiWrapper().release();

  const std::string mime = GetMimeType(kCodecDolbyVisionHEVC, profile, level);
  if (mime.empty()) {
    return false;
  }

  const bool supported =
      starboard_api->CanPlayMimeAndKeySystem(mime.c_str(), /*key_system=*/"") ==
      kStarboardMediaSupportTypeProbably;
  LOG(INFO) << "HEVC profile=" << profile << ", level=" << level << " is "
            << (supported ? "supported" : "not supported");
  return supported;
}

}  // namespace

void CastMediaShlib::Initialize(const std::vector<std::string>& argv) {
  CHECK(g_video_plane == nullptr);
  g_video_plane = new StarboardVideoPlane();
}

void CastMediaShlib::Finalize() {
  delete g_video_plane;
  g_video_plane = nullptr;
}

VideoPlane* CastMediaShlib::GetVideoPlane() {
  return g_video_plane;
}

MediaPipelineBackend* CastMediaShlib::CreateMediaPipelineBackend(
    const MediaPipelineDeviceParams& params) {
  CHECK(g_video_plane);
  return new MediaPipelineBackendStarboard(params, g_video_plane);
}

double CastMediaShlib::GetMediaClockRate() {
  return 0.0;
}

double CastMediaShlib::MediaClockRatePrecision() {
  return 0.0;
}

void CastMediaShlib::MediaClockRateRange(double* minimum_rate,
                                         double* maximum_rate) {
  *minimum_rate = 0.0;
  *maximum_rate = 1.0;
}

bool CastMediaShlib::SetMediaClockRate(double new_rate) {
  return false;
}

bool CastMediaShlib::SupportsMediaClockRateChange() {
  return false;
}

VideoPlane::Coordinates VideoPlane::GetCoordinates() {
  // SbPlayerSetBounds takes coordinates in terms of the graphics resolution.
  return VideoPlane::Coordinates::kGraphics;
}

bool MediaCapabilitiesShlib::IsSupportedVideoConfig(VideoCodec codec,
                                                    VideoProfile profile,
                                                    int level) {
  // TODO(b/275430044): expand this to cover all video codecs/profiles/levels.
  if (codec == kCodecDolbyVisionHEVC) {
    return IsHEVCDolbyVisionSupported(profile, level);
  }

  return codec == kCodecH264 || codec == kCodecVP8 || codec == kCodecVP9 ||
         codec == kCodecHEVC;
}

bool MediaCapabilitiesShlib::IsSupportedAudioConfig(const AudioConfig& config) {
  // TODO(b/275430044): potentially call Starboard here, to determine codec
  // support. This is probably only necessary for optional codecs (AC3/E-AC3).
  return config.codec == kCodecAAC || config.codec == kCodecMP3 ||
         config.codec == kCodecPCM || config.codec == kCodecVorbis ||
         config.codec == kCodecOpus || config.codec == kCodecAC3 ||
         config.codec == kCodecEAC3 || config.codec == kCodecFLAC;
}

}  // namespace media
}  // namespace chromecast