Commit c2e5609b authored by Eugene Zemtsov's avatar Eugene Zemtsov Committed by Commit Bot

[webcodecs] Make encoder's framerate optional

Bug: 1139059
Change-Id: I1e142da5f9f1d6c7cfce42294b9022a0fab1e12f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2520080Reviewed-by: default avatarDan Sanders <sandersd@chromium.org>
Commit-Queue: Eugene Zemtsov <eugene@chromium.org>
Cr-Commit-Position: refs/heads/master@{#824706}
parent a025ad91
...@@ -39,7 +39,7 @@ class MEDIA_EXPORT VideoEncoder { ...@@ -39,7 +39,7 @@ class MEDIA_EXPORT VideoEncoder {
Options(const Options&); Options(const Options&);
~Options(); ~Options();
base::Optional<uint64_t> bitrate; base::Optional<uint64_t> bitrate;
double framerate = 30.0; base::Optional<double> framerate;
int width = 0; int width = 0;
int height = 0; int height = 0;
......
...@@ -27,7 +27,8 @@ Status SetUpOpenH264Params(const VideoEncoder::Options& options, ...@@ -27,7 +27,8 @@ Status SetUpOpenH264Params(const VideoEncoder::Options& options,
params->bEnableDenoise = false; params->bEnableDenoise = false;
// Set to 1 due to https://crbug.com/583348 // Set to 1 due to https://crbug.com/583348
params->iMultipleThreadIdc = 1; params->iMultipleThreadIdc = 1;
params->fMaxFrameRate = options.framerate; if (options.framerate.has_value())
params->fMaxFrameRate = options.framerate.value();
params->iPicHeight = options.height; params->iPicHeight = options.height;
params->iPicWidth = options.width; params->iPicWidth = options.width;
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "media/video/vpx_video_encoder.h" #include "media/video/vpx_video_encoder.h"
#include "base/numerics/ranges.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/system/sys_info.h" #include "base/system/sys_info.h"
#include "base/time/time.h" #include "base/time/time.h"
...@@ -275,12 +276,13 @@ void VpxVideoEncoder::Encode(scoped_refptr<VideoFrame> frame, ...@@ -275,12 +276,13 @@ void VpxVideoEncoder::Encode(scoped_refptr<VideoFrame> frame,
break; break;
} }
auto timestamp = frame->timestamp().InMicroseconds(); auto duration_us = GetFrameDuration(*frame).InMicroseconds();
auto duration = GetFrameDuration(*frame); auto timestamp_us = frame->timestamp().InMicroseconds();
last_frame_timestamp_ = frame->timestamp();
auto deadline = VPX_DL_REALTIME; auto deadline = VPX_DL_REALTIME;
vpx_codec_flags_t flags = key_frame ? VPX_EFLAG_FORCE_KF : 0; vpx_codec_flags_t flags = key_frame ? VPX_EFLAG_FORCE_KF : 0;
auto vpx_error = vpx_codec_encode(codec_.get(), &vpx_image_, timestamp, auto vpx_error = vpx_codec_encode(codec_.get(), &vpx_image_, timestamp_us,
duration, flags, deadline); duration_us, flags, deadline);
if (vpx_error != VPX_CODEC_OK) { if (vpx_error != VPX_CODEC_OK) {
std::string msg = base::StringPrintf("VPX encoding error: %s (%s)", std::string msg = base::StringPrintf("VPX encoding error: %s (%s)",
...@@ -321,12 +323,21 @@ void VpxVideoEncoder::ChangeOptions(const Options& options, StatusCB done_cb) { ...@@ -321,12 +323,21 @@ void VpxVideoEncoder::ChangeOptions(const Options& options, StatusCB done_cb) {
return; return;
} }
uint64_t VpxVideoEncoder::GetFrameDuration(const VideoFrame& frame) { base::TimeDelta VpxVideoEncoder::GetFrameDuration(const VideoFrame& frame) {
base::TimeDelta default_duration = // Frame has duration in metadata, use it.
base::TimeDelta::FromSecondsD(1.0 / options_.framerate); if (frame.metadata()->frame_duration.has_value())
return frame.metadata() return frame.metadata()->frame_duration.value();
->frame_duration.value_or(default_duration)
.InMicroseconds(); // Options have framerate specified, use it.
if (options_.framerate.has_value())
return base::TimeDelta::FromSecondsD(1.0 / options_.framerate.value());
// No real way to figure out duration, use time passed since the last frame
// as an educated guess, but clamp it within a reasonable limits.
constexpr auto min_duration = base::TimeDelta::FromSecondsD(1.0 / 60.0);
constexpr auto max_duration = base::TimeDelta::FromSecondsD(1.0 / 24.0);
auto duration = frame.timestamp() - last_frame_timestamp_;
return base::ClampToRange(duration, min_duration, max_duration);
} }
VpxVideoEncoder::~VpxVideoEncoder() { VpxVideoEncoder::~VpxVideoEncoder() {
......
...@@ -32,7 +32,7 @@ class MEDIA_EXPORT VpxVideoEncoder : public VideoEncoder { ...@@ -32,7 +32,7 @@ class MEDIA_EXPORT VpxVideoEncoder : public VideoEncoder {
void Flush(StatusCB done_cb) override; void Flush(StatusCB done_cb) override;
private: private:
uint64_t GetFrameDuration(const VideoFrame& frame); base::TimeDelta GetFrameDuration(const VideoFrame& frame);
void DrainOutputs(); void DrainOutputs();
using vpx_codec_unique_ptr = using vpx_codec_unique_ptr =
...@@ -42,6 +42,7 @@ class MEDIA_EXPORT VpxVideoEncoder : public VideoEncoder { ...@@ -42,6 +42,7 @@ class MEDIA_EXPORT VpxVideoEncoder : public VideoEncoder {
bool is_vp9_ = false; bool is_vp9_ = false;
vpx_codec_enc_cfg_t codec_config_ = {}; vpx_codec_enc_cfg_t codec_config_ = {};
vpx_image_t vpx_image_ = {}; vpx_image_t vpx_image_ = {};
base::TimeDelta last_frame_timestamp_;
VideoCodecProfile profile_ = VIDEO_CODEC_PROFILE_UNKNOWN; VideoCodecProfile profile_ = VIDEO_CODEC_PROFILE_UNKNOWN;
Options options_; Options options_;
OutputCB output_cb_; OutputCB output_cb_;
......
...@@ -83,7 +83,8 @@ std::unique_ptr<media::VideoEncoder> CreateAcceleratedVideoEncoder( ...@@ -83,7 +83,8 @@ std::unique_ptr<media::VideoEncoder> CreateAcceleratedVideoEncoder(
double max_supported_framerate = double max_supported_framerate =
double{supported_profile.max_framerate_numerator} / double{supported_profile.max_framerate_numerator} /
supported_profile.max_framerate_denominator; supported_profile.max_framerate_denominator;
if (options.framerate > max_supported_framerate) if (options.framerate.has_value() &&
options.framerate.value() > max_supported_framerate)
continue; continue;
found_supported_profile = true; found_supported_profile = true;
...@@ -198,7 +199,8 @@ std::unique_ptr<VideoEncoder::ParsedConfig> VideoEncoder::ParseConfig( ...@@ -198,7 +199,8 @@ std::unique_ptr<VideoEncoder::ParsedConfig> VideoEncoder::ParseConfig(
return nullptr; return nullptr;
} }
parsed->options.framerate = config->framerate(); if (config->hasFramerate())
parsed->options.framerate = config->framerate();
if (config->hasBitrate()) if (config->hasBitrate())
parsed->options.bitrate = config->bitrate(); parsed->options.bitrate = config->bitrate();
......
...@@ -17,7 +17,7 @@ dictionary VideoEncoderConfig { ...@@ -17,7 +17,7 @@ dictionary VideoEncoderConfig {
unsigned long long bitrate; unsigned long long bitrate;
required double framerate; double framerate;
required unsigned long width; required unsigned long width;
required unsigned long height; required unsigned long height;
......
...@@ -88,7 +88,6 @@ ...@@ -88,7 +88,6 @@
width: w, width: w,
height: h, height: h,
bitrate: 5000000, bitrate: 5000000,
framerate: 30,
}; };
let encoder = new VideoEncoder(encoder_init); let encoder = new VideoEncoder(encoder_init);
...@@ -135,7 +134,7 @@ ...@@ -135,7 +134,7 @@
const init = { const init = {
output: process_video_chunk, output: process_video_chunk,
error: (e) => { error: (e) => {
error++; errors++;
console.log(e.message); console.log(e.message);
}, },
}; };
...@@ -180,11 +179,11 @@ ...@@ -180,11 +179,11 @@
"encoding and decoding avc1.42001E"); "encoding and decoding avc1.42001E");
/* Uncomment this for manual testing, before we have GPU tests for that */ /* Uncomment this for manual testing, before we have GPU tests for that */
// promise_test(encode_test.bind(null, "avc1.42001E", "require"), //promise_test(encode_test.bind(null, "avc1.42001E", "require"),
// "encoding avc1.42001E"); // "encoding avc1.42001E");
// promise_test(encode_decode_test.bind(null, "avc1.42001E", "require"), //promise_test(encode_decode_test.bind(null, "avc1.42001E", "require"),
// "encoding and decoding avc1.42001E"); // "encoding and decoding avc1.42001E req");
</script> </script>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment