#if BUILDFLAG(IS_TIZEN_TV)
MEDIA_EXPORT extern const char kEnableFrameRawDataCopy[];
+MEDIA_EXPORT extern const char kDualDecodingWebRTC[];
#endif
#if BUILDFLAG(IS_CHROMEOS)
"//third_party/blink/renderer:non_test_config",
]
+ if (tizen_product_tv && tizen_multimedia) {
+ if (tizen_version > 60) {
+ configs += [
+ # Workaround for media/filters/esplusplayer_util.h in //media which fails
+ # to export required configs.
+ "//tizen_src/build:libesplusplayer",
+ ]
+ } else {
+ configs += [ "//tizen_src/build:libplusplayer" ]
+ }
+ }
+
include_dirs = []
allow_circular_includes_from = [
sources += [ "fonts/fuchsia/font_cache_fuchsia.cc" ]
}
+ if (tizen_product_tv) {
+ deps += [
+ "//third_party/blink/renderer/bindings:generate_bindings_all",
+ "//tizen_src/chromium_impl/third_party/blink/renderer/platform/peerconnection:tizen_media_coding",
+ ]
+ }
+
if (use_minikin_hyphenation) {
sources += [
"text/hyphenation/hyphenation_minikin.cc",
#include <memory>
#include "base/check.h"
+#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/size.h"
+#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE)
+#include "media/filters/esplusplayer_util.h"
+#include "third_party/blink/renderer/platform/peerconnection/rtc_video_decoder_remote_tv.h"
+#endif // BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE)
+
namespace blink {
namespace {
{media::VideoCodec::kAV1, media::AV1PROFILE_PROFILE_MAIN},
}};
+bool DualDecodingSupportedCodec(const media::VideoCodec& codec) {
+#if BUILDFLAG(IS_TIZEN_TV)
+ return codec == media::VideoCodec::kVP8 || codec == media::VideoCodec::kH264;
+#else
+ return false;
+#endif
+}
+
+bool UseDualDecoding() {
+#if BUILDFLAG(IS_TIZEN_TV)
+ return base::CommandLine::ForCurrentProcess() &&
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDualDecodingWebRTC);
+#else
+ return false;
+#endif
+}
+
// Translate from media::VideoDecoderConfig to webrtc::SdpVideoFormat, or return
// nothing if the profile isn't supported.
absl::optional<webrtc::SdpVideoFormat> VdcToWebRtcFormat(
media::VideoColorSpace(), media::kNoTransformation, kDefaultSize,
gfx::Rect(kDefaultSize), kDefaultSize, media::EmptyExtraData(),
media::EncryptionScheme::kUnencrypted);
+
+#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE)
+ if (UseDualDecoding() && DualDecodingSupportedCodec(codec_config.codec)) {
+ // Since it can not be determined which hardware codec will be selected,
+ // limit it to the base codecs by `DualDecodingSupportedCodec`.
+ auto format = VdcToWebRtcFormat(config);
+ if (format) {
+ supported_formats.push_back(*format);
+ }
+ continue;
+ }
+#endif // BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE)
config.set_is_rtc(true);
absl::optional<webrtc::SdpVideoFormat> format;
}
}
+#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE)
+ if (UseDualDecoding() && DualDecodingSupportedCodec(codec)) {
+ return {true, true};
+ }
+#endif // BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE)
+
media::VideoCodecProfile codec_profile =
WebRtcVideoFormatToMediaVideoCodecProfile(format);
media::VideoDecoderConfig config(
DVLOG(2) << __func__;
CheckAndWaitDecoderSupportStatusIfNeeded();
+#if BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE)
+ if (UseDualDecoding()) {
+ return RTCVideoDecoderRemoteTV::Create(format);
+ }
+#endif // BUILDFLAG(IS_TIZEN_TV) && defined(TIZEN_VIDEO_HOLE)
+
std::unique_ptr<webrtc::VideoDecoder> decoder;
if (base::FeatureList::IsEnabled(media::kUseDecoderStreamForWebRTC)) {
decoder = RTCVideoDecoderStreamAdapter::Create(
return !(lhs == rhs);
}
+ friend bool operator<(const RenderResolution& lhs,
+ const RenderResolution& rhs) {
+ return lhs.width_ < rhs.width_ && lhs.height_ < rhs.height_;
+ }
+
constexpr bool Valid() const { return width_ > 0 && height_ > 0; }
constexpr int Width() const { return width_; }
namespace {
#if BUILDFLAG(IS_TIZEN_TV)
-bool IsCameraHardwareEncoderEnabled() {
-#if !defined(EWK_BRINGUP) // Fixme: Remove after Port Video Encoders Patch is merged
-// const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
-// return cmd_line->HasSwitch(switches::kEnableWebRtcHWEncodingForCamera);
-#else
- return false;
-#endif
-}
-
bool IsDualDecodingSupported() {
const auto tv_chipset = GetTVChipset();
// TODO(b.chechlinsk): Add NikeL 1.5G chipset code
- if (tv_chipset == "KANTS2" || tv_chipset == "KANTSU2E" ||
- tv_chipset == "NIKEL_XXX")
+ if (tv_chipset == "KANTS2" || tv_chipset == "NIKEL_XXX")
+ return false;
+
+ if (IsMultiviewMode())
+ return false;
+
+ if (!content::IsHbbTV() && !base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDualDecodingWebRTC))
return false;
+
return true;
}
-#endif
+#endif // BUILDFLAG(IS_TIZEN_TV)
std::size_t TVMaxCount(MediaType type) {
-// On LFD TV: web app support 3 videos and 1 audio at most.
-// browser support 1 video and 1 audio at most.
-// Reason : browser cannot support mixer mode, scroll function
-// has some issue when browser in mixer mode(video shows issue).
-#if defined(TIZEN_VD_MULTIPLE_MIXERDECODER)
- if ((MediaType::Video == type) && content::IsTIZENWRT())
- return 3;
-#elif BUILDFLAG(IS_TIZEN_TV)
- if (MediaType::Video == type) {
- if (
-#if !defined(EWK_BRINGUP) // Fixme: Remove after HDR and codec related patch is merged
- !IsMultiviewMode() &&
-#endif
- IsDualDecodingSupported() &&
- (blink::IsHbbTV() || IsCameraHardwareEncoderEnabled()))
- return 2;
+ std::size_t count = 1;
+#if BUILDFLAG(IS_TIZEN_TV)
+ if ((GetProductType() == "LFD") && (content::IsTIZENWRT())) {
+ // On LFD TV: web app support 3 videos and 1 audio at most.
+ // browser support 1 video and 1 audio at most.
+ // Reason : browser cannot support mixer mode, scroll function
+ // has some issue when browser in mixer mode(video shows issue).
+ count = 3;
+ } else if (MediaType::Video == type && IsDualDecodingSupported()) {
+ count = 2;
}
- if (blink::IsTIZENWRT())
- return 4;
-#endif
+#endif // BUILDFLAG(IS_TIZEN_TV)
- return 1;
+ LOG(INFO) << "Return " << count << " as max count.";
+ return count;
}
} // namespace
--- /dev/null
+# Copyright (c) 2021 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.
+
+import("//tizen_src/build/config/tizen_features.gni")
+
+source_set("tizen_media_coding") {
+ cflags = [
+ "-Werror",
+ "-Wall",
+ ]
+
+ if (tizen_version < 60 && is_clang) {
+ cflags -= [ "-Werror" ]
+ }
+
+ if (!is_clang) {
+ cflags += [
+ "-Wformat=2",
+ "-Wnull-dereference",
+ "-Wimplicit-fallthrough=4",
+ "-Wno-builtin-macro-redefined",
+ "-Wno-deprecated-copy",
+ "-Wno-error=attributes",
+ "-Wno-error=ignored-qualifiers",
+ ]
+ }
+
+ cflags_cc = [
+ # Added to make it possible to extend platform enums with new values,
+ # while still reporting not handled enum cases during compilation
+ "-Wno-error=switch",
+ ]
+
+ deps = [
+ "//media",
+ "//third_party/blink/public:blink_headers",
+ "//third_party/webrtc_overrides:webrtc_component",
+ ]
+
+ # TODO(m.napiorkows): This should be in public_configs
+ # of //media/base
+ configs += [
+ # Needed for including renderer_media_player_manager_efl.h
+ "//tizen_src/build:capi-media-player",
+ "//tizen_src/build:libcapi-media-player",
+ ]
+
+ sources = [
+ "video_coding_constants.h",
+ "video_coding_utils.cc",
+ "video_coding_utils.h",
+ ]
+
+ if (tizen_multimedia && tizen_video_hole) {
+ sources += [
+ "rtc_video_decoder_remote_tv.cc",
+ "rtc_video_decoder_remote_tv.h"
+ ]
+ }
+
+}
--- /dev/null
+// Copyright 2023 Samsung Electronics Inc. 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/platform/peerconnection/rtc_video_decoder_remote_tv.h"
+
+#include <utility>
+
+#include "media/base/video_frame.h"
+#include "media/blink/renderer/tizen_esplusplayer_renderer.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "third_party/blink/renderer/platform/peerconnection/video_coding_utils.h"
+#include "third_party/blink/renderer/platform/webrtc/webrtc_video_frame_adapter.h"
+#include "third_party/webrtc/modules/video_coding/include/video_error_codes.h"
+
+namespace blink {
+
+// static
+std::unique_ptr<webrtc::VideoDecoder> RTCVideoDecoderRemoteTV::Create(
+ const webrtc::SdpVideoFormat& format) {
+ return std::unique_ptr<RTCVideoDecoderRemoteTV>(
+ new RTCVideoDecoderRemoteTV(format));
+}
+
+RTCVideoDecoderRemoteTV::RTCVideoDecoderRemoteTV(
+ const webrtc::SdpVideoFormat& format)
+ : format_(format) {}
+
+bool RTCVideoDecoderRemoteTV::NeedRecreate(const Settings& settings) {
+ LOG(INFO) << " max render size:" << settings_.max_render_resolution().Width()
+ << "x" << settings_.max_render_resolution().Height()
+ << " codec type:" << settings.codec_type();
+
+ return !renderer_ ||
+ settings_.max_render_resolution() < settings.max_render_resolution() ||
+ settings_.codec_type() != settings.codec_type();
+}
+
+void RTCVideoDecoderRemoteTV::OnRendererInit(bool result) {
+ sync_with_init_result.Signal();
+}
+
+void RTCVideoDecoderRemoteTV::RecreateRenderer(const Settings& settings) {
+ LOG(INFO) << __func__;
+ renderer_.reset();
+ renderer_ =
+ media::TizenEsPlusPlayerRendererManager::GetInstance()
+ .CreateTizenEsPlusPlayerRenderer(
+ blink::ToMediaVideoCodec(settings.codec_type()),
+ current_size_.value_or(
+ gfx::Size(settings.max_render_resolution().Width(),
+ settings.max_render_resolution().Height())),
+ media::HardwareResouceType::kMain, /* Main-scaler */
+ media::HardwareResouceType::kSub, /* Sub-decoder */
+ media::CanDropFrames::kYes, media::Mode::kVideoHole,
+ base::BindOnce(&RTCVideoDecoderRemoteTV::OnRendererInit,
+ base::Unretained(this)),
+ base::BindPostTaskToCurrentDefault(base::BindRepeating(
+ &RTCVideoDecoderRemoteTV::OnVideoFrameReadyFromRenderer,
+ base::Unretained(this))),
+ true, false);
+ // Wait for initialization to complete, otherwise frames into Decode()
+ // will be lost.
+ sync_with_init_result.Wait();
+ sync_with_init_result.Reset();
+ settings_ = settings;
+ ms_to_tick_.clear();
+}
+
+void RTCVideoDecoderRemoteTV::RecreateRendererIfNeeded(
+ const Settings& settings) {
+ if (NeedRecreate(settings)) {
+ RecreateRenderer(settings);
+ }
+}
+
+void RTCVideoDecoderRemoteTV::OnVideoFrameReadyFromRenderer(
+ scoped_refptr<media::VideoFrame> frame,
+ base::TimeTicks reference_time) {
+ if (!decode_complete_callback_) {
+ LOG(INFO) << "no decoded callback!";
+ return;
+ }
+
+ if (ms_to_tick_.empty()) {
+ LOG(INFO) << "unexpected frame.";
+ return;
+ }
+
+ auto time_ms = frame->timestamp().InMilliseconds();
+ const auto& pair = ms_to_tick_.front();
+ if (pair.first != time_ms) {
+ LOG(INFO) << "unexpected frame.";
+ }
+
+ rtc::scoped_refptr<webrtc::VideoFrameBuffer> frame_buffer(
+ new rtc::RefCountedObject<WebRtcVideoFrameAdapter>(std::move(frame)));
+ auto rtc_frame = webrtc::VideoFrame::Builder{}
+ .set_video_frame_buffer(frame_buffer)
+ .set_timestamp_rtp(pair.second)
+ .set_timestamp_ms(time_ms)
+ .build();
+ ms_to_tick_.pop_front();
+ decode_complete_callback_->Decoded(rtc_frame, absl::nullopt, absl::nullopt);
+}
+
+bool RTCVideoDecoderRemoteTV::Configure(const Settings& settings) {
+ RecreateRendererIfNeeded(settings);
+ if (!renderer_)
+ return false;
+
+ return true;
+}
+
+int32_t RTCVideoDecoderRemoteTV::Decode(const webrtc::EncodedImage& input_image,
+ bool missing_frames,
+ int64_t render_time_ms) {
+ if (IsKeyFrame(input_image)) {
+ auto size =
+ gfx::Size(input_image._encodedWidth, input_image._encodedHeight);
+ if (size == gfx::Size(0, 0)) {
+ LOG(ERROR) << "Invalid size.";
+ return WEBRTC_VIDEO_CODEC_ERROR;
+ }
+
+ current_size_ = size;
+ LOG(INFO) << " key frame, size:" << (*current_size_).ToString()
+ << " rtp time:" << input_image.RtpTimestamp();
+ }
+
+ if (!current_size_.has_value()) {
+ LOG(ERROR) << "There is no key frame yet.";
+ return WEBRTC_VIDEO_CODEC_OK_REQUEST_KEYFRAME;
+ }
+
+ base::AutoLock lk(lock_);
+ if (!renderer_) {
+ LOG(ERROR) << "Decoder does not exist!";
+ return WEBRTC_VIDEO_CODEC_ERROR;
+ }
+
+ if (!renderer_->IsReady()) {
+ LOG(ERROR) << "Decoder is not ready!";
+ return WEBRTC_VIDEO_CODEC_OK_REQUEST_KEYFRAME;
+ }
+
+ media::VideoFrameMetadata meta;
+ int64_t ms = input_image.RtpTimestamp() / kTicksPerMillisecond;
+ meta.reference_time = base::TimeTicks::FromInternalValue(
+ ms * base::Time::kMicrosecondsPerMillisecond);
+ meta.rtp_timestamp = input_image.RtpTimestamp();
+ ms_to_tick_.push_back(std::make_pair(ms, input_image.RtpTimestamp()));
+
+ if (renderer_->QueueBuffer(meta, *current_size_, input_image.data(),
+ input_image.size(), IsKeyFrame(input_image))) {
+ LOG(INFO) << "Request key frame.";
+ return WEBRTC_VIDEO_CODEC_OK_REQUEST_KEYFRAME;
+ }
+ return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t RTCVideoDecoderRemoteTV::RegisterDecodeCompleteCallback(
+ webrtc::DecodedImageCallback* callback) {
+ decode_complete_callback_ = callback;
+ return WEBRTC_VIDEO_CODEC_OK;
+}
+
+int32_t RTCVideoDecoderRemoteTV::Release() {
+ renderer_.reset();
+ return WEBRTC_VIDEO_CODEC_OK;
+}
+
+} // namespace blink
--- /dev/null
+// Copyright 2023 Samsung Electronics Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_VIDEO_DECODER_REMOTE_TV_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_VIDEO_DECODER_REMOTE_TV_H_
+
+#include <deque>
+
+#include "api/video_codecs/sdp_video_format.h"
+#include "api/video_codecs/video_decoder.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
+#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace media {
+class TizenEsPlusPlayerRenderer;
+class VideoFrame;
+} // namespace media
+
+namespace blink {
+
+class RTCVideoDecoderRemoteTV : public webrtc::VideoDecoder {
+ public:
+ static constexpr int64_t kTicksPerMillisecond =
+ webrtc::kVideoPayloadTypeFrequency / base::Time::kMillisecondsPerSecond;
+ static std::unique_ptr<webrtc::VideoDecoder> Create(
+ const webrtc::SdpVideoFormat& format);
+
+ // webrtc::VideoDecoder implementation
+ bool Configure(const Settings& settings) override;
+
+ int32_t Decode(const webrtc::EncodedImage& input_image,
+ bool missing_frames,
+ int64_t render_time_ms) override;
+ int32_t RegisterDecodeCompleteCallback(
+ webrtc::DecodedImageCallback* callback) override;
+ int32_t Release() override;
+ const char* ImplementationName() const override {
+ return "tizen-tv-espp-decoder";
+ }
+
+ private:
+ RTCVideoDecoderRemoteTV(const webrtc::SdpVideoFormat& format);
+ bool NeedRecreate(const Settings& settings);
+ void RecreateRenderer(const Settings& settings);
+ void RecreateRendererIfNeeded(const Settings& settings);
+ void OnVideoFrameReadyFromRenderer(scoped_refptr<media::VideoFrame> frame,
+ base::TimeTicks reference_time);
+ inline bool IsKeyFrame(const webrtc::EncodedImage& img) const {
+ return img._frameType == webrtc::VideoFrameType::kVideoFrameKey;
+ }
+ void OnRendererInit(bool result);
+
+ std::unique_ptr<media::TizenEsPlusPlayerRenderer> renderer_;
+ webrtc::SdpVideoFormat format_;
+ Settings settings_;
+ webrtc::DecodedImageCallback* decode_complete_callback_;
+ absl::optional<gfx::Size> current_size_;
+ std::deque<std::pair<int64_t, uint32_t>> ms_to_tick_;
+ base::Lock lock_{};
+ base::WaitableEvent sync_with_init_result{
+ base::WaitableEvent::ResetPolicy::MANUAL};
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_RTC_VIDEO_DECODER_REMOTE_TV_H_
\ No newline at end of file
--- /dev/null
+// Copyright 2021 Samsung Electronics Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_VIDEO_CODING_CONSTANTS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_VIDEO_CODING_CONSTANTS_H_
+
+namespace blink {
+// Synced with
+// third_party/webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.cc
+// QP (quantization parameter) values below kLowH264QpThreshold are considered
+// too high quality values above kHighH264QpThreshold are too low quality
+constexpr int kLowH264QpThreshold = 24;
+constexpr int kHighH264QpThreshold = 37;
+
+// Arbitraty values in range 0-63
+// TODO(m.napiorkows): Adjust based on visual quality
+constexpr int kLowVP8QpThreshold = 25;
+constexpr int kHighVP8QpThreshold = 53;
+
+// https://tools.ietf.org/html/rfc6184#section-5.1:
+// "The RTP timestamp is set to the sampling timestamp of the content.
+// A 90 kHz clock rate MUST be used."
+constexpr int kVideoRtpTimestampClockRate = 90;
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_VIDEO_CODING_CONSTANTS_H_
--- /dev/null
+// Copyright 2021 Samsung Electronics Inc. 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/platform/peerconnection/video_coding_utils.h"
+
+#include "api/video/video_rotation.h"
+#include "media/base/video_transformation.h"
+#include "media/media_buildflags.h"
+#include "rtc_base/time_utils.h"
+#include "third_party/blink/renderer/platform/peerconnection/video_coding_constants.h"
+
+namespace blink {
+bool IsKeyframeRequested(
+ const std::vector<webrtc::VideoFrameType>* const frame_types) {
+ return std::any_of(frame_types->begin(), frame_types->end(),
+ [](const auto& type) {
+ return type == webrtc::VideoFrameType::kVideoFrameKey;
+ });
+}
+
+media::VideoCodec ToMediaVideoCodec(webrtc::VideoCodecType codec) noexcept {
+ switch (codec) {
+ case webrtc::kVideoCodecGeneric:
+ // No support for multiplex for now
+ case webrtc::kVideoCodecMultiplex:
+ return media::VideoCodec::kUnknown;
+ case webrtc::kVideoCodecVP8:
+ return media::VideoCodec::kVP8;
+ case webrtc::kVideoCodecVP9:
+ return media::VideoCodec::kVP9;
+ case webrtc::kVideoCodecAV1:
+ return media::VideoCodec::kAV1;
+ case webrtc::kVideoCodecH264:
+ return media::VideoCodec::kH264;
+#if BUILDFLAG(IS_TIZEN_TV) && BUILDFLAG(ENABLE_PLATFORM_HEVC)
+ case webrtc::kVideoCodecH265:
+ return media::VideoCodec::kHEVC;
+#endif
+ }
+ return media::VideoCodec::kUnknown;
+}
+
+webrtc::VideoRotation ToWebRTCRotation(media::VideoRotation rotation) noexcept {
+ switch (rotation) {
+ case media::VIDEO_ROTATION_0:
+ return webrtc::kVideoRotation_0;
+ case media::VIDEO_ROTATION_90:
+ return webrtc::kVideoRotation_90;
+ case media::VIDEO_ROTATION_180:
+ return webrtc::kVideoRotation_180;
+ case media::VIDEO_ROTATION_270:
+ return webrtc::kVideoRotation_270;
+ }
+ return webrtc::kVideoRotation_0;
+}
+
+void TimestampConverter::OnInputFrame(uint32_t timestamp_rtp,
+ int64_t timestamp_us) {
+ if (first_input_frame_wall_clock_.is_zero()) {
+ first_input_frame_wall_clock_ = base::Milliseconds(rtc::TimeMillis());
+ first_input_frame_timestamp_ = base::Microseconds(timestamp_us);
+ first_input_frame_rtp_timestamp_ = timestamp_rtp;
+ }
+}
+
+int64_t TimestampConverter::GetCaptureTime(base::TimeDelta now) const {
+ return (first_input_frame_timestamp_ - first_input_frame_wall_clock_ + now)
+ .InMilliseconds();
+}
+
+uint32_t TimestampConverter::GetRtpTime(base::TimeDelta now) const {
+ return static_cast<uint32_t>(
+ kVideoRtpTimestampClockRate *
+ (now - first_input_frame_wall_clock_).InMilliseconds() +
+ first_input_frame_rtp_timestamp_);
+}
+
+void TimestampConverter::Reset() {
+ first_input_frame_wall_clock_ = {};
+}
+
+} // namespace blink
--- /dev/null
+// Copyright 2021 Samsung Electronics Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_VIDEO_CODING_UTILS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_VIDEO_CODING_UTILS_H_
+
+#include <vector>
+
+#include "api/video/video_codec_type.h"
+#include "api/video/video_rotation.h"
+#include "base/time/time.h"
+#include "media/base/video_codecs.h"
+#include "media/base/video_transformation.h"
+#include "third_party/webrtc/api/video/video_frame_type.h"
+
+namespace blink {
+bool IsKeyframeRequested(const std::vector<webrtc::VideoFrameType>* const);
+media::VideoCodec ToMediaVideoCodec(webrtc::VideoCodecType codec) noexcept;
+webrtc::VideoRotation ToWebRTCRotation(media::VideoRotation rotation) noexcept;
+
+class TimestampConverter {
+ public:
+ void OnInputFrame(uint32_t timestamp_rtp, int64_t timestamp_us);
+
+ int64_t GetCaptureTime(base::TimeDelta now) const;
+ uint32_t GetRtpTime(base::TimeDelta now) const;
+
+ void Reset();
+
+ private:
+ base::TimeDelta first_input_frame_wall_clock_{};
+ base::TimeDelta first_input_frame_timestamp_{};
+ uint32_t first_input_frame_rtp_timestamp_{};
+};
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_PEERCONNECTION_VIDEO_CODING_UTILS_H_
\ No newline at end of file