summaryrefslogtreecommitdiff
path: root/chromium/media/base
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-07-16 11:45:35 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-07-17 08:59:23 +0000
commit552906b0f222c5d5dd11b9fd73829d510980461a (patch)
tree3a11e6ed0538a81dd83b20cf3a4783e297f26d91 /chromium/media/base
parent1b05827804eaf047779b597718c03e7d38344261 (diff)
downloadqtwebengine-chromium-552906b0f222c5d5dd11b9fd73829d510980461a.tar.gz
BASELINE: Update Chromium to 83.0.4103.122
Change-Id: Ie3a82f5bb0076eec2a7c6a6162326b4301ee291e Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/media/base')
-rw-r--r--chromium/media/base/BUILD.gn58
-rw-r--r--chromium/media/base/android/BUILD.gn19
-rw-r--r--chromium/media/base/android/android_cdm_factory.cc45
-rw-r--r--chromium/media/base/android/android_cdm_factory.h6
-rw-r--r--chromium/media/base/android/media_codec_bridge_impl.cc74
-rw-r--r--chromium/media/base/android/media_codec_loop.h4
-rw-r--r--chromium/media/base/android/media_crypto_context_impl.cc8
-rw-r--r--chromium/media/base/android/media_crypto_context_impl.h4
-rw-r--r--chromium/media/base/android/media_drm_bridge.cc30
-rw-r--r--chromium/media/base/android/media_drm_bridge.h10
-rw-r--r--chromium/media/base/android/media_drm_bridge_factory.cc15
-rw-r--r--chromium/media/base/android/media_drm_bridge_factory.h6
-rw-r--r--chromium/media/base/android/media_drm_storage_bridge.cc11
-rw-r--r--chromium/media/base/android/media_drm_storage_bridge.h2
-rw-r--r--chromium/media/base/android/media_server_crash_listener.cc4
-rw-r--r--chromium/media/base/android/media_server_crash_listener.h6
-rw-r--r--chromium/media/base/android/media_service_throttler.cc10
-rw-r--r--chromium/media/base/android/media_service_throttler.h4
-rw-r--r--chromium/media/base/android/mock_media_crypto_context.cc2
-rw-r--r--chromium/media/base/android/mock_media_crypto_context.h8
-rw-r--r--chromium/media/base/android/test_destruction_observable.cc4
-rw-r--r--chromium/media/base/audio_buffer.cc2
-rw-r--r--chromium/media/base/audio_buffer.h4
-rw-r--r--chromium/media/base/audio_buffer_queue.cc5
-rw-r--r--chromium/media/base/audio_codecs.cc11
-rw-r--r--chromium/media/base/audio_codecs.h11
-rw-r--r--chromium/media/base/audio_converter.cc6
-rw-r--r--chromium/media/base/audio_converter.h6
-rw-r--r--chromium/media/base/audio_decoder.h3
-rw-r--r--chromium/media/base/audio_decoder_config.cc4
-rw-r--r--chromium/media/base/audio_decoder_config.h6
-rw-r--r--chromium/media/base/audio_latency.cc7
-rw-r--r--chromium/media/base/audio_latency_unittest.cc6
-rw-r--r--chromium/media/base/audio_parameters.cc21
-rw-r--r--chromium/media/base/audio_power_monitor.cc93
-rw-r--r--chromium/media/base/audio_power_monitor.h88
-rw-r--r--chromium/media/base/audio_power_monitor_unittest.cc309
-rw-r--r--chromium/media/base/audio_pull_fifo.cc4
-rw-r--r--chromium/media/base/audio_pull_fifo.h5
-rw-r--r--chromium/media/base/audio_renderer.h8
-rw-r--r--chromium/media/base/audio_renderer_mixer_unittest.cc4
-rw-r--r--chromium/media/base/bit_reader_fuzzertest.cc20
-rw-r--r--chromium/media/base/buffering_state.cc33
-rw-r--r--chromium/media/base/buffering_state.h25
-rw-r--r--chromium/media/base/cdm_factory.h6
-rw-r--r--chromium/media/base/channel_layout.h7
-rw-r--r--chromium/media/base/content_decryption_module.h25
-rw-r--r--chromium/media/base/data_source.h5
-rw-r--r--chromium/media/base/decoder_buffer.cc29
-rw-r--r--chromium/media/base/decoder_buffer.h42
-rw-r--r--chromium/media/base/decoder_buffer_unittest.cc44
-rw-r--r--chromium/media/base/decoder_factory.cc2
-rw-r--r--chromium/media/base/decoder_factory.h2
-rw-r--r--chromium/media/base/decryptor.h15
-rw-r--r--chromium/media/base/demuxer.h6
-rw-r--r--chromium/media/base/fallback_video_decoder.cc6
-rw-r--r--chromium/media/base/fallback_video_decoder.h2
-rw-r--r--chromium/media/base/fallback_video_decoder_unittest.cc22
-rw-r--r--chromium/media/base/frame_rate_estimator.cc87
-rw-r--r--chromium/media/base/frame_rate_estimator.h51
-rw-r--r--chromium/media/base/frame_rate_estimator_unittest.cc142
-rw-r--r--chromium/media/base/ipc/media_param_traits_macros.h23
-rw-r--r--chromium/media/base/key_systems.cc11
-rw-r--r--chromium/media/base/key_systems.h3
-rw-r--r--chromium/media/base/keyboard_event_counter.h2
-rw-r--r--chromium/media/base/mac/BUILD.gn4
-rw-r--r--chromium/media/base/mac/video_frame_mac_unittests.cc2
-rw-r--r--chromium/media/base/media_drm_key_type.h (renamed from chromium/media/base/android/media_drm_key_type.h)6
-rw-r--r--chromium/media/base/media_drm_storage.cc (renamed from chromium/media/base/android/media_drm_storage.cc)2
-rw-r--r--chromium/media/base/media_drm_storage.h (renamed from chromium/media/base/android/media_drm_storage.h)13
-rw-r--r--chromium/media/base/media_log.cc313
-rw-r--r--chromium/media/base/media_log.h159
-rw-r--r--chromium/media/base/media_log_event.h109
-rw-r--r--chromium/media/base/media_log_events.cc44
-rw-r--r--chromium/media/base/media_log_events.h103
-rw-r--r--chromium/media/base/media_log_message_levels.cc28
-rw-r--r--chromium/media/base/media_log_message_levels.h28
-rw-r--r--chromium/media/base/media_log_properties.h4
-rw-r--r--chromium/media/base/media_log_properties_helper.h182
-rw-r--r--chromium/media/base/media_log_record.h54
-rw-r--r--chromium/media/base/media_log_type_enforcement.h59
-rw-r--r--chromium/media/base/media_log_unittest.cc64
-rw-r--r--chromium/media/base/media_observer.h3
-rw-r--r--chromium/media/base/media_serializers.h392
-rw-r--r--chromium/media/base/media_serializers_base.h34
-rw-r--r--chromium/media/base/media_serializers_unittest.cc59
-rw-r--r--chromium/media/base/media_switches.cc89
-rw-r--r--chromium/media/base/media_switches.h21
-rw-r--r--chromium/media/base/media_types.cc5
-rw-r--r--chromium/media/base/media_types.h3
-rw-r--r--chromium/media/base/media_util.h3
-rw-r--r--chromium/media/base/memory_dump_provider_proxy.cc34
-rw-r--r--chromium/media/base/memory_dump_provider_proxy.h50
-rw-r--r--chromium/media/base/mime_util_internal.cc14
-rw-r--r--chromium/media/base/mime_util_internal.h1
-rw-r--r--chromium/media/base/mime_util_unittest.cc5
-rw-r--r--chromium/media/base/mock_filters.cc10
-rw-r--r--chromium/media/base/mock_filters.h72
-rw-r--r--chromium/media/base/mock_media_log.cc22
-rw-r--r--chromium/media/base/mock_media_log.h44
-rw-r--r--chromium/media/base/moving_average.cc14
-rw-r--r--chromium/media/base/moving_average.h6
-rw-r--r--chromium/media/base/moving_average_unittest.cc15
-rw-r--r--chromium/media/base/multi_channel_resampler.cc5
-rw-r--r--chromium/media/base/multi_channel_resampler.h3
-rw-r--r--chromium/media/base/null_video_sink.h6
-rw-r--r--chromium/media/base/null_video_sink_unittest.cc8
-rw-r--r--chromium/media/base/overlay_info.h7
-rw-r--r--chromium/media/base/pipeline.h15
-rw-r--r--chromium/media/base/pipeline_impl.cc73
-rw-r--r--chromium/media/base/pipeline_impl.h13
-rw-r--r--chromium/media/base/pipeline_impl_unittest.cc36
-rw-r--r--chromium/media/base/player_tracker.h4
-rw-r--r--chromium/media/base/provision_fetcher.h3
-rw-r--r--chromium/media/base/renderer_client.h5
-rw-r--r--chromium/media/base/renderer_factory.h2
-rw-r--r--chromium/media/base/renderer_factory_selector_unittest.cc2
-rw-r--r--chromium/media/base/serial_runner.cc6
-rw-r--r--chromium/media/base/serial_runner_unittest.cc7
-rw-r--r--chromium/media/base/silent_sink_suspender_unittest.cc12
-rw-r--r--chromium/media/base/sinc_resampler.cc8
-rw-r--r--chromium/media/base/sinc_resampler.h4
-rw-r--r--chromium/media/base/sinc_resampler_unittest.cc42
-rw-r--r--chromium/media/base/speech_recognition_client.h28
-rw-r--r--chromium/media/base/status.cc76
-rw-r--r--chromium/media/base/status.h214
-rw-r--r--chromium/media/base/status_codes.cc15
-rw-r--r--chromium/media/base/status_codes.h81
-rw-r--r--chromium/media/base/status_unittest.cc246
-rw-r--r--chromium/media/base/supported_types.cc15
-rw-r--r--chromium/media/base/supported_types_unittest.cc80
-rw-r--r--chromium/media/base/test_data_util.cc2
-rw-r--r--chromium/media/base/test_helpers.cc31
-rw-r--r--chromium/media/base/test_helpers.h25
-rw-r--r--chromium/media/base/text_renderer.cc21
-rw-r--r--chromium/media/base/text_renderer.h10
-rw-r--r--chromium/media/base/text_renderer_unittest.cc40
-rw-r--r--chromium/media/base/text_track.h7
-rw-r--r--chromium/media/base/time_source.h4
-rw-r--r--chromium/media/base/video_codecs.h5
-rw-r--r--chromium/media/base/video_decoder.h3
-rw-r--r--chromium/media/base/video_decoder_config.cc33
-rw-r--r--chromium/media/base/video_decoder_config.h32
-rw-r--r--chromium/media/base/video_frame.cc29
-rw-r--r--chromium/media/base/video_frame.h36
-rw-r--r--chromium/media/base/video_frame_layout.cc1
-rw-r--r--chromium/media/base/video_frame_layout.h20
-rw-r--r--chromium/media/base/video_frame_metadata.cc138
-rw-r--r--chromium/media/base/video_frame_metadata.h20
-rw-r--r--chromium/media/base/video_frame_pool.cc8
-rw-r--r--chromium/media/base/video_frame_pool_unittest.cc61
-rw-r--r--chromium/media/base/video_frame_unittest.cc69
-rw-r--r--chromium/media/base/video_renderer.h9
-rw-r--r--chromium/media/base/video_thumbnail_decoder.cc19
-rw-r--r--chromium/media/base/video_thumbnail_decoder.h2
-rw-r--r--chromium/media/base/video_thumbnail_decoder_unittest.cc8
-rw-r--r--chromium/media/base/video_types.cc5
-rw-r--r--chromium/media/base/video_types.h3
-rw-r--r--chromium/media/base/video_util.cc4
-rw-r--r--chromium/media/base/video_util.h11
-rw-r--r--chromium/media/base/video_util_unittest.cc6
-rw-r--r--chromium/media/base/win/BUILD.gn8
-rw-r--r--chromium/media/base/win/d3d11_mocks.cc9
-rw-r--r--chromium/media/base/win/d3d11_mocks.h130
-rw-r--r--chromium/media/base/win/dxgi_device_scope_handle_unittest.cc91
-rw-r--r--chromium/media/base/win/mf_helpers.cc45
-rw-r--r--chromium/media/base/win/mf_helpers.h66
-rw-r--r--chromium/media/base/win/mf_initializer.cc16
-rw-r--r--chromium/media/base/win/mf_initializer.h20
169 files changed, 4096 insertions, 1580 deletions
diff --git a/chromium/media/base/BUILD.gn b/chromium/media/base/BUILD.gn
index ed396499e1a..80cc2864762 100644
--- a/chromium/media/base/BUILD.gn
+++ b/chromium/media/base/BUILD.gn
@@ -60,6 +60,8 @@ jumbo_source_set("base") {
"audio_fifo.h",
"audio_hash.cc",
"audio_hash.h",
+ "audio_power_monitor.cc",
+ "audio_power_monitor.h",
"audio_processing.cc",
"audio_processing.h",
"audio_pull_fifo.cc",
@@ -85,6 +87,7 @@ jumbo_source_set("base") {
"bit_reader_core.h",
"bitstream_buffer.cc",
"bitstream_buffer.h",
+ "buffering_state.cc",
"buffering_state.h",
"byte_queue.cc",
"byte_queue.h",
@@ -153,6 +156,8 @@ jumbo_source_set("base") {
"flinging_controller.h",
"format_utils.cc",
"format_utils.h",
+ "frame_rate_estimator.cc",
+ "frame_rate_estimator.h",
"hdr_metadata.cc",
"hdr_metadata.h",
"key_system_names.cc",
@@ -176,16 +181,22 @@ jumbo_source_set("base") {
"media_export.h",
"media_log.cc",
"media_log.h",
- "media_log_event.h",
+ "media_log_events.cc",
+ "media_log_events.h",
+ "media_log_message_levels.cc",
+ "media_log_message_levels.h",
"media_log_properties.cc",
"media_log_properties.h",
- "media_log_properties_helper.h",
+ "media_log_record.h",
+ "media_log_type_enforcement.h",
"media_observer.cc",
"media_observer.h",
"media_permission.cc",
"media_permission.h",
"media_resource.cc",
"media_resource.h",
+ "media_serializers.h",
+ "media_serializers_base.h",
"media_status.cc",
"media_status.h",
"media_status_observer.h",
@@ -203,6 +214,8 @@ jumbo_source_set("base") {
"media_url_params.h",
"media_util.cc",
"media_util.h",
+ "memory_dump_provider_proxy.cc",
+ "memory_dump_provider_proxy.h",
"mime_util.cc",
"mime_util.h",
"mime_util_internal.cc",
@@ -256,6 +269,11 @@ jumbo_source_set("base") {
"simple_watch_timer.h",
"sinc_resampler.cc",
"sinc_resampler.h",
+ "speech_recognition_client.h",
+ "status.cc",
+ "status.h",
+ "status_codes.cc",
+ "status_codes.h",
"stream_parser.cc",
"stream_parser.h",
"stream_parser_buffer.cc",
@@ -406,12 +424,18 @@ jumbo_source_set("base") {
} else {
sources += [ "demuxer_memory_limit_default.cc" ]
}
+
+ if (enable_media_drm_storage) {
+ sources += [
+ "media_drm_key_type.h",
+ "media_drm_storage.cc",
+ "media_drm_storage.h",
+ ]
+ }
}
source_set("video_facing") {
- sources = [
- "video_facing.h",
- ]
+ sources = [ "video_facing.h" ]
}
if (is_android) {
@@ -467,9 +491,7 @@ static_library("test_support") {
# Do not add any other //media deps except this; this ensures other
# test_support targets all use the same //media component to avoid duplicate
# and undefined symbol issues on Windows.
- public_deps = [
- "//media",
- ]
+ public_deps = [ "//media" ]
deps = [
"//base",
@@ -499,6 +521,7 @@ source_set("unit_tests") {
"audio_latency_unittest.cc",
"audio_parameters_unittest.cc",
"audio_point_unittest.cc",
+ "audio_power_monitor_unittest.cc",
"audio_pull_fifo_unittest.cc",
"audio_push_fifo_unittest.cc",
"audio_renderer_mixer_input_unittest.cc",
@@ -522,8 +545,10 @@ source_set("unit_tests") {
"fake_demuxer_stream_unittest.cc",
"fallback_video_decoder_unittest.cc",
"feedback_signal_accumulator_unittest.cc",
+ "frame_rate_estimator_unittest.cc",
"key_systems_unittest.cc",
"media_log_unittest.cc",
+ "media_serializers_unittest.cc",
"media_url_demuxer_unittest.cc",
"mime_util_unittest.cc",
"moving_average_unittest.cc",
@@ -537,6 +562,7 @@ source_set("unit_tests") {
"serial_runner_unittest.cc",
"silent_sink_suspender_unittest.cc",
"sinc_resampler_unittest.cc",
+ "status_unittest.cc",
"stream_parser_unittest.cc",
"subsample_entry_unittest.cc",
"supported_types_unittest.cc",
@@ -582,6 +608,14 @@ source_set("unit_tests") {
if (is_linux || is_win) {
sources += [ "keyboard_event_counter_unittest.cc" ]
}
+ if (is_win) {
+ sources += [ "win/dxgi_device_scope_handle_unittest.cc" ]
+ deps += [ "//media/base/win:media_foundation_util" ]
+ libs = [
+ "d3d11.lib",
+ "mfplat.lib",
+ ]
+ }
}
source_set("perftests") {
@@ -609,9 +643,7 @@ source_set("perftests") {
}
fuzzer_test("media_bit_reader_fuzzer") {
- sources = [
- "bit_reader_fuzzertest.cc",
- ]
+ sources = [ "bit_reader_fuzzertest.cc" ]
deps = [
"//base",
"//media:test_support",
@@ -619,9 +651,7 @@ fuzzer_test("media_bit_reader_fuzzer") {
}
fuzzer_test("media_container_names_fuzzer") {
- sources = [
- "container_names_fuzzertest.cc",
- ]
+ sources = [ "container_names_fuzzertest.cc" ]
deps = [
"//base",
"//media:test_support",
diff --git a/chromium/media/base/android/BUILD.gn b/chromium/media/base/android/BUILD.gn
index 89c724d5379..480089fa540 100644
--- a/chromium/media/base/android/BUILD.gn
+++ b/chromium/media/base/android/BUILD.gn
@@ -47,9 +47,6 @@ if (is_android) {
"media_drm_bridge_delegate.h",
"media_drm_bridge_factory.cc",
"media_drm_bridge_factory.h",
- "media_drm_key_type.h",
- "media_drm_storage.cc",
- "media_drm_storage.h",
"media_drm_storage_bridge.cc",
"media_drm_storage_bridge.h",
"media_player_bridge.cc",
@@ -66,9 +63,7 @@ if (is_android) {
"stream_texture_wrapper.h",
]
configs += [ "//media:subcomponent_config" ]
- public_deps = [
- ":media_jni_headers",
- ]
+ public_deps = [ ":media_jni_headers" ]
deps = [
"//media/audio",
"//media/base",
@@ -154,15 +149,13 @@ if (is_android) {
}
java_cpp_strings("java_switches") {
- sources = [
- "//media/base/media_switches.cc",
- ]
+ sources = [ "//media/base/media_switches.cc" ]
template = "//media/base/android/java_templates/MediaSwitches.java.tmpl"
}
android_resources("media_java_resources") {
custom_package = "org.chromium.media"
- resource_dirs = [ "java/res" ]
+ sources = [ "java/res/raw/empty.wav" ]
}
android_library("media_java") {
@@ -178,7 +171,7 @@ if (is_android) {
":java_switches",
"//media/base:java_enums",
]
- java_files = [
+ sources = [
"java/src/org/chromium/media/AudioManagerAndroid.java",
"java/src/org/chromium/media/AudioTrackOutputStream.java",
"java/src/org/chromium/media/BitrateAdjuster.java",
@@ -186,8 +179,8 @@ if (is_android) {
"java/src/org/chromium/media/HdrMetadata.java",
"java/src/org/chromium/media/MediaCodecBridge.java",
"java/src/org/chromium/media/MediaCodecBridgeBuilder.java",
- "java/src/org/chromium/media/MediaCodecUtil.java",
"java/src/org/chromium/media/MediaCodecEncoder.java",
+ "java/src/org/chromium/media/MediaCodecUtil.java",
"java/src/org/chromium/media/MediaDrmBridge.java",
"java/src/org/chromium/media/MediaDrmSessionManager.java",
"java/src/org/chromium/media/MediaDrmStorageBridge.java",
@@ -199,7 +192,7 @@ if (is_android) {
}
junit_binary("media_base_junit_tests") {
- java_files = [
+ sources = [
"java/src/test/org/chromium/media/AudioTrackOutputStreamTest.java",
"java/src/test/org/chromium/media/BitrateAdjusterTest.java",
"java/src/test/org/chromium/media/MediaFormatBuilderTest.java",
diff --git a/chromium/media/base/android/android_cdm_factory.cc b/chromium/media/base/android/android_cdm_factory.cc
index 4844d1316eb..a2c20394f23 100644
--- a/chromium/media/base/android/android_cdm_factory.cc
+++ b/chromium/media/base/android/android_cdm_factory.cc
@@ -28,16 +28,16 @@ void ReportMediaDrmBridgeKeySystemSupport(bool supported) {
} // namespace
-AndroidCdmFactory::AndroidCdmFactory(const CreateFetcherCB& create_fetcher_cb,
- const CreateStorageCB& create_storage_cb)
- : create_fetcher_cb_(create_fetcher_cb),
- create_storage_cb_(create_storage_cb) {}
+AndroidCdmFactory::AndroidCdmFactory(CreateFetcherCB create_fetcher_cb,
+ CreateStorageCB create_storage_cb)
+ : create_fetcher_cb_(std::move(create_fetcher_cb)),
+ create_storage_cb_(std::move(create_storage_cb)) {}
AndroidCdmFactory::~AndroidCdmFactory() {
weak_factory_.InvalidateWeakPtrs();
for (auto& pending_creation : pending_creations_) {
- auto& cdm_created_cb = pending_creation.second.second;
- cdm_created_cb.Run(nullptr, "CDM creation aborted");
+ CdmCreatedCB cdm_created_cb = std::move(pending_creation.second.second);
+ std::move(cdm_created_cb).Run(nullptr, "CDM creation aborted");
}
}
@@ -49,14 +49,15 @@ void AndroidCdmFactory::Create(
const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb,
- const CdmCreatedCB& cdm_created_cb) {
+ CdmCreatedCB cdm_created_cb) {
DVLOG(1) << __func__;
// Bound |cdm_created_cb| so we always fire it asynchronously.
- CdmCreatedCB bound_cdm_created_cb = BindToCurrentLoop(cdm_created_cb);
+ CdmCreatedCB bound_cdm_created_cb =
+ BindToCurrentLoop(std::move(cdm_created_cb));
if (security_origin.opaque()) {
- bound_cdm_created_cb.Run(nullptr, "Invalid origin.");
+ std::move(bound_cdm_created_cb).Run(nullptr, "Invalid origin.");
return;
}
@@ -67,7 +68,7 @@ void AndroidCdmFactory::Create(
scoped_refptr<ContentDecryptionModule> cdm(
new AesDecryptor(session_message_cb, session_closed_cb,
session_keys_change_cb, session_expiration_update_cb));
- bound_cdm_created_cb.Run(cdm, "");
+ std::move(bound_cdm_created_cb).Run(cdm, "");
return;
}
@@ -75,8 +76,8 @@ void AndroidCdmFactory::Create(
if (!MediaDrmBridge::IsKeySystemSupported(key_system)) {
ReportMediaDrmBridgeKeySystemSupport(false);
- bound_cdm_created_cb.Run(
- nullptr, "Key system not supported unexpectedly: " + key_system);
+ std::move(bound_cdm_created_cb)
+ .Run(nullptr, "Key system not supported unexpectedly: " + key_system);
return;
}
@@ -88,13 +89,14 @@ void AndroidCdmFactory::Create(
creation_id_++;
pending_creations_.emplace(
- creation_id_, PendingCreation(std::move(factory), bound_cdm_created_cb));
-
- raw_factory->Create(
- key_system, security_origin, cdm_config, session_message_cb,
- session_closed_cb, session_keys_change_cb, session_expiration_update_cb,
- base::BindRepeating(&AndroidCdmFactory::OnCdmCreated,
- weak_factory_.GetWeakPtr(), creation_id_));
+ creation_id_,
+ PendingCreation(std::move(factory), std::move(bound_cdm_created_cb)));
+
+ raw_factory->Create(key_system, security_origin, cdm_config,
+ session_message_cb, session_closed_cb,
+ session_keys_change_cb, session_expiration_update_cb,
+ base::BindOnce(&AndroidCdmFactory::OnCdmCreated,
+ weak_factory_.GetWeakPtr(), creation_id_));
}
void AndroidCdmFactory::OnCdmCreated(
@@ -104,11 +106,12 @@ void AndroidCdmFactory::OnCdmCreated(
DVLOG(1) << __func__ << ": creation_id = " << creation_id;
DCHECK(pending_creations_.count(creation_id));
- auto cdm_created_cb = pending_creations_[creation_id].second;
+ CdmCreatedCB cdm_created_cb =
+ std::move(pending_creations_[creation_id].second);
pending_creations_.erase(creation_id);
LOG_IF(ERROR, !cdm) << error_message;
- cdm_created_cb.Run(cdm, error_message);
+ std::move(cdm_created_cb).Run(cdm, error_message);
}
} // namespace media
diff --git a/chromium/media/base/android/android_cdm_factory.h b/chromium/media/base/android/android_cdm_factory.h
index 1ca1c77943f..b32b7935b77 100644
--- a/chromium/media/base/android/android_cdm_factory.h
+++ b/chromium/media/base/android/android_cdm_factory.h
@@ -23,8 +23,8 @@ struct CdmConfig;
class MEDIA_EXPORT AndroidCdmFactory : public CdmFactory {
public:
- AndroidCdmFactory(const CreateFetcherCB& create_fetcher_cb,
- const CreateStorageCB& create_storage_cb);
+ AndroidCdmFactory(CreateFetcherCB create_fetcher_cb,
+ CreateStorageCB create_storage_cb);
~AndroidCdmFactory() final;
// CdmFactory implementation.
@@ -35,7 +35,7 @@ class MEDIA_EXPORT AndroidCdmFactory : public CdmFactory {
const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb,
- const CdmCreatedCB& cdm_created_cb) final;
+ CdmCreatedCB cdm_created_cb) final;
private:
// Callback for MediaDrmBridgeFactory::Create().
diff --git a/chromium/media/base/android/media_codec_bridge_impl.cc b/chromium/media/base/android/media_codec_bridge_impl.cc
index 48350424847..8bd73acadf1 100644
--- a/chromium/media/base/android/media_codec_bridge_impl.cc
+++ b/chromium/media/base/android/media_codec_bridge_impl.cc
@@ -22,7 +22,6 @@
#include "media/base/android/media_jni_headers/MediaCodecBridgeBuilder_jni.h"
#include "media/base/android/media_jni_headers/MediaCodecBridge_jni.h"
#include "media/base/audio_codecs.h"
-#include "media/base/bit_reader.h"
#include "media/base/subsample_entry.h"
#include "media/base/video_codecs.h"
@@ -55,20 +54,27 @@ enum {
using CodecSpecificData = std::vector<uint8_t>;
// Parses |extra_data| to get info to be added to a Java MediaFormat.
-bool GetCodecSpecificDataForAudio(AudioCodec codec,
- const uint8_t* extra_data,
- size_t extra_data_size,
- int64_t codec_delay_ns,
- int64_t seek_preroll_ns,
+bool GetCodecSpecificDataForAudio(const AudioDecoderConfig& config,
CodecSpecificData* output_csd0,
CodecSpecificData* output_csd1,
CodecSpecificData* output_csd2,
bool* output_frame_has_adts_header) {
+ // It's important that the multiplication is first in this calculation to
+ // reduce the precision loss due to integer truncation.
+ const int64_t codec_delay_ns = base::Time::kNanosecondsPerSecond *
+ config.codec_delay() /
+ config.samples_per_second();
+ const int64_t seek_preroll_ns = config.seek_preroll().InMicroseconds() *
+ base::Time::kNanosecondsPerMicrosecond;
+
+ const uint8_t* extra_data = config.extra_data().data();
+ const size_t extra_data_size = config.extra_data().size();
+
*output_frame_has_adts_header = false;
- if (extra_data_size == 0 && codec != kCodecOpus)
+ if (extra_data_size == 0 && config.codec() != kCodecOpus)
return true;
- switch (codec) {
+ switch (config.codec()) {
case kCodecVorbis: {
if (extra_data[0] != 2) {
LOG(ERROR) << "Invalid number of vorbis headers before the codec "
@@ -111,39 +117,9 @@ bool GetCodecSpecificDataForAudio(AudioCodec codec,
break;
}
case kCodecAAC: {
- media::BitReader reader(extra_data, extra_data_size);
-
- // The following code is copied from aac.cc
- // TODO(qinmin): refactor the code in aac.cc to make it more reusable.
- uint8_t profile = 0;
- uint8_t frequency_index = 0;
- uint8_t channel_config = 0;
- RETURN_ON_ERROR(reader.ReadBits(5, &profile));
- RETURN_ON_ERROR(reader.ReadBits(4, &frequency_index));
-
- if (0xf == frequency_index)
- RETURN_ON_ERROR(reader.SkipBits(24));
- RETURN_ON_ERROR(reader.ReadBits(4, &channel_config));
-
- if (profile == 5 || profile == 29) {
- // Read extension config.
- uint8_t ext_frequency_index = 0;
- RETURN_ON_ERROR(reader.ReadBits(4, &ext_frequency_index));
- if (ext_frequency_index == 0xf)
- RETURN_ON_ERROR(reader.SkipBits(24));
- RETURN_ON_ERROR(reader.ReadBits(5, &profile));
- }
-
- if (profile < 1 || profile > 4 || frequency_index == 0xf ||
- channel_config > 7) {
- LOG(ERROR) << "Invalid AAC header";
- return false;
- }
-
- output_csd0->push_back(profile << 3 | frequency_index >> 1);
- output_csd0->push_back((frequency_index & 0x01) << 7 | channel_config
- << 3);
- *output_frame_has_adts_header = true;
+ output_csd0->assign(extra_data, extra_data + extra_data_size);
+ *output_frame_has_adts_header =
+ config.profile() != AudioCodecProfile::kXHE_AAC;
break;
}
case kCodecOpus: {
@@ -170,8 +146,8 @@ bool GetCodecSpecificDataForAudio(AudioCodec codec,
break;
}
default:
- LOG(ERROR) << "Invalid header encountered for codec: "
- << GetCodecName(codec);
+ LOG(ERROR) << "Unsupported audio codec encountered: "
+ << GetCodecName(config.codec());
return false;
}
return true;
@@ -204,19 +180,9 @@ std::unique_ptr<MediaCodecBridge> MediaCodecBridgeImpl::CreateAudioDecoder(
const int channel_count =
ChannelLayoutToChannelCount(config.channel_layout());
- // It's important that the multiplication is first in this calculation to
- // reduce the precision loss due to integer truncation.
- const int64_t codec_delay_ns = base::Time::kNanosecondsPerSecond *
- config.codec_delay() /
- config.samples_per_second();
- const int64_t seek_preroll_ns = config.seek_preroll().InMicroseconds() *
- base::Time::kNanosecondsPerMicrosecond;
-
CodecSpecificData csd0, csd1, csd2;
bool output_frame_has_adts_header;
- if (!GetCodecSpecificDataForAudio(config.codec(), config.extra_data().data(),
- config.extra_data().size(), codec_delay_ns,
- seek_preroll_ns, &csd0, &csd1, &csd2,
+ if (!GetCodecSpecificDataForAudio(config, &csd0, &csd1, &csd2,
&output_frame_has_adts_header)) {
return nullptr;
}
diff --git a/chromium/media/base/android/media_codec_loop.h b/chromium/media/base/android/media_codec_loop.h
index 3eb0d81da0c..81651149a3c 100644
--- a/chromium/media/base/android/media_codec_loop.h
+++ b/chromium/media/base/android/media_codec_loop.h
@@ -107,10 +107,6 @@ namespace media {
class MEDIA_EXPORT MediaCodecLoop {
public:
- // TODO(liberato): this exists in video_decoder.h and audio_decoder.h too.
- using InitCB = base::Callback<void(bool success)>;
- using DecodeCB = base::Callback<void(DecodeStatus status)>;
-
// Data that the client wants to put into an input buffer.
struct InputData {
InputData();
diff --git a/chromium/media/base/android/media_crypto_context_impl.cc b/chromium/media/base/android/media_crypto_context_impl.cc
index 434c94250ec..4304fc2bb90 100644
--- a/chromium/media/base/android/media_crypto_context_impl.cc
+++ b/chromium/media/base/android/media_crypto_context_impl.cc
@@ -15,9 +15,11 @@ MediaCryptoContextImpl::MediaCryptoContextImpl(MediaDrmBridge* media_drm_bridge)
MediaCryptoContextImpl::~MediaCryptoContextImpl() {}
-int MediaCryptoContextImpl::RegisterPlayer(const base::Closure& new_key_cb,
- const base::Closure& cdm_unset_cb) {
- return media_drm_bridge_->RegisterPlayer(new_key_cb, cdm_unset_cb);
+int MediaCryptoContextImpl::RegisterPlayer(
+ base::RepeatingClosure new_key_cb,
+ base::RepeatingClosure cdm_unset_cb) {
+ return media_drm_bridge_->RegisterPlayer(std::move(new_key_cb),
+ std::move(cdm_unset_cb));
}
void MediaCryptoContextImpl::UnregisterPlayer(int registration_id) {
diff --git a/chromium/media/base/android/media_crypto_context_impl.h b/chromium/media/base/android/media_crypto_context_impl.h
index 24a4ca1423a..3bc2d5f2e7e 100644
--- a/chromium/media/base/android/media_crypto_context_impl.h
+++ b/chromium/media/base/android/media_crypto_context_impl.h
@@ -36,8 +36,8 @@ class MEDIA_EXPORT MediaCryptoContextImpl : public MediaCryptoContext {
//
// Note: RegisterPlayer() must be called before SetMediaCryptoReadyCB() to
// avoid missing any new key notifications.
- int RegisterPlayer(const base::Closure& new_key_cb,
- const base::Closure& cdm_unset_cb) final;
+ int RegisterPlayer(base::RepeatingClosure new_key_cb,
+ base::RepeatingClosure cdm_unset_cb) final;
void UnregisterPlayer(int registration_id) final;
// MediaCryptoContext implementation.
diff --git a/chromium/media/base/android/media_drm_bridge.cc b/chromium/media/base/android/media_drm_bridge.cc
index d90fc4f7f2e..6bdfc3a974d 100644
--- a/chromium/media/base/android/media_drm_bridge.cc
+++ b/chromium/media/base/android/media_drm_bridge.cc
@@ -30,9 +30,9 @@
#include "media/base/android/media_codec_util.h"
#include "media/base/android/media_drm_bridge_client.h"
#include "media/base/android/media_drm_bridge_delegate.h"
-#include "media/base/android/media_drm_key_type.h"
#include "media/base/android/media_jni_headers/MediaDrmBridge_jni.h"
#include "media/base/cdm_key_information.h"
+#include "media/base/media_drm_key_type.h"
#include "media/base/media_switches.h"
#include "media/base/provision_fetcher.h"
#include "third_party/widevine/cdm/widevine_cdm_common.h"
@@ -368,7 +368,7 @@ scoped_refptr<MediaDrmBridge> MediaDrmBridge::CreateInternal(
SecurityLevel security_level,
bool requires_media_crypto,
std::unique_ptr<MediaDrmStorageBridge> storage,
- const CreateFetcherCB& create_fetcher_cb,
+ CreateFetcherCB create_fetcher_cb,
const SessionMessageCB& session_message_cb,
const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb,
@@ -382,7 +382,7 @@ scoped_refptr<MediaDrmBridge> MediaDrmBridge::CreateInternal(
scoped_refptr<MediaDrmBridge> media_drm_bridge(new MediaDrmBridge(
scheme_uuid, origin_id, security_level, requires_media_crypto,
- std::move(storage), create_fetcher_cb, session_message_cb,
+ std::move(storage), std::move(create_fetcher_cb), session_message_cb,
session_closed_cb, session_keys_change_cb, session_expiration_update_cb));
if (!media_drm_bridge->j_media_drm_)
@@ -396,7 +396,7 @@ scoped_refptr<MediaDrmBridge> MediaDrmBridge::CreateWithoutSessionSupport(
const std::string& key_system,
const std::string& origin_id,
SecurityLevel security_level,
- const CreateFetcherCB& create_fetcher_cb) {
+ CreateFetcherCB create_fetcher_cb) {
DVLOG(1) << __func__;
// Sessions won't be used so decoding capability is not required.
@@ -412,7 +412,7 @@ scoped_refptr<MediaDrmBridge> MediaDrmBridge::CreateWithoutSessionSupport(
return CreateInternal(
scheme_uuid, origin_id, security_level, requires_media_crypto,
- std::make_unique<MediaDrmStorageBridge>(), create_fetcher_cb,
+ std::make_unique<MediaDrmStorageBridge>(), std::move(create_fetcher_cb),
SessionMessageCB(), SessionClosedCB(), SessionKeysChangeCB(),
SessionExpirationUpdateCB());
}
@@ -579,10 +579,11 @@ MediaCryptoContext* MediaDrmBridge::GetMediaCryptoContext() {
return &media_crypto_context_;
}
-int MediaDrmBridge::RegisterPlayer(const base::Closure& new_key_cb,
- const base::Closure& cdm_unset_cb) {
+int MediaDrmBridge::RegisterPlayer(base::RepeatingClosure new_key_cb,
+ base::RepeatingClosure cdm_unset_cb) {
// |player_tracker_| can be accessed from any thread.
- return player_tracker_.RegisterPlayer(new_key_cb, cdm_unset_cb);
+ return player_tracker_.RegisterPlayer(std::move(new_key_cb),
+ std::move(cdm_unset_cb));
}
void MediaDrmBridge::UnregisterPlayer(int registration_id) {
@@ -680,10 +681,9 @@ void MediaDrmBridge::OnMediaCryptoReady(
DVLOG(1) << __func__;
task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&MediaDrmBridge::NotifyMediaCryptoReady,
- weak_factory_.GetWeakPtr(),
- base::Passed(CreateJavaObjectPtr(j_media_crypto.obj()))));
+ FROM_HERE, base::BindOnce(&MediaDrmBridge::NotifyMediaCryptoReady,
+ weak_factory_.GetWeakPtr(),
+ CreateJavaObjectPtr(j_media_crypto.obj())));
}
void MediaDrmBridge::OnProvisionRequest(
@@ -815,7 +815,7 @@ void MediaDrmBridge::OnSessionKeysChange(
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(session_keys_change_cb_, std::move(session_id),
- has_additional_usable_key, base::Passed(&cdm_keys_info)));
+ has_additional_usable_key, std::move(cdm_keys_info)));
if (has_additional_usable_key) {
task_runner_->PostTask(
@@ -963,8 +963,8 @@ void MediaDrmBridge::SendProvisioningRequest(const std::string& default_url,
provision_fetcher_->Retrieve(
default_url, request_data,
- base::Bind(&MediaDrmBridge::ProcessProvisionResponse,
- weak_factory_.GetWeakPtr()));
+ base::BindOnce(&MediaDrmBridge::ProcessProvisionResponse,
+ weak_factory_.GetWeakPtr()));
}
void MediaDrmBridge::ProcessProvisionResponse(bool success,
diff --git a/chromium/media/base/android/media_drm_bridge.h b/chromium/media/base/android/media_drm_bridge.h
index dc0829626ca..3c800d2c5ee 100644
--- a/chromium/media/base/android/media_drm_bridge.h
+++ b/chromium/media/base/android/media_drm_bridge.h
@@ -21,12 +21,12 @@
#include "media/base/android/android_util.h"
#include "media/base/android/media_crypto_context.h"
#include "media/base/android/media_crypto_context_impl.h"
-#include "media/base/android/media_drm_storage.h"
#include "media/base/android/media_drm_storage_bridge.h"
#include "media/base/cdm_context.h"
#include "media/base/cdm_promise.h"
#include "media/base/cdm_promise_adapter.h"
#include "media/base/content_decryption_module.h"
+#include "media/base/media_drm_storage.h"
#include "media/base/media_export.h"
#include "media/base/player_tracker.h"
#include "media/base/provision_fetcher.h"
@@ -100,7 +100,7 @@ class MEDIA_EXPORT MediaDrmBridge : public ContentDecryptionModule,
const std::string& key_system,
const std::string& origin_id,
SecurityLevel security_level,
- const CreateFetcherCB& create_fetcher_cb);
+ CreateFetcherCB create_fetcher_cb);
// ContentDecryptionModule implementation.
void SetServerCertificate(
@@ -147,8 +147,8 @@ class MEDIA_EXPORT MediaDrmBridge : public ContentDecryptionModule,
//
// Note: RegisterPlayer() should be called before SetMediaCryptoReadyCB() to
// avoid missing any new key notifications.
- int RegisterPlayer(const base::Closure& new_key_cb,
- const base::Closure& cdm_unset_cb) override;
+ int RegisterPlayer(base::RepeatingClosure new_key_cb,
+ base::RepeatingClosure cdm_unset_cb) override;
void UnregisterPlayer(int registration_id) override;
// Helper function to determine whether a secure decoder is required for the
@@ -256,7 +256,7 @@ class MEDIA_EXPORT MediaDrmBridge : public ContentDecryptionModule,
SecurityLevel security_level,
bool requires_media_crypto,
std::unique_ptr<MediaDrmStorageBridge> storage,
- const CreateFetcherCB& create_fetcher_cb,
+ CreateFetcherCB create_fetcher_cb,
const SessionMessageCB& session_message_cb,
const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb,
diff --git a/chromium/media/base/android/media_drm_bridge_factory.cc b/chromium/media/base/android/media_drm_bridge_factory.cc
index dc32b11d8ab..52b3e01c271 100644
--- a/chromium/media/base/android/media_drm_bridge_factory.cc
+++ b/chromium/media/base/android/media_drm_bridge_factory.cc
@@ -13,11 +13,10 @@
namespace media {
-MediaDrmBridgeFactory::MediaDrmBridgeFactory(
- const CreateFetcherCB& create_fetcher_cb,
- const CreateStorageCB& create_storage_cb)
- : create_fetcher_cb_(create_fetcher_cb),
- create_storage_cb_(create_storage_cb) {
+MediaDrmBridgeFactory::MediaDrmBridgeFactory(CreateFetcherCB create_fetcher_cb,
+ CreateStorageCB create_storage_cb)
+ : create_fetcher_cb_(std::move(create_fetcher_cb)),
+ create_storage_cb_(std::move(create_storage_cb)) {
DCHECK(create_fetcher_cb_);
DCHECK(create_storage_cb_);
}
@@ -35,7 +34,7 @@ void MediaDrmBridgeFactory::Create(
const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb,
- const CdmCreatedCB& cdm_created_cb) {
+ CdmCreatedCB cdm_created_cb) {
DCHECK(MediaDrmBridge::IsKeySystemSupported(key_system));
DCHECK(MediaDrmBridge::IsAvailable());
DCHECK(!security_origin.opaque());
@@ -56,7 +55,7 @@ void MediaDrmBridgeFactory::Create(
key_system +
" may require use_video_overlay_for_embedded_encrypted_video";
NOTREACHED() << error_message;
- cdm_created_cb.Run(nullptr, error_message);
+ std::move(cdm_created_cb).Run(nullptr, error_message);
return;
}
@@ -64,7 +63,7 @@ void MediaDrmBridgeFactory::Create(
session_closed_cb_ = session_closed_cb;
session_keys_change_cb_ = session_keys_change_cb;
session_expiration_update_cb_ = session_expiration_update_cb;
- cdm_created_cb_ = cdm_created_cb;
+ cdm_created_cb_ = std::move(cdm_created_cb);
// MediaDrmStorage may be lazy created in MediaDrmStorageBridge.
storage_ = std::make_unique<MediaDrmStorageBridge>();
diff --git a/chromium/media/base/android/media_drm_bridge_factory.h b/chromium/media/base/android/media_drm_bridge_factory.h
index 088cbe67ad2..4dfa133dcf2 100644
--- a/chromium/media/base/android/media_drm_bridge_factory.h
+++ b/chromium/media/base/android/media_drm_bridge_factory.h
@@ -26,8 +26,8 @@ struct CdmConfig;
// at any time.
class MEDIA_EXPORT MediaDrmBridgeFactory : public CdmFactory {
public:
- MediaDrmBridgeFactory(const CreateFetcherCB& create_fetcher_cb,
- const CreateStorageCB& create_storage_cb);
+ MediaDrmBridgeFactory(CreateFetcherCB create_fetcher_cb,
+ CreateStorageCB create_storage_cb);
~MediaDrmBridgeFactory() final;
// CdmFactory implementation.
@@ -38,7 +38,7 @@ class MEDIA_EXPORT MediaDrmBridgeFactory : public CdmFactory {
const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb,
- const CdmCreatedCB& cdm_created_cb) final;
+ CdmCreatedCB cdm_created_cb) final;
private:
// Callback for Initialize() on |storage_|.
diff --git a/chromium/media/base/android/media_drm_storage_bridge.cc b/chromium/media/base/android/media_drm_storage_bridge.cc
index 23c0bfffb7c..606951bc800 100644
--- a/chromium/media/base/android/media_drm_storage_bridge.cc
+++ b/chromium/media/base/android/media_drm_storage_bridge.cc
@@ -18,8 +18,8 @@
#include "base/unguessable_token.h"
#include "media/base/android/android_util.h"
#include "media/base/android/media_drm_bridge.h"
-#include "media/base/android/media_drm_key_type.h"
#include "media/base/android/media_jni_headers/MediaDrmStorageBridge_jni.h"
+#include "media/base/media_drm_key_type.h"
using base::android::AttachCurrentThread;
using base::android::ConvertUTF8ToJavaString;
@@ -62,7 +62,7 @@ void MediaDrmStorageBridge::OnProvisioned(
// Bind callback to WeakPtr in case callback is called
// after object is deleted.
weak_factory_.GetWeakPtr(),
- base::Passed(CreateJavaObjectPtr(j_callback.obj())))));
+ CreateJavaObjectPtr(j_callback.obj()))));
}
void MediaDrmStorageBridge::OnLoadInfo(
@@ -81,8 +81,7 @@ void MediaDrmStorageBridge::OnLoadInfo(
session_id,
base::BindOnce(&MediaDrmStorageBridge::OnSessionDataLoaded,
weak_factory_.GetWeakPtr(),
- base::Passed(CreateJavaObjectPtr(j_callback.obj())),
- session_id)));
+ CreateJavaObjectPtr(j_callback.obj()), session_id)));
}
void MediaDrmStorageBridge::OnSaveInfo(
@@ -120,7 +119,7 @@ void MediaDrmStorageBridge::OnSaveInfo(
key_type),
base::BindOnce(&MediaDrmStorageBridge::RunAndroidBoolCallback,
weak_factory_.GetWeakPtr(),
- base::Passed(CreateJavaObjectPtr(j_callback.obj())))));
+ CreateJavaObjectPtr(j_callback.obj()))));
}
void MediaDrmStorageBridge::OnClearInfo(
@@ -139,7 +138,7 @@ void MediaDrmStorageBridge::OnClearInfo(
std::move(session_id),
base::BindOnce(&MediaDrmStorageBridge::RunAndroidBoolCallback,
weak_factory_.GetWeakPtr(),
- base::Passed(CreateJavaObjectPtr(j_callback.obj())))));
+ CreateJavaObjectPtr(j_callback.obj()))));
}
void MediaDrmStorageBridge::RunAndroidBoolCallback(JavaObjectPtr j_callback,
diff --git a/chromium/media/base/android/media_drm_storage_bridge.h b/chromium/media/base/android/media_drm_storage_bridge.h
index 8e6dd2bcd61..ee4edf9fc43 100644
--- a/chromium/media/base/android/media_drm_storage_bridge.h
+++ b/chromium/media/base/android/media_drm_storage_bridge.h
@@ -14,7 +14,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "media/base/android/android_util.h"
-#include "media/base/android/media_drm_storage.h"
+#include "media/base/media_drm_storage.h"
#include "url/origin.h"
namespace base {
diff --git a/chromium/media/base/android/media_server_crash_listener.cc b/chromium/media/base/android/media_server_crash_listener.cc
index 51238982ca9..958df440d1f 100644
--- a/chromium/media/base/android/media_server_crash_listener.cc
+++ b/chromium/media/base/android/media_server_crash_listener.cc
@@ -11,9 +11,9 @@
namespace media {
MediaServerCrashListener::MediaServerCrashListener(
- const OnMediaServerCrashCB& on_server_crash_cb,
+ OnMediaServerCrashCB on_server_crash_cb,
scoped_refptr<base::SingleThreadTaskRunner> callback_thread)
- : on_server_crash_cb_(on_server_crash_cb),
+ : on_server_crash_cb_(std::move(on_server_crash_cb)),
callback_task_runner_(std::move(callback_thread)) {
JNIEnv* env = base::android::AttachCurrentThread();
CHECK(env);
diff --git a/chromium/media/base/android/media_server_crash_listener.h b/chromium/media/base/android/media_server_crash_listener.h
index 74e7f87076c..7a19e20205e 100644
--- a/chromium/media/base/android/media_server_crash_listener.h
+++ b/chromium/media/base/android/media_server_crash_listener.h
@@ -22,12 +22,12 @@ namespace media {
// be more than a single instance of this class per process.
class MediaServerCrashListener {
public:
- using OnMediaServerCrashCB = base::Callback<void(bool)>;
+ using OnMediaServerCrashCB = base::RepeatingCallback<void(bool)>;
// Basic constructor. |on_server_crash_cb| will be posted to
- // |callback_task_runner| everytime the watchdog MediaPlayer detects a crash.
+ // |callback_task_runner| every time the watchdog MediaPlayer detects a crash.
MediaServerCrashListener(
- const OnMediaServerCrashCB& on_server_crash_cb,
+ OnMediaServerCrashCB on_server_crash_cb,
scoped_refptr<base::SingleThreadTaskRunner> callback_task_runner);
~MediaServerCrashListener();
diff --git a/chromium/media/base/android/media_service_throttler.cc b/chromium/media/base/android/media_service_throttler.cc
index 2d69884be87..eb42e0c58a1 100644
--- a/chromium/media/base/android/media_service_throttler.cc
+++ b/chromium/media/base/android/media_service_throttler.cc
@@ -7,6 +7,7 @@
#include <memory>
#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/default_tick_clock.h"
#include "media/base/android/media_server_crash_listener.h"
@@ -89,7 +90,7 @@ MediaServiceThrottler::MediaServiceThrottler()
crash_listener_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
// base::Unretained is safe because the MediaServiceThrottler is supposed to
// live until the process dies.
- release_crash_listener_cb_ = base::Bind(
+ release_crash_listener_cb_ = base::BindRepeating(
&MediaServiceThrottler::ReleaseCrashListener, base::Unretained(this));
EnsureCrashListenerStarted();
}
@@ -197,8 +198,8 @@ void MediaServiceThrottler::EnsureCrashListenerStarted() {
// base::Unretained is safe here because the MediaServiceThrottler will live
// until the process is terminated.
crash_listener_ = std::make_unique<MediaServerCrashListener>(
- base::Bind(&MediaServiceThrottler::OnMediaServerCrash,
- base::Unretained(this)),
+ base::BindRepeating(&MediaServiceThrottler::OnMediaServerCrash,
+ base::Unretained(this)),
crash_listener_task_runner_);
} else {
crash_listener_->EnsureListening();
@@ -225,8 +226,7 @@ void MediaServiceThrottler::SetCrashListenerTaskRunnerForTesting(
// Re-create the crash listener.
crash_listener_ = std::make_unique<MediaServerCrashListener>(
- MediaServerCrashListener::OnMediaServerCrashCB(),
- crash_listener_task_runner_);
+ base::NullCallback(), crash_listener_task_runner_);
}
} // namespace media
diff --git a/chromium/media/base/android/media_service_throttler.h b/chromium/media/base/android/media_service_throttler.h
index 3c7c34b7c53..8c2c292bf15 100644
--- a/chromium/media/base/android/media_service_throttler.h
+++ b/chromium/media/base/android/media_service_throttler.h
@@ -100,8 +100,8 @@ class MEDIA_EXPORT MediaServiceThrottler {
base::TimeTicks last_schedule_call_;
// Callbacks used to release |crash_listener_| after 60s of inactivity.
- base::Closure release_crash_listener_cb_;
- base::CancelableClosure cancelable_release_crash_listener_cb_;
+ base::RepeatingClosure release_crash_listener_cb_;
+ base::CancelableRepeatingClosure cancelable_release_crash_listener_cb_;
// Listens for MediaServer crashes using a watchdog MediaPlayer.
std::unique_ptr<MediaServerCrashListener> crash_listener_;
diff --git a/chromium/media/base/android/mock_media_crypto_context.cc b/chromium/media/base/android/mock_media_crypto_context.cc
index 017677287a0..e20d085c3f4 100644
--- a/chromium/media/base/android/mock_media_crypto_context.cc
+++ b/chromium/media/base/android/mock_media_crypto_context.cc
@@ -25,7 +25,7 @@ MockMediaCryptoContext::MockMediaCryptoContext(bool has_media_crypto_context)
// Provide some sane defaults.
ON_CALL(*this, RegisterPlayer(_, _))
- .WillByDefault(DoAll(SaveArg<0>(&new_key_cb), SaveArg<1>(&cdm_unset_cb),
+ .WillByDefault(DoAll(MoveArg<0>(&new_key_cb), MoveArg<1>(&cdm_unset_cb),
Return(kRegistrationId)));
ON_CALL(*this, SetMediaCryptoReadyCB_(_))
.WillByDefault(MoveArg<0>(&media_crypto_ready_cb));
diff --git a/chromium/media/base/android/mock_media_crypto_context.h b/chromium/media/base/android/mock_media_crypto_context.h
index 6630574cd39..745019fc18a 100644
--- a/chromium/media/base/android/mock_media_crypto_context.h
+++ b/chromium/media/base/android/mock_media_crypto_context.h
@@ -27,8 +27,8 @@ class MEDIA_EXPORT MockMediaCryptoContext
// MediaCryptoContext implementation.
MOCK_METHOD2(RegisterPlayer,
- int(const base::Closure& new_key_cb,
- const base::Closure& cdm_unset_cb));
+ int(base::RepeatingClosure new_key_cb,
+ base::RepeatingClosure cdm_unset_cb));
MOCK_METHOD1(UnregisterPlayer, void(int registration_id));
void SetMediaCryptoReadyCB(
MediaCryptoReadyCB media_crypto_ready_cb) override {
@@ -39,8 +39,8 @@ class MEDIA_EXPORT MockMediaCryptoContext
static constexpr int kRegistrationId = 1000;
- base::Closure new_key_cb;
- base::Closure cdm_unset_cb;
+ base::RepeatingClosure new_key_cb;
+ base::RepeatingClosure cdm_unset_cb;
MediaCryptoReadyCB media_crypto_ready_cb;
// To be set to true when |media_crypto_ready_cb| is consumed and run.
bool ran_media_crypto_ready_cb = false;
diff --git a/chromium/media/base/android/test_destruction_observable.cc b/chromium/media/base/android/test_destruction_observable.cc
index cf323942865..eb8c226323a 100644
--- a/chromium/media/base/android/test_destruction_observable.cc
+++ b/chromium/media/base/android/test_destruction_observable.cc
@@ -23,8 +23,8 @@ DestructionObserver::DestructionObserver(DestructionObservable* observable)
// Only one observer is allowed.
DCHECK(!observable->destruction_cb.Release());
observable->destruction_cb.ReplaceClosure(
- base::Bind(&DestructionObserver::OnObservableDestructed,
- weak_factory_.GetWeakPtr()));
+ base::BindOnce(&DestructionObserver::OnObservableDestructed,
+ weak_factory_.GetWeakPtr()));
}
DestructionObserver::~DestructionObserver() {
diff --git a/chromium/media/base/audio_buffer.cc b/chromium/media/base/audio_buffer.cc
index 6de13f0cc5e..d0f34c51e5b 100644
--- a/chromium/media/base/audio_buffer.cc
+++ b/chromium/media/base/audio_buffer.cc
@@ -82,6 +82,8 @@ AudioBuffer::AudioBuffer(SampleFormat sample_format,
if (!create_buffer)
return;
+ CHECK_NE(sample_format, kUnknownSampleFormat);
+
int data_size_per_channel = frame_count * bytes_per_channel;
if (IsPlanar(sample_format)) {
DCHECK(!IsBitstreamFormat()) << sample_format_;
diff --git a/chromium/media/base/audio_buffer.h b/chromium/media/base/audio_buffer.h
index e96bfa8edf9..71f5c87e8b7 100644
--- a/chromium/media/base/audio_buffer.h
+++ b/chromium/media/base/audio_buffer.h
@@ -157,6 +157,10 @@ class MEDIA_EXPORT AudioBuffer
// Return the sample rate.
int sample_rate() const { return sample_rate_; }
+ // Return the sample format of the internal buffer, not that of what is
+ // returned by ReadFrames().
+ int sample_format() const { return sample_format_; }
+
// Return the channel layout.
ChannelLayout channel_layout() const { return channel_layout_; }
diff --git a/chromium/media/base/audio_buffer_queue.cc b/chromium/media/base/audio_buffer_queue.cc
index 3e699663898..d77946578d1 100644
--- a/chromium/media/base/audio_buffer_queue.cc
+++ b/chromium/media/base/audio_buffer_queue.cc
@@ -75,8 +75,11 @@ int AudioBufferQueue::InternalRead(int frames,
int taken = buffer->frame_count();
// if |dest| is NULL, there's no need to copy.
- if (dest)
+ if (dest) {
+ // We always copy a whole bitstream buffer. Make sure we have space.
+ CHECK_GE(frames, buffer->frame_count());
buffer->ReadFrames(buffer->frame_count(), 0, dest_frame_offset, dest);
+ }
if (advance_position) {
// Update the appropriate values since |taken| frames have been copied
diff --git a/chromium/media/base/audio_codecs.cc b/chromium/media/base/audio_codecs.cc
index 5b39eb04738..ba5dbc66d12 100644
--- a/chromium/media/base/audio_codecs.cc
+++ b/chromium/media/base/audio_codecs.cc
@@ -47,8 +47,15 @@ std::string GetCodecName(AudioCodec codec) {
case kCodecMpegHAudio:
return "mpeg-h-audio";
}
- NOTREACHED();
- return "";
+}
+
+std::string GetProfileName(AudioCodecProfile profile) {
+ switch (profile) {
+ case AudioCodecProfile::kUnknown:
+ return "unknown";
+ case AudioCodecProfile::kXHE_AAC:
+ return "xhe-aac";
+ }
}
AudioCodec StringToAudioCodec(const std::string& codec_id) {
diff --git a/chromium/media/base/audio_codecs.h b/chromium/media/base/audio_codecs.h
index 756a3bb3293..5eb5ddcb1a4 100644
--- a/chromium/media/base/audio_codecs.h
+++ b/chromium/media/base/audio_codecs.h
@@ -42,7 +42,18 @@ enum AudioCodec {
kAudioCodecMax = kCodecMpegHAudio,
};
+enum class AudioCodecProfile {
+ // These values are histogrammed over time; do not change their ordinal
+ // values. When deleting a profile replace it with a dummy value; when adding
+ // a profile, do so at the bottom before kMaxValue, and update the value of
+ // kMaxValue to equal the new codec.
+ kUnknown = 0,
+ kXHE_AAC = 1,
+ kMaxValue = kXHE_AAC,
+};
+
std::string MEDIA_EXPORT GetCodecName(AudioCodec codec);
+std::string MEDIA_EXPORT GetProfileName(AudioCodecProfile profile);
MEDIA_EXPORT AudioCodec StringToAudioCodec(const std::string& codec_id);
diff --git a/chromium/media/base/audio_converter.cc b/chromium/media/base/audio_converter.cc
index 35115c58976..e54ded8b8fc 100644
--- a/chromium/media/base/audio_converter.cc
+++ b/chromium/media/base/audio_converter.cc
@@ -118,6 +118,12 @@ void AudioConverter::PrimeWithSilence() {
}
}
+int AudioConverter::GetMaxInputFramesRequested(int output_frames_requested) {
+ return resampler_
+ ? resampler_->GetMaxInputFramesRequested(output_frames_requested)
+ : output_frames_requested;
+}
+
void AudioConverter::ConvertWithDelay(uint32_t initial_frames_delayed,
AudioBus* dest) {
initial_frames_delayed_ = initial_frames_delayed;
diff --git a/chromium/media/base/audio_converter.h b/chromium/media/base/audio_converter.h
index ba6d2a7c18c..5e1b609fabf 100644
--- a/chromium/media/base/audio_converter.h
+++ b/chromium/media/base/audio_converter.h
@@ -96,6 +96,12 @@ class MEDIA_EXPORT AudioConverter {
// See SincResampler::PrimeWithSilence.
void PrimeWithSilence();
+ // Maximum number of frames requested via InputCallback::ProvideInput, when
+ // trying to convert |output_frames_requested| at a time.
+ // Returns |output_frames_requested| when we are not resampling, and a
+ // multiple of the request size when we are.
+ int GetMaxInputFramesRequested(int output_frames_requested);
+
bool empty() const { return transform_inputs_.empty(); }
private:
diff --git a/chromium/media/base/audio_decoder.h b/chromium/media/base/audio_decoder.h
index 39a893bd693..23bf7ae5037 100644
--- a/chromium/media/base/audio_decoder.h
+++ b/chromium/media/base/audio_decoder.h
@@ -16,6 +16,7 @@
#include "media/base/decoder_buffer.h"
#include "media/base/media_export.h"
#include "media/base/pipeline_status.h"
+#include "media/base/status.h"
#include "media/base/waiting.h"
namespace media {
@@ -26,7 +27,7 @@ class CdmContext;
class MEDIA_EXPORT AudioDecoder {
public:
// Callback for VideoDecoder initialization.
- using InitCB = base::OnceCallback<void(bool success)>;
+ using InitCB = base::OnceCallback<void(Status)>;
// Callback for AudioDecoder to return a decoded frame whenever it becomes
// available. Only non-EOS frames should be returned via this callback.
diff --git a/chromium/media/base/audio_decoder_config.cc b/chromium/media/base/audio_decoder_config.cc
index 4f13ee3eebf..c05a64e5fae 100644
--- a/chromium/media/base/audio_decoder_config.cc
+++ b/chromium/media/base/audio_decoder_config.cc
@@ -75,12 +75,14 @@ bool AudioDecoderConfig::Matches(const AudioDecoderConfig& config) const {
(seek_preroll() == config.seek_preroll()) &&
(codec_delay() == config.codec_delay()) &&
(should_discard_decoder_delay() ==
- config.should_discard_decoder_delay()));
+ config.should_discard_decoder_delay()) &&
+ (profile() == config.profile()));
}
std::string AudioDecoderConfig::AsHumanReadableString() const {
std::ostringstream s;
s << "codec: " << GetCodecName(codec())
+ << ", profile: " << GetProfileName(profile())
<< ", bytes_per_channel: " << bytes_per_channel()
<< ", channel_layout: " << ChannelLayoutToString(channel_layout())
<< ", channels: " << channels()
diff --git a/chromium/media/base/audio_decoder_config.h b/chromium/media/base/audio_decoder_config.h
index a7f294d7973..8fc0cd8d58d 100644
--- a/chromium/media/base/audio_decoder_config.h
+++ b/chromium/media/base/audio_decoder_config.h
@@ -112,8 +112,14 @@ class MEDIA_EXPORT AudioDecoderConfig {
return target_output_channel_layout_;
}
+ // Optionally set if the AudioCodec has a profile which may preclude certain
+ // decoders from having support.
+ void set_profile(AudioCodecProfile profile) { profile_ = profile; }
+ AudioCodecProfile profile() const { return profile_; }
+
private:
AudioCodec codec_ = kUnknownAudioCodec;
+ AudioCodecProfile profile_ = AudioCodecProfile::kUnknown;
SampleFormat sample_format_ = kUnknownSampleFormat;
int bytes_per_channel_ = 0;
int samples_per_second_ = 0;
diff --git a/chromium/media/base/audio_latency.cc b/chromium/media/base/audio_latency.cc
index 9d2d1e6a6ec..887dea9cf0d 100644
--- a/chromium/media/base/audio_latency.cc
+++ b/chromium/media/base/audio_latency.cc
@@ -61,7 +61,9 @@ bool AudioLatency::IsResamplingPassthroughSupported(LatencyType type) {
int AudioLatency::GetHighLatencyBufferSize(int sample_rate,
int preferred_buffer_size) {
// Empirically, we consider 20ms of samples to be high latency.
+#if !defined(USE_CRAS)
const double twenty_ms_size = 2.0 * sample_rate / 100;
+#endif
#if defined(OS_WIN)
preferred_buffer_size = std::max(preferred_buffer_size, 1);
@@ -84,7 +86,12 @@ int AudioLatency::GetHighLatencyBufferSize(int sample_rate,
//
// On Linux, the minimum hardware buffer size is 512, so the lower calculated
// values are unused. OSX may have a value as low as 128.
+#if defined(USE_CRAS)
+ const double eighty_ms_size = 8.0 * sample_rate / 100;
+ const int high_latency_buffer_size = RoundUpToPowerOfTwo(eighty_ms_size);
+#else
const int high_latency_buffer_size = RoundUpToPowerOfTwo(twenty_ms_size);
+#endif // defined(USE_CRAS)
#endif // defined(OS_WIN)
return std::max(preferred_buffer_size, high_latency_buffer_size);
diff --git a/chromium/media/base/audio_latency_unittest.cc b/chromium/media/base/audio_latency_unittest.cc
index e3540690a72..b4c3d9496f1 100644
--- a/chromium/media/base/audio_latency_unittest.cc
+++ b/chromium/media/base/audio_latency_unittest.cc
@@ -137,7 +137,11 @@ TEST(AudioLatency, HighLatencyBufferSizes) {
}
#else
for (int i = 6400; i <= 204800; i *= 2)
+#if defined(USE_CRAS)
+ EXPECT_EQ(8 * (i / 100), AudioLatency::GetHighLatencyBufferSize(i, 32));
+#else
EXPECT_EQ(2 * (i / 100), AudioLatency::GetHighLatencyBufferSize(i, 32));
+#endif // defined(USE_CRAS)
#endif // defined(OS_WIN)
}
@@ -165,7 +169,7 @@ TEST_P(AudioLatencyTest, ExactBufferSizes) {
}
INSTANTIATE_TEST_SUITE_P(
- /* no prefix */,
+ All,
AudioLatencyTest,
#if defined(OS_WIN)
// Windows 10 with supported driver will have valid min and max buffer sizes
diff --git a/chromium/media/base/audio_parameters.cc b/chromium/media/base/audio_parameters.cc
index 801896f1e6d..8bf16c27f67 100644
--- a/chromium/media/base/audio_parameters.cc
+++ b/chromium/media/base/audio_parameters.cc
@@ -9,6 +9,22 @@
namespace media {
+const char* FormatToString(AudioParameters::Format format) {
+ switch (format) {
+ case AudioParameters::AUDIO_PCM_LINEAR:
+ return "PCM_LINEAR";
+ case AudioParameters::AUDIO_PCM_LOW_LATENCY:
+ return "PCM_LOW_LATENCY";
+ case AudioParameters::AUDIO_BITSTREAM_AC3:
+ return "BITSTREAM_AC3";
+ case AudioParameters::AUDIO_BITSTREAM_EAC3:
+ return "BITSTREAM_EAC3";
+ case AudioParameters::AUDIO_FAKE:
+ return "FAKE";
+ }
+ return "INVALID";
+}
+
base::CheckedNumeric<uint32_t> ComputeAudioInputBufferSizeChecked(
const AudioParameters& parameters,
uint32_t shared_memory_count) {
@@ -117,8 +133,9 @@ bool AudioParameters::IsValid() const {
std::string AudioParameters::AsHumanReadableString() const {
std::ostringstream s;
- s << "format: " << format() << ", channel_layout: " << channel_layout()
- << ", channels: " << channels() << ", sample_rate: " << sample_rate()
+ s << "format: " << FormatToString(format())
+ << ", channel_layout: " << channel_layout() << ", channels: " << channels()
+ << ", sample_rate: " << sample_rate()
<< ", frames_per_buffer: " << frames_per_buffer()
<< ", effects: " << effects()
<< ", mic_positions: " << PointsToString(mic_positions_);
diff --git a/chromium/media/base/audio_power_monitor.cc b/chromium/media/base/audio_power_monitor.cc
new file mode 100644
index 00000000000..70d9afd4172
--- /dev/null
+++ b/chromium/media/base/audio_power_monitor.cc
@@ -0,0 +1,93 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/base/audio_power_monitor.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "base/logging.h"
+#include "base/numerics/ranges.h"
+#include "base/time/time.h"
+#include "media/base/audio_bus.h"
+#include "media/base/vector_math.h"
+
+namespace media {
+
+AudioPowerMonitor::AudioPowerMonitor(int sample_rate,
+ base::TimeDelta time_constant)
+ : sample_weight_(1.0f -
+ expf(-1.0f / (sample_rate * time_constant.InSecondsF()))) {
+ Reset();
+}
+
+AudioPowerMonitor::~AudioPowerMonitor() = default;
+
+void AudioPowerMonitor::Reset() {
+ // These are only read/written by Scan(), but Scan() should not be running
+ // when Reset() is called.
+ average_power_ = 0.0f;
+ has_clipped_ = false;
+
+ // These are the copies read by ReadCurrentPowerAndClip(). The lock here is
+ // not necessary, as racey writes/reads are acceptable, but this prevents
+ // quality-enhancement tools like TSAN from complaining.
+ base::AutoLock for_reset(reading_lock_);
+ power_reading_ = 0.0f;
+ clipped_reading_ = false;
+}
+
+void AudioPowerMonitor::Scan(const AudioBus& buffer, int num_frames) {
+ DCHECK_LE(num_frames, buffer.frames());
+ const int num_channels = buffer.channels();
+ if (num_frames <= 0 || num_channels <= 0)
+ return;
+
+ // Calculate a new average power by applying a first-order low-pass filter
+ // (a.k.a. an exponentially-weighted moving average) over the audio samples in
+ // each channel in |buffer|.
+ float sum_power = 0.0f;
+ for (int i = 0; i < num_channels; ++i) {
+ const std::pair<float, float> ewma_and_max = vector_math::EWMAAndMaxPower(
+ average_power_, buffer.channel(i), num_frames, sample_weight_);
+ // If data in audio buffer is garbage, ignore its effect on the result.
+ if (!std::isfinite(ewma_and_max.first)) {
+ sum_power += average_power_;
+ } else {
+ sum_power += ewma_and_max.first;
+ has_clipped_ |= (ewma_and_max.second > 1.0f);
+ }
+ }
+
+ // Update accumulated results, with clamping for sanity.
+ average_power_ = base::ClampToRange(sum_power / num_channels, 0.0f, 1.0f);
+
+ // Push results for reading by other threads, non-blocking.
+ if (reading_lock_.Try()) {
+ power_reading_ = average_power_;
+ if (has_clipped_) {
+ clipped_reading_ = true;
+ has_clipped_ = false;
+ }
+ reading_lock_.Release();
+ }
+}
+
+std::pair<float, bool> AudioPowerMonitor::ReadCurrentPowerAndClip() {
+ base::AutoLock for_reading(reading_lock_);
+
+ // Convert power level to dBFS units, and pin it down to zero if it is
+ // insignificantly small.
+ const float kInsignificantPower = 1.0e-10f; // -100 dBFS
+ const float power_dbfs = power_reading_ < kInsignificantPower
+ ? zero_power()
+ : 10.0f * log10f(power_reading_);
+
+ const bool clipped = clipped_reading_;
+ clipped_reading_ = false;
+
+ return std::make_pair(power_dbfs, clipped);
+}
+
+} // namespace media
diff --git a/chromium/media/base/audio_power_monitor.h b/chromium/media/base/audio_power_monitor.h
new file mode 100644
index 00000000000..d95b2836064
--- /dev/null
+++ b/chromium/media/base/audio_power_monitor.h
@@ -0,0 +1,88 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_BASE_AUDIO_POWER_MONITOR_H_
+#define MEDIA_BASE_AUDIO_POWER_MONITOR_H_
+
+#include <limits>
+#include <utility>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
+#include "media/base/media_export.h"
+
+// An audio signal power monitor. It is periodically provided an AudioBus by
+// the native audio thread, and the audio samples in each channel are analyzed
+// to determine the average power of the signal over a time period. Here
+// "average power" is a running average calculated by using a first-order
+// low-pass filter over the square of the samples scanned. Whenever reporting
+// the power level, this running average is converted to dBFS (decibels relative
+// to full-scale) units.
+//
+// Note that extreme care has been taken to make the AudioPowerMonitor::Scan()
+// method safe to be called on the native audio thread. The code acquires no
+// locks, nor engages in any operation that could result in an
+// undetermined/unbounded amount of run-time.
+
+namespace base {
+class TimeDelta;
+}
+
+namespace media {
+
+class AudioBus;
+
+class MEDIA_EXPORT AudioPowerMonitor {
+ public:
+ // |sample_rate| is the audio signal sample rate (Hz). |time_constant|
+ // characterizes how samples are averaged over time to determine the power
+ // level; and is the amount of time it takes a zero power level to increase to
+ // ~63.2% of maximum given a step input signal.
+ AudioPowerMonitor(int sample_rate, base::TimeDelta time_constant);
+
+ ~AudioPowerMonitor();
+
+ // Reset power monitor to initial state (zero power level). This should not
+ // be called while another thread is scanning.
+ void Reset();
+
+ // Scan more |frames| of audio data from |buffer|. It is safe to call this
+ // from a real-time priority thread.
+ void Scan(const AudioBus& buffer, int frames);
+
+ // Returns the current power level in dBFS and clip status. Clip status is
+ // true whenever any *one* sample scanned exceeded maximum amplitude since
+ // this method's last invocation. It is safe to call this method from any
+ // thread.
+ std::pair<float, bool> ReadCurrentPowerAndClip();
+
+ // dBFS value corresponding to zero power in the audio signal.
+ static float zero_power() { return -std::numeric_limits<float>::infinity(); }
+
+ // dBFS value corresponding to maximum power in the audio signal.
+ static float max_power() { return 0.0f; }
+
+ private:
+ // The weight applied when averaging-in each sample. Computed from the
+ // |sample_rate| and |time_constant|.
+ const float sample_weight_;
+
+ // Accumulated results over one or more calls to Scan(). These should only be
+ // touched by the thread invoking Scan().
+ float average_power_;
+ bool has_clipped_;
+
+ // Copies of power and clip status, used to deliver results synchronously
+ // across threads.
+ base::Lock reading_lock_;
+ float power_reading_;
+ bool clipped_reading_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioPowerMonitor);
+};
+
+} // namespace media
+
+#endif // MEDIA_BASE_AUDIO_POWER_MONITOR_H_
diff --git a/chromium/media/base/audio_power_monitor_unittest.cc b/chromium/media/base/audio_power_monitor_unittest.cc
new file mode 100644
index 00000000000..7ce16e04301
--- /dev/null
+++ b/chromium/media/base/audio_power_monitor_unittest.cc
@@ -0,0 +1,309 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/base/audio_power_monitor.h"
+
+#include <limits>
+#include <memory>
+
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "media/base/audio_bus.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+static const int kSampleRate = 48000;
+static const int kFramesPerBuffer = 128;
+
+static const int kTimeConstantMillis = 5;
+
+namespace {
+
+// Container for each parameterized test's data (input and expected results).
+class TestScenario {
+ public:
+ TestScenario(const float* data,
+ int num_channels,
+ int num_frames,
+ float expected_power,
+ bool expected_clipped)
+ : expected_power_(expected_power), expected_clipped_(expected_clipped) {
+ CreatePopulatedBuffer(data, num_channels, num_frames);
+ }
+
+ // Copy constructor and assignment operator for ::testing::Values(...).
+ TestScenario(const TestScenario& other) { *this = other; }
+ TestScenario& operator=(const TestScenario& other) {
+ this->expected_power_ = other.expected_power_;
+ this->expected_clipped_ = other.expected_clipped_;
+ this->bus_ = AudioBus::Create(other.bus_->channels(), other.bus_->frames());
+ other.bus_->CopyTo(this->bus_.get());
+ return *this;
+ }
+
+ // Returns this TestScenario, but with a bad sample value placed in the middle
+ // of channel 0.
+ TestScenario WithABadSample(float bad_value) const {
+ TestScenario result(*this);
+ result.bus_->channel(0)[result.bus_->frames() / 2] = bad_value;
+ return result;
+ }
+
+ const AudioBus& data() const { return *bus_; }
+
+ float expected_power() const { return expected_power_; }
+
+ bool expected_clipped() const { return expected_clipped_; }
+
+ private:
+ // Creates an AudioBus, sized and populated with kFramesPerBuffer frames of
+ // data. The given test |data| is repeated to fill the buffer.
+ void CreatePopulatedBuffer(const float* data,
+ int num_channels,
+ int num_frames) {
+ bus_ = AudioBus::Create(num_channels, kFramesPerBuffer);
+ for (int ch = 0; ch < num_channels; ++ch) {
+ for (int frames = 0; frames < kFramesPerBuffer; frames += num_frames) {
+ const int num_to_copy = std::min(num_frames, kFramesPerBuffer - frames);
+ memcpy(bus_->channel(ch) + frames, data + num_frames * ch,
+ sizeof(float) * num_to_copy);
+ }
+ }
+ }
+
+ float expected_power_;
+ bool expected_clipped_;
+ std::unique_ptr<AudioBus> bus_;
+};
+
+// Value printer for TestScenario. Required to prevent Valgrind "access to
+// uninitialized memory" errors (http://crbug.com/263315).
+::std::ostream& operator<<(::std::ostream& os, const TestScenario& ts) {
+ return os << "{" << ts.data().channels() << "-channel signal} --> {"
+ << ts.expected_power() << " dBFS, "
+ << (ts.expected_clipped() ? "clipped" : "not clipped") << "}";
+}
+
+// An observer that receives power measurements. Each power measurement should
+// should make progress towards the goal value.
+class MeasurementObserver {
+ public:
+ explicit MeasurementObserver(float goal_power_measurement)
+ : goal_power_measurement_(goal_power_measurement),
+ measurement_count_(0),
+ last_power_measurement_(AudioPowerMonitor::zero_power()),
+ last_clipped_(false) {}
+
+ int measurement_count() const { return measurement_count_; }
+
+ float last_power_measurement() const { return last_power_measurement_; }
+
+ bool last_clipped() const { return last_clipped_; }
+
+ void OnPowerMeasured(float cur_power_measurement, bool clipped) {
+ if (measurement_count_ == 0) {
+ measurements_should_increase_ =
+ (cur_power_measurement < goal_power_measurement_);
+ } else {
+ SCOPED_TRACE(::testing::Message()
+ << "Power: goal=" << goal_power_measurement_
+ << "; last=" << last_power_measurement_
+ << "; cur=" << cur_power_measurement);
+
+ if (last_power_measurement_ != goal_power_measurement_) {
+ if (measurements_should_increase_) {
+ EXPECT_LE(last_power_measurement_, cur_power_measurement)
+ << "Measurements should be monotonically increasing.";
+ } else {
+ EXPECT_GE(last_power_measurement_, cur_power_measurement)
+ << "Measurements should be monotonically decreasing.";
+ }
+ } else {
+ EXPECT_EQ(last_power_measurement_, cur_power_measurement)
+ << "Measurements are numerically unstable at goal value.";
+ }
+ }
+
+ last_power_measurement_ = cur_power_measurement;
+ last_clipped_ = clipped;
+ ++measurement_count_;
+ }
+
+ private:
+ const float goal_power_measurement_;
+ int measurement_count_;
+ bool measurements_should_increase_;
+ float last_power_measurement_;
+ bool last_clipped_;
+
+ DISALLOW_COPY_AND_ASSIGN(MeasurementObserver);
+};
+
+} // namespace
+
+class AudioPowerMonitorTest : public ::testing::TestWithParam<TestScenario> {
+ public:
+ AudioPowerMonitorTest()
+ : power_monitor_(kSampleRate,
+ base::TimeDelta::FromMilliseconds(kTimeConstantMillis)) {
+ }
+
+ void FeedAndCheckExpectedPowerIsMeasured(const AudioBus& bus,
+ float power,
+ bool clipped) {
+ // Feed the AudioPowerMonitor, read measurements from it, and record them in
+ // MeasurementObserver.
+ static const int kNumFeedIters = 100;
+ MeasurementObserver observer(power);
+ for (int i = 0; i < kNumFeedIters; ++i) {
+ power_monitor_.Scan(bus, bus.frames());
+ const std::pair<float, bool>& reading =
+ power_monitor_.ReadCurrentPowerAndClip();
+ observer.OnPowerMeasured(reading.first, reading.second);
+ }
+
+ // Check that the results recorded by the observer are the same whole-number
+ // dBFS.
+ EXPECT_EQ(static_cast<int>(power),
+ static_cast<int>(observer.last_power_measurement()));
+ EXPECT_EQ(clipped, observer.last_clipped());
+ }
+
+ private:
+ AudioPowerMonitor power_monitor_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioPowerMonitorTest);
+};
+
+TEST_P(AudioPowerMonitorTest, MeasuresPowerOfSignal) {
+ const TestScenario& scenario = GetParam();
+
+ std::unique_ptr<AudioBus> zeroed_bus =
+ AudioBus::Create(scenario.data().channels(), scenario.data().frames());
+ zeroed_bus->Zero();
+
+ // Send a "zero power" audio signal, then this scenario's audio signal, then
+ // the "zero power" audio signal again; testing that the power monitor
+ // measurements match expected values.
+ FeedAndCheckExpectedPowerIsMeasured(*zeroed_bus,
+ AudioPowerMonitor::zero_power(), false);
+ FeedAndCheckExpectedPowerIsMeasured(
+ scenario.data(), scenario.expected_power(), scenario.expected_clipped());
+ FeedAndCheckExpectedPowerIsMeasured(*zeroed_bus,
+ AudioPowerMonitor::zero_power(), false);
+}
+
+static const float kMonoSilentNoise[] = {0.01f, -0.01f};
+
+static const float kMonoMaxAmplitude[] = {1.0f};
+
+static const float kMonoMaxAmplitude2[] = {-1.0f, 1.0f};
+
+static const float kMonoHalfMaxAmplitude[] = {0.5f, -0.5f, 0.5f, -0.5f};
+
+static const float kMonoAmplitudeClipped[] = {2.0f, -2.0f};
+
+static const float kMonoMaxAmplitudeWithClip[] = {2.0f, 0.0, 0.0f, 0.0f};
+
+static const float kMonoMaxAmplitudeWithClip2[] = {4.0f, 0.0, 0.0f, 0.0f};
+
+static const float kStereoSilentNoise[] = {
+ // left channel
+ 0.005f, -0.005f,
+ // right channel
+ 0.005f, -0.005f};
+
+static const float kStereoMaxAmplitude[] = {
+ // left channel
+ 1.0f, -1.0f,
+ // right channel
+ -1.0f, 1.0f};
+
+static const float kRightChannelMaxAmplitude[] = {
+ // left channel
+ 0.0f, 0.0f, 0.0f, 0.0f,
+ // right channel
+ -1.0f, 1.0f, -1.0f, 1.0f};
+
+static const float kLeftChannelHalfMaxAmplitude[] = {
+ // left channel
+ 0.5f,
+ -0.5f,
+ 0.5f,
+ -0.5f,
+ // right channel
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+};
+
+static const float kStereoMixed[] = {
+ // left channel
+ 0.5f, -0.5f, 0.5f, -0.5f,
+ // right channel
+ -1.0f, 1.0f, -1.0f, 1.0f};
+
+static const float kStereoMixed2[] = {
+ // left channel
+ 1.0f, -1.0f, 0.75f, -0.75f, 0.5f, -0.5f, 0.25f, -0.25f,
+ // right channel
+ 0.25f, -0.25f, 0.5f, -0.5f, 0.75f, -0.75f, 1.0f, -1.0f};
+
+INSTANTIATE_TEST_SUITE_P(
+ Scenarios,
+ AudioPowerMonitorTest,
+ ::testing::Values(
+ TestScenario(kMonoSilentNoise, 1, 2, -40, false),
+ TestScenario(kMonoMaxAmplitude,
+ 1,
+ 1,
+ AudioPowerMonitor::max_power(),
+ false),
+ TestScenario(kMonoMaxAmplitude2,
+ 1,
+ 2,
+ AudioPowerMonitor::max_power(),
+ false),
+ TestScenario(kMonoHalfMaxAmplitude, 1, 4, -6, false),
+ TestScenario(kMonoAmplitudeClipped,
+ 1,
+ 2,
+ AudioPowerMonitor::max_power(),
+ true),
+ TestScenario(kMonoMaxAmplitudeWithClip,
+ 1,
+ 4,
+ AudioPowerMonitor::max_power(),
+ true),
+ TestScenario(kMonoMaxAmplitudeWithClip2,
+ 1,
+ 4,
+ AudioPowerMonitor::max_power(),
+ true),
+ TestScenario(kMonoSilentNoise,
+ 1,
+ 2,
+ AudioPowerMonitor::zero_power(),
+ false)
+ .WithABadSample(std::numeric_limits<float>::infinity()),
+ TestScenario(kMonoHalfMaxAmplitude,
+ 1,
+ 4,
+ AudioPowerMonitor::zero_power(),
+ false)
+ .WithABadSample(std::numeric_limits<float>::quiet_NaN()),
+ TestScenario(kStereoSilentNoise, 2, 2, -46, false),
+ TestScenario(kStereoMaxAmplitude,
+ 2,
+ 2,
+ AudioPowerMonitor::max_power(),
+ false),
+ TestScenario(kRightChannelMaxAmplitude, 2, 4, -3, false),
+ TestScenario(kLeftChannelHalfMaxAmplitude, 2, 4, -9, false),
+ TestScenario(kStereoMixed, 2, 4, -2, false),
+ TestScenario(kStereoMixed2, 2, 8, -3, false)));
+
+} // namespace media
diff --git a/chromium/media/base/audio_pull_fifo.cc b/chromium/media/base/audio_pull_fifo.cc
index 549adddcc8e..65a637d11e4 100644
--- a/chromium/media/base/audio_pull_fifo.cc
+++ b/chromium/media/base/audio_pull_fifo.cc
@@ -11,8 +11,8 @@
namespace media {
-AudioPullFifo::AudioPullFifo(int channels, int frames, const ReadCB& read_cb)
- : read_cb_(read_cb),
+AudioPullFifo::AudioPullFifo(int channels, int frames, ReadCB read_cb)
+ : read_cb_(std::move(read_cb)),
fifo_(AudioBus::Create(channels, frames)),
fifo_index_(frames) {}
diff --git a/chromium/media/base/audio_pull_fifo.h b/chromium/media/base/audio_pull_fifo.h
index 3983e09407b..9d9ac6f5a9d 100644
--- a/chromium/media/base/audio_pull_fifo.h
+++ b/chromium/media/base/audio_pull_fifo.h
@@ -25,13 +25,14 @@ class MEDIA_EXPORT AudioPullFifo {
// to be completely filled with data upon return; zero padded if not enough
// frames are available to satisfy the request. |frame_delay| is the number
// of output frames already processed and can be used to estimate delay.
- typedef base::Callback<void(int frame_delay, AudioBus* audio_bus)> ReadCB;
+ using ReadCB =
+ base::RepeatingCallback<void(int frame_delay, AudioBus* audio_bus)>;
// Constructs an AudioPullFifo with the specified |read_cb|, which is used to
// read audio data to the FIFO if data is not already available. The internal
// FIFO can contain |channel| number of channels, where each channel is of
// length |frames| audio frames.
- AudioPullFifo(int channels, int frames, const ReadCB& read_cb);
+ AudioPullFifo(int channels, int frames, ReadCB read_cb);
virtual ~AudioPullFifo();
// Consumes |frames_to_consume| audio frames from the FIFO and copies
diff --git a/chromium/media/base/audio_renderer.h b/chromium/media/base/audio_renderer.h
index 988d917a09a..eac3c82ffea 100644
--- a/chromium/media/base/audio_renderer.h
+++ b/chromium/media/base/audio_renderer.h
@@ -7,6 +7,7 @@
#include "base/callback.h"
#include "base/macros.h"
+#include "base/optional.h"
#include "base/time/time.h"
#include "media/base/buffering_state.h"
#include "media/base/media_export.h"
@@ -40,7 +41,7 @@ class MEDIA_EXPORT AudioRenderer {
virtual void Initialize(DemuxerStream* stream,
CdmContext* cdm_context,
RendererClient* client,
- const PipelineStatusCB& init_cb) = 0;
+ PipelineStatusCallback init_cb) = 0;
// Returns the TimeSource associated with audio rendering.
virtual TimeSource* GetTimeSource() = 0;
@@ -59,6 +60,11 @@ class MEDIA_EXPORT AudioRenderer {
// Sets the output volume.
virtual void SetVolume(float volume) = 0;
+ // Set a hint indicating target latency. See comment in renderer.h.
+ // |latency_hint| may be nullopt to indicate the hint has been cleared
+ // (restore UA default).
+ virtual void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) = 0;
+
private:
DISALLOW_COPY_AND_ASSIGN(AudioRenderer);
};
diff --git a/chromium/media/base/audio_renderer_mixer_unittest.cc b/chromium/media/base/audio_renderer_mixer_unittest.cc
index 55a9d6f8766..14cdde6d460 100644
--- a/chromium/media/base/audio_renderer_mixer_unittest.cc
+++ b/chromium/media/base/audio_renderer_mixer_unittest.cc
@@ -526,7 +526,7 @@ TEST_P(AudioRendererMixerBehavioralTest, MixerPausesStream) {
}
INSTANTIATE_TEST_SUITE_P(
- /* no prefix */,
+ All,
AudioRendererMixerTest,
testing::Values(
// No resampling, 1 input sample rate.
@@ -560,7 +560,7 @@ INSTANTIATE_TEST_SUITE_P(
// support single item lists and we don't want these test cases to run for every
// parameter set.
INSTANTIATE_TEST_SUITE_P(
- /* no prefix */,
+ All,
AudioRendererMixerBehavioralTest,
testing::ValuesIn(std::vector<AudioRendererMixerTestData>(
1,
diff --git a/chromium/media/base/bit_reader_fuzzertest.cc b/chromium/media/base/bit_reader_fuzzertest.cc
index cb6205b17d2..9b91f1317c3 100644
--- a/chromium/media/base/bit_reader_fuzzertest.cc
+++ b/chromium/media/base/bit_reader_fuzzertest.cc
@@ -5,19 +5,29 @@
#include <stddef.h>
#include <stdint.h>
-#include "base/hash/hash.h"
+#include "base/containers/buffer_iterator.h"
+#include "base/containers/span.h"
#include "base/numerics/safe_conversions.h"
#include "media/base/bit_reader.h"
#include "media/base/test_random.h"
// Entry point for LibFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- media::BitReader reader(data, base::checked_cast<int>(size));
+ base::BufferIterator<const uint8_t> iterator(data, size);
+
+ const uint32_t* random_seed = iterator.Object<uint32_t>();
+ if (!random_seed)
+ return 0;
// Need a simple random number generator to generate the number of bits to
- // read/skip in a reproducible way (given the same |data|). Using Hash() to
- // ensure the seed varies significantly over minor changes in |data|.
- media::TestRandom rnd(base::Hash(data, size));
+ // read/skip in a reproducible way (given the same |data|).
+ media::TestRandom rnd(*random_seed);
+
+ base::span<const uint8_t> remaining =
+ iterator.Span<uint8_t>(iterator.total_size() - iterator.position());
+
+ media::BitReader reader(remaining.data(),
+ base::checked_cast<int>(remaining.size()));
// Read and skip through the data in |reader|.
while (reader.bits_available() > 0) {
diff --git a/chromium/media/base/buffering_state.cc b/chromium/media/base/buffering_state.cc
new file mode 100644
index 00000000000..4cf3af511fd
--- /dev/null
+++ b/chromium/media/base/buffering_state.cc
@@ -0,0 +1,33 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/base/buffering_state.h"
+#include <string>
+#include "base/logging.h"
+
+namespace media {
+
+std::string BufferingStateToString(BufferingState state,
+ BufferingStateChangeReason reason) {
+ DCHECK(state == BUFFERING_HAVE_NOTHING || state == BUFFERING_HAVE_ENOUGH);
+ DCHECK(reason == BUFFERING_CHANGE_REASON_UNKNOWN ||
+ reason == DEMUXER_UNDERFLOW || reason == DECODER_UNDERFLOW ||
+ reason == REMOTING_NETWORK_CONGESTION);
+
+ std::string state_string = state == BUFFERING_HAVE_NOTHING
+ ? "BUFFERING_HAVE_NOTHING"
+ : "BUFFERING_HAVE_ENOUGH";
+
+ std::vector<std::string> flag_strings;
+ if (reason == DEMUXER_UNDERFLOW)
+ state_string += " (DEMUXER_UNDERFLOW)";
+ else if (reason == DECODER_UNDERFLOW)
+ state_string += " (DECODER_UNDERFLOW)";
+ else if (reason == REMOTING_NETWORK_CONGESTION)
+ state_string += " (REMOTING_NETWORK_CONGESTION)";
+
+ return state_string;
+}
+
+} // namespace media
diff --git a/chromium/media/base/buffering_state.h b/chromium/media/base/buffering_state.h
index 2de430f6cf1..3bae42ec3f8 100644
--- a/chromium/media/base/buffering_state.h
+++ b/chromium/media/base/buffering_state.h
@@ -5,6 +5,8 @@
#ifndef MEDIA_BASE_BUFFERING_STATE_H_
#define MEDIA_BASE_BUFFERING_STATE_H_
+#include <string>
+
#include "base/callback_forward.h"
namespace media {
@@ -48,9 +50,28 @@ enum BufferingStateChangeReason {
BUFFERING_STATE_CHANGE_REASON_MAX = REMOTING_NETWORK_CONGESTION,
};
+enum class SerializableBufferingStateType {
+ kPipeline,
+ kVideo,
+ kAudio,
+};
+
+// A serializable combo of the state, type, and reason.
+template <SerializableBufferingStateType T>
+struct SerializableBufferingState {
+ BufferingState state;
+ BufferingStateChangeReason reason;
+ // Only included in the serialized state if |type == kPipeline|
+ bool suspended_start = false;
+};
+
// Used to indicate changes in buffering state;
-typedef base::Callback<void(BufferingState, BufferingStateChangeReason)>
- BufferingStateCB;
+using BufferingStateCB =
+ base::RepeatingCallback<void(BufferingState, BufferingStateChangeReason)>;
+
+std::string BufferingStateToString(
+ BufferingState state,
+ BufferingStateChangeReason reason = BUFFERING_CHANGE_REASON_UNKNOWN);
} // namespace media
diff --git a/chromium/media/base/cdm_factory.h b/chromium/media/base/cdm_factory.h
index 36056a4e2d5..29d764d8ae0 100644
--- a/chromium/media/base/cdm_factory.h
+++ b/chromium/media/base/cdm_factory.h
@@ -20,8 +20,8 @@ namespace media {
// Callback used when CDM is created. |error_message| only used if
// ContentDecryptionModule is null (i.e. CDM can't be created).
using CdmCreatedCB =
- base::Callback<void(const scoped_refptr<ContentDecryptionModule>&,
- const std::string& error_message)>;
+ base::OnceCallback<void(const scoped_refptr<ContentDecryptionModule>&,
+ const std::string& error_message)>;
struct CdmConfig;
@@ -40,7 +40,7 @@ class MEDIA_EXPORT CdmFactory {
const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb,
- const CdmCreatedCB& cdm_created_cb) = 0;
+ CdmCreatedCB cdm_created_cb) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(CdmFactory);
diff --git a/chromium/media/base/channel_layout.h b/chromium/media/base/channel_layout.h
index 008c081208b..0b13d509d99 100644
--- a/chromium/media/base/channel_layout.h
+++ b/chromium/media/base/channel_layout.h
@@ -143,7 +143,12 @@ constexpr int kMaxConcurrentChannels = 8;
// from 0 to ChannelLayoutToChannelCount(layout) - 1.
MEDIA_SHMEM_EXPORT int ChannelOrder(ChannelLayout layout, Channels channel);
-// Returns the number of channels in a given ChannelLayout.
+// Returns the number of channels in a given ChannelLayout or 0 if the
+// channel layout can't be mapped to a valid value. Currently, 0
+// is returned for CHANNEL_LAYOUT_NONE, CHANNEL_LAYOUT_UNSUPPORTED,
+// CHANNEL_LAYOUT_DISCRETE, and CHANNEL_LAYOUT_BITSTREAM. For these cases,
+// additional steps must be taken to manually figure out the corresponding
+// number of channels.
MEDIA_SHMEM_EXPORT int ChannelLayoutToChannelCount(ChannelLayout layout);
// Given the number of channels, return the best layout,
diff --git a/chromium/media/base/content_decryption_module.h b/chromium/media/base/content_decryption_module.h
index 112d6ed866f..b6185c8b7c0 100644
--- a/chromium/media/base/content_decryption_module.h
+++ b/chromium/media/base/content_decryption_module.h
@@ -187,32 +187,33 @@ struct MEDIA_EXPORT ContentDecryptionModuleTraits {
// Called when the CDM needs to queue a message event to the session object.
// See http://w3c.github.io/encrypted-media/#dom-evt-message
-typedef base::Callback<void(const std::string& session_id,
- CdmMessageType message_type,
- const std::vector<uint8_t>& message)>
- SessionMessageCB;
+using SessionMessageCB =
+ base::RepeatingCallback<void(const std::string& session_id,
+ CdmMessageType message_type,
+ const std::vector<uint8_t>& message)>;
// Called when the session specified by |session_id| is closed. Note that the
// CDM may close a session at any point, such as in response to a CloseSession()
// call, when the session is no longer needed, or when system resources are
// lost. See http://w3c.github.io/encrypted-media/#session-close
-typedef base::Callback<void(const std::string& session_id)> SessionClosedCB;
+using SessionClosedCB =
+ base::RepeatingCallback<void(const std::string& session_id)>;
// Called when there has been a change in the keys in the session or their
// status. See http://w3c.github.io/encrypted-media/#dom-evt-keystatuseschange
-typedef base::Callback<void(const std::string& session_id,
- bool has_additional_usable_key,
- CdmKeysInfo keys_info)>
- SessionKeysChangeCB;
+using SessionKeysChangeCB =
+ base::RepeatingCallback<void(const std::string& session_id,
+ bool has_additional_usable_key,
+ CdmKeysInfo keys_info)>;
// Called when the CDM changes the expiration time of a session.
// See http://w3c.github.io/encrypted-media/#update-expiration
// A null base::Time() will be translated to NaN in Javascript, which means "no
// such time exists or if the license explicitly never expires, as determined
// by the CDM", according to the EME spec.
-typedef base::Callback<void(const std::string& session_id,
- base::Time new_expiry_time)>
- SessionExpirationUpdateCB;
+using SessionExpirationUpdateCB =
+ base::RepeatingCallback<void(const std::string& session_id,
+ base::Time new_expiry_time)>;
} // namespace media
diff --git a/chromium/media/base/data_source.h b/chromium/media/base/data_source.h
index 27902b2c87c..82dd76485fa 100644
--- a/chromium/media/base/data_source.h
+++ b/chromium/media/base/data_source.h
@@ -16,8 +16,7 @@ namespace media {
class MEDIA_EXPORT DataSource {
public:
- typedef base::Callback<void(int64_t, int64_t)> StatusCallback;
- typedef base::Callback<void(int)> ReadCB;
+ using ReadCB = base::OnceCallback<void(int)>;
enum { kReadError = -1, kAborted = -2 };
@@ -30,7 +29,7 @@ class MEDIA_EXPORT DataSource {
virtual void Read(int64_t position,
int size,
uint8_t* data,
- const DataSource::ReadCB& read_cb) = 0;
+ DataSource::ReadCB read_cb) = 0;
// Stops the DataSource. Once this is called all future Read() calls will
// return an error. This is a synchronous call and may be called from any
diff --git a/chromium/media/base/decoder_buffer.cc b/chromium/media/base/decoder_buffer.cc
index 9a2648e810a..5a07221ef8a 100644
--- a/chromium/media/base/decoder_buffer.cc
+++ b/chromium/media/base/decoder_buffer.cc
@@ -8,15 +8,6 @@
namespace media {
-// Allocates a block of memory which is padded for use with the SIMD
-// optimizations used by FFmpeg.
-static uint8_t* AllocateFFmpegSafeBlock(size_t size) {
- uint8_t* const block = reinterpret_cast<uint8_t*>(base::AlignedAlloc(
- size + DecoderBuffer::kPaddingSize, DecoderBuffer::kAlignmentSize));
- memset(block + size, 0, DecoderBuffer::kPaddingSize);
- return block;
-}
-
DecoderBuffer::DecoderBuffer(size_t size)
: size_(size), side_data_size_(0), is_key_frame_(false) {
Initialize();
@@ -46,6 +37,12 @@ DecoderBuffer::DecoderBuffer(const uint8_t* data,
memcpy(side_data_.get(), side_data, side_data_size_);
}
+DecoderBuffer::DecoderBuffer(std::unique_ptr<uint8_t[]> data, size_t size)
+ : data_(std::move(data)),
+ size_(size),
+ side_data_size_(0),
+ is_key_frame_(false) {}
+
DecoderBuffer::DecoderBuffer(std::unique_ptr<UnalignedSharedMemory> shm,
size_t size)
: size_(size),
@@ -67,9 +64,9 @@ DecoderBuffer::~DecoderBuffer() {
}
void DecoderBuffer::Initialize() {
- data_.reset(AllocateFFmpegSafeBlock(size_));
+ data_.reset(new uint8_t[size_]);
if (side_data_size_ > 0)
- side_data_.reset(AllocateFFmpegSafeBlock(side_data_size_));
+ side_data_.reset(new uint8_t[side_data_size_]);
}
// static
@@ -93,6 +90,14 @@ scoped_refptr<DecoderBuffer> DecoderBuffer::CopyFrom(const uint8_t* data,
}
// static
+scoped_refptr<DecoderBuffer> DecoderBuffer::FromArray(
+ std::unique_ptr<uint8_t[]> data,
+ size_t size) {
+ CHECK(data);
+ return base::WrapRefCounted(new DecoderBuffer(std::move(data), size));
+}
+
+// static
scoped_refptr<DecoderBuffer> DecoderBuffer::FromSharedMemoryRegion(
base::subtle::PlatformSharedMemoryRegion region,
off_t offset,
@@ -185,7 +190,7 @@ void DecoderBuffer::CopySideDataFrom(const uint8_t* side_data,
size_t side_data_size) {
if (side_data_size > 0) {
side_data_size_ = side_data_size;
- side_data_.reset(AllocateFFmpegSafeBlock(side_data_size_));
+ side_data_.reset(new uint8_t[side_data_size_]);
memcpy(side_data_.get(), side_data, side_data_size_);
} else {
side_data_.reset();
diff --git a/chromium/media/base/decoder_buffer.h b/chromium/media/base/decoder_buffer.h
index 05ab14e9227..e1bd6297b47 100644
--- a/chromium/media/base/decoder_buffer.h
+++ b/chromium/media/base/decoder_buffer.h
@@ -28,10 +28,6 @@ namespace media {
// A specialized buffer for interfacing with audio / video decoders.
//
-// Specifically ensures that data is aligned and padded as necessary by the
-// underlying decoding framework. On desktop platforms this means memory is
-// allocated using FFmpeg with particular alignment and padding requirements.
-//
// Also includes decoder specific functionality for decryption.
//
// NOTE: It is illegal to call any method when end_of_stream() is true.
@@ -47,25 +43,30 @@ class MEDIA_EXPORT DecoderBuffer
#endif
};
- // Allocates buffer with |size| >= 0. Buffer will be padded and aligned
- // as necessary, and |is_key_frame_| will default to false.
+ // Allocates buffer with |size| >= 0. |is_key_frame_| will default to false.
explicit DecoderBuffer(size_t size);
- // Create a DecoderBuffer whose |data_| is copied from |data|. Buffer will be
- // padded and aligned as necessary. |data| must not be NULL and |size| >= 0.
- // The buffer's |is_key_frame_| will default to false.
+ // Create a DecoderBuffer whose |data_| is copied from |data|. |data| must not
+ // be NULL and |size| >= 0. The buffer's |is_key_frame_| will default to
+ // false.
static scoped_refptr<DecoderBuffer> CopyFrom(const uint8_t* data,
size_t size);
// Create a DecoderBuffer whose |data_| is copied from |data| and |side_data_|
- // is copied from |side_data|. Buffers will be padded and aligned as necessary
- // Data pointers must not be NULL and sizes must be >= 0. The buffer's
- // |is_key_frame_| will default to false.
+ // is copied from |side_data|. Data pointers must not be NULL and sizes must
+ // be >= 0. The buffer's |is_key_frame_| will default to false.
static scoped_refptr<DecoderBuffer> CopyFrom(const uint8_t* data,
size_t size,
const uint8_t* side_data,
size_t side_data_size);
+ // Create a DecoderBuffer where data() of |size| bytes resides within the heap
+ // as byte array. The buffer's |is_key_frame_| will default to false.
+ //
+ // Ownership of |data| is transferred to the buffer.
+ static scoped_refptr<DecoderBuffer> FromArray(std::unique_ptr<uint8_t[]> data,
+ size_t size);
+
// Create a DecoderBuffer where data() of |size| bytes resides within the
// memory referred to by |region| at non-negative offset |offset|. The
// buffer's |is_key_frame_| will default to false.
@@ -197,21 +198,26 @@ class MEDIA_EXPORT DecoderBuffer
protected:
friend class base::RefCountedThreadSafe<DecoderBuffer>;
- // Allocates a buffer of size |size| >= 0 and copies |data| into it. Buffer
- // will be padded and aligned as necessary. If |data| is NULL then |data_| is
- // set to NULL and |buffer_size_| to 0. |is_key_frame_| will default to
- // false.
+ // Allocates a buffer of size |size| >= 0 and copies |data| into it. If |data|
+ // is NULL then |data_| is set to NULL and |buffer_size_| to 0.
+ // |is_key_frame_| will default to false.
DecoderBuffer(const uint8_t* data,
size_t size,
const uint8_t* side_data,
size_t side_data_size);
+ DecoderBuffer(std::unique_ptr<uint8_t[]> data, size_t size);
+
DecoderBuffer(std::unique_ptr<UnalignedSharedMemory> shm, size_t size);
DecoderBuffer(std::unique_ptr<ReadOnlyUnalignedMapping> shared_mem_mapping,
size_t size);
+
virtual ~DecoderBuffer();
+ // Encoded data, if it is stored on the heap.
+ std::unique_ptr<uint8_t[]> data_;
+
private:
// Presentation time of the frame.
base::TimeDelta timestamp_;
@@ -220,12 +226,10 @@ class MEDIA_EXPORT DecoderBuffer
// Size of the encoded data.
size_t size_;
- // Encoded data, if it is stored on the heap.
- std::unique_ptr<uint8_t, base::AlignedFreeDeleter> data_;
// Side data. Used for alpha channel in VPx, and for text cues.
size_t side_data_size_;
- std::unique_ptr<uint8_t, base::AlignedFreeDeleter> side_data_;
+ std::unique_ptr<uint8_t[]> side_data_;
// Encoded data, if it is stored in a shared memory mapping.
std::unique_ptr<ReadOnlyUnalignedMapping> shared_mem_mapping_;
diff --git a/chromium/media/base/decoder_buffer_unittest.cc b/chromium/media/base/decoder_buffer_unittest.cc
index 49a393f9f1a..a58d81de99b 100644
--- a/chromium/media/base/decoder_buffer_unittest.cc
+++ b/chromium/media/base/decoder_buffer_unittest.cc
@@ -63,6 +63,21 @@ TEST(DecoderBufferTest, CopyFrom) {
EXPECT_FALSE(buffer3->is_key_frame());
}
+TEST(DecoderBufferTest, FromArray) {
+ const uint8_t kData[] = "hello";
+ const size_t kDataSize = base::size(kData);
+ std::unique_ptr<uint8_t[]> ptr(new uint8_t[kDataSize]);
+ memcpy(ptr.get(), kData, kDataSize);
+
+ scoped_refptr<DecoderBuffer> buffer(
+ DecoderBuffer::FromArray(std::move(ptr), kDataSize));
+ ASSERT_TRUE(buffer.get());
+ EXPECT_EQ(buffer->data_size(), kDataSize);
+ EXPECT_EQ(0, memcmp(buffer->data(), kData, kDataSize));
+ EXPECT_FALSE(buffer->end_of_stream());
+ EXPECT_FALSE(buffer->is_key_frame());
+}
+
TEST(DecoderBufferTest, FromPlatformSharedMemoryRegion) {
const uint8_t kData[] = "hello";
const size_t kDataSize = base::size(kData);
@@ -171,35 +186,6 @@ TEST(DecoderBufferTest, FromSharedMemoryRegion_ZeroSize) {
ASSERT_FALSE(buffer.get());
}
-#if !defined(OS_ANDROID)
-TEST(DecoderBufferTest, PaddingAlignment) {
- const uint8_t kData[] = "hello";
- const size_t kDataSize = base::size(kData);
- scoped_refptr<DecoderBuffer> buffer2(DecoderBuffer::CopyFrom(
- reinterpret_cast<const uint8_t*>(&kData), kDataSize));
- ASSERT_TRUE(buffer2.get());
-
- // Padding data should always be zeroed.
- for(int i = 0; i < DecoderBuffer::kPaddingSize; i++)
- EXPECT_EQ((buffer2->data() + kDataSize)[i], 0);
-
- // If the data is padded correctly we should be able to read and write past
- // the end of the data by DecoderBuffer::kPaddingSize bytes without crashing
- // or Valgrind/ASAN throwing errors.
- const uint8_t kFillChar = 0xFF;
- memset(
- buffer2->writable_data() + kDataSize, kFillChar,
- DecoderBuffer::kPaddingSize);
- for(int i = 0; i < DecoderBuffer::kPaddingSize; i++)
- EXPECT_EQ((buffer2->data() + kDataSize)[i], kFillChar);
-
- EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(
- buffer2->data()) & (DecoderBuffer::kAlignmentSize - 1));
-
- EXPECT_FALSE(buffer2->is_key_frame());
-}
-#endif
-
TEST(DecoderBufferTest, ReadingWriting) {
const char kData[] = "hello";
const size_t kDataSize = base::size(kData);
diff --git a/chromium/media/base/decoder_factory.cc b/chromium/media/base/decoder_factory.cc
index 1eb9877eb6c..47aa49bab02 100644
--- a/chromium/media/base/decoder_factory.cc
+++ b/chromium/media/base/decoder_factory.cc
@@ -21,7 +21,7 @@ void DecoderFactory::CreateVideoDecoders(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
GpuVideoAcceleratorFactories* gpu_factories,
MediaLog* media_log,
- const RequestOverlayInfoCB& request_overlay_info_cb,
+ RequestOverlayInfoCB request_overlay_info_cb,
const gfx::ColorSpace& target_color_space,
std::vector<std::unique_ptr<VideoDecoder>>* video_decoders) {}
diff --git a/chromium/media/base/decoder_factory.h b/chromium/media/base/decoder_factory.h
index eed5bec05fa..d01d55e6e56 100644
--- a/chromium/media/base/decoder_factory.h
+++ b/chromium/media/base/decoder_factory.h
@@ -47,7 +47,7 @@ class MEDIA_EXPORT DecoderFactory {
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
GpuVideoAcceleratorFactories* gpu_factories,
MediaLog* media_log,
- const RequestOverlayInfoCB& request_overlay_info_cb,
+ RequestOverlayInfoCB request_overlay_info_cb,
const gfx::ColorSpace& target_color_space,
std::vector<std::unique_ptr<VideoDecoder>>* video_decoders);
diff --git a/chromium/media/base/decryptor.h b/chromium/media/base/decryptor.h
index 62b7902c6df..e084056471c 100644
--- a/chromium/media/base/decryptor.h
+++ b/chromium/media/base/decryptor.h
@@ -46,7 +46,7 @@ class MEDIA_EXPORT Decryptor {
// Indicates that a new key has been added to the ContentDecryptionModule
// object associated with the Decryptor.
- typedef base::Callback<void()> NewKeyCB;
+ using NewKeyCB = base::RepeatingClosure;
// Registers a NewKeyCB which should be called when a new key is added to the
// decryptor. Only one NewKeyCB can be registered for one |stream_type|.
@@ -55,7 +55,7 @@ class MEDIA_EXPORT Decryptor {
// registering a null callback cancels the originally registered callback.
// TODO(crbug.com/821288): Replace this with CdmContext::RegisterEventCB().
virtual void RegisterNewKeyCB(StreamType stream_type,
- const NewKeyCB& key_added_cb) = 0;
+ NewKeyCB key_added_cb) = 0;
// Indicates completion of a decryption operation.
//
@@ -71,7 +71,8 @@ class MEDIA_EXPORT Decryptor {
// - Only |data|, |data_size| and |timestamp| are set in the returned
// DecoderBuffer. The callback handler is responsible for setting other
// fields as appropriate.
- typedef base::Callback<void(Status, scoped_refptr<DecoderBuffer>)> DecryptCB;
+ using DecryptCB =
+ base::OnceCallback<void(Status, scoped_refptr<DecoderBuffer>)>;
// Decrypts the |encrypted| buffer. The decrypt status and decrypted buffer
// are returned via the provided callback |decrypt_cb|. The |encrypted| buffer
@@ -81,7 +82,7 @@ class MEDIA_EXPORT Decryptor {
// a time for a given |stream_type|.
virtual void Decrypt(StreamType stream_type,
scoped_refptr<DecoderBuffer> encrypted,
- const DecryptCB& decrypt_cb) = 0;
+ DecryptCB decrypt_cb) = 0;
// Cancels the scheduled decryption operation for |stream_type| and fires the
// pending DecryptCB immediately with kSuccess and NULL.
@@ -93,14 +94,14 @@ class MEDIA_EXPORT Decryptor {
//
// First Parameter: Indicates initialization success.
// - Set to true if initialization was successful. False if an error occurred.
- typedef base::Callback<void(bool)> DecoderInitCB;
+ using DecoderInitCB = base::OnceCallback<void(bool)>;
// Initializes a decoder with the given |config|, executing the |init_cb|
// upon completion.
virtual void InitializeAudioDecoder(const AudioDecoderConfig& config,
- const DecoderInitCB& init_cb) = 0;
+ DecoderInitCB init_cb) = 0;
virtual void InitializeVideoDecoder(const VideoDecoderConfig& config,
- const DecoderInitCB& init_cb) = 0;
+ DecoderInitCB init_cb) = 0;
// Helper structure for managing multiple decoded audio buffers per input.
typedef std::list<scoped_refptr<AudioBuffer> > AudioFrames;
diff --git a/chromium/media/base/demuxer.h b/chromium/media/base/demuxer.h
index 820744b4148..c41493a781d 100644
--- a/chromium/media/base/demuxer.h
+++ b/chromium/media/base/demuxer.h
@@ -57,14 +57,14 @@ class MEDIA_EXPORT Demuxer : public MediaResource {
// First parameter - The type of initialization data.
// Second parameter - The initialization data associated with the stream.
using EncryptedMediaInitDataCB =
- base::Callback<void(EmeInitDataType type,
- const std::vector<uint8_t>& init_data)>;
+ base::RepeatingCallback<void(EmeInitDataType type,
+ const std::vector<uint8_t>& init_data)>;
// Notifies demuxer clients that media track configuration has been updated
// (e.g. the initial stream metadata has been parsed successfully, or a new
// init segment has been parsed successfully in MSE case).
using MediaTracksUpdatedCB =
- base::Callback<void(std::unique_ptr<MediaTracks>)>;
+ base::RepeatingCallback<void(std::unique_ptr<MediaTracks>)>;
// Called once the demuxer has finished enabling or disabling tracks. The type
// argument is required because the vector may be empty.
diff --git a/chromium/media/base/fallback_video_decoder.cc b/chromium/media/base/fallback_video_decoder.cc
index 07b047edae6..a4796c2ef4e 100644
--- a/chromium/media/base/fallback_video_decoder.cc
+++ b/chromium/media/base/fallback_video_decoder.cc
@@ -48,11 +48,11 @@ void FallbackVideoDecoder::FallbackInitialize(const VideoDecoderConfig& config,
InitCB init_cb,
const OutputCB& output_cb,
const WaitingCB& waiting_cb,
- bool success) {
+ Status status) {
// The preferred decoder was successfully initialized.
- if (success) {
+ if (status.is_ok()) {
selected_decoder_ = preferred_decoder_.get();
- std::move(init_cb).Run(true);
+ std::move(init_cb).Run(OkStatus());
return;
}
diff --git a/chromium/media/base/fallback_video_decoder.h b/chromium/media/base/fallback_video_decoder.h
index c0833ad3f30..98c06c82949 100644
--- a/chromium/media/base/fallback_video_decoder.h
+++ b/chromium/media/base/fallback_video_decoder.h
@@ -43,7 +43,7 @@ class MEDIA_EXPORT FallbackVideoDecoder : public VideoDecoder {
InitCB init_cb,
const OutputCB& output_cb,
const WaitingCB& waiting_cb,
- bool success);
+ Status status);
std::unique_ptr<media::VideoDecoder> preferred_decoder_;
std::unique_ptr<media::VideoDecoder> fallback_decoder_;
diff --git a/chromium/media/base/fallback_video_decoder_unittest.cc b/chromium/media/base/fallback_video_decoder_unittest.cc
index d54bd02a6f1..ecf80f36b23 100644
--- a/chromium/media/base/fallback_video_decoder_unittest.cc
+++ b/chromium/media/base/fallback_video_decoder_unittest.cc
@@ -42,13 +42,15 @@ class FallbackVideoDecoderUnittest : public ::testing::TestWithParam<bool> {
if (is_fallback && !preferred_should_succeed) {
EXPECT_CALL(*result, Initialize_(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<3>(true));
+ .WillOnce(RunOnceCallback<3>(OkStatus()));
}
if (!is_fallback) {
preferred_decoder_ = result;
EXPECT_CALL(*result, Initialize_(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<3>(preferred_should_succeed));
+ .WillOnce(RunOnceCallback<3>(preferred_should_succeed
+ ? OkStatus()
+ : StatusCode::kCodeOnlyForTesting));
} else {
backup_decoder_ = result;
}
@@ -63,7 +65,7 @@ class FallbackVideoDecoderUnittest : public ::testing::TestWithParam<bool> {
fallback_decoder_->Initialize(
video_decoder_config_, false, nullptr,
- base::BindRepeating([](bool success) { EXPECT_TRUE(success); }),
+ base::BindOnce([](Status status) { EXPECT_TRUE(status.is_ok()); }),
base::DoNothing(), base::DoNothing());
}
@@ -123,16 +125,16 @@ TEST_P(FallbackVideoDecoderUnittest, ReinitializeWithPreferredFailing) {
Initialize(PreferredShouldSucceed());
// If we succeedd the first time, it should still be alive.
- if (PreferredShouldSucceed()) {
+ if (PreferredShouldSucceed()) { // fail initialization
EXPECT_CALL(*preferred_decoder_, Initialize_(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<3>(false)); // fail initialization
+ .WillOnce(RunOnceCallback<3>(StatusCode::kCodeOnlyForTesting));
}
EXPECT_CALL(*backup_decoder_, Initialize_(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<3>(true));
+ .WillOnce(RunOnceCallback<3>(OkStatus()));
fallback_decoder_->Initialize(
video_decoder_config_, false, nullptr,
- base::BindRepeating([](bool success) { EXPECT_TRUE(success); }),
+ base::BindOnce([](Status status) { EXPECT_TRUE(status.is_ok()); }),
base::DoNothing(), base::DoNothing());
}
@@ -148,16 +150,16 @@ TEST_P(FallbackVideoDecoderUnittest, ReinitializeWithPreferredSuccessful) {
// If we succeedd the first time, it should still be alive.
if (PreferredShouldSucceed()) {
EXPECT_CALL(*preferred_decoder_, Initialize_(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<3>(true)); // pass initialization
+ .WillOnce(RunOnceCallback<3>(OkStatus())); // pass initialization
} else {
// Otherwise, preferred was deleted, and we only backup still exists.
EXPECT_CALL(*backup_decoder_, Initialize_(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<3>(true));
+ .WillOnce(RunOnceCallback<3>(OkStatus()));
}
fallback_decoder_->Initialize(
video_decoder_config_, false, nullptr,
- base::BindOnce([](bool success) { EXPECT_TRUE(success); }),
+ base::BindOnce([](Status status) { EXPECT_TRUE(status.is_ok()); }),
base::DoNothing(), base::DoNothing());
}
diff --git a/chromium/media/base/frame_rate_estimator.cc b/chromium/media/base/frame_rate_estimator.cc
new file mode 100644
index 00000000000..96a39b90707
--- /dev/null
+++ b/chromium/media/base/frame_rate_estimator.cc
@@ -0,0 +1,87 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/base/frame_rate_estimator.h"
+
+#include <array>
+
+namespace media {
+
+// Number of samples we need before we'll trust the estimate. All samples must
+// end up in the same bucket, else we won't report an FPS for the window.
+// kMaxSamples is the maximum that we'll need, if we think that things are
+// unstable. kMinSamples is the minimum that we'll need to establish a
+// baseline fps optimistically.
+static constexpr int kMaxSamples = 15;
+static constexpr int kMinSamples = 3;
+
+// Size (in FPS) of our buckets, which take on integral multiples of
+// |BucketSize|. Observed frame rates are rounded to the nearest bucket, so
+// that 1.75 and 1.25 might both end up in bucket 2.
+static constexpr int BucketSize = 1;
+
+namespace {
+
+// Convert |duration| into an FPS bucket.
+int ToBucket(base::TimeDelta duration) {
+ return static_cast<int>(((1.0 / duration.InSecondsF()) + (BucketSize / 2.0)) /
+ BucketSize) *
+ BucketSize;
+}
+
+} // namespace
+
+FrameRateEstimator::FrameRateEstimator()
+ : duration_(kMaxSamples), required_samples_(kMinSamples) {}
+
+FrameRateEstimator::~FrameRateEstimator() = default;
+
+void FrameRateEstimator::AddSample(base::TimeDelta frame_duration) {
+ duration_.AddSample(frame_duration);
+
+ // See if the duration averages have enough samples. If not, then we can't
+ // do anything else yet.
+ if (duration_.count() < required_samples_)
+ return;
+
+ // Make sure that the entire window is in the same bucket.
+ auto extremes = duration_.GetMinAndMax();
+ // See if the current sample is too far from the bucketed average.
+ int bucketed_fps_min = ToBucket(extremes.first);
+ int bucketed_fps_max = ToBucket(extremes.second);
+
+ if (bucketed_fps_min != bucketed_fps_max) {
+ // There's no current bucket until the entire window agrees. Use the
+ // maximum window size since we don't like disagreement.
+ most_recent_bucket_.reset();
+ required_samples_ = kMaxSamples;
+ return;
+ }
+
+ most_recent_bucket_ = bucketed_fps_min;
+}
+
+base::Optional<int> FrameRateEstimator::ComputeFPS() {
+ return most_recent_bucket_;
+}
+
+void FrameRateEstimator::Reset() {
+ duration_.Reset();
+ most_recent_bucket_.reset();
+ required_samples_ = kMinSamples;
+}
+
+int FrameRateEstimator::GetRequiredSamplesForTesting() const {
+ return required_samples_;
+}
+
+int FrameRateEstimator::GetMinSamplesForTesting() const {
+ return kMinSamples;
+}
+
+int FrameRateEstimator::GetMaxSamplesForTesting() const {
+ return kMaxSamples;
+}
+
+} // namespace media
diff --git a/chromium/media/base/frame_rate_estimator.h b/chromium/media/base/frame_rate_estimator.h
new file mode 100644
index 00000000000..3a00f7bcd5e
--- /dev/null
+++ b/chromium/media/base/frame_rate_estimator.h
@@ -0,0 +1,51 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_BASE_FRAME_RATE_ESTIMATOR_H_
+#define MEDIA_BASE_FRAME_RATE_ESTIMATOR_H_
+
+#include "base/macros.h"
+#include "base/optional.h"
+#include "media/base/media_export.h"
+#include "media/base/moving_average.h"
+
+namespace media {
+
+// Utility class to provide a bucketed frame rate estimator. This class should
+// provide a stable frame rate, as measured by a sequence of frame durations,
+// or an indication that the fps isn't currently stable.
+class MEDIA_EXPORT FrameRateEstimator {
+ public:
+ FrameRateEstimator();
+ ~FrameRateEstimator();
+
+ // Add a frame with the given duration.
+ void AddSample(base::TimeDelta frame_duration);
+
+ // Return the current (bucketed) frame rate (not duration), or nullopt if one
+ // isn't available with suitable certainty.
+ base::Optional<int> ComputeFPS();
+
+ // Reset everything.
+ void Reset();
+
+ // Return the current number of required samples.
+ int GetRequiredSamplesForTesting() const;
+
+ // Return the min / max samples that we'll require for fast / slow estimates.
+ int GetMinSamplesForTesting() const;
+ int GetMaxSamplesForTesting() const;
+
+ private:
+ MovingAverage duration_;
+
+ uint64_t required_samples_;
+
+ // Most recently computed bucketed FPS (not duration), if any.
+ base::Optional<int> most_recent_bucket_;
+};
+
+} // namespace media
+
+#endif // MEDIA_BASE_FRAME_RATE_ESTIMATOR_H_
diff --git a/chromium/media/base/frame_rate_estimator_unittest.cc b/chromium/media/base/frame_rate_estimator_unittest.cc
new file mode 100644
index 00000000000..4701c3bd03a
--- /dev/null
+++ b/chromium/media/base/frame_rate_estimator_unittest.cc
@@ -0,0 +1,142 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/base/frame_rate_estimator.h"
+
+#include <tuple>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+using FpsPair = std::tuple<int, int>;
+
+class FrameRateEstimatorTest : public testing::TestWithParam<FpsPair> {
+ public:
+ void ProvideSamples(base::TimeDelta duration, int count) {
+ while (count--)
+ estimator_.AddSample(duration);
+ }
+
+ void ProvideSample(base::TimeDelta duration) {
+ estimator_.AddSample(duration);
+ }
+
+ int low_fps() const { return std::get<0>(GetParam()); }
+ int high_fps() const { return std::get<1>(GetParam()); }
+
+ base::TimeDelta duration(int fps) {
+ return base::TimeDelta::FromSecondsD(1.0 / fps);
+ }
+
+ FrameRateEstimator estimator_;
+};
+
+TEST_P(FrameRateEstimatorTest, NoEstimateInitially) {
+ // Asking for an estimate with no samples is okay, though it shouldn't return
+ // an estimate.
+ EXPECT_FALSE(estimator_.ComputeFPS());
+}
+
+TEST_P(FrameRateEstimatorTest, AverageConvergesThenReset) {
+ // Verify that the estimate is provided after the required samples are reached
+ // and that Reset() clears it.
+
+ // The initial sample requirement should allow quick convergence.
+ EXPECT_EQ(estimator_.GetRequiredSamplesForTesting(),
+ estimator_.GetMinSamplesForTesting());
+
+ // Make sure that it doesn't converge before the required sample count.
+ ProvideSamples(duration(low_fps()),
+ estimator_.GetRequiredSamplesForTesting() - 1);
+ EXPECT_FALSE(estimator_.ComputeFPS());
+ ProvideSample(duration(low_fps()));
+ EXPECT_EQ(*estimator_.ComputeFPS(), low_fps());
+
+ estimator_.Reset();
+ EXPECT_FALSE(estimator_.ComputeFPS());
+ ProvideSamples(duration(low_fps()),
+ estimator_.GetRequiredSamplesForTesting() - 1);
+ EXPECT_FALSE(estimator_.ComputeFPS());
+}
+
+TEST_P(FrameRateEstimatorTest, DurationJitterIsFine) {
+ // A little jitter doesn't change anything.
+ ProvideSamples(duration(low_fps()),
+ estimator_.GetRequiredSamplesForTesting());
+
+ // Compute a jitter that's not big enough to move it out of its bucket. We
+ // use +1 so it works either above or below (below has more room). 2.0 would
+ // be fine ideally, but we make it a bit smaller than that just to prevent
+ // floating point weirdness.
+ auto jitter = (duration(low_fps()) - duration(low_fps() + 1)) / 2.1;
+ for (int i = 0; i < estimator_.GetRequiredSamplesForTesting(); i++) {
+ ProvideSample(duration(low_fps()) + jitter);
+ EXPECT_EQ(*estimator_.ComputeFPS(), low_fps());
+ }
+
+ for (int i = 0; i < estimator_.GetRequiredSamplesForTesting(); i++) {
+ ProvideSample(duration(low_fps()) - jitter);
+ EXPECT_EQ(*estimator_.ComputeFPS(), low_fps());
+ }
+}
+
+TEST_P(FrameRateEstimatorTest, AverageDoesntSkew) {
+ // Changing frame rates shouldn't skew between them. It should stop providing
+ // estimates temporarily.
+ ProvideSamples(duration(low_fps()),
+ estimator_.GetRequiredSamplesForTesting());
+ EXPECT_EQ(*estimator_.ComputeFPS(), low_fps());
+
+ ProvideSample(duration(high_fps()));
+ EXPECT_FALSE(estimator_.ComputeFPS());
+ // We should now require more samples one we destabilized.
+ EXPECT_EQ(estimator_.GetRequiredSamplesForTesting(),
+ estimator_.GetMaxSamplesForTesting());
+ ProvideSamples(duration(high_fps()),
+ estimator_.GetRequiredSamplesForTesting() - 2);
+ EXPECT_FALSE(estimator_.ComputeFPS());
+ ProvideSample(duration(high_fps()));
+ EXPECT_EQ(*estimator_.ComputeFPS(), high_fps());
+}
+
+TEST_P(FrameRateEstimatorTest, ResetAllowsFastConvergence) {
+ // If we're in slow-convergence mode, Reset() should allow fast convergence.
+
+ // Get into slow convergence mode by providing a non-uniform window.
+ ProvideSamples(duration(low_fps()), estimator_.GetMinSamplesForTesting() - 1);
+ ProvideSamples(duration(high_fps()), 1);
+ EXPECT_EQ(estimator_.GetRequiredSamplesForTesting(),
+ estimator_.GetMaxSamplesForTesting());
+
+ // See if Reset() gets us back to fast convergence.
+ estimator_.Reset();
+ EXPECT_EQ(estimator_.GetRequiredSamplesForTesting(),
+ estimator_.GetMinSamplesForTesting());
+}
+
+// Instantiate tests for lots of common frame rates.
+INSTANTIATE_TEST_SUITE_P(All,
+ FrameRateEstimatorTest,
+ testing::Values(FpsPair(24, 30),
+ FpsPair(24, 60),
+ FpsPair(24, 90),
+ FpsPair(24, 120),
+ FpsPair(24, 240),
+
+ FpsPair(30, 60),
+ FpsPair(30, 90),
+ FpsPair(30, 120),
+ FpsPair(30, 240),
+
+ FpsPair(60, 90),
+ FpsPair(60, 120),
+ FpsPair(60, 240),
+
+ FpsPair(90, 120),
+ FpsPair(90, 240),
+
+ FpsPair(120, 240)));
+
+} // namespace media
diff --git a/chromium/media/base/ipc/media_param_traits_macros.h b/chromium/media/base/ipc/media_param_traits_macros.h
index 805726bcfe0..3e09669bce0 100644
--- a/chromium/media/base/ipc/media_param_traits_macros.h
+++ b/chromium/media/base/ipc/media_param_traits_macros.h
@@ -23,12 +23,13 @@
#include "media/base/eme_constants.h"
#include "media/base/encryption_scheme.h"
#include "media/base/hdr_metadata.h"
-#include "media/base/media_log_event.h"
+#include "media/base/media_log_record.h"
#include "media/base/media_status.h"
#include "media/base/output_device_info.h"
#include "media/base/overlay_info.h"
#include "media/base/pipeline_status.h"
#include "media/base/sample_format.h"
+#include "media/base/status_codes.h"
#include "media/base/subsample_entry.h"
#include "media/base/video_codecs.h"
#include "media/base/video_color_space.h"
@@ -43,13 +44,15 @@
#include "media/video/supported_video_decoder_config.h"
#include "ui/gfx/ipc/color/gfx_param_traits_macros.h"
-#if defined(OS_ANDROID)
-#include "media/base/android/media_drm_key_type.h"
-#endif // defined(OS_ANDROID)
+#if BUILDFLAG(ENABLE_MEDIA_DRM_STORAGE)
+#include "media/base/media_drm_key_type.h"
+#endif // BUILDFLAG(ENABLE_MEDIA_DRM_STORAGE)
// Enum traits.
IPC_ENUM_TRAITS_MAX_VALUE(media::AudioCodec, media::AudioCodec::kAudioCodecMax)
+IPC_ENUM_TRAITS_MAX_VALUE(media::AudioCodecProfile,
+ media::AudioCodecProfile::kMaxValue)
IPC_ENUM_TRAITS_MAX_VALUE(media::AudioLatency::LatencyType,
media::AudioLatency::LATENCY_COUNT)
@@ -110,8 +113,8 @@ IPC_ENUM_TRAITS_MAX_VALUE(media::EncryptionScheme,
IPC_ENUM_TRAITS_MAX_VALUE(media::HdcpVersion,
media::HdcpVersion::kHdcpVersionMax)
-IPC_ENUM_TRAITS_MAX_VALUE(media::MediaLogEvent::Type,
- media::MediaLogEvent::TYPE_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(media::MediaLogRecord::Type,
+ media::MediaLogRecord::Type::kMaxValue)
IPC_ENUM_TRAITS_MAX_VALUE(media::MediaStatus::State,
media::MediaStatus::State::STATE_MAX)
@@ -145,11 +148,13 @@ IPC_ENUM_TRAITS_MAX_VALUE(media::VideoRotation, media::VIDEO_ROTATION_MAX)
IPC_ENUM_TRAITS_MAX_VALUE(media::container_names::MediaContainerName,
media::container_names::CONTAINER_MAX)
-#if defined(OS_ANDROID)
+IPC_ENUM_TRAITS_MAX_VALUE(media::StatusCode, media::StatusCode::kMaxValue)
+
+#if BUILDFLAG(ENABLE_MEDIA_DRM_STORAGE)
IPC_ENUM_TRAITS_MIN_MAX_VALUE(media::MediaDrmKeyType,
media::MediaDrmKeyType::MIN,
media::MediaDrmKeyType::MAX)
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(ENABLE_MEDIA_DRM_STORAGE)
IPC_ENUM_TRAITS_VALIDATE(
media::VideoColorSpace::PrimaryID,
@@ -177,7 +182,7 @@ IPC_STRUCT_TRAITS_BEGIN(media::CdmConfig)
IPC_STRUCT_TRAITS_MEMBER(use_hw_secure_codecs)
IPC_STRUCT_TRAITS_END()
-IPC_STRUCT_TRAITS_BEGIN(media::MediaLogEvent)
+IPC_STRUCT_TRAITS_BEGIN(media::MediaLogRecord)
IPC_STRUCT_TRAITS_MEMBER(id)
IPC_STRUCT_TRAITS_MEMBER(type)
IPC_STRUCT_TRAITS_MEMBER(params)
diff --git a/chromium/media/base/key_systems.cc b/chromium/media/base/key_systems.cc
index 88cb98dd58d..eabf9796a93 100644
--- a/chromium/media/base/key_systems.cc
+++ b/chromium/media/base/key_systems.cc
@@ -10,6 +10,7 @@
#include <unordered_map>
#include "base/logging.h"
+#include "base/no_destructor.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_checker.h"
@@ -232,8 +233,6 @@ class KeySystemsImpl : public KeySystems {
public:
static KeySystemsImpl* GetInstance();
- void UpdateIfNeeded();
-
// These two functions are for testing purpose only.
void AddCodecMaskForTesting(EmeMediaType media_type,
const std::string& codec,
@@ -242,6 +241,8 @@ class KeySystemsImpl : public KeySystems {
uint32_t mask);
// Implementation of KeySystems interface.
+ void UpdateIfNeeded() override;
+
bool IsSupportedKeySystem(const std::string& key_system) const override;
bool CanUseAesDecryptor(const std::string& key_system) const override;
@@ -277,6 +278,8 @@ class KeySystemsImpl : public KeySystems {
const std::string& key_system) const override;
private:
+ friend class base::NoDestructor<KeySystemsImpl>;
+
KeySystemsImpl();
~KeySystemsImpl() override;
@@ -328,9 +331,9 @@ class KeySystemsImpl : public KeySystems {
};
KeySystemsImpl* KeySystemsImpl::GetInstance() {
- static KeySystemsImpl* key_systems = new KeySystemsImpl();
+ static base::NoDestructor<KeySystemsImpl> key_systems;
key_systems->UpdateIfNeeded();
- return key_systems;
+ return key_systems.get();
}
// Because we use a thread-safe static, the key systems info must be populated
diff --git a/chromium/media/base/key_systems.h b/chromium/media/base/key_systems.h
index c912c1bbf72..d57aa8e6c96 100644
--- a/chromium/media/base/key_systems.h
+++ b/chromium/media/base/key_systems.h
@@ -28,6 +28,9 @@ class MEDIA_EXPORT KeySystems {
public:
static KeySystems* GetInstance();
+ // Refreshes the list of available key systems if it may be out of date.
+ virtual void UpdateIfNeeded() = 0;
+
// Returns whether |key_system| is a supported key system.
virtual bool IsSupportedKeySystem(const std::string& key_system) const = 0;
diff --git a/chromium/media/base/keyboard_event_counter.h b/chromium/media/base/keyboard_event_counter.h
index 5e84730c672..d9f4e56d24f 100644
--- a/chromium/media/base/keyboard_event_counter.h
+++ b/chromium/media/base/keyboard_event_counter.h
@@ -12,8 +12,8 @@
#include "base/macros.h"
#include "media/base/media_export.h"
-#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
+#include "ui/events/types/event_type.h"
namespace media {
diff --git a/chromium/media/base/mac/BUILD.gn b/chromium/media/base/mac/BUILD.gn
index 459cd144711..9a1e04142a8 100644
--- a/chromium/media/base/mac/BUILD.gn
+++ b/chromium/media/base/mac/BUILD.gn
@@ -39,9 +39,7 @@ jumbo_source_set("mac") {
source_set("unit_tests") {
testonly = true
- sources = [
- "video_frame_mac_unittests.cc",
- ]
+ sources = [ "video_frame_mac_unittests.cc" ]
libs = [ "CoreVideo.framework" ]
configs += [ "//media:media_config" ]
deps = [
diff --git a/chromium/media/base/mac/video_frame_mac_unittests.cc b/chromium/media/base/mac/video_frame_mac_unittests.cc
index 86ecdf5bfe9..f0b6de5857f 100644
--- a/chromium/media/base/mac/video_frame_mac_unittests.cc
+++ b/chromium/media/base/mac/video_frame_mac_unittests.cc
@@ -96,7 +96,7 @@ TEST(VideoFrameMac, CheckLifetime) {
auto wrapper_frame = VideoFrame::WrapVideoFrame(
frame, frame->format(), frame->visible_rect(), frame->natural_size());
wrapper_frame->AddDestructionObserver(
- base::Bind(&Increment, &instances_destroyed));
+ base::BindOnce(&Increment, &instances_destroyed));
ASSERT_TRUE(wrapper_frame.get());
auto pb = WrapVideoFrameInCVPixelBuffer(*wrapper_frame);
diff --git a/chromium/media/base/android/media_drm_key_type.h b/chromium/media/base/media_drm_key_type.h
index 4996085af0b..fea284d0ed2 100644
--- a/chromium/media/base/android/media_drm_key_type.h
+++ b/chromium/media/base/media_drm_key_type.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef MEDIA_BASE_ANDROID_MEDIA_DRM_KEY_TYPE_H_
-#define MEDIA_BASE_ANDROID_MEDIA_DRM_KEY_TYPE_H_
+#ifndef MEDIA_BASE_MEDIA_DRM_KEY_TYPE_H_
+#define MEDIA_BASE_MEDIA_DRM_KEY_TYPE_H_
#include <stdint.h>
@@ -22,4 +22,4 @@ enum class MediaDrmKeyType : uint32_t {
};
} // namespace media
-#endif // MEDIA_BASE_ANDROID_MEDIA_DRM_KEY_TYPE_H_
+#endif // MEDIA_BASE_MEDIA_DRM_KEY_TYPE_H_
diff --git a/chromium/media/base/android/media_drm_storage.cc b/chromium/media/base/media_drm_storage.cc
index 9f4a92b9b01..f27eba98ea1 100644
--- a/chromium/media/base/android/media_drm_storage.cc
+++ b/chromium/media/base/media_drm_storage.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "media/base/android/media_drm_storage.h"
+#include "media/base/media_drm_storage.h"
#include <utility>
diff --git a/chromium/media/base/android/media_drm_storage.h b/chromium/media/base/media_drm_storage.h
index 276ebc9ae6e..ac17314bc3e 100644
--- a/chromium/media/base/android/media_drm_storage.h
+++ b/chromium/media/base/media_drm_storage.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef MEDIA_BASE_ANDROID_MEDIA_DRM_STORAGE_H_
-#define MEDIA_BASE_ANDROID_MEDIA_DRM_STORAGE_H_
+#ifndef MEDIA_BASE_MEDIA_DRM_STORAGE_H_
+#define MEDIA_BASE_MEDIA_DRM_STORAGE_H_
#include <stdint.h>
@@ -15,7 +15,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
-#include "media/base/android/media_drm_key_type.h"
+#include "media/base/media_drm_key_type.h"
#include "media/base/media_export.h"
#include "url/origin.h"
@@ -34,7 +34,7 @@ class MEDIA_EXPORT MediaDrmStorage
// If not specified, the device specific origin ID is to be used.
using MediaDrmOriginId = base::Optional<base::UnguessableToken>;
- struct SessionData {
+ struct MEDIA_EXPORT SessionData {
SessionData(std::vector<uint8_t> key_set_id,
std::string mime_type,
MediaDrmKeyType key_type);
@@ -99,8 +99,9 @@ class MEDIA_EXPORT MediaDrmStorage
DISALLOW_COPY_AND_ASSIGN(MediaDrmStorage);
};
-using CreateStorageCB = base::Callback<std::unique_ptr<MediaDrmStorage>()>;
+using CreateStorageCB =
+ base::RepeatingCallback<std::unique_ptr<MediaDrmStorage>()>;
} // namespace media
-#endif // MEDIA_BASE_ANDROID_MEDIA_DRM_STORAGE_H_
+#endif // MEDIA_BASE_MEDIA_DRM_STORAGE_H_
diff --git a/chromium/media/base/media_log.cc b/chromium/media/base/media_log.cc
index 177866c8ee4..babef2baa8a 100644
--- a/chromium/media/base/media_log.cc
+++ b/chromium/media/base/media_log.cc
@@ -14,145 +14,13 @@
namespace media {
+const char MediaLog::kEventKey[] = "event";
+const char MediaLog::kStatusText[] = "pipeline_error";
+
// A count of all MediaLogs created in the current process. Used to generate
// unique IDs.
static base::AtomicSequenceNumber g_media_log_count;
-std::string MediaLog::MediaLogLevelToString(MediaLogLevel level) {
- switch (level) {
- case MEDIALOG_ERROR:
- return "error";
- case MEDIALOG_WARNING:
- return "warning";
- case MEDIALOG_INFO:
- return "info";
- case MEDIALOG_DEBUG:
- return "debug";
- }
- NOTREACHED();
- return NULL;
-}
-
-MediaLogEvent::Type MediaLog::MediaLogLevelToEventType(MediaLogLevel level) {
- switch (level) {
- case MEDIALOG_ERROR:
- return MediaLogEvent::MEDIA_ERROR_LOG_ENTRY;
- case MEDIALOG_WARNING:
- return MediaLogEvent::MEDIA_WARNING_LOG_ENTRY;
- case MEDIALOG_INFO:
- return MediaLogEvent::MEDIA_INFO_LOG_ENTRY;
- case MEDIALOG_DEBUG:
- return MediaLogEvent::MEDIA_DEBUG_LOG_ENTRY;
- }
- NOTREACHED();
- return MediaLogEvent::MEDIA_ERROR_LOG_ENTRY;
-}
-
-std::string MediaLog::EventTypeToString(MediaLogEvent::Type type) {
- switch (type) {
- case MediaLogEvent::WEBMEDIAPLAYER_CREATED:
- return "WEBMEDIAPLAYER_CREATED";
- case MediaLogEvent::WEBMEDIAPLAYER_DESTROYED:
- return "WEBMEDIAPLAYER_DESTROYED";
- case MediaLogEvent::LOAD:
- return "LOAD";
- case MediaLogEvent::SEEK:
- return "SEEK";
- case MediaLogEvent::PLAY:
- return "PLAY";
- case MediaLogEvent::PAUSE:
- return "PAUSE";
- case MediaLogEvent::PIPELINE_STATE_CHANGED:
- return "PIPELINE_STATE_CHANGED";
- case MediaLogEvent::PIPELINE_ERROR:
- return "PIPELINE_ERROR";
- case MediaLogEvent::VIDEO_SIZE_SET:
- return "VIDEO_SIZE_SET";
- case MediaLogEvent::DURATION_SET:
- return "DURATION_SET";
- case MediaLogEvent::ENDED:
- return "ENDED";
- case MediaLogEvent::TEXT_ENDED:
- return "TEXT_ENDED";
- case MediaLogEvent::MEDIA_ERROR_LOG_ENTRY:
- return "MEDIA_ERROR_LOG_ENTRY";
- case MediaLogEvent::MEDIA_WARNING_LOG_ENTRY:
- return "MEDIA_WARNING_LOG_ENTRY";
- case MediaLogEvent::MEDIA_INFO_LOG_ENTRY:
- return "MEDIA_INFO_LOG_ENTRY";
- case MediaLogEvent::MEDIA_DEBUG_LOG_ENTRY:
- return "MEDIA_DEBUG_LOG_ENTRY";
- case MediaLogEvent::PROPERTY_CHANGE:
- return "PROPERTY_CHANGE";
- case MediaLogEvent::BUFFERING_STATE_CHANGE:
- return "BUFFERING_STATE_CHANGE";
- case MediaLogEvent::SUSPENDED:
- return "SUSPENDED";
- }
- NOTREACHED();
- return NULL;
-}
-
-std::string MediaLog::MediaEventToLogString(const MediaLogEvent& event) {
- // Special case for PIPELINE_ERROR, since that's by far the most useful
- // event for figuring out media pipeline failures, and just reporting
- // pipeline status as numeric code is not very helpful/user-friendly.
- int error_code = 0;
- if (event.type == MediaLogEvent::PIPELINE_ERROR &&
- event.params.GetInteger("pipeline_error", &error_code)) {
- PipelineStatus status = static_cast<PipelineStatus>(error_code);
- return EventTypeToString(event.type) + " " + PipelineStatusToString(status);
- }
-
- std::string params_json;
- base::JSONWriter::Write(event.params, &params_json);
- return EventTypeToString(event.type) + " " + params_json;
-}
-
-std::string MediaLog::MediaEventToMessageString(const MediaLogEvent& event) {
- switch (event.type) {
- case MediaLogEvent::PIPELINE_ERROR: {
- int error_code = 0;
- event.params.GetInteger("pipeline_error", &error_code);
- DCHECK_NE(error_code, 0);
- return PipelineStatusToString(static_cast<PipelineStatus>(error_code));
- }
- case MediaLogEvent::MEDIA_ERROR_LOG_ENTRY: {
- std::string result = "";
- if (event.params.GetString(MediaLogLevelToString(MEDIALOG_ERROR),
- &result))
- base::ReplaceChars(result, "\n", " ", &result);
- return result;
- }
- default:
- NOTREACHED();
- return "";
- }
-}
-
-std::string MediaLog::BufferingStateToString(
- BufferingState state,
- BufferingStateChangeReason reason) {
- DCHECK(state == BUFFERING_HAVE_NOTHING || state == BUFFERING_HAVE_ENOUGH);
- DCHECK(reason == BUFFERING_CHANGE_REASON_UNKNOWN ||
- reason == DEMUXER_UNDERFLOW || reason == DECODER_UNDERFLOW ||
- reason == REMOTING_NETWORK_CONGESTION);
-
- std::string state_string = state == BUFFERING_HAVE_NOTHING
- ? "BUFFERING_HAVE_NOTHING"
- : "BUFFERING_HAVE_ENOUGH";
-
- std::vector<std::string> flag_strings;
- if (reason == DEMUXER_UNDERFLOW)
- state_string += " (DEMUXER_UNDERFLOW)";
- else if (reason == DECODER_UNDERFLOW)
- state_string += " (DECODER_UNDERFLOW)";
- else if (reason == REMOTING_NETWORK_CONGESTION)
- state_string += " (REMOTING_NETWORK_CONGESTION)";
-
- return state_string;
-}
-
MediaLog::MediaLog() : MediaLog(new ParentLogRecord(this)) {}
MediaLog::MediaLog(scoped_refptr<ParentLogRecord> parent_log_record)
@@ -175,25 +43,37 @@ MediaLog::~MediaLog() {
InvalidateLog();
}
-void MediaLog::OnWebMediaPlayerDestroyed() {
- AddEvent(CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
- base::AutoLock auto_lock(parent_log_record_->lock);
- // Forward to the parent log's implementation.
- if (parent_log_record_->media_log)
- parent_log_record_->media_log->OnWebMediaPlayerDestroyedLocked();
+// Default *Locked implementations
+void MediaLog::AddLogRecordLocked(std::unique_ptr<MediaLogRecord> event) {}
+
+std::string MediaLog::GetErrorMessageLocked() {
+ return "";
}
-void MediaLog::OnWebMediaPlayerDestroyedLocked() {}
+void MediaLog::AddMessage(MediaLogMessageLevel level, std::string message) {
+ std::unique_ptr<MediaLogRecord> record(
+ CreateRecord(MediaLogRecord::Type::kMessage));
+ record->params.SetStringPath(MediaLogMessageLevelToString(level),
+ std::move(message));
+ AddLogRecord(std::move(record));
+}
-void MediaLog::AddEvent(std::unique_ptr<MediaLogEvent> event) {
+void MediaLog::NotifyError(PipelineStatus status) {
+ std::unique_ptr<MediaLogRecord> record(
+ CreateRecord(MediaLogRecord::Type::kMediaStatus));
+ record->params.SetIntPath(MediaLog::kStatusText, status);
+ AddLogRecord(std::move(record));
+}
+
+void MediaLog::OnWebMediaPlayerDestroyedLocked() {}
+void MediaLog::OnWebMediaPlayerDestroyed() {
+ AddEvent<MediaLogEvent::kWebMediaPlayerDestroyed>();
base::AutoLock auto_lock(parent_log_record_->lock);
// Forward to the parent log's implementation.
if (parent_log_record_->media_log)
- parent_log_record_->media_log->AddEventLocked(std::move(event));
+ parent_log_record_->media_log->OnWebMediaPlayerDestroyedLocked();
}
-void MediaLog::AddEventLocked(std::unique_ptr<MediaLogEvent> event) {}
-
std::string MediaLog::GetErrorMessage() {
base::AutoLock auto_lock(parent_log_record_->lock);
// Forward to the parent log's implementation.
@@ -203,132 +83,26 @@ std::string MediaLog::GetErrorMessage() {
return "";
}
-std::string MediaLog::GetErrorMessageLocked() {
- return "";
-}
-
-std::unique_ptr<MediaLogEvent> MediaLog::CreateCreatedEvent(
- const std::string& origin_url) {
- std::unique_ptr<MediaLogEvent> event(
- CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_CREATED));
- event->params.SetString("origin_url", TruncateUrlString(origin_url));
- return event;
-}
-
-std::unique_ptr<MediaLogEvent> MediaLog::CreateEvent(MediaLogEvent::Type type) {
- std::unique_ptr<MediaLogEvent> event(new MediaLogEvent);
- event->id = id_;
- event->type = type;
- event->time = base::TimeTicks::Now();
- return event;
-}
-
-std::unique_ptr<MediaLogEvent> MediaLog::CreateBooleanEvent(
- MediaLogEvent::Type type,
- const std::string& property,
- bool value) {
- std::unique_ptr<MediaLogEvent> event(CreateEvent(type));
- event->params.SetBoolean(property, value);
- return event;
-}
-
-std::unique_ptr<MediaLogEvent> MediaLog::CreateStringEvent(
- MediaLogEvent::Type type,
- const std::string& property,
- const std::string& value) {
- std::unique_ptr<MediaLogEvent> event(CreateEvent(type));
- event->params.SetString(property, value);
- return event;
-}
-
-std::unique_ptr<MediaLogEvent> MediaLog::CreateTimeEvent(
- MediaLogEvent::Type type,
- const std::string& property,
- base::TimeDelta value) {
- return CreateTimeEvent(type, property, value.InSecondsF());
-}
-
-std::unique_ptr<MediaLogEvent> MediaLog::CreateTimeEvent(
- MediaLogEvent::Type type,
- const std::string& property,
- double value) {
- std::unique_ptr<MediaLogEvent> event(CreateEvent(type));
- if (std::isfinite(value))
- event->params.SetDouble(property, value);
- else
- event->params.SetString(property, "unknown");
- return event;
-}
-
-std::unique_ptr<MediaLogEvent> MediaLog::CreateLoadEvent(
- const std::string& url) {
- std::unique_ptr<MediaLogEvent> event(CreateEvent(MediaLogEvent::LOAD));
- event->params.SetString("url", TruncateUrlString(url));
- return event;
-}
-
-std::unique_ptr<MediaLogEvent> MediaLog::CreatePipelineStateChangedEvent(
- PipelineImpl::State state) {
- std::unique_ptr<MediaLogEvent> event(
- CreateEvent(MediaLogEvent::PIPELINE_STATE_CHANGED));
- event->params.SetString("pipeline_state",
- PipelineImpl::GetStateString(state));
- return event;
-}
-
-std::unique_ptr<MediaLogEvent> MediaLog::CreatePipelineErrorEvent(
- PipelineStatus error) {
- std::unique_ptr<MediaLogEvent> event(
- CreateEvent(MediaLogEvent::PIPELINE_ERROR));
- event->params.SetInteger("pipeline_error", error);
- return event;
-}
-
-std::unique_ptr<MediaLogEvent> MediaLog::CreateVideoSizeSetEvent(
- size_t width,
- size_t height) {
- std::unique_ptr<MediaLogEvent> event(
- CreateEvent(MediaLogEvent::VIDEO_SIZE_SET));
- event->params.SetInteger("width", width);
- event->params.SetInteger("height", height);
- return event;
-}
-
-std::unique_ptr<MediaLogEvent> MediaLog::CreateBufferingStateChangedEvent(
- const std::string& property,
- BufferingState state,
- BufferingStateChangeReason reason) {
- return CreateStringEvent(MediaLogEvent::BUFFERING_STATE_CHANGE, property,
- BufferingStateToString(state, reason));
-}
-
-void MediaLog::AddLogEvent(MediaLogLevel level, const std::string& message) {
- std::unique_ptr<MediaLogEvent> event(
- CreateEvent(MediaLogLevelToEventType(level)));
- event->params.SetString(MediaLogLevelToString(level), message);
- AddEvent(std::move(event));
-}
-
std::unique_ptr<MediaLog> MediaLog::Clone() {
// Protected ctor, so we can't use std::make_unique.
return base::WrapUnique(new MediaLog(parent_log_record_));
}
-// static
-std::string MediaLog::TruncateUrlString(std::string log_string) {
- if (log_string.length() > kMaxUrlLength) {
- log_string.resize(kMaxUrlLength);
-
- // Room for the ellipsis.
- DCHECK_GE(kMaxUrlLength, std::size_t{3});
- log_string.replace(log_string.end() - 3, log_string.end(), "...");
- }
-
- return log_string;
+void MediaLog::AddLogRecord(std::unique_ptr<MediaLogRecord> record) {
+ base::AutoLock auto_lock(parent_log_record_->lock);
+ // Forward to the parent log's implementation.
+ if (parent_log_record_->media_log)
+ parent_log_record_->media_log->AddLogRecordLocked(std::move(record));
}
-MediaLog::ParentLogRecord::ParentLogRecord(MediaLog* log) : media_log(log) {}
-MediaLog::ParentLogRecord::~ParentLogRecord() = default;
+std::unique_ptr<MediaLogRecord> MediaLog::CreateRecord(
+ MediaLogRecord::Type type) {
+ auto record = std::make_unique<MediaLogRecord>();
+ record->id = id_;
+ record->type = type;
+ record->time = base::TimeTicks::Now();
+ return record;
+}
void MediaLog::InvalidateLog() {
base::AutoLock auto_lock(parent_log_record_->lock);
@@ -340,17 +114,20 @@ void MediaLog::InvalidateLog() {
// Keep |parent_log_record_| around, since the lock must keep working.
}
-LogHelper::LogHelper(MediaLog::MediaLogLevel level, MediaLog* media_log)
+MediaLog::ParentLogRecord::ParentLogRecord(MediaLog* log) : media_log(log) {}
+MediaLog::ParentLogRecord::~ParentLogRecord() = default;
+
+LogHelper::LogHelper(MediaLogMessageLevel level, MediaLog* media_log)
: level_(level), media_log_(media_log) {
DCHECK(media_log_);
}
-LogHelper::LogHelper(MediaLog::MediaLogLevel level,
+LogHelper::LogHelper(MediaLogMessageLevel level,
const std::unique_ptr<MediaLog>& media_log)
: LogHelper(level, media_log.get()) {}
LogHelper::~LogHelper() {
- media_log_->AddLogEvent(level_, stream_.str());
+ media_log_->AddMessage(level_, stream_.str());
}
} //namespace media
diff --git a/chromium/media/base/media_log.h b/chromium/media/base/media_log.h
index 25ea7c84176..957181676fd 100644
--- a/chromium/media/base/media_log.h
+++ b/chromium/media/base/media_log.h
@@ -19,8 +19,10 @@
#include "base/thread_annotations.h"
#include "media/base/buffering_state.h"
#include "media/base/media_export.h"
-#include "media/base/media_log_event.h"
+#include "media/base/media_log_events.h"
+#include "media/base/media_log_message_levels.h"
#include "media/base/media_log_properties.h"
+#include "media/base/media_log_record.h"
#include "media/base/pipeline_impl.h"
#include "media/base/pipeline_status.h"
#include "url/gurl.h"
@@ -31,55 +33,53 @@ namespace media {
//
// To provide a logging implementation, derive from MediaLog instead.
//
-// Implementations only need to implement AddEventLocked(), which must be thread
-// safe in the sense that it may be called from multiple threads, though it will
-// not be called concurrently. See below for more details.
+// Implementations only need to implement AddLogRecordLocked(), which must be
+// thread safe in the sense that it may be called from multiple threads, though
+// it will not be called concurrently. See below for more details.
//
// Implementations should also call InvalidateLog during destruction, to signal
// to any child logs that the underlying log is no longer available.
class MEDIA_EXPORT MediaLog {
public:
- enum MediaLogLevel {
- // Fatal error, e.g. cause of playback failure. Since this is also used to
- // form MediaError.message, do NOT use this for non-fatal errors to avoid
- // contaminating MediaError.message.
- MEDIALOG_ERROR,
-
- // Warning about non-fatal issues, e.g. quality of playback issues such as
- // audio/video out of sync.
- MEDIALOG_WARNING,
-
- // General info useful for Chromium and/or web developers, testers and even
- // users, e.g. audio/video codecs used in a playback instance.
- MEDIALOG_INFO,
-
- // Misc debug info for Chromium developers.
- MEDIALOG_DEBUG,
- };
-
- // Convert various enums to strings.
- static std::string MediaLogLevelToString(MediaLogLevel level);
- static MediaLogEvent::Type MediaLogLevelToEventType(MediaLogLevel level);
- static std::string EventTypeToString(MediaLogEvent::Type type);
-
- static std::string BufferingStateToString(
- BufferingState state,
- BufferingStateChangeReason reason = BUFFERING_CHANGE_REASON_UNKNOWN);
-
- static std::string MediaEventToLogString(const MediaLogEvent& event);
-
- // Returns a string usable as part of a MediaError.message, for only
- // PIPELINE_ERROR or MEDIA_ERROR_LOG_ENTRY events, with any newlines replaced
- // with whitespace in the latter kind of events.
- static std::string MediaEventToMessageString(const MediaLogEvent& event);
+ static const char kEventKey[];
+ static const char kStatusText[];
// Constructor is protected, see below.
-
virtual ~MediaLog();
- // Add an event to this log. Inheritors should override AddEventLocked to
- // do something.
- void AddEvent(std::unique_ptr<MediaLogEvent> event);
+ // Report a log message at the specified log level.
+ void AddMessage(MediaLogMessageLevel level, std::string message);
+
+ // Typechecked property setter, since all properties must take values.
+ // For example, MediaLogProperty::kResolution supports only gfx::Size as
+ // an argument (see media_log_properties.h for this), so calling
+ // media_log->SetProperty<MediaLogProperty::kResolution>(1);
+ // would lead to a compile error, while
+ // gfx::Size rect = {100, 100};
+ // media_log->SetProperty<MediaLogProperty::kResolution>(rect);
+ // is correct.
+ template <MediaLogProperty P, typename T>
+ void SetProperty(const T& value) {
+ AddLogRecord(CreatePropertyRecord<P, T>(value));
+ }
+
+ // TODO(tmathmeyer) add the ability to report events with a separated
+ // start and end time.
+ // Send an event to the media log that may or may not have attached data.
+ // For example, MediaLogEvent::kPlay takes no arguments, while
+ // MediaLogEvent::kSeek takes a double as an argument, representing the time.
+ // A proper way to add either of these events would be
+ // media_log->AddEvent<MediaLogEvent::kPlay>();
+ // media_log->AddEvent<MediaLogEvent::kSeek>(1.99);
+ template <MediaLogEvent E, typename... T>
+ void AddEvent(const T&... value) {
+ std::unique_ptr<MediaLogRecord> record = CreateEventRecord<E, T...>();
+ MediaLogEventTypeSupport<E, T...>::AddExtraData(&record->params, value...);
+ AddLogRecord(std::move(record));
+ }
+
+ // TODO(tmathmeyer) replace with Status when that's ready.
+ void NotifyError(PipelineStatus status);
// Notify the media log that the player is destroyed. Some implementations
// will want to change event handling based on this.
@@ -91,50 +91,18 @@ class MEDIA_EXPORT MediaLog {
// Note: The base class definition only produces empty messages. See
// RenderMediaLog for where this method is meaningful.
// Inheritors should override GetErrorMessageLocked().
+ // TODO(tmathmeyer) Use a media::Status when that is ready.
std::string GetErrorMessage();
- // Helper methods to create events and their parameters.
- std::unique_ptr<MediaLogEvent> CreateEvent(MediaLogEvent::Type type);
- std::unique_ptr<MediaLogEvent> CreateBooleanEvent(MediaLogEvent::Type type,
- const std::string& property,
- bool value);
- std::unique_ptr<MediaLogEvent> CreateCreatedEvent(
- const std::string& origin_url);
- std::unique_ptr<MediaLogEvent> CreateStringEvent(MediaLogEvent::Type type,
- const std::string& property,
- const std::string& value);
- std::unique_ptr<MediaLogEvent> CreateTimeEvent(MediaLogEvent::Type type,
- const std::string& property,
- base::TimeDelta value);
- std::unique_ptr<MediaLogEvent> CreateTimeEvent(MediaLogEvent::Type type,
- const std::string& property,
- double value);
- std::unique_ptr<MediaLogEvent> CreateLoadEvent(const std::string& url);
- std::unique_ptr<MediaLogEvent> CreatePipelineStateChangedEvent(
- PipelineImpl::State state);
- std::unique_ptr<MediaLogEvent> CreatePipelineErrorEvent(PipelineStatus error);
- std::unique_ptr<MediaLogEvent> CreateVideoSizeSetEvent(size_t width,
- size_t height);
- std::unique_ptr<MediaLogEvent> CreateBufferingStateChangedEvent(
- const std::string& property,
- BufferingState state,
- BufferingStateChangeReason reason);
-
- // Report a log message at the specified log level.
- void AddLogEvent(MediaLogLevel level, const std::string& message);
-
- // Only way to access the MediaLogEvent::PROPERTY_CHANGE event type,
- // so that parameter types can be checked from media_log_properties.h.
- template <MediaLogProperty P, typename T>
- void SetProperty(const T& value) {
- AddEvent(CreatePropertyEvent<P, T>(value));
- }
-
- // Getter for |id_|. Used by MojoMediaLogService to construct MediaLogEvents
+ // Getter for |id_|. Used by MojoMediaLogService to construct MediaLogRecords
// to log into this MediaLog. Also used in trace events to associate each
// event with a specific media playback.
int32_t id() const { return id_; }
+ // Add a record to this log. Inheritors should override AddLogRecordLocked to
+ // do something. This needs to be public for MojoMediaLogService to use it.
+ void AddLogRecord(std::unique_ptr<MediaLogRecord> event);
+
// Provide a MediaLog which can have a separate lifetime from this one, but
// still write to the same log. It is not guaranteed that this will log
// forever; it might start silently discarding log messages if the original
@@ -150,21 +118,29 @@ class MEDIA_EXPORT MediaLog {
// any other thread, and with any parent log invalidation.
//
// Please see the documentation for the corresponding public methods.
- virtual void AddEventLocked(std::unique_ptr<MediaLogEvent> event);
+ virtual void AddLogRecordLocked(std::unique_ptr<MediaLogRecord> event);
virtual void OnWebMediaPlayerDestroyedLocked();
virtual std::string GetErrorMessageLocked();
// MockMediaLog also needs to call this method.
template <MediaLogProperty P, typename T>
- std::unique_ptr<MediaLogEvent> CreatePropertyEvent(const T& value) {
- auto event = CreateEvent(MediaLogEvent::PROPERTY_CHANGE);
- event->params.SetKey(MediaLogPropertyKeyToString(P),
- MediaLogPropertyTypeSupport<P, T>::Convert(value));
- return event;
+ std::unique_ptr<MediaLogRecord> CreatePropertyRecord(const T& value) {
+ auto record = CreateRecord(MediaLogRecord::Type::kMediaPropertyChange);
+ record->params.SetKey(MediaLogPropertyKeyToString(P),
+ MediaLogPropertyTypeSupport<P, T>::Convert(value));
+ return record;
+ }
+ template <MediaLogEvent E, typename... Opt>
+ std::unique_ptr<MediaLogRecord> CreateEventRecord() {
+ std::unique_ptr<MediaLogRecord> record(
+ CreateRecord(MediaLogRecord::Type::kMediaEventTriggered));
+ record->params.SetString(MediaLog::kEventKey,
+ MediaLogEventTypeSupport<E, Opt...>::TypeName());
+ return record;
}
// Notify all child logs that they should stop working. This should be called
- // to guarantee that no further calls into AddEvent should be allowed.
+ // to guarantee that no further calls into AddLogRecord should be allowed.
// Further, since calls into this log may happen on any thread, it's important
// to call this while the log is still in working order. For example, calling
// it immediately during destruction is a good idea.
@@ -195,6 +171,9 @@ class MEDIA_EXPORT MediaLog {
FRIEND_TEST_ALL_PREFIXES(MediaLogTest, EventsAreForwarded);
FRIEND_TEST_ALL_PREFIXES(MediaLogTest, EventsAreNotForwardedAfterInvalidate);
+ // Helper methods to create events and their parameters.
+ std::unique_ptr<MediaLogRecord> CreateRecord(MediaLogRecord::Type type);
+
enum : size_t {
// Max length of URLs in Created/Load events. Exceeding triggers truncation.
kMaxUrlLength = 1000,
@@ -216,15 +195,15 @@ class MEDIA_EXPORT MediaLog {
// Helper class to make it easier to use MediaLog like DVLOG().
class MEDIA_EXPORT LogHelper {
public:
- LogHelper(MediaLog::MediaLogLevel level, MediaLog* media_log);
- LogHelper(MediaLog::MediaLogLevel level,
+ LogHelper(MediaLogMessageLevel level, MediaLog* media_log);
+ LogHelper(MediaLogMessageLevel level,
const std::unique_ptr<MediaLog>& media_log);
~LogHelper();
std::ostream& stream() { return stream_; }
private:
- const MediaLog::MediaLogLevel level_;
+ const MediaLogMessageLevel level_;
MediaLog* const media_log_;
std::stringstream stream_;
};
@@ -232,7 +211,7 @@ class MEDIA_EXPORT LogHelper {
// Provides a stringstream to collect a log entry to pass to the provided
// MediaLog at the requested level.
#define MEDIA_LOG(level, media_log) \
- LogHelper((MediaLog::MEDIALOG_##level), (media_log)).stream()
+ LogHelper((MediaLogMessageLevel::k##level), (media_log)).stream()
// Logs only while |count| < |max|, increments |count| for each log, and warns
// in the log if |count| has just reached |max|.
diff --git a/chromium/media/base/media_log_event.h b/chromium/media/base/media_log_event.h
deleted file mode 100644
index 96d3e364503..00000000000
--- a/chromium/media/base/media_log_event.h
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_BASE_MEDIA_LOG_EVENT_H_
-#define MEDIA_BASE_MEDIA_LOG_EVENT_H_
-
-#include <stdint.h>
-#include <memory>
-
-#include "base/time/time.h"
-#include "base/values.h"
-
-namespace media {
-
-struct MediaLogEvent {
- MediaLogEvent() {}
-
- MediaLogEvent(const MediaLogEvent& event) { *this = event; }
-
- MediaLogEvent& operator=(const MediaLogEvent& event) {
- id = event.id;
- type = event.type;
- std::unique_ptr<base::DictionaryValue> event_copy(event.params.DeepCopy());
- params.Swap(event_copy.get());
- time = event.time;
- return *this;
- }
-
- enum Type {
- // A WebMediaPlayer is being created or destroyed.
- // params: none.
- WEBMEDIAPLAYER_CREATED,
- WEBMEDIAPLAYER_DESTROYED,
-
- // A media player is loading a resource.
- // params: "url": <URL of the resource>.
- LOAD,
-
- // A media player has started seeking.
- // params: "seek_target": <number of seconds to which to seek>.
- SEEK,
-
- // A media player has been told to play or pause.
- // params: none.
- PLAY,
- PAUSE,
-
- // The state of Pipeline has changed.
- // params: "pipeline_state": <string name of the state>.
- PIPELINE_STATE_CHANGED,
-
- // An error has occurred in the pipeline.
- // params: "pipeline_error": <integral PipelineStatus error code>.
- PIPELINE_ERROR,
-
- // The size of the video has been determined.
- // params: "width": <integral width of the video>.
- // "height": <integral height of the video>.
- VIDEO_SIZE_SET,
-
- // A property of the pipeline has been set by a filter.
- // These take a single parameter based upon the name of the event and of
- // the appropriate type. e.g. DURATION_SET: "duration" of type TimeDelta.
- DURATION_SET,
-
- // Audio/Video stream playback has ended.
- ENDED,
-
- // Text stream playback has ended.
- TEXT_ENDED,
-
- // Error log reported by media code such as reasons of playback error.
- MEDIA_ERROR_LOG_ENTRY,
- // params: "error": Error string describing the error detected.
-
- // Warning log reported by media code such as playback quality issues.
- MEDIA_WARNING_LOG_ENTRY,
- // params: "warning": String describing the warning.
-
- // Informative log reported by media code.
- MEDIA_INFO_LOG_ENTRY,
- // params: "info": String with details of an informative log entry.
-
- // Debug log reported by media code.
- MEDIA_DEBUG_LOG_ENTRY,
- // params: "debug": String with details of a debug log entry.
-
- // A property has changed without any special event occurring.
- PROPERTY_CHANGE,
-
- // A change to any demuxer or pipeline buffer state.
- BUFFERING_STATE_CHANGE,
-
- // Issued when a player is suspended.
- SUSPENDED,
-
- TYPE_LAST = SUSPENDED
- };
-
- int32_t id;
- Type type;
- base::DictionaryValue params;
- base::TimeTicks time;
-};
-
-} // namespace media
-
-#endif // MEDIA_BASE_MEDIA_LOG_EVENT_H_
diff --git a/chromium/media/base/media_log_events.cc b/chromium/media/base/media_log_events.cc
new file mode 100644
index 00000000000..187ddcc9b5e
--- /dev/null
+++ b/chromium/media/base/media_log_events.cc
@@ -0,0 +1,44 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/base/media_log_events.h"
+
+#include <string>
+
+#include "base/logging.h"
+
+namespace media {
+
+std::string MediaLogEventToString(MediaLogEvent level) {
+ switch (level) {
+ case MediaLogEvent::kPlay:
+ return "PLAY";
+ case MediaLogEvent::kPause:
+ return "PAUSE";
+ case MediaLogEvent::kSeek:
+ return "SEEK";
+ case MediaLogEvent::kPipelineStateChange:
+ return "PIPELINE_STATE_CHANGED";
+ case MediaLogEvent::kWebMediaPlayerCreated:
+ return "WEBMEDIAPLAYER_CREATED";
+ case MediaLogEvent::kWebMediaPlayerDestroyed:
+ return "WEBMEDIAPLAYER_DESTROYED";
+ case MediaLogEvent::kLoad:
+ return "LOAD";
+ case MediaLogEvent::kVideoSizeChanged:
+ return "VIDEO_SIZE_SET";
+ case MediaLogEvent::kDurationChanged:
+ return "DURATION_SET";
+ case MediaLogEvent::kEnded:
+ return "ENDED";
+ case MediaLogEvent::kBufferingStateChanged:
+ return "BUFFERING_STATE_CHANGE";
+ case MediaLogEvent::kSuspended:
+ return "SUSPENDED";
+ }
+ NOTREACHED();
+ return "";
+}
+
+} // namespace media
diff --git a/chromium/media/base/media_log_events.h b/chromium/media/base/media_log_events.h
new file mode 100644
index 00000000000..eed7a29725b
--- /dev/null
+++ b/chromium/media/base/media_log_events.h
@@ -0,0 +1,103 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_BASE_MEDIA_LOG_EVENTS_H_
+#define MEDIA_BASE_MEDIA_LOG_EVENTS_H_
+
+#include <string>
+#include "media/base/media_export.h"
+#include "media/base/media_log_type_enforcement.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace media {
+
+// Events are changes in the state of a player, or a user interaction, or any
+// other internal representation of a player at a given point in time.
+// This list contains both events that are instant, such as play/pause, as
+// well as events that span ranges of time, such as waiting for more data
+// from the network, or decoding a video frame.
+enum class MediaLogEvent {
+ // The media player has started playing.
+ kPlay,
+
+ // The media player has entered a paused state.
+ kPause,
+
+ // The media player has _started_ a seek operation.
+ kSeek,
+
+ // The pipeline state has changed - see PipelineStatus in
+ // media/base/pipeline_status.h
+ kPipelineStateChange,
+
+ // The media stack implementation of the blink media player has been created
+ // but may not be fully initialized.
+ kWebMediaPlayerCreated,
+
+ // The media player has been destroyed and the log will soon die. No events
+ // can come after receiving this one.
+ kWebMediaPlayerDestroyed,
+
+ // A web request has finished and the pipeline will start iminently.
+ kLoad,
+
+ // The video size has changed.
+ // TODO(tmathmeyer) This is already a property, it might be useless to have it
+ // be an event too. consider removing it.
+ kVideoSizeChanged,
+
+ // The runtime of the video was changed by the demuxer.
+ kDurationChanged,
+
+ // There is no more content to consume.
+ kEnded,
+
+ // There was a change to the buffering state of the video. This can be caused
+ // by either network slowness or decoding slowness. See the comments in
+ // media/base/buffering_state.h for more information.
+ kBufferingStateChanged,
+
+ // The player has been suspended to save resources.
+ kSuspended,
+};
+
+// This has to be declared before the macros use it - Some infra code relies on
+// the enum names to be UPPER_CASE, so this will convert them manually
+// instead of using macro stringification.
+MEDIA_EXPORT std::string MediaLogEventToString(MediaLogEvent level);
+
+// These events can be triggered with no extra associated data.
+MEDIA_LOG_EVENT_TYPELESS(kPlay);
+MEDIA_LOG_EVENT_TYPELESS(kPause);
+MEDIA_LOG_EVENT_TYPELESS(kWebMediaPlayerDestroyed);
+MEDIA_LOG_EVENT_TYPELESS(kEnded);
+MEDIA_LOG_EVENT_TYPELESS(kSuspended);
+MEDIA_LOG_EVENT_TYPELESS(kWebMediaPlayerCreated);
+
+// These events can be triggered with the extra data / names as defined here.
+// Note that some events can be defined multiple times.
+MEDIA_LOG_EVENT_NAMED_DATA(kLoad, std::string, "url");
+MEDIA_LOG_EVENT_NAMED_DATA(kSeek, double, "seek_target");
+MEDIA_LOG_EVENT_NAMED_DATA(kVideoSizeChanged, gfx::Size, "dimensions");
+MEDIA_LOG_EVENT_NAMED_DATA(kDurationChanged, base::TimeDelta, "duration");
+MEDIA_LOG_EVENT_NAMED_DATA(kWebMediaPlayerCreated, std::string, "origin_url");
+MEDIA_LOG_EVENT_NAMED_DATA(kPipelineStateChange, std::string, "pipeline_state");
+
+// Each type of buffering state gets a different name.
+MEDIA_LOG_EVENT_NAMED_DATA(
+ kBufferingStateChanged,
+ SerializableBufferingState<SerializableBufferingStateType::kVideo>,
+ "video_buffering_state");
+MEDIA_LOG_EVENT_NAMED_DATA(
+ kBufferingStateChanged,
+ SerializableBufferingState<SerializableBufferingStateType::kAudio>,
+ "audio_buffering_state");
+MEDIA_LOG_EVENT_NAMED_DATA(
+ kBufferingStateChanged,
+ SerializableBufferingState<SerializableBufferingStateType::kPipeline>,
+ "pipeline_buffering_state");
+
+} // namespace media
+
+#endif // MEDIA_BASE_MEDIA_LOG_EVENTS_H_
diff --git a/chromium/media/base/media_log_message_levels.cc b/chromium/media/base/media_log_message_levels.cc
new file mode 100644
index 00000000000..bea3f563008
--- /dev/null
+++ b/chromium/media/base/media_log_message_levels.cc
@@ -0,0 +1,28 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/base/media_log_message_levels.h"
+
+#include <string>
+
+#include "base/logging.h"
+
+namespace media {
+
+std::string MediaLogMessageLevelToString(MediaLogMessageLevel level) {
+ switch (level) {
+ case MediaLogMessageLevel::kERROR:
+ return "error";
+ case MediaLogMessageLevel::kWARNING:
+ return "warning";
+ case MediaLogMessageLevel::kINFO:
+ return "info";
+ case MediaLogMessageLevel::kDEBUG:
+ return "debug";
+ }
+ NOTREACHED();
+ return "";
+}
+
+} // namespace media \ No newline at end of file
diff --git a/chromium/media/base/media_log_message_levels.h b/chromium/media/base/media_log_message_levels.h
new file mode 100644
index 00000000000..d79df67db10
--- /dev/null
+++ b/chromium/media/base/media_log_message_levels.h
@@ -0,0 +1,28 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_BASE_MEDIA_LOG_MESSAGE_LEVELS_H_
+#define MEDIA_BASE_MEDIA_LOG_MESSAGE_LEVELS_H_
+
+#include <string>
+
+#include "media/base/media_export.h"
+
+namespace media {
+
+// TODO(tmathmeyer) Find a nice way to make this use the kCamelCase style, while
+// still preserving the "MEDIA_LOG(ERROR, ...)" syntax. macros are bad :(
+enum class MediaLogMessageLevel {
+ kERROR,
+ kWARNING,
+ kINFO,
+ kDEBUG,
+};
+
+MEDIA_EXPORT std::string MediaLogMessageLevelToString(
+ MediaLogMessageLevel level);
+
+} // namespace media
+
+#endif // MEDIA_BASE_MEDIA_LOG_MESSAGE_LEVELS_H_
diff --git a/chromium/media/base/media_log_properties.h b/chromium/media/base/media_log_properties.h
index 1c897915a08..f5283195094 100644
--- a/chromium/media/base/media_log_properties.h
+++ b/chromium/media/base/media_log_properties.h
@@ -6,11 +6,11 @@
#define MEDIA_BASE_MEDIA_LOG_PROPERTIES_H_
#include <string>
-#include <utility>
+#include <vector>
#include "media/base/audio_decoder_config.h"
#include "media/base/media_export.h"
-#include "media/base/media_log_properties_helper.h"
+#include "media/base/media_log_type_enforcement.h"
#include "media/base/video_decoder_config.h"
#include "ui/gfx/geometry/size.h"
diff --git a/chromium/media/base/media_log_properties_helper.h b/chromium/media/base/media_log_properties_helper.h
deleted file mode 100644
index 95ff70a82be..00000000000
--- a/chromium/media/base/media_log_properties_helper.h
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_BASE_MEDIA_LOG_PROPERTIES_HELPER_H_
-#define MEDIA_BASE_MEDIA_LOG_PROPERTIES_HELPER_H_
-
-#include <string>
-#include <vector>
-
-#include "base/strings/stringprintf.h"
-#include "base/values.h"
-#include "media/base/audio_decoder_config.h"
-#include "media/base/video_decoder_config.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace media {
-
-namespace internal {
-
-// Converter struct.
-template <typename T>
-struct MediaLogPropertyTypeConverter {};
-
-// Some types can be passed to the base::Value constructor.
-#define _VALUE_CONSTRUCTOR_TYPE(TEMPLATE_TYPE, PARAM_TYPE) \
- template <> \
- struct MediaLogPropertyTypeConverter<TEMPLATE_TYPE> { \
- static base::Value Convert(PARAM_TYPE value) { \
- return base::Value(value); \
- } \
- }
-
-_VALUE_CONSTRUCTOR_TYPE(std::string, const std::string&);
-_VALUE_CONSTRUCTOR_TYPE(bool, bool);
-_VALUE_CONSTRUCTOR_TYPE(int, int);
-#undef _VALUE_CONSTRUCTOR_TYPE
-
-// Can't send non-finite double values to a base::Value.
-template <>
-struct MediaLogPropertyTypeConverter<double> {
- static base::Value Convert(double value) {
- return std::isfinite(value) ? base::Value(value) : base::Value("unknown");
- }
-};
-
-// Just upcast this to get the NaN check.
-template <>
-struct MediaLogPropertyTypeConverter<float> {
- static base::Value Convert(float value) {
- return MediaLogPropertyTypeConverter<double>::Convert(value);
- }
-};
-
-/* Support serializing for a selection of types */
-// support 64 bit ints, this is a weird workaround for the base::Value
-// int type only being 32 bit, as specified in the base/values.h header comment.
-template <>
-struct MediaLogPropertyTypeConverter<int64_t> {
- static base::Value Convert(int64_t value) {
- return base::Value(static_cast<double>(value));
- }
-};
-
-// Support gfx::Size -> "{x}x{y}"
-template <>
-struct MediaLogPropertyTypeConverter<gfx::Size> {
- static base::Value Convert(const gfx::Size& value) {
- return base::Value(value.ToString());
- }
-};
-
-// Support vectors of anything else thiat can be serialized
-template <typename T>
-struct MediaLogPropertyTypeConverter<std::vector<T>> {
- static base::Value Convert(const std::vector<T>& value) {
- base::Value result(base::Value::Type::LIST);
- for (const auto& entry : value)
- result.Append(MediaLogPropertyTypeConverter<T>::Convert(entry));
- return result;
- }
-};
-
-// Specializer for sending AudioDecoderConfigs to the media tab in devtools.
-template <>
-struct internal::MediaLogPropertyTypeConverter<media::AudioDecoderConfig> {
- static base::Value Convert(const AudioDecoderConfig& value) {
- base::Value result(base::Value::Type::DICTIONARY);
- result.SetStringKey("codec", GetCodecName(value.codec()));
- result.SetIntKey("bytes per channel", value.bytes_per_channel());
- result.SetStringKey("channel layout",
- ChannelLayoutToString(value.channel_layout()));
- result.SetIntKey("channels", value.channels());
- result.SetIntKey("samples per second", value.samples_per_second());
- result.SetStringKey("sample format",
- SampleFormatToString(value.sample_format()));
- result.SetIntKey("bytes per frame", value.bytes_per_frame());
- // TODO(tmathmeyer) drop the units, let the frontend handle it.
- // use ostringstreams because windows & linux have _different types_
- // defined for int64_t, (long vs long long) so format specifiers dont work.
- std::ostringstream preroll;
- preroll << value.seek_preroll().InMicroseconds() << "us";
- result.SetStringKey("seek preroll", preroll.str());
- result.SetIntKey("codec delay", value.codec_delay());
- result.SetBoolKey("has extra data", !value.extra_data().empty());
- std::ostringstream encryptionSchemeString;
- encryptionSchemeString << value.encryption_scheme();
- result.SetStringKey("encryption scheme", encryptionSchemeString.str());
- result.SetBoolKey("discard decoder delay",
- value.should_discard_decoder_delay());
- return result;
- }
-};
-
-// Specializer for sending VideoDecoderConfigs to the media tab in devtools.
-template <>
-struct internal::MediaLogPropertyTypeConverter<VideoDecoderConfig> {
- static base::Value Convert(const VideoDecoderConfig& value) {
- base::Value result(base::Value::Type::DICTIONARY);
- result.SetStringKey("codec", GetCodecName(value.codec()));
- result.SetStringKey("profile", GetProfileName(value.profile()));
- result.SetStringKey(
- "alpha mode",
- (value.alpha_mode() == VideoDecoderConfig::AlphaMode::kHasAlpha
- ? "has_alpha"
- : "is_opaque"));
- result.SetStringKey("coded size", value.coded_size().ToString());
- result.SetStringKey("visible rect", value.visible_rect().ToString());
- result.SetStringKey("natural size", value.natural_size().ToString());
- result.SetBoolKey("has_extra_data", !value.extra_data().empty());
- std::ostringstream encryptionSchemeString;
- encryptionSchemeString << value.encryption_scheme();
- result.SetStringKey("encryption scheme", encryptionSchemeString.str());
- result.SetStringKey("rotation", VideoRotationToString(
- value.video_transformation().rotation));
- result.SetBoolKey("flipped", value.video_transformation().mirrored);
- result.SetStringKey("color space",
- value.color_space_info().ToGfxColorSpace().ToString());
-
- if (value.hdr_metadata().has_value()) {
- result.SetKey(
- "luminance range",
- MediaLogPropertyTypeConverter<float>::Convert(
- value.hdr_metadata()->mastering_metadata.luminance_min));
- result.SetStringKey(
- "primaries",
- base::StringPrintf(
- "[r:%.4f,%.4f, g:%.4f,%.4f, b:%.4f,%.4f, wp:%.4f,%.4f]",
- value.hdr_metadata()->mastering_metadata.primary_r.x(),
- value.hdr_metadata()->mastering_metadata.primary_r.y(),
- value.hdr_metadata()->mastering_metadata.primary_g.x(),
- value.hdr_metadata()->mastering_metadata.primary_g.y(),
- value.hdr_metadata()->mastering_metadata.primary_b.x(),
- value.hdr_metadata()->mastering_metadata.primary_b.y(),
- value.hdr_metadata()->mastering_metadata.white_point.x(),
- value.hdr_metadata()->mastering_metadata.white_point.y()));
- }
- return result;
- }
-};
-
-} // namespace internal
-
-// Forward declare the enum.
-enum class MediaLogProperty;
-
-// Allow only specific types for an individual property.
-template <MediaLogProperty PROP, typename T>
-struct MediaLogPropertyTypeSupport {};
-
-// Lets us define the supported type in a single line in media_log_properties.h.
-#define MEDIA_LOG_PROPERTY_SUPPORTS_TYPE(PROPERTY, TYPE) \
- template <> \
- struct MediaLogPropertyTypeSupport<MediaLogProperty::PROPERTY, TYPE> { \
- static base::Value Convert(const TYPE& type) { \
- return internal::MediaLogPropertyTypeConverter<TYPE>::Convert(type); \
- } \
- }
-
-} // namespace media
-
-#endif // MEDIA_BASE_MEDIA_LOG_PROPERTIES_HELPER_H_
diff --git a/chromium/media/base/media_log_record.h b/chromium/media/base/media_log_record.h
new file mode 100644
index 00000000000..76822114c9e
--- /dev/null
+++ b/chromium/media/base/media_log_record.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_BASE_MEDIA_LOG_RECORD_H_
+#define MEDIA_BASE_MEDIA_LOG_RECORD_H_
+
+#include <stdint.h>
+#include <memory>
+
+#include "base/time/time.h"
+#include "base/values.h"
+
+namespace media {
+
+struct MediaLogRecord {
+ MediaLogRecord() {}
+
+ MediaLogRecord(const MediaLogRecord& event) { *this = event; }
+
+ MediaLogRecord& operator=(const MediaLogRecord& event) {
+ id = event.id;
+ type = event.type;
+ std::unique_ptr<base::DictionaryValue> event_copy(event.params.DeepCopy());
+ params.Swap(event_copy.get());
+ time = event.time;
+ return *this;
+ }
+
+ enum class Type {
+ // See media/base/media_log_message_levels.h for info.
+ kMessage,
+
+ // See media/base/media_log_properties.h for info.
+ kMediaPropertyChange,
+
+ // See media/base/media_log_events.h for info.
+ kMediaEventTriggered,
+
+ // TODO(tmathmeyer) use media::Status eventually instead of PipelineStatus
+ kMediaStatus,
+
+ kMaxValue = kMediaStatus,
+ };
+
+ int32_t id;
+ Type type;
+ base::DictionaryValue params;
+ base::TimeTicks time;
+};
+
+} // namespace media
+
+#endif // MEDIA_BASE_MEDIA_LOG_RECORD_H_
diff --git a/chromium/media/base/media_log_type_enforcement.h b/chromium/media/base/media_log_type_enforcement.h
new file mode 100644
index 00000000000..8404e00a23f
--- /dev/null
+++ b/chromium/media/base/media_log_type_enforcement.h
@@ -0,0 +1,59 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_BASE_MEDIA_LOG_TYPE_ENFORCEMENT_H_
+#define MEDIA_BASE_MEDIA_LOG_TYPE_ENFORCEMENT_H_
+
+#include "media/base/media_serializers.h"
+
+namespace media {
+
+namespace internal {
+enum class UnmatchableType {};
+} // namespace internal
+
+// Forward declare the enums.
+enum class MediaLogProperty;
+enum class MediaLogEvent;
+
+// Allow only specific types for an individual property.
+template <MediaLogProperty PROP, typename T>
+struct MediaLogPropertyTypeSupport {};
+
+// Allow only specific types for an individual event.
+// However unlike Property, T is not required, so we default it to some
+// unmatchable type that will never be passed as an argument accidentally.
+template <MediaLogEvent EVENT, typename T = internal::UnmatchableType>
+struct MediaLogEventTypeSupport {};
+
+// Lets us define the supported type in a single line in media_log_properties.h.
+#define MEDIA_LOG_PROPERTY_SUPPORTS_TYPE(PROPERTY, TYPE) \
+ template <> \
+ struct MediaLogPropertyTypeSupport<MediaLogProperty::PROPERTY, TYPE> { \
+ static base::Value Convert(const TYPE& type) { \
+ return MediaSerialize<TYPE>(type); \
+ } \
+ }
+
+#define MEDIA_LOG_EVENT_NAMED_DATA(EVENT, TYPE, DISPLAY) \
+ template <> \
+ struct MediaLogEventTypeSupport<MediaLogEvent::EVENT, TYPE> { \
+ static void AddExtraData(base::Value* params, const TYPE& t) { \
+ DCHECK(params); \
+ params->SetKey(DISPLAY, MediaSerialize<TYPE>(t)); \
+ } \
+ static std::string TypeName() { return #EVENT; } \
+ }
+
+// Specifically do not create the Convert or DisplayName methods
+#define MEDIA_LOG_EVENT_TYPELESS(EVENT) \
+ template <> \
+ struct MediaLogEventTypeSupport<MediaLogEvent::EVENT> { \
+ static std::string TypeName() { return #EVENT; } \
+ static void AddExtraData(base::Value* params) {} \
+ }
+
+} // namespace media
+
+#endif // MEDIA_BASE_MEDIA_LOG_TYPE_ENFORCEMENT_H_
diff --git a/chromium/media/base/media_log_unittest.cc b/chromium/media/base/media_log_unittest.cc
index 741806b8c55..09a5126bca3 100644
--- a/chromium/media/base/media_log_unittest.cc
+++ b/chromium/media/base/media_log_unittest.cc
@@ -25,69 +25,13 @@ class MediaLogTest : public testing::Test {
constexpr size_t MediaLogTest::kMaxUrlLength;
-TEST_F(MediaLogTest, DontTruncateShortUrlString) {
- const std::string short_url("chromium.org");
- EXPECT_LT(short_url.length(), MediaLogTest::kMaxUrlLength);
-
- // Verify that CreatedEvent does not truncate the short URL.
- std::unique_ptr<MediaLogEvent> created_event =
- media_log.CreateCreatedEvent(short_url);
- std::string stored_url;
- created_event->params.GetString("origin_url", &stored_url);
- EXPECT_EQ(stored_url, short_url);
-
- // Verify that LoadEvent does not truncate the short URL.
- std::unique_ptr<MediaLogEvent> load_event =
- media_log.CreateLoadEvent(short_url);
- load_event->params.GetString("url", &stored_url);
- EXPECT_EQ(stored_url, short_url);
-}
-
-TEST_F(MediaLogTest, TruncateLongUrlStrings) {
- // Build a long string that exceeds the URL length limit.
- std::stringstream string_builder;
- constexpr size_t kLongStringLength = MediaLogTest::kMaxUrlLength + 10;
- for (size_t i = 0; i < kLongStringLength; i++) {
- string_builder << "c";
- }
- const std::string long_url = string_builder.str();
- EXPECT_GT(long_url.length(), MediaLogTest::kMaxUrlLength);
-
- // Verify that long CreatedEvent URL...
- std::unique_ptr<MediaLogEvent> created_event =
- media_log.CreateCreatedEvent(long_url);
- std::string stored_url;
- created_event->params.GetString("origin_url", &stored_url);
-
- // ... is truncated
- EXPECT_EQ(stored_url.length(), MediaLogTest::kMaxUrlLength);
- // ... ends with ellipsis
- EXPECT_EQ(stored_url.compare(MediaLogTest::kMaxUrlLength - 3, 3, "..."), 0);
- // ... is otherwise a substring of the longer URL
- EXPECT_EQ(stored_url.compare(0, MediaLogTest::kMaxUrlLength - 3, long_url, 0,
- MediaLogTest::kMaxUrlLength - 3),
- 0);
-
- // Verify that long LoadEvent URL...
- std::unique_ptr<MediaLogEvent> load_event =
- media_log.CreateCreatedEvent(long_url);
- load_event->params.GetString("url", &stored_url);
- // ... is truncated
- EXPECT_EQ(stored_url.length(), MediaLogTest::kMaxUrlLength);
- // ... ends with ellipsis
- EXPECT_EQ(stored_url.compare(MediaLogTest::kMaxUrlLength - 3, 3, "..."), 0);
- // ... is otherwise a substring of the longer URL
- EXPECT_EQ(stored_url.compare(0, MediaLogTest::kMaxUrlLength - 3, long_url, 0,
- MediaLogTest::kMaxUrlLength - 3),
- 0);
-}
TEST_F(MediaLogTest, EventsAreForwarded) {
// Make sure that |root_log_| receives events.
std::unique_ptr<MockMediaLog> root_log(std::make_unique<MockMediaLog>());
std::unique_ptr<MediaLog> child_media_log(root_log->Clone());
- EXPECT_CALL(*root_log, DoAddEventLogString(_)).Times(1);
- child_media_log->AddLogEvent(MediaLog::MediaLogLevel::MEDIALOG_ERROR, "test");
+ EXPECT_CALL(*root_log, DoAddLogRecordLogString(_)).Times(1);
+ child_media_log->AddMessage(MediaLogMessageLevel::kERROR, "test");
}
TEST_F(MediaLogTest, EventsAreNotForwardedAfterInvalidate) {
@@ -95,9 +39,9 @@ TEST_F(MediaLogTest, EventsAreNotForwardedAfterInvalidate) {
// underlying log.
std::unique_ptr<MockMediaLog> root_log(std::make_unique<MockMediaLog>());
std::unique_ptr<MediaLog> child_media_log(root_log->Clone());
- EXPECT_CALL(*root_log, DoAddEventLogString(_)).Times(0);
+ EXPECT_CALL(*root_log, DoAddLogRecordLogString(_)).Times(0);
root_log.reset();
- child_media_log->AddLogEvent(MediaLog::MediaLogLevel::MEDIALOG_ERROR, "test");
+ child_media_log->AddMessage(MediaLogMessageLevel::kERROR, "test");
}
} // namespace media
diff --git a/chromium/media/base/media_observer.h b/chromium/media/base/media_observer.h
index 1bb629930e5..225cc8d7985 100644
--- a/chromium/media/base/media_observer.h
+++ b/chromium/media/base/media_observer.h
@@ -34,9 +34,6 @@ class MEDIA_EXPORT MediaObserverClient {
// may be displayed to explain why the switch occurred.
virtual void SwitchToLocalRenderer(ReasonToSwitchToLocal reason) = 0;
- // Requests to activate monitoring changes on viewport intersection.
- virtual void ActivateViewportIntersectionMonitoring(bool activate) = 0;
-
// Reports the latest compatibility state of the element's source for remote
// playback.
virtual void UpdateRemotePlaybackCompatibility(bool is_compatible) = 0;
diff --git a/chromium/media/base/media_serializers.h b/chromium/media/base/media_serializers.h
new file mode 100644
index 00000000000..6333c44170f
--- /dev/null
+++ b/chromium/media/base/media_serializers.h
@@ -0,0 +1,392 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_BASE_MEDIA_SERIALIZERS_H_
+#define MEDIA_BASE_MEDIA_SERIALIZERS_H_
+
+#include <vector>
+
+#include "base/location.h"
+#include "base/strings/stringprintf.h"
+#include "media/base/audio_decoder_config.h"
+#include "media/base/buffering_state.h"
+#include "media/base/media_serializers_base.h"
+#include "media/base/status.h"
+#include "media/base/status_codes.h"
+#include "media/base/video_decoder_config.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace media {
+
+namespace internal {
+
+// Serializing any const or reference combination.
+template <typename T>
+struct MediaSerializer<const T> {
+ static base::Value Serialize(const T& value) {
+ return MediaSerializer<T>::Serialize(value);
+ }
+};
+
+template <typename T>
+struct MediaSerializer<T&> {
+ static base::Value Serialize(const T& value) {
+ return MediaSerializer<T>::Serialize(value);
+ }
+};
+
+// Serialize default value.
+template <>
+struct MediaSerializer<base::Value> {
+ static base::Value Serialize(const base::Value& value) {
+ return value.Clone();
+ }
+};
+
+// Serialize vectors of things
+template <typename VecType>
+struct MediaSerializer<std::vector<VecType>> {
+ static base::Value Serialize(const std::vector<VecType>& vec) {
+ base::Value result(base::Value::Type::LIST);
+ for (const VecType& value : vec)
+ result.Append(MediaSerializer<VecType>::Serialize(value));
+ return result;
+ }
+};
+
+// serialize optional types
+template <typename OptType>
+struct MediaSerializer<base::Optional<OptType>> {
+ static base::Value Serialize(const base::Optional<OptType>& opt) {
+ return opt ? MediaSerializer<OptType>::Serialize(opt.value())
+ : base::Value("unset"); // TODO(tmathmeyer) maybe empty string?
+ }
+};
+
+// Sometimes raw strings wont template match to a char*.
+template <int len>
+struct MediaSerializer<char[len]> {
+ static inline base::Value Serialize(const char* code) {
+ return base::Value(code);
+ }
+};
+
+// Can't send non-finite double values to a base::Value.
+template <>
+struct MediaSerializer<double> {
+ static inline base::Value Serialize(double value) {
+ return std::isfinite(value) ? base::Value(value) : base::Value("unknown");
+ }
+};
+
+template <>
+struct MediaSerializer<int64_t> {
+ static inline base::Value Serialize(int64_t value) {
+ return MediaSerializer<double>::Serialize(static_cast<double>(value));
+ }
+};
+
+// Just upcast this to get the NaN check.
+template <>
+struct MediaSerializer<float> {
+ static inline base::Value Serialize(float value) {
+ return MediaSerializer<double>::Serialize(value);
+ }
+};
+
+// Serialization for chromium-specific types.
+// Each serializer should be commented like:
+// Class/Enum (simple/complex)
+// where Classes should take constref arguments, and "simple" methods should
+// be declared inline.
+
+// the FIELD_SERIALIZE method can be used whenever the result is a dict named
+// |result|.
+#define FIELD_SERIALIZE(NAME, CONSTEXPR) \
+ result.SetKey(NAME, MediaSerialize(CONSTEXPR))
+
+// Class (simple)
+template <>
+struct MediaSerializer<gfx::Size> {
+ static inline base::Value Serialize(const gfx::Size& value) {
+ return base::Value(value.ToString());
+ }
+};
+
+// Class (simple)
+template <>
+struct MediaSerializer<gfx::Rect> {
+ static inline base::Value Serialize(const gfx::Rect& value) {
+ return base::Value(value.ToString());
+ }
+};
+
+// enum (simple)
+template <>
+struct MediaSerializer<base::TimeDelta> {
+ static inline base::Value Serialize(const base::TimeDelta value) {
+ return MediaSerializer<double>::Serialize(value.InSecondsF());
+ }
+};
+
+// Enum (simple)
+template <>
+struct MediaSerializer<media::AudioCodec> {
+ static inline base::Value Serialize(media::AudioCodec value) {
+ return base::Value(GetCodecName(value));
+ }
+};
+
+// Enum (simple)
+template <>
+struct MediaSerializer<media::AudioCodecProfile> {
+ static inline base::Value Serialize(media::AudioCodecProfile value) {
+ return base::Value(GetProfileName(value));
+ }
+};
+
+// Enum (simple)
+template <>
+struct MediaSerializer<media::VideoCodec> {
+ static inline base::Value Serialize(media::VideoCodec value) {
+ return base::Value(GetCodecName(value));
+ }
+};
+
+// Enum (simple)
+template <>
+struct MediaSerializer<media::VideoCodecProfile> {
+ static inline base::Value Serialize(media::VideoCodecProfile value) {
+ return base::Value(GetProfileName(value));
+ }
+};
+
+// Enum (simple)
+template <>
+struct MediaSerializer<media::ChannelLayout> {
+ static inline base::Value Serialize(media::ChannelLayout value) {
+ return base::Value(ChannelLayoutToString(value));
+ }
+};
+
+// Enum (simple)
+template <>
+struct MediaSerializer<media::SampleFormat> {
+ static inline base::Value Serialize(media::SampleFormat value) {
+ return base::Value(SampleFormatToString(value));
+ }
+};
+
+// Enum (complex)
+template <>
+struct MediaSerializer<media::EncryptionScheme> {
+ static base::Value Serialize(const media::EncryptionScheme& value) {
+ std::ostringstream encryptionSchemeString;
+ encryptionSchemeString << value;
+ return base::Value(encryptionSchemeString.str());
+ }
+};
+
+// Class (complex)
+template <>
+struct MediaSerializer<media::VideoTransformation> {
+ static base::Value Serialize(const media::VideoTransformation& value) {
+ std::string rotation = VideoRotationToString(value.rotation);
+ if (value.mirrored)
+ rotation += ", mirrored";
+ return base::Value(rotation);
+ }
+};
+
+// Class (simple)
+template <>
+struct MediaSerializer<media::VideoColorSpace> {
+ static inline base::Value Serialize(const media::VideoColorSpace& value) {
+ return base::Value(value.ToGfxColorSpace().ToString());
+ }
+};
+
+// Class (complex)
+template <>
+struct MediaSerializer<media::HDRMetadata> {
+ static base::Value Serialize(const media::HDRMetadata& value) {
+ // TODO(tmathmeyer) serialize more fields here potentially.
+ base::Value result(base::Value::Type::DICTIONARY);
+ FIELD_SERIALIZE("luminance range",
+ base::StringPrintf("%.2f => %.2f",
+ value.mastering_metadata.luminance_min,
+ value.mastering_metadata.luminance_max));
+ FIELD_SERIALIZE("primaries",
+ base::StringPrintf(
+ "[r:%.4f,%.4f, g:%.4f,%.4f, b:%.4f,%.4f, wp:%.4f,%.4f]",
+ value.mastering_metadata.primary_r.x(),
+ value.mastering_metadata.primary_r.y(),
+ value.mastering_metadata.primary_g.x(),
+ value.mastering_metadata.primary_g.y(),
+ value.mastering_metadata.primary_b.x(),
+ value.mastering_metadata.primary_b.y(),
+ value.mastering_metadata.white_point.x(),
+ value.mastering_metadata.white_point.y()));
+ return result;
+ }
+};
+
+// Class (complex)
+template <>
+struct MediaSerializer<media::AudioDecoderConfig> {
+ static base::Value Serialize(const media::AudioDecoderConfig& value) {
+ base::Value result(base::Value::Type::DICTIONARY);
+ FIELD_SERIALIZE("codec", value.codec());
+ FIELD_SERIALIZE("profile", value.profile());
+ FIELD_SERIALIZE("bytes per channel", value.bytes_per_channel());
+ FIELD_SERIALIZE("channel layout", value.channel_layout());
+ FIELD_SERIALIZE("channels", value.channels());
+ FIELD_SERIALIZE("samples per second", value.samples_per_second());
+ FIELD_SERIALIZE("sample format", value.sample_format());
+ FIELD_SERIALIZE("bytes per frame", value.bytes_per_frame());
+ FIELD_SERIALIZE("codec delay", value.codec_delay());
+ FIELD_SERIALIZE("has extra data", !value.extra_data().empty());
+ FIELD_SERIALIZE("encryption scheme", value.encryption_scheme());
+ FIELD_SERIALIZE("discard decoder delay",
+ value.should_discard_decoder_delay());
+
+ // TODO(tmathmeyer) drop the units, let the frontend handle it.
+ // use ostringstreams because windows & linux have _different types_
+ // defined for int64_t, (long vs long long) so format specifiers dont work.
+ std::ostringstream preroll;
+ preroll << value.seek_preroll().InMicroseconds() << "us";
+ result.SetStringKey("seek preroll", preroll.str());
+
+ return result;
+ }
+};
+
+// Enum (simple)
+template <>
+struct MediaSerializer<media::VideoDecoderConfig::AlphaMode> {
+ static inline base::Value Serialize(
+ media::VideoDecoderConfig::AlphaMode value) {
+ return base::Value(value == VideoDecoderConfig::AlphaMode::kHasAlpha
+ ? "has_alpha"
+ : "is_opaque");
+ }
+};
+
+// Class (complex)
+template <>
+struct MediaSerializer<media::VideoDecoderConfig> {
+ static base::Value Serialize(const media::VideoDecoderConfig& value) {
+ base::Value result(base::Value::Type::DICTIONARY);
+ FIELD_SERIALIZE("codec", value.codec());
+ FIELD_SERIALIZE("profile", value.profile());
+ FIELD_SERIALIZE("alpha mode", value.alpha_mode());
+ FIELD_SERIALIZE("coded size", value.coded_size());
+ FIELD_SERIALIZE("visible rect", value.visible_rect());
+ FIELD_SERIALIZE("natural size", value.natural_size());
+ FIELD_SERIALIZE("has extra data", !value.extra_data().empty());
+ FIELD_SERIALIZE("encryption scheme", value.encryption_scheme());
+ FIELD_SERIALIZE("orientation", value.video_transformation());
+ FIELD_SERIALIZE("color space", value.color_space_info());
+ FIELD_SERIALIZE("hdr metadata", value.hdr_metadata());
+ return result;
+ }
+};
+
+// enum (simple)
+template <>
+struct MediaSerializer<media::BufferingState> {
+ static inline base::Value Serialize(const media::BufferingState value) {
+ return base::Value(value == media::BufferingState::BUFFERING_HAVE_ENOUGH
+ ? "BUFFERING_HAVE_ENOUGH"
+ : "BUFFERING_HAVE_NOTHING");
+ }
+};
+
+// enum (complex)
+template <>
+struct MediaSerializer<media::BufferingStateChangeReason> {
+ static base::Value Serialize(const media::BufferingStateChangeReason value) {
+ switch (value) {
+ case DEMUXER_UNDERFLOW:
+ return base::Value("DEMUXER_UNDERFLOW");
+ case DECODER_UNDERFLOW:
+ return base::Value("DECODER_UNDERFLOW");
+ case REMOTING_NETWORK_CONGESTION:
+ return base::Value("REMOTING_NETWORK_CONGESTION");
+ case BUFFERING_CHANGE_REASON_UNKNOWN:
+ return base::Value("BUFFERING_CHANGE_REASON_UNKNOWN");
+ }
+ }
+};
+
+// Class (complex)
+template <media::SerializableBufferingStateType T>
+struct MediaSerializer<media::SerializableBufferingState<T>> {
+ static base::Value Serialize(
+ const media::SerializableBufferingState<T>& value) {
+ base::Value result(base::Value::Type::DICTIONARY);
+ FIELD_SERIALIZE("state", value.state);
+
+ switch (value.reason) {
+ case DEMUXER_UNDERFLOW:
+ case DECODER_UNDERFLOW:
+ case REMOTING_NETWORK_CONGESTION:
+ FIELD_SERIALIZE("reason", value.reason);
+ break;
+
+ // Don't write anything here if the reason is unknown.
+ case BUFFERING_CHANGE_REASON_UNKNOWN:
+ break;
+ }
+
+ if (T == SerializableBufferingStateType::kPipeline)
+ result.SetBoolKey("for_suspended_start", value.suspended_start);
+
+ return result;
+ }
+};
+
+// enum (simple)
+template <>
+struct MediaSerializer<media::StatusCode> {
+ static inline base::Value Serialize(media::StatusCode code) {
+ return base::Value(static_cast<int>(code));
+ }
+};
+
+// Class (complex)
+template <>
+struct MediaSerializer<media::Status> {
+ static base::Value Serialize(const media::Status& status) {
+ if (status.is_ok())
+ return base::Value("Ok");
+
+ base::Value result(base::Value::Type::DICTIONARY);
+ FIELD_SERIALIZE("status_code", status.code());
+ FIELD_SERIALIZE("status_message", status.message());
+ FIELD_SERIALIZE("stack", status.data_->frames);
+ FIELD_SERIALIZE("data", status.data_->data);
+ FIELD_SERIALIZE("causes", status.data_->causes);
+ return result;
+ }
+};
+
+// Class (complex)
+template <>
+struct MediaSerializer<base::Location> {
+ static base::Value Serialize(const base::Location& value) {
+ base::Value result(base::Value::Type::DICTIONARY);
+ FIELD_SERIALIZE("file", value.file_name());
+ FIELD_SERIALIZE("line", value.line_number());
+ return result;
+ }
+};
+
+#undef FIELD_SERIALIZE
+
+} // namespace internal
+
+} // namespace media
+
+#endif // MEDIA_BASE_MEDIA_SERIALIZERS_H_
diff --git a/chromium/media/base/media_serializers_base.h b/chromium/media/base/media_serializers_base.h
new file mode 100644
index 00000000000..8e1359b9841
--- /dev/null
+++ b/chromium/media/base/media_serializers_base.h
@@ -0,0 +1,34 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_BASE_MEDIA_SERIALIZERS_BASE_H_
+#define MEDIA_BASE_MEDIA_SERIALIZERS_BASE_H_
+
+#include <vector>
+
+#include "base/values.h"
+#include "media/base/media_export.h"
+
+namespace media {
+
+namespace internal {
+
+// Serializer specializer struct.
+// All the types that base::Value's constructor can take should be passed
+// by non-const values. (int, bool, std::string, char*, etc).
+template <typename T>
+struct MediaSerializer {
+ static inline base::Value Serialize(T value) { return base::Value(value); }
+};
+
+} // namespace internal
+
+template <typename T>
+base::Value MediaSerialize(const T& t) {
+ return internal::MediaSerializer<T>::Serialize(t);
+}
+
+} // namespace media
+
+#endif // MEDIA_BASE_MEDIA_SERIALIZERS_BASE_H_
diff --git a/chromium/media/base/media_serializers_unittest.cc b/chromium/media/base/media_serializers_unittest.cc
new file mode 100644
index 00000000000..e3f3a7bfc5c
--- /dev/null
+++ b/chromium/media/base/media_serializers_unittest.cc
@@ -0,0 +1,59 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/base/media_serializers.h"
+
+#include <memory>
+
+#include "base/json/json_writer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+std::string ToString(const base::Value& value) {
+ if (value.is_string()) {
+ return value.GetString();
+ }
+ std::string output_str;
+ base::JSONWriter::Write(value, &output_str);
+ return output_str;
+}
+
+TEST(MediaSerializersTest, BaseTypes) {
+ int a = 1;
+ int64_t b = 2;
+ bool c = false;
+ double d = 100;
+ float e = 4523;
+ std::string f = "foo";
+ const char* g = "bar";
+
+ ASSERT_EQ(ToString(MediaSerialize(a)), "1");
+ ASSERT_EQ(ToString(MediaSerialize(b)), "2.0");
+ ASSERT_EQ(ToString(MediaSerialize(c)), "false");
+ ASSERT_EQ(ToString(MediaSerialize(d)), "100.0");
+ ASSERT_EQ(ToString(MediaSerialize(e)), "4523.0");
+ ASSERT_EQ(ToString(MediaSerialize(f)), "foo");
+ ASSERT_EQ(ToString(MediaSerialize(g)), "bar");
+
+ ASSERT_EQ(ToString(MediaSerialize("raw string")), "raw string");
+}
+
+TEST(MediaSerializersTest, Optional) {
+ base::Optional<int> foo;
+ ASSERT_EQ(ToString(MediaSerialize(foo)), "unset");
+
+ foo = 1;
+ ASSERT_EQ(ToString(MediaSerialize(foo)), "1");
+}
+
+TEST(MediaSerializersTest, Vector) {
+ std::vector<int> foo = {1, 2, 3, 6, 78, 8};
+ ASSERT_EQ(ToString(MediaSerialize(foo)), "[1,2,3,6,78,8]");
+
+ std::vector<std::string> bar = {"1", "3"};
+ ASSERT_EQ(ToString(MediaSerialize(bar)), "[\"1\",\"3\"]");
+}
+
+} // namespace media
diff --git a/chromium/media/base/media_switches.cc b/chromium/media/base/media_switches.cc
index 5f33919f151..636dec1c063 100644
--- a/chromium/media/base/media_switches.cc
+++ b/chromium/media/base/media_switches.cc
@@ -98,6 +98,8 @@ const char kUnsafelyAllowProtectedMediaIdentifierForDomain[] =
"unsafely-allow-protected-media-identifier-for-domain";
// Use fake device for Media Stream to replace actual camera and microphone.
+// For the list of allowed parameters, see
+// FakeVideoCaptureDeviceFactory::ParseFakeDevicesConfigFromOptionsString().
const char kUseFakeDeviceForMediaStream[] = "use-fake-device-for-media-stream";
// Use an .y4m file to play as the webcam. See the comments in
@@ -182,9 +184,11 @@ const char kOverrideEnabledCdmInterfaceVersion[] =
const char kOverrideHardwareSecureCodecsForTesting[] =
"override-hardware-secure-codecs-for-testing";
-// Enables GpuMemoryBuffer-based buffer pool.
-const char kVideoCaptureUseGpuMemoryBuffer[] =
- "video-capture-use-gpu-memory-buffer";
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
+// Force to disable kChromeosVideoDecoder feature, used for unsupported boards.
+const char kForceDisableNewAcceleratedVideoDecoder[] =
+ "force-disable-new-accelerated-video-decoder";
+#endif // BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
namespace autoplay {
@@ -255,6 +259,11 @@ const base::Feature kUseAndroidOverlayAggressively{
const base::Feature kBackgroundVideoPauseOptimization{
"BackgroundVideoPauseOptimization", base::FEATURE_ENABLED_BY_DEFAULT};
+// CDM host verification is enabled by default. Can be disabled for testing.
+// Has no effect if ENABLE_CDM_HOST_VERIFICATION buildflag is false.
+const base::Feature kCdmHostVerification{"CdmHostVerification",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
// Make MSE garbage collection algorithm more aggressive when we are under
// moderate or critical memory pressure. This will relieve memory pressure by
// releasing stale data from MSE buffers.
@@ -284,10 +293,6 @@ const base::Feature kRevokeMediaSourceObjectURLOnAttach{
const base::Feature kChromeosVideoDecoder{"ChromeosVideoDecoder",
base::FEATURE_DISABLED_BY_DEFAULT};
-// Don't allow use of 11.1 devices, even if supported. They might be more crashy
-const base::Feature kD3D11LimitTo11_0{"D3D11VideoDecoderLimitTo11_0",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
// Enable saving playback information in a crash trace, to see if some codecs
// are crashier than others.
const base::Feature kD3D11PrintCodecOnCrash{"D3D11PrintCodecOnCrash",
@@ -333,9 +338,24 @@ const base::Feature kD3D11VideoDecoderAllowOverlay{
const base::Feature kFallbackAfterDecodeError{"FallbackAfterDecodeError",
base::FEATURE_ENABLED_BY_DEFAULT};
+// Use Gav1VideoDecoder to decode AV1 streams.
+const base::Feature kGav1VideoDecoder{"Gav1VideoDecoder",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Show toolbar button that opens dialog for controlling media sessions.
-const base::Feature kGlobalMediaControls{"GlobalMediaControls",
- base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kGlobalMediaControls {
+ "GlobalMediaControls",
+#if defined(OS_WIN) || defined(OS_MACOSX) || \
+ (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+ base::FEATURE_ENABLED_BY_DEFAULT
+#else
+ base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+};
+
+// Auto-dismiss global media controls.
+const base::Feature kGlobalMediaControlsAutoDismiss{
+ "GlobalMediaControlsAutoDismiss", base::FEATURE_ENABLED_BY_DEFAULT};
// Show Cast sessions in Global Media Controls. It is no-op if
// kGlobalMediaControls is not enabled.
@@ -347,6 +367,10 @@ const base::Feature kGlobalMediaControlsForCast{
const base::Feature kGlobalMediaControlsOverlayControls{
"GlobalMediaControlsOverlayControls", base::FEATURE_DISABLED_BY_DEFAULT};
+// Show picture-in-picture button in Global Media Controls.
+const base::Feature kGlobalMediaControlsPictureInPicture{
+ "GlobalMediaControlsPictureInPicture", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Enable new cpu load estimator. Intended for evaluation in local
// testing and origin-trial.
// TODO(nisse): Delete once we have switched over to always using the
@@ -366,6 +390,12 @@ const base::Feature kUseNewMediaCache{"use-new-media-cache",
const base::Feature kUseMediaHistoryStore{"UseMediaHistoryStore",
base::FEATURE_DISABLED_BY_DEFAULT};
+// Causes video.requestAniationFrame to use a microtask instead of running with
+// the rendering steps. TODO(crbug.com/1012063): Remove this once we figure out
+// which implementation to use.
+const base::Feature kUseMicrotaskForVideoRAF{"UseMicrotaskForVideoRAF",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Use R16 texture for 9-16 bit channel instead of half-float conversion by CPU.
const base::Feature kUseR16Texture{"use-r16-texture",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -377,7 +407,7 @@ const base::Feature kUnifiedAutoplay{"UnifiedAutoplay",
// Enable VA-API hardware encode acceleration for H264 on AMD.
const base::Feature kVaapiH264AMDEncoder{"VaapiH264AMDEncoder",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
// Enable VA-API hardware low power encoder for all codecs.
const base::Feature kVaapiLowPowerEncoder{"VaapiLowPowerEncoder",
@@ -407,6 +437,10 @@ const base::Feature kVideoBlitColorAccuracy{"video-blit-color-accuracy",
const base::Feature kExternalClearKeyForTesting{
"ExternalClearKeyForTesting", base::FEATURE_DISABLED_BY_DEFAULT};
+// Enables the LiveCaption feature.
+const base::Feature kLiveCaption{"LiveCaption",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Prevents UrlProvisionFetcher from making a provisioning request. If
// specified, any provisioning request made will not be sent to the provisioning
// server, and the response will indicate a failure to communicate with the
@@ -489,10 +523,6 @@ const base::Feature kMediaDrmPreprovisioning{"MediaDrmPreprovisioning",
const base::Feature kMediaDrmPreprovisioningAtStartup{
"MediaDrmPreprovisioningAtStartup", base::FEATURE_ENABLED_BY_DEFAULT};
-// Enables the Android Image Reader path for Video decoding(for AVDA and MCVD)
-const base::Feature kAImageReaderVideoOutput{"AImageReaderVideoOutput",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
// Prevents using SurfaceLayer for videos. This is meant to be used by embedders
// that cannot support SurfaceLayer at the moment.
const base::Feature kDisableSurfaceLayerForVideo{
@@ -511,6 +541,11 @@ const base::Feature kCanPlayHls{"CanPlayHls", base::FEATURE_ENABLED_BY_DEFAULT};
// HLS manifests will fail to load (triggering source fallback or load error).
const base::Feature kHlsPlayer{"HlsPlayer", base::FEATURE_ENABLED_BY_DEFAULT};
+// When enabled, Playing media sessions will request audio focus from the
+// Android system.
+const base::Feature kRequestSystemAudioFocus{"RequestSystemAudioFocus",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
// Use the (hacky) AudioManager.getOutputLatency() call to get the estimated
// hardware latency for a stream for OpenSLES playback. This is normally not
// needed, except for some Android TV devices.
@@ -538,6 +573,10 @@ const base::Feature kMediaFoundationH264Encoding{
const base::Feature kMediaFoundationVideoCapture{
"MediaFoundationVideoCapture", base::FEATURE_ENABLED_BY_DEFAULT};
+// Enables VP8 decode acceleration for Windows.
+const base::Feature MEDIA_EXPORT kMediaFoundationVP8Decoding{
+ "MediaFoundationVP8Decoding", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Enables DirectShow GetPhotoState implementation
// Created to act as a kill switch by disabling it, in the case of the
// resurgence of https://crbug.com/722038
@@ -598,6 +637,15 @@ const base::Feature kPreloadMediaEngagementData{
const base::Feature kMediaEngagementHTTPSOnly{
"MediaEngagementHTTPSOnly", base::FEATURE_DISABLED_BY_DEFAULT};
+// Enables Media Feeds to allow sites to provide specific recommendations for
+// users.
+const base::Feature kMediaFeeds{"MediaFeeds",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables checking Media Feeds against safe search to prevent adult content.
+const base::Feature kMediaFeedsSafeSearch{"MediaFeedsSafeSearch",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Send events to devtools rather than to chrome://media-internals
const base::Feature kMediaInspectorLogging{"MediaInspectorLogging",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -612,6 +660,11 @@ const base::Feature kMediaLearningExperiment{"MediaLearningExperiment",
const base::Feature kMediaLearningFramework{"MediaLearningFramework",
base::FEATURE_DISABLED_BY_DEFAULT};
+// Enables the smoothness prediction experiment. Requires
+// kMediaLearningFramework to be enabled also, else it does nothing.
+const base::Feature kMediaLearningSmoothnessExperiment{
+ "MediaLearningSmoothnessExperiment", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Enable aggregate power measurement for media playback.
const base::Feature kMediaPowerExperiment{"MediaPowerExperiment",
base::FEATURE_DISABLED_BY_DEFAULT};
@@ -645,9 +698,17 @@ const base::Feature kInternalMediaSession {
#endif
};
+const base::Feature kKaleidoscope{"Kaleidoscope",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
const base::Feature kUseFakeDeviceForMediaStream{
"use-fake-device-for-media-stream", base::FEATURE_DISABLED_BY_DEFAULT};
+// Makes VideoCadenceEstimator use Bresenham-like algorithm for frame cadence
+// estimations.
+const base::Feature kBresenhamCadence{"BresenhamCadence",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
bool IsVideoCaptureAcceleratedJpegDecodingEnabled() {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableAcceleratedMjpegDecode)) {
diff --git a/chromium/media/base/media_switches.h b/chromium/media/base/media_switches.h
index 6bf9883256c..dfe622f670c 100644
--- a/chromium/media/base/media_switches.h
+++ b/chromium/media/base/media_switches.h
@@ -55,6 +55,10 @@ MEDIA_EXPORT extern const char kForceProtectedVideoOutputBuffers[];
MEDIA_EXPORT extern const char kEnableFuchsiaAudioConsumer[];
#endif
+#if BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
+MEDIA_EXPORT extern const char kForceDisableNewAcceleratedVideoDecoder[];
+#endif
+
#if defined(USE_CRAS)
MEDIA_EXPORT extern const char kUseCras[];
#endif
@@ -84,8 +88,6 @@ MEDIA_EXPORT extern const char kClearKeyCdmPathForTesting[];
MEDIA_EXPORT extern const char kOverrideEnabledCdmInterfaceVersion[];
MEDIA_EXPORT extern const char kOverrideHardwareSecureCodecsForTesting[];
-MEDIA_EXPORT extern const char kVideoCaptureUseGpuMemoryBuffer[];
-
namespace autoplay {
MEDIA_EXPORT extern const char kDocumentUserActivationRequiredPolicy[];
@@ -107,7 +109,8 @@ MEDIA_EXPORT extern const base::Feature kAutoplayIgnoreWebAudio;
MEDIA_EXPORT extern const base::Feature kAutoplayDisableSettings;
MEDIA_EXPORT extern const base::Feature kAutoplayWhitelistSettings;
MEDIA_EXPORT extern const base::Feature kBackgroundVideoPauseOptimization;
-MEDIA_EXPORT extern const base::Feature kD3D11LimitTo11_0;
+MEDIA_EXPORT extern const base::Feature kBresenhamCadence;
+MEDIA_EXPORT extern const base::Feature kCdmHostVerification;
MEDIA_EXPORT extern const base::Feature kD3D11PrintCodecOnCrash;
MEDIA_EXPORT extern const base::Feature kD3D11VideoDecoder;
MEDIA_EXPORT extern const base::Feature kD3D11VideoDecoderIgnoreWorkarounds;
@@ -120,20 +123,28 @@ MEDIA_EXPORT extern const base::Feature kExternalClearKeyForTesting;
MEDIA_EXPORT extern const base::Feature kFFmpegDecodeOpaqueVP8;
MEDIA_EXPORT extern const base::Feature kFailUrlProvisionFetcherForTesting;
MEDIA_EXPORT extern const base::Feature kFallbackAfterDecodeError;
+MEDIA_EXPORT extern const base::Feature kGav1VideoDecoder;
MEDIA_EXPORT extern const base::Feature kGlobalMediaControls;
+MEDIA_EXPORT extern const base::Feature kGlobalMediaControlsAutoDismiss;
MEDIA_EXPORT extern const base::Feature kGlobalMediaControlsForCast;
MEDIA_EXPORT extern const base::Feature kGlobalMediaControlsOverlayControls;
+MEDIA_EXPORT extern const base::Feature kGlobalMediaControlsPictureInPicture;
MEDIA_EXPORT extern const base::Feature kHardwareMediaKeyHandling;
MEDIA_EXPORT extern const base::Feature kHardwareSecureDecryption;
MEDIA_EXPORT extern const base::Feature kInternalMediaSession;
+MEDIA_EXPORT extern const base::Feature kKaleidoscope;
+MEDIA_EXPORT extern const base::Feature kLiveCaption;
MEDIA_EXPORT extern const base::Feature kLowDelayVideoRenderingOnLiveStream;
MEDIA_EXPORT extern const base::Feature kMediaCapabilitiesWithParameters;
MEDIA_EXPORT extern const base::Feature kMediaCastOverlayButton;
MEDIA_EXPORT extern const base::Feature kMediaEngagementBypassAutoplayPolicies;
MEDIA_EXPORT extern const base::Feature kMediaEngagementHTTPSOnly;
+MEDIA_EXPORT extern const base::Feature kMediaFeeds;
+MEDIA_EXPORT extern const base::Feature kMediaFeedsSafeSearch;
MEDIA_EXPORT extern const base::Feature kMediaInspectorLogging;
MEDIA_EXPORT extern const base::Feature kMediaLearningExperiment;
MEDIA_EXPORT extern const base::Feature kMediaLearningFramework;
+MEDIA_EXPORT extern const base::Feature kMediaLearningSmoothnessExperiment;
MEDIA_EXPORT extern const base::Feature kMediaPowerExperiment;
MEDIA_EXPORT extern const base::Feature kMemoryPressureBasedSourceBufferGC;
MEDIA_EXPORT extern const base::Feature kChromeosVideoDecoder;
@@ -153,6 +164,7 @@ MEDIA_EXPORT extern const base::Feature kUnifiedAutoplay;
MEDIA_EXPORT extern const base::Feature kUseAndroidOverlayAggressively;
MEDIA_EXPORT extern const base::Feature kUseFakeDeviceForMediaStream;
MEDIA_EXPORT extern const base::Feature kUseMediaHistoryStore;
+MEDIA_EXPORT extern const base::Feature kUseMicrotaskForVideoRAF;
MEDIA_EXPORT extern const base::Feature kUseNewMediaCache;
MEDIA_EXPORT extern const base::Feature kUseR16Texture;
MEDIA_EXPORT extern const base::Feature kVaapiH264AMDEncoder;
@@ -172,11 +184,11 @@ MEDIA_EXPORT extern const base::Feature kMediaControlsExpandGesture;
MEDIA_EXPORT extern const base::Feature kMediaDrmPersistentLicense;
MEDIA_EXPORT extern const base::Feature kMediaDrmPreprovisioning;
MEDIA_EXPORT extern const base::Feature kMediaDrmPreprovisioningAtStartup;
-MEDIA_EXPORT extern const base::Feature kAImageReaderVideoOutput;
MEDIA_EXPORT extern const base::Feature kDisableSurfaceLayerForVideo;
MEDIA_EXPORT extern const base::Feature kCanPlayHls;
MEDIA_EXPORT extern const base::Feature kPictureInPictureAPI;
MEDIA_EXPORT extern const base::Feature kHlsPlayer;
+MEDIA_EXPORT extern const base::Feature kRequestSystemAudioFocus;
MEDIA_EXPORT extern const base::Feature kUseAudioLatencyFromHAL;
MEDIA_EXPORT extern const base::Feature kUsePooledSharedImageVideoProvider;
#endif // defined(OS_ANDROID)
@@ -185,6 +197,7 @@ MEDIA_EXPORT extern const base::Feature kUsePooledSharedImageVideoProvider;
MEDIA_EXPORT extern const base::Feature kDelayCopyNV12Textures;
MEDIA_EXPORT extern const base::Feature kMediaFoundationH264Encoding;
MEDIA_EXPORT extern const base::Feature kMediaFoundationVideoCapture;
+MEDIA_EXPORT extern const base::Feature kMediaFoundationVP8Decoding;
MEDIA_EXPORT extern const base::Feature kDirectShowGetPhotoState;
#endif // defined(OS_WIN)
diff --git a/chromium/media/base/media_types.cc b/chromium/media/base/media_types.cc
index bc980c125aa..ceaddc7f7b6 100644
--- a/chromium/media/base/media_types.cc
+++ b/chromium/media/base/media_types.cc
@@ -10,7 +10,7 @@ namespace media {
// static
AudioType AudioType::FromDecoderConfig(const AudioDecoderConfig& config) {
- return {config.codec()};
+ return {config.codec(), AudioCodecProfile::kUnknown, false};
}
// static
@@ -57,7 +57,8 @@ VideoType VideoType::FromDecoderConfig(const VideoDecoderConfig& config) {
}
bool operator==(const AudioType& x, const AudioType& y) {
- return x.codec == y.codec;
+ return std::tie(x.codec, x.profile, x.spatial_rendering) ==
+ std::tie(y.codec, y.profile, y.spatial_rendering);
}
bool operator!=(const AudioType& x, const AudioType& y) {
diff --git a/chromium/media/base/media_types.h b/chromium/media/base/media_types.h
index 7ee96a1ff52..c7f6f2a5d99 100644
--- a/chromium/media/base/media_types.h
+++ b/chromium/media/base/media_types.h
@@ -22,7 +22,8 @@ struct MEDIA_EXPORT AudioType {
static AudioType FromDecoderConfig(const AudioDecoderConfig& config);
AudioCodec codec;
- bool spatialRendering;
+ AudioCodecProfile profile;
+ bool spatial_rendering;
};
struct MEDIA_EXPORT VideoType {
diff --git a/chromium/media/base/media_util.h b/chromium/media/base/media_util.h
index 65aee57e2f8..fac5af522da 100644
--- a/chromium/media/base/media_util.h
+++ b/chromium/media/base/media_util.h
@@ -28,7 +28,8 @@ class MEDIA_EXPORT NullMediaLog : public media::MediaLog {
NullMediaLog() = default;
~NullMediaLog() override = default;
- void AddEventLocked(std::unique_ptr<media::MediaLogEvent> event) override {}
+ void AddLogRecordLocked(
+ std::unique_ptr<media::MediaLogRecord> event) override {}
private:
DISALLOW_COPY_AND_ASSIGN(NullMediaLog);
diff --git a/chromium/media/base/memory_dump_provider_proxy.cc b/chromium/media/base/memory_dump_provider_proxy.cc
new file mode 100644
index 00000000000..72117cb3a78
--- /dev/null
+++ b/chromium/media/base/memory_dump_provider_proxy.cc
@@ -0,0 +1,34 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/base/memory_dump_provider_proxy.h"
+
+#include <utility>
+
+#include "base/trace_event/memory_dump_manager.h"
+
+namespace media {
+
+MemoryDumpProviderProxy::MemoryDumpProviderProxy(
+ const char* name,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ MemoryDumpCB dump_cb)
+ : dump_cb_(std::move(dump_cb)) {
+ base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+ this, name, std::move(task_runner));
+}
+
+MemoryDumpProviderProxy::~MemoryDumpProviderProxy() {
+ base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
+ this);
+}
+
+bool MemoryDumpProviderProxy::OnMemoryDump(
+ const base::trace_event::MemoryDumpArgs& args,
+ base::trace_event::ProcessMemoryDump* pmd) {
+ dump_cb_.Run(args, pmd);
+ return true;
+}
+
+} // namespace media
diff --git a/chromium/media/base/memory_dump_provider_proxy.h b/chromium/media/base/memory_dump_provider_proxy.h
new file mode 100644
index 00000000000..72767e003fe
--- /dev/null
+++ b/chromium/media/base/memory_dump_provider_proxy.h
@@ -0,0 +1,50 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_BASE_MEMORY_DUMP_PROVIDER_PROXY_H_
+#define MEDIA_BASE_MEMORY_DUMP_PROVIDER_PROXY_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_piece.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "media/base/media_export.h"
+
+namespace media {
+
+using MemoryDumpCB =
+ base::RepeatingCallback<void(const base::trace_event::MemoryDumpArgs& args,
+ base::trace_event::ProcessMemoryDump* pmd)>;
+
+class MEDIA_EXPORT MemoryDumpProviderProxy final
+ : public base::trace_event::MemoryDumpProvider {
+ public:
+ MemoryDumpProviderProxy(
+ const char* name,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ MemoryDumpCB dump_cb);
+
+ ~MemoryDumpProviderProxy() override;
+
+ bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
+ base::trace_event::ProcessMemoryDump* pmd) override;
+
+ private:
+ MemoryDumpCB dump_cb_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryDumpProviderProxy);
+};
+
+} // namespace media
+
+#endif // MEDIA_BASE_MEMORY_DUMP_PROVIDER_PROXY_H_
diff --git a/chromium/media/base/mime_util_internal.cc b/chromium/media/base/mime_util_internal.cc
index 23381d026f1..000325d0dd4 100644
--- a/chromium/media/base/mime_util_internal.cc
+++ b/chromium/media/base/mime_util_internal.cc
@@ -69,6 +69,7 @@ const StringToCodecMap& GetStringToCodecMap() {
{"mp4a.40.5", MimeUtil::MPEG4_AAC},
{"mp4a.40.05", MimeUtil::MPEG4_AAC},
{"mp4a.40.29", MimeUtil::MPEG4_AAC},
+ {"mp4a.40.42", MimeUtil::MPEG4_XHE_AAC},
// TODO(servolk): Strictly speaking only mp4a.A5 and mp4a.A6
// codec ids are valid according to RFC 6381 section 3.3, 3.4.
// Lower-case oti (mp4a.a5 and mp4a.a6) should be rejected. But
@@ -170,6 +171,7 @@ AudioCodec MimeUtilToAudioCodec(MimeUtil::Codec codec) {
return kCodecEAC3;
case MimeUtil::MPEG2_AAC:
case MimeUtil::MPEG4_AAC:
+ case MimeUtil::MPEG4_XHE_AAC:
return kCodecAAC;
case MimeUtil::MPEG_H_AUDIO:
return kCodecMpegHAudio;
@@ -310,7 +312,7 @@ void MimeUtil::AddSupportedMediaFormats() {
mp4_video_codecs.emplace(VP9);
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
- const CodecSet aac{MPEG2_AAC, MPEG4_AAC};
+ const CodecSet aac{MPEG2_AAC, MPEG4_AAC, MPEG4_XHE_AAC};
mp4_audio_codecs.insert(aac.begin(), aac.end());
CodecSet avc_and_aac(aac);
@@ -585,6 +587,10 @@ bool MimeUtil::IsCodecSupportedOnAndroid(
DCHECK(!is_encrypted || platform_info.has_platform_decoders);
return true;
+ case MPEG4_XHE_AAC:
+ // xHE-AAC is only supported via MediaCodec.
+ return platform_info.has_platform_decoders;
+
case MPEG_H_AUDIO:
return false;
@@ -885,7 +891,11 @@ SupportsType MimeUtil::IsCodecSupported(const std::string& mime_type_lower_case,
AudioCodec audio_codec = MimeUtilToAudioCodec(codec);
if (audio_codec != kUnknownAudioCodec) {
- if (!IsSupportedAudioType({audio_codec}))
+ AudioCodecProfile audio_profile = AudioCodecProfile::kUnknown;
+ if (codec == MPEG4_XHE_AAC)
+ audio_profile = AudioCodecProfile::kXHE_AAC;
+
+ if (!IsSupportedAudioType({audio_codec, audio_profile, false}))
return IsNotSupported;
}
diff --git a/chromium/media/base/mime_util_internal.h b/chromium/media/base/mime_util_internal.h
index 5f604ae93fe..1401ba2e1a9 100644
--- a/chromium/media/base/mime_util_internal.h
+++ b/chromium/media/base/mime_util_internal.h
@@ -35,6 +35,7 @@ class MEDIA_EXPORT MimeUtil {
EAC3,
MPEG2_AAC,
MPEG4_AAC,
+ MPEG4_XHE_AAC,
VORBIS,
OPUS,
FLAC,
diff --git a/chromium/media/base/mime_util_unittest.cc b/chromium/media/base/mime_util_unittest.cc
index 01a6de51539..31258457dc0 100644
--- a/chromium/media/base/mime_util_unittest.cc
+++ b/chromium/media/base/mime_util_unittest.cc
@@ -440,6 +440,7 @@ TEST(IsCodecSupportedOnAndroidTest, EncryptedCodecBehavior) {
case MimeUtil::MP3:
case MimeUtil::MPEG2_AAC:
case MimeUtil::MPEG4_AAC:
+ case MimeUtil::MPEG4_XHE_AAC:
case MimeUtil::VORBIS:
case MimeUtil::FLAC:
case MimeUtil::H264:
@@ -514,6 +515,10 @@ TEST(IsCodecSupportedOnAndroidTest, ClearCodecBehavior) {
break;
// These codecs are only supported if platform decoders are supported.
+ case MimeUtil::MPEG4_XHE_AAC:
+ EXPECT_EQ(info.has_platform_decoders, result);
+ break;
+
case MimeUtil::HEVC:
#if BUILDFLAG(ENABLE_PLATFORM_HEVC)
EXPECT_EQ(
diff --git a/chromium/media/base/mock_filters.cc b/chromium/media/base/mock_filters.cc
index 85f9ed7a303..85c3e6dd11f 100644
--- a/chromium/media/base/mock_filters.cc
+++ b/chromium/media/base/mock_filters.cc
@@ -220,10 +220,10 @@ void MockCdmFactory::Create(
const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb,
- const CdmCreatedCB& cdm_created_cb) {
+ CdmCreatedCB cdm_created_cb) {
// If no key system specified, notify that Create() failed.
if (key_system.empty()) {
- cdm_created_cb.Run(nullptr, "CDM creation failed");
+ std::move(cdm_created_cb).Run(nullptr, "CDM creation failed");
return;
}
@@ -239,7 +239,7 @@ void MockCdmFactory::Create(
key_system, security_origin, session_message_cb, session_closed_cb,
session_keys_change_cb, session_expiration_update_cb);
created_cdm_ = cdm.get();
- cdm_created_cb.Run(std::move(cdm), "");
+ std::move(cdm_created_cb).Run(std::move(cdm), "");
}
MockCdm* MockCdmFactory::GetCreatedCdm() {
@@ -247,8 +247,8 @@ MockCdm* MockCdmFactory::GetCreatedCdm() {
}
void MockCdmFactory::SetBeforeCreationCB(
- const base::Closure& before_creation_cb) {
- before_creation_cb_ = before_creation_cb;
+ base::RepeatingClosure before_creation_cb) {
+ before_creation_cb_ = std::move(before_creation_cb);
}
MockStreamParser::MockStreamParser() = default;
diff --git a/chromium/media/base/mock_filters.h b/chromium/media/base/mock_filters.h
index 9b679e99c08..36a270f7101 100644
--- a/chromium/media/base/mock_filters.h
+++ b/chromium/media/base/mock_filters.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright (c) 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -59,12 +59,13 @@ class MockPipelineClient : public Pipeline::Client {
void(BufferingState, BufferingStateChangeReason));
MOCK_METHOD0(OnDurationChange, void());
MOCK_METHOD2(OnAddTextTrack,
- void(const TextTrackConfig&, const AddTextTrackDoneCB&));
+ void(const TextTrackConfig&, AddTextTrackDoneCB));
MOCK_METHOD1(OnWaiting, void(WaitingReason));
MOCK_METHOD1(OnAudioConfigChange, void(const AudioDecoderConfig&));
MOCK_METHOD1(OnVideoConfigChange, void(const VideoDecoderConfig&));
MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size&));
MOCK_METHOD1(OnVideoOpacityChange, void(bool));
+ MOCK_METHOD1(OnVideoFrameRateChange, void(base::Optional<int>));
MOCK_METHOD0(OnVideoAverageKeyframeDistanceUpdate, void());
MOCK_METHOD1(OnAudioDecoderChange, void(const PipelineDecoderInfo&));
MOCK_METHOD1(OnVideoDecoderChange, void(const PipelineDecoderInfo&));
@@ -76,12 +77,25 @@ class MockPipeline : public Pipeline {
MockPipeline();
~MockPipeline() override;
- MOCK_METHOD4(Start,
- void(StartType, Demuxer*, Client*, const PipelineStatusCB&));
+ void Start(StartType start_type,
+ Demuxer* demuxer,
+ Client* client,
+ PipelineStatusCallback seek_cb) {
+ OnStart(start_type, demuxer, client, seek_cb);
+ }
+ MOCK_METHOD4(OnStart,
+ void(StartType, Demuxer*, Client*, PipelineStatusCallback&));
MOCK_METHOD0(Stop, void());
- MOCK_METHOD2(Seek, void(base::TimeDelta, const PipelineStatusCB&));
- MOCK_METHOD1(Suspend, void(const PipelineStatusCB&));
- MOCK_METHOD2(Resume, void(base::TimeDelta, const PipelineStatusCB&));
+ void Seek(base::TimeDelta time, PipelineStatusCallback seek_cb) {
+ OnSeek(time, seek_cb);
+ }
+ MOCK_METHOD2(OnSeek, void(base::TimeDelta, PipelineStatusCallback&));
+ void Suspend(PipelineStatusCallback cb) { OnSuspend(cb); }
+ MOCK_METHOD1(OnSuspend, void(PipelineStatusCallback&));
+ void Resume(base::TimeDelta time, PipelineStatusCallback seek_cb) {
+ OnResume(time, seek_cb);
+ }
+ MOCK_METHOD2(OnResume, void(base::TimeDelta, PipelineStatusCallback&));
MOCK_METHOD2(OnEnabledAudioTracksChanged,
void(const std::vector<MediaTrack::Id>&, base::OnceClosure));
MOCK_METHOD2(OnSelectedVideoTrackChanged,
@@ -281,6 +295,7 @@ class MockRendererClient : public RendererClient {
MOCK_METHOD1(OnVideoConfigChange, void(const VideoDecoderConfig&));
MOCK_METHOD1(OnVideoNaturalSizeChange, void(const gfx::Size&));
MOCK_METHOD1(OnVideoOpacityChange, void(bool));
+ MOCK_METHOD1(OnVideoFrameRateChange, void(base::Optional<int>));
MOCK_METHOD1(OnDurationChange, void(base::TimeDelta));
MOCK_METHOD1(OnRemotePlayStateChange, void(MediaStatus::State state));
MOCK_METHOD0(IsVideoStreamAvailable, bool());
@@ -292,16 +307,25 @@ class MockVideoRenderer : public VideoRenderer {
~MockVideoRenderer() override;
// VideoRenderer implementation.
- MOCK_METHOD5(Initialize,
+ void Initialize(DemuxerStream* stream,
+ CdmContext* cdm_context,
+ RendererClient* client,
+ const TimeSource::WallClockTimeCB& wall_clock_time_cb,
+ PipelineStatusCallback init_cb) {
+ OnInitialize(stream, cdm_context, client, wall_clock_time_cb, init_cb);
+ }
+ MOCK_METHOD5(OnInitialize,
void(DemuxerStream* stream,
CdmContext* cdm_context,
RendererClient* client,
const TimeSource::WallClockTimeCB& wall_clock_time_cb,
- const PipelineStatusCB& init_cb));
+ PipelineStatusCallback& init_cb));
MOCK_METHOD1(Flush, void(base::OnceClosure flush_cb));
MOCK_METHOD1(StartPlayingFrom, void(base::TimeDelta));
MOCK_METHOD0(OnTimeProgressing, void());
MOCK_METHOD0(OnTimeStopped, void());
+ MOCK_METHOD1(SetLatencyHint,
+ void(base::Optional<base::TimeDelta> latency_hint));
private:
DISALLOW_COPY_AND_ASSIGN(MockVideoRenderer);
@@ -313,15 +337,23 @@ class MockAudioRenderer : public AudioRenderer {
~MockAudioRenderer() override;
// AudioRenderer implementation.
- MOCK_METHOD4(Initialize,
+ void Initialize(DemuxerStream* stream,
+ CdmContext* cdm_context,
+ RendererClient* client,
+ PipelineStatusCallback init_cb) {
+ OnInitialize(stream, cdm_context, client, init_cb);
+ }
+ MOCK_METHOD4(OnInitialize,
void(DemuxerStream* stream,
CdmContext* cdm_context,
RendererClient* client,
- const PipelineStatusCB& init_cb));
+ PipelineStatusCallback& init_cb));
MOCK_METHOD0(GetTimeSource, TimeSource*());
MOCK_METHOD1(Flush, void(base::OnceClosure flush_cb));
MOCK_METHOD0(StartPlaying, void());
MOCK_METHOD1(SetVolume, void(float volume));
+ MOCK_METHOD1(SetLatencyHint,
+ void(base::Optional<base::TimeDelta> latency_hint));
private:
DISALLOW_COPY_AND_ASSIGN(MockAudioRenderer);
@@ -377,7 +409,7 @@ class MockRendererFactory : public RendererFactory {
const scoped_refptr<base::TaskRunner>&,
AudioRendererSink*,
VideoRendererSink*,
- const RequestOverlayInfoCB&,
+ RequestOverlayInfoCB,
const gfx::ColorSpace&));
private:
@@ -459,18 +491,16 @@ class MockDecryptor : public Decryptor {
~MockDecryptor() override;
MOCK_METHOD2(RegisterNewKeyCB,
- void(StreamType stream_type, const NewKeyCB& new_key_cb));
+ void(StreamType stream_type, NewKeyCB new_key_cb));
MOCK_METHOD3(Decrypt,
void(StreamType stream_type,
scoped_refptr<DecoderBuffer> encrypted,
- const DecryptCB& decrypt_cb));
+ DecryptCB decrypt_cb));
MOCK_METHOD1(CancelDecrypt, void(StreamType stream_type));
MOCK_METHOD2(InitializeAudioDecoder,
- void(const AudioDecoderConfig& config,
- const DecoderInitCB& init_cb));
+ void(const AudioDecoderConfig& config, DecoderInitCB init_cb));
MOCK_METHOD2(InitializeVideoDecoder,
- void(const VideoDecoderConfig& config,
- const DecoderInitCB& init_cb));
+ void(const VideoDecoderConfig& config, DecoderInitCB init_cb));
MOCK_METHOD2(DecryptAndDecodeAudio,
void(scoped_refptr<DecoderBuffer> encrypted,
const AudioDecodeCB& audio_decode_cb));
@@ -614,20 +644,20 @@ class MockCdmFactory : public CdmFactory {
const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb,
- const CdmCreatedCB& cdm_created_cb) override;
+ CdmCreatedCB cdm_created_cb) override;
// Return a pointer to the created CDM.
MockCdm* GetCreatedCdm();
// Provide a callback to be called before the CDM is created and returned.
- void SetBeforeCreationCB(const base::Closure& before_creation_cb);
+ void SetBeforeCreationCB(base::RepeatingClosure before_creation_cb);
private:
// Reference to the created CDM.
scoped_refptr<MockCdm> created_cdm_;
// Callback to be used before Create() successfully calls |cdm_created_cb|.
- base::Closure before_creation_cb_;
+ base::RepeatingClosure before_creation_cb_;
DISALLOW_COPY_AND_ASSIGN(MockCdmFactory);
};
diff --git a/chromium/media/base/mock_media_log.cc b/chromium/media/base/mock_media_log.cc
index dd60bcb0934..3ae29f64829 100644
--- a/chromium/media/base/mock_media_log.cc
+++ b/chromium/media/base/mock_media_log.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "media/base/mock_media_log.h"
+#include "base/json/json_writer.h"
namespace media {
@@ -10,10 +11,27 @@ MockMediaLog::MockMediaLog() = default;
MockMediaLog::~MockMediaLog() = default;
-void MockMediaLog::AddEventLocked(std::unique_ptr<MediaLogEvent> event) {
+void MockMediaLog::AddLogRecordLocked(std::unique_ptr<MediaLogRecord> event) {
const auto log_string = MediaEventToLogString(*event);
VLOG(2) << "MediaLog: " << log_string;
- DoAddEventLogString(log_string);
+ DoAddLogRecordLogString(log_string);
+}
+
+std::string MockMediaLog::MediaEventToLogString(const MediaLogRecord& event) {
+ // Special case for PIPELINE_ERROR, since that's by far the most useful
+ // event for figuring out media pipeline failures, and just reporting
+ // pipeline status as numeric code is not very helpful/user-friendly.
+ int error_code = 0;
+ if (event.type == MediaLogRecord::Type::kMediaStatus &&
+ event.params.GetInteger(media::MediaLog::kStatusText, &error_code)) {
+ PipelineStatus status = static_cast<PipelineStatus>(error_code);
+ return std::string(media::MediaLog::kStatusText) + " " +
+ PipelineStatusToString(status);
+ }
+
+ std::string params_json;
+ base::JSONWriter::Write(event.params, &params_json);
+ return params_json;
}
} // namespace media
diff --git a/chromium/media/base/mock_media_log.h b/chromium/media/base/mock_media_log.h
index a8f04576071..828960f0171 100644
--- a/chromium/media/base/mock_media_log.h
+++ b/chromium/media/base/mock_media_log.h
@@ -37,35 +37,37 @@ struct TypeAndCodec {
// |log| is expected to evaluate to a MockMediaLog, optionally a NiceMock or
// StrictMock, in scope of the usage of this macro.
-#define EXPECT_MEDIA_LOG_ON(log, x) EXPECT_CALL((log), DoAddEventLogString((x)))
+#define EXPECT_MEDIA_LOG_ON(log, x) \
+ EXPECT_CALL((log), DoAddLogRecordLogString((x)))
// Requires |media_log_| to be available.
#define EXPECT_MEDIA_LOG_PROPERTY(property, value) \
EXPECT_CALL( \
media_log_, \
- DoAddEventLogString( \
- MatchesPropertyExactValue(MediaLog::MediaEventToLogString( \
+ DoAddLogRecordLogString( \
+ MatchesPropertyExactValue(MockMediaLog::MediaEventToLogString( \
*media_log_.CreatePropertyTestEvent<MediaLogProperty::property>( \
value)))))
-#define EXPECT_MEDIA_LOG_PROPERTY_ANY_VALUE(property) \
- EXPECT_CALL( \
- media_log_, \
- DoAddEventLogString(MatchesPropertyAnyValue( \
- "PROPERTY_CHANGE {\"" + \
- MediaLogPropertyKeyToString(MediaLogProperty::property) + "\"")))
+#define EXPECT_MEDIA_LOG_PROPERTY_ANY_VALUE(property) \
+ EXPECT_CALL( \
+ media_log_, \
+ DoAddLogRecordLogString(MatchesPropertyAnyValue( \
+ "{\"" + MediaLogPropertyKeyToString(MediaLogProperty::property) + \
+ "\"")))
-#define EXPECT_FOUND_CODEC_NAME(stream_type, codec_name) \
- EXPECT_CALL(media_log_, DoAddEventLogString(TracksHasCodecName(TypeAndCodec( \
- MediaLogPropertyKeyToString( \
- MediaLogProperty::k##stream_type##Tracks), \
- codec_name))))
+#define EXPECT_FOUND_CODEC_NAME(stream_type, codec_name) \
+ EXPECT_CALL(media_log_, \
+ DoAddLogRecordLogString(TracksHasCodecName( \
+ TypeAndCodec(MediaLogPropertyKeyToString( \
+ MediaLogProperty::k##stream_type##Tracks), \
+ codec_name))))
namespace media {
MATCHER_P(TracksHasCodecName, tandc, "") {
- return (arg.substr(0, 31) == "PROPERTY_CHANGE {\"" + tandc.type + "\"") &&
- (arg[33] != ']') && CONTAINS_STRING(arg, tandc.codec);
+ return (arg.substr(0, 15) == "{\"" + tandc.type + "\"") && (arg[16] != ']') &&
+ CONTAINS_STRING(arg, tandc.codec);
}
MATCHER_P(MatchesPropertyExactValue, message, "") {
@@ -81,18 +83,20 @@ class MockMediaLog : public MediaLog {
MockMediaLog();
~MockMediaLog() override;
- MOCK_METHOD1(DoAddEventLogString, void(const std::string& event));
+ MOCK_METHOD1(DoAddLogRecordLogString, void(const std::string& event));
// Trampoline method to workaround GMOCK problems with std::unique_ptr<>.
// Also simplifies tests to be able to string match on the log string
// representation on the added event.
- void AddEventLocked(std::unique_ptr<MediaLogEvent> event) override;
+ void AddLogRecordLocked(std::unique_ptr<MediaLogRecord> event) override;
template <MediaLogProperty P, typename T>
- std::unique_ptr<MediaLogEvent> CreatePropertyTestEvent(const T& value) {
- return CreatePropertyEvent<P, T>(value);
+ std::unique_ptr<MediaLogRecord> CreatePropertyTestEvent(const T& value) {
+ return CreatePropertyRecord<P, T>(value);
}
+ static std::string MediaEventToLogString(const MediaLogRecord& event);
+
private:
DISALLOW_COPY_AND_ASSIGN(MockMediaLog);
};
diff --git a/chromium/media/base/moving_average.cc b/chromium/media/base/moving_average.cc
index 0f188e2ca14..124e0b51046 100644
--- a/chromium/media/base/moving_average.cc
+++ b/chromium/media/base/moving_average.cc
@@ -55,4 +55,18 @@ void MovingAverage::Reset() {
std::fill(samples_.begin(), samples_.end(), base::TimeDelta());
}
+std::pair<base::TimeDelta, base::TimeDelta> MovingAverage::GetMinAndMax() {
+ std::pair<base::TimeDelta, base::TimeDelta> result(samples_[0], samples_[0]);
+
+ const uint64_t size = std::min(static_cast<uint64_t>(depth_), count_);
+ for (uint64_t i = 1; i < size; i++) {
+ if (samples_[i] < result.first)
+ result.first = samples_[i];
+ if (samples_[i] > result.second)
+ result.second = samples_[i];
+ }
+
+ return result;
+}
+
} // namespace media
diff --git a/chromium/media/base/moving_average.h b/chromium/media/base/moving_average.h
index 9f6032e5bb7..d1a966e632f 100644
--- a/chromium/media/base/moving_average.h
+++ b/chromium/media/base/moving_average.h
@@ -8,6 +8,7 @@
#include <stddef.h>
#include <stdint.h>
+#include <utility>
#include <vector>
#include "base/macros.h"
@@ -41,6 +42,11 @@ class MEDIA_EXPORT MovingAverage {
base::TimeDelta max() const { return max_; }
+ size_t depth() const { return depth_; }
+
+ // |first| is min, |second| is max of all samples in the window.
+ std::pair<base::TimeDelta, base::TimeDelta> GetMinAndMax();
+
private:
// Maximum number of elements allowed in the average.
const size_t depth_;
diff --git a/chromium/media/base/moving_average_unittest.cc b/chromium/media/base/moving_average_unittest.cc
index 39ad094231a..a195985297d 100644
--- a/chromium/media/base/moving_average_unittest.cc
+++ b/chromium/media/base/moving_average_unittest.cc
@@ -45,4 +45,19 @@ TEST(MovingAverageTest, Reset) {
EXPECT_EQ(base::TimeDelta(), moving_average.Deviation());
}
+TEST(MovingAverageTest, MinAndMax) {
+ MovingAverage moving_average(5);
+ base::TimeDelta min = base::TimeDelta::FromSeconds(1);
+ base::TimeDelta med = base::TimeDelta::FromSeconds(50);
+ base::TimeDelta max = base::TimeDelta::FromSeconds(100);
+ moving_average.AddSample(min);
+ moving_average.AddSample(med);
+ moving_average.AddSample(med);
+ moving_average.AddSample(med);
+ moving_average.AddSample(max);
+ auto extremes = moving_average.GetMinAndMax();
+ EXPECT_EQ(extremes.first, min);
+ EXPECT_EQ(extremes.second, max);
+}
+
} // namespace media
diff --git a/chromium/media/base/multi_channel_resampler.cc b/chromium/media/base/multi_channel_resampler.cc
index 155441057c0..ecc1e0b9574 100644
--- a/chromium/media/base/multi_channel_resampler.cc
+++ b/chromium/media/base/multi_channel_resampler.cc
@@ -117,6 +117,11 @@ int MultiChannelResampler::ChunkSize() const {
return resamplers_[0]->ChunkSize();
}
+int MultiChannelResampler::GetMaxInputFramesRequested(
+ int output_frames_requested) const {
+ DCHECK(!resamplers_.empty());
+ return resamplers_[0]->GetMaxInputFramesRequested(output_frames_requested);
+}
double MultiChannelResampler::BufferedFrames() const {
DCHECK(!resamplers_.empty());
diff --git a/chromium/media/base/multi_channel_resampler.h b/chromium/media/base/multi_channel_resampler.h
index f5dd5716acd..b455adb4163 100644
--- a/chromium/media/base/multi_channel_resampler.h
+++ b/chromium/media/base/multi_channel_resampler.h
@@ -54,6 +54,9 @@ class MEDIA_EXPORT MultiChannelResampler {
// single call to |read_cb_| for more data.
int ChunkSize() const;
+ // See SincResampler::GetMaxInputFramesRequested().
+ int GetMaxInputFramesRequested(int output_frames_requested) const;
+
// See SincResampler::BufferedFrames.
double BufferedFrames() const;
diff --git a/chromium/media/base/null_video_sink.h b/chromium/media/base/null_video_sink.h
index 1d5a31ad87b..3b972a9a156 100644
--- a/chromium/media/base/null_video_sink.h
+++ b/chromium/media/base/null_video_sink.h
@@ -43,9 +43,7 @@ class MEDIA_EXPORT NullVideoSink : public VideoRendererSink {
}
// Sets |stop_cb_|, which will be fired when Stop() is called.
- void set_stop_cb(const base::Closure& stop_cb) {
- stop_cb_ = stop_cb;
- }
+ void set_stop_cb(base::OnceClosure stop_cb) { stop_cb_ = std::move(stop_cb); }
bool is_started() const { return started_; }
@@ -84,7 +82,7 @@ class MEDIA_EXPORT NullVideoSink : public VideoRendererSink {
const base::TickClock* tick_clock_;
// If set, called when Stop() is called.
- base::Closure stop_cb_;
+ base::OnceClosure stop_cb_;
// Value passed to RenderCallback::Render().
bool background_render_;
diff --git a/chromium/media/base/null_video_sink_unittest.cc b/chromium/media/base/null_video_sink_unittest.cc
index 33b3aea3c93..4ead7a76dfc 100644
--- a/chromium/media/base/null_video_sink_unittest.cc
+++ b/chromium/media/base/null_video_sink_unittest.cc
@@ -16,7 +16,7 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-using base::test::RunClosure;
+using base::test::RunOnceClosure;
using testing::_;
using testing::DoAll;
using testing::Return;
@@ -84,7 +84,7 @@ TEST_F(NullVideoSinkTest, BasicFunctionality) {
.WillOnce(Return(test_frame));
WaitableMessageLoopEvent event;
EXPECT_CALL(*this, FrameReceived(test_frame))
- .WillOnce(RunClosure(event.GetClosure()));
+ .WillOnce(RunOnceClosure(event.GetClosure()));
event.RunAndWait();
}
@@ -103,7 +103,7 @@ TEST_F(NullVideoSinkTest, BasicFunctionality) {
.WillOnce(Return(test_frame_2));
EXPECT_CALL(*this, FrameReceived(test_frame)).Times(0);
EXPECT_CALL(*this, FrameReceived(test_frame_2))
- .WillOnce(RunClosure(event.GetClosure()));
+ .WillOnce(RunOnceClosure(event.GetClosure()));
event.RunAndWait();
}
@@ -147,7 +147,7 @@ TEST_F(NullVideoSinkTest, ClocklessFunctionality) {
EXPECT_CALL(*this, Render(current_time + i * interval,
current_time + (i + 1) * interval, false))
.WillOnce(
- DoAll(RunClosure(event.GetClosure()), Return(test_frame_2)));
+ DoAll(RunOnceClosure(event.GetClosure()), Return(test_frame_2)));
}
}
event.RunAndWait();
diff --git a/chromium/media/base/overlay_info.h b/chromium/media/base/overlay_info.h
index 489e0ec2e61..603a2208f86 100644
--- a/chromium/media/base/overlay_info.h
+++ b/chromium/media/base/overlay_info.h
@@ -40,9 +40,12 @@ struct MEDIA_EXPORT OverlayInfo {
bool is_persistent_video = false;
};
-using ProvideOverlayInfoCB = base::Callback<void(const OverlayInfo&)>;
+// Used by the WebMediaPlayer to provide overlay information to the decoder,
+// which can ask for that information repeatedly (see
+// WebMediaPlayerImpl::OnOverlayInfoRequested).
+using ProvideOverlayInfoCB = base::RepeatingCallback<void(const OverlayInfo&)>;
using RequestOverlayInfoCB =
- base::Callback<void(bool, const ProvideOverlayInfoCB&)>;
+ base::RepeatingCallback<void(bool, ProvideOverlayInfoCB)>;
} // namespace media
diff --git a/chromium/media/base/pipeline.h b/chromium/media/base/pipeline.h
index b09ac029c91..fbd6575e3d0 100644
--- a/chromium/media/base/pipeline.h
+++ b/chromium/media/base/pipeline.h
@@ -58,7 +58,7 @@ class MEDIA_EXPORT Pipeline {
// Executed whenever a text track is added.
// The client is expected to create a TextTrack and call |done_cb|.
virtual void OnAddTextTrack(const TextTrackConfig& config,
- const AddTextTrackDoneCB& done_cb) = 0;
+ AddTextTrackDoneCB done_cb) = 0;
// Executed whenever the pipeline is waiting because of |reason|.
virtual void OnWaiting(WaitingReason reason) = 0;
@@ -81,6 +81,11 @@ class MEDIA_EXPORT Pipeline {
// during playback.
virtual void OnAudioDecoderChange(const PipelineDecoderInfo& info) = 0;
virtual void OnVideoDecoderChange(const PipelineDecoderInfo& info) = 0;
+
+ // Executed whenever the video frame rate changes. |fps| will be unset if
+ // the frame rate is unstable. The duration used for the frame rate is
+ // based on wall clock time, not media time.
+ virtual void OnVideoFrameRateChange(base::Optional<int> fps) = 0;
};
virtual ~Pipeline() {}
@@ -106,7 +111,7 @@ class MEDIA_EXPORT Pipeline {
virtual void Start(StartType start_type,
Demuxer* demuxer,
Client* client,
- const PipelineStatusCB& seek_cb) = 0;
+ PipelineStatusCallback seek_cb) = 0;
// Track switching works similarly for both audio and video. Callbacks are
// used to notify when it is time to procede to the next step, since many of
@@ -163,7 +168,7 @@ class MEDIA_EXPORT Pipeline {
//
// It is an error to call this method if the pipeline has not started or
// has been suspended.
- virtual void Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb) = 0;
+ virtual void Seek(base::TimeDelta time, PipelineStatusCallback seek_cb) = 0;
// Suspends the pipeline, discarding the current renderer.
//
@@ -172,14 +177,14 @@ class MEDIA_EXPORT Pipeline {
//
// It is an error to call this method if the pipeline has not started or is
// seeking.
- virtual void Suspend(const PipelineStatusCB& suspend_cb) = 0;
+ virtual void Suspend(PipelineStatusCallback suspend_cb) = 0;
// Resume the pipeline and seek to |timestamp|.
//
// It is an error to call this method if the pipeline has not finished
// suspending.
virtual void Resume(base::TimeDelta timestamp,
- const PipelineStatusCB& seek_cb) = 0;
+ PipelineStatusCallback seek_cb) = 0;
// Returns true if the pipeline has been started via Start(). If IsRunning()
// returns true, it is expected that Stop() will be called before destroying
diff --git a/chromium/media/base/pipeline_impl.cc b/chromium/media/base/pipeline_impl.cc
index 81252cf1238..e1d7be53c5c 100644
--- a/chromium/media/base/pipeline_impl.cc
+++ b/chromium/media/base/pipeline_impl.cc
@@ -5,6 +5,7 @@
#include "media/base/pipeline_impl.h"
#include <algorithm>
+#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
@@ -144,6 +145,7 @@ class PipelineImpl::RendererWrapper : public DemuxerHost,
void OnVideoConfigChange(const VideoDecoderConfig& config) final;
void OnVideoNaturalSizeChange(const gfx::Size& size) final;
void OnVideoOpacityChange(bool opaque) final;
+ void OnVideoFrameRateChange(base::Optional<int> fps) final;
// Common handlers for notifications from renderers and demuxer.
void OnPipelineError(PipelineStatus error);
@@ -297,8 +299,8 @@ void PipelineImpl::RendererWrapper::Start(
// Run tasks.
pending_callbacks_ = SerialRunner::Run(
std::move(fns),
- base::BindRepeating(&RendererWrapper::CompleteSeek,
- weak_factory_.GetWeakPtr(), base::TimeDelta()));
+ base::BindOnce(&RendererWrapper::CompleteSeek, weak_factory_.GetWeakPtr(),
+ base::TimeDelta()));
}
void PipelineImpl::RendererWrapper::Stop() {
@@ -370,8 +372,8 @@ void PipelineImpl::RendererWrapper::Seek(base::TimeDelta time) {
// Run tasks.
pending_callbacks_ = SerialRunner::Run(
std::move(bound_fns),
- base::BindRepeating(&RendererWrapper::CompleteSeek,
- weak_factory_.GetWeakPtr(), seek_timestamp));
+ base::BindOnce(&RendererWrapper::CompleteSeek, weak_factory_.GetWeakPtr(),
+ seek_timestamp));
}
void PipelineImpl::RendererWrapper::Suspend() {
@@ -402,8 +404,8 @@ void PipelineImpl::RendererWrapper::Suspend() {
// No need to flush the renderer since it's going to be destroyed.
pending_callbacks_ = SerialRunner::Run(
- std::move(fns), base::BindRepeating(&RendererWrapper::CompleteSuspend,
- weak_factory_.GetWeakPtr()));
+ std::move(fns), base::BindOnce(&RendererWrapper::CompleteSuspend,
+ weak_factory_.GetWeakPtr()));
}
void PipelineImpl::RendererWrapper::Resume(
@@ -436,8 +438,8 @@ void PipelineImpl::RendererWrapper::Resume(
// Queue the asynchronous actions required to start playback.
SerialRunner::Queue fns;
- fns.Push(base::BindRepeating(&Demuxer::Seek, base::Unretained(demuxer_),
- start_timestamp));
+ fns.Push(base::BindOnce(&Demuxer::Seek, base::Unretained(demuxer_),
+ start_timestamp));
fns.Push(base::BindOnce(&RendererWrapper::CreateRenderer,
weak_factory_.GetWeakPtr()));
@@ -447,8 +449,8 @@ void PipelineImpl::RendererWrapper::Resume(
pending_callbacks_ = SerialRunner::Run(
std::move(fns),
- base::BindRepeating(&RendererWrapper::CompleteSeek,
- weak_factory_.GetWeakPtr(), start_timestamp));
+ base::BindOnce(&RendererWrapper::CompleteSeek, weak_factory_.GetWeakPtr(),
+ start_timestamp));
}
void PipelineImpl::RendererWrapper::SetPlaybackRate(double playback_rate) {
@@ -580,8 +582,7 @@ void PipelineImpl::RendererWrapper::OnBufferedTimeRangesChanged(
void PipelineImpl::RendererWrapper::SetDuration(base::TimeDelta duration) {
// TODO(alokp): Add thread DCHECK after ensuring that all Demuxer
// implementations call DemuxerHost on the media thread.
- media_log_->AddEvent(media_log_->CreateTimeEvent(MediaLogEvent::DURATION_SET,
- "duration", duration));
+ media_log_->AddEvent<MediaLogEvent::kDurationChanged>(duration);
main_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&PipelineImpl::OnDurationChange, weak_pipeline_,
duration));
@@ -602,7 +603,7 @@ void PipelineImpl::RendererWrapper::OnError(PipelineStatus error) {
void PipelineImpl::RendererWrapper::OnEnded() {
DCHECK(media_task_runner_->BelongsToCurrentThread());
- media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::ENDED));
+ media_log_->AddEvent<MediaLogEvent::kEnded>();
if (state_ != kPlaying)
return;
@@ -660,7 +661,7 @@ void PipelineImpl::RendererWrapper::OnEnabledAudioTracksChanged(
enabled_track_ids, GetCurrentTimestamp(),
base::BindOnce(&RendererWrapper::OnDemuxerCompletedTrackChange,
weak_factory_.GetWeakPtr(),
- base::Passed(&change_completed_cb)));
+ std::move(change_completed_cb)));
}
void PipelineImpl::OnSelectedVideoTrackChanged(
@@ -700,7 +701,7 @@ void PipelineImpl::RendererWrapper::OnSelectedVideoTrackChanged(
tracks, GetCurrentTimestamp(),
base::BindOnce(&RendererWrapper::OnDemuxerCompletedTrackChange,
weak_factory_.GetWeakPtr(),
- base::Passed(&change_completed_cb)));
+ std::move(change_completed_cb)));
}
void PipelineImpl::RendererWrapper::OnDemuxerCompletedTrackChange(
@@ -818,6 +819,15 @@ void PipelineImpl::RendererWrapper::OnVideoOpacityChange(bool opaque) {
weak_pipeline_, opaque));
}
+void PipelineImpl::RendererWrapper::OnVideoFrameRateChange(
+ base::Optional<int> fps) {
+ DCHECK(media_task_runner_->BelongsToCurrentThread());
+
+ main_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&PipelineImpl::OnVideoFrameRateChange,
+ weak_pipeline_, fps));
+}
+
void PipelineImpl::RendererWrapper::OnAudioConfigChange(
const AudioDecoderConfig& config) {
DCHECK(media_task_runner_->BelongsToCurrentThread());
@@ -890,7 +900,11 @@ void PipelineImpl::RendererWrapper::SetState(State next_state) {
<< PipelineImpl::GetStateString(next_state);
state_ = next_state;
- media_log_->AddEvent(media_log_->CreatePipelineStateChangedEvent(next_state));
+
+ // TODO(tmathmeyer) Make State serializable so GetStateString won't need
+ // to be called here.
+ media_log_->AddEvent<MediaLogEvent::kPipelineStateChange>(
+ std::string(PipelineImpl::GetStateString(next_state)));
}
void PipelineImpl::RendererWrapper::CompleteSeek(base::TimeDelta seek_time,
@@ -1155,7 +1169,7 @@ PipelineImpl::~PipelineImpl() {
void PipelineImpl::Start(StartType start_type,
Demuxer* demuxer,
Client* client,
- const PipelineStatusCB& seek_cb) {
+ PipelineStatusCallback seek_cb) {
DVLOG(2) << __func__ << ": start_type=" << static_cast<int>(start_type);
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(demuxer);
@@ -1165,7 +1179,7 @@ void PipelineImpl::Start(StartType start_type,
DCHECK(!client_);
DCHECK(!seek_cb_);
client_ = client;
- seek_cb_ = seek_cb;
+ seek_cb_ = std::move(seek_cb);
last_media_time_ = base::TimeDelta();
seek_time_ = kNoTimestamp;
@@ -1216,19 +1230,19 @@ void PipelineImpl::Stop() {
weak_factory_.InvalidateWeakPtrs();
}
-void PipelineImpl::Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb) {
+void PipelineImpl::Seek(base::TimeDelta time, PipelineStatusCallback seek_cb) {
DVLOG(2) << __func__ << " to " << time.InMicroseconds();
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(seek_cb);
if (!IsRunning()) {
DLOG(ERROR) << "Media pipeline isn't running. Ignoring Seek().";
- seek_cb.Run(PIPELINE_ERROR_INVALID_STATE);
+ std::move(seek_cb).Run(PIPELINE_ERROR_INVALID_STATE);
return;
}
DCHECK(!seek_cb_);
- seek_cb_ = seek_cb;
+ seek_cb_ = std::move(seek_cb);
seek_time_ = time;
last_media_time_ = base::TimeDelta();
media_task_runner_->PostTask(
@@ -1237,13 +1251,13 @@ void PipelineImpl::Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb) {
base::Unretained(renderer_wrapper_.get()), time));
}
-void PipelineImpl::Suspend(const PipelineStatusCB& suspend_cb) {
+void PipelineImpl::Suspend(PipelineStatusCallback suspend_cb) {
DVLOG(2) << __func__;
DCHECK(suspend_cb);
DCHECK(IsRunning());
DCHECK(!suspend_cb_);
- suspend_cb_ = suspend_cb;
+ suspend_cb_ = std::move(suspend_cb);
media_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&RendererWrapper::Suspend,
@@ -1251,14 +1265,14 @@ void PipelineImpl::Suspend(const PipelineStatusCB& suspend_cb) {
}
void PipelineImpl::Resume(base::TimeDelta time,
- const PipelineStatusCB& seek_cb) {
+ PipelineStatusCallback seek_cb) {
DVLOG(2) << __func__;
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(seek_cb);
DCHECK(IsRunning());
DCHECK(!seek_cb_);
- seek_cb_ = seek_cb;
+ seek_cb_ = std::move(seek_cb);
seek_time_ = time;
last_media_time_ = base::TimeDelta();
@@ -1531,6 +1545,15 @@ void PipelineImpl::OnVideoOpacityChange(bool opaque) {
client_->OnVideoOpacityChange(opaque);
}
+void PipelineImpl::OnVideoFrameRateChange(base::Optional<int> fps) {
+ DVLOG(2) << __func__;
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(IsRunning());
+
+ DCHECK(client_);
+ client_->OnVideoFrameRateChange(fps);
+}
+
void PipelineImpl::OnAudioConfigChange(const AudioDecoderConfig& config) {
DVLOG(2) << __func__;
DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/chromium/media/base/pipeline_impl.h b/chromium/media/base/pipeline_impl.h
index 0f4a036c45d..101de818805 100644
--- a/chromium/media/base/pipeline_impl.h
+++ b/chromium/media/base/pipeline_impl.h
@@ -92,11 +92,11 @@ class MEDIA_EXPORT PipelineImpl : public Pipeline {
void Start(StartType start_type,
Demuxer* demuxer,
Client* client,
- const PipelineStatusCB& seek_cb) override;
+ PipelineStatusCallback seek_cb) override;
void Stop() override;
- void Seek(base::TimeDelta time, const PipelineStatusCB& seek_cb) override;
- void Suspend(const PipelineStatusCB& suspend_cb) override;
- void Resume(base::TimeDelta time, const PipelineStatusCB& seek_cb) override;
+ void Seek(base::TimeDelta time, PipelineStatusCallback seek_cb) override;
+ void Suspend(PipelineStatusCallback suspend_cb) override;
+ void Resume(base::TimeDelta time, PipelineStatusCallback seek_cb) override;
bool IsRunning() const override;
bool IsSuspended() const override;
double GetPlaybackRate() const override;
@@ -163,6 +163,7 @@ class MEDIA_EXPORT PipelineImpl : public Pipeline {
void OnAudioDecoderChange(const PipelineDecoderInfo& info);
void OnVideoDecoderChange(const PipelineDecoderInfo& info);
void OnRemotePlayStateChange(MediaStatus::State state);
+ void OnVideoFrameRateChange(base::Optional<int> fps);
// Task completion callbacks from RendererWrapper.
void OnSeekDone(bool is_suspended);
@@ -180,10 +181,10 @@ class MEDIA_EXPORT PipelineImpl : public Pipeline {
std::unique_ptr<RendererWrapper> renderer_wrapper_;
// Temporary callback used for Start(), Seek(), and Resume().
- PipelineStatusCB seek_cb_;
+ PipelineStatusCallback seek_cb_;
// Temporary callback used for Suspend().
- PipelineStatusCB suspend_cb_;
+ PipelineStatusCallback suspend_cb_;
// Current playback rate (>= 0.0). This value is set immediately via
// SetPlaybackRate() and a task is dispatched on the task runner to notify
diff --git a/chromium/media/base/pipeline_impl_unittest.cc b/chromium/media/base/pipeline_impl_unittest.cc
index c5897b78633..444f22ca07c 100644
--- a/chromium/media/base/pipeline_impl_unittest.cc
+++ b/chromium/media/base/pipeline_impl_unittest.cc
@@ -176,9 +176,9 @@ class PipelineImplTest : public ::testing::Test {
void StartPipeline(
Pipeline::StartType start_type = Pipeline::StartType::kNormal) {
EXPECT_CALL(callbacks_, OnWaiting(_)).Times(0);
- pipeline_->Start(
- start_type, demuxer_.get(), &callbacks_,
- base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)));
+ pipeline_->Start(start_type, demuxer_.get(), &callbacks_,
+ base::BindOnce(&CallbackHelper::OnStart,
+ base::Unretained(&callbacks_)));
}
void SetRendererPostStartExpectations() {
@@ -250,8 +250,8 @@ class PipelineImplTest : public ::testing::Test {
EXPECT_CALL(*renderer_, OnSetCdm(_, _)).WillOnce(RunOnceCallback<1>(true));
EXPECT_CALL(callbacks_, OnCdmAttached(expected_result));
pipeline_->SetCdm(&cdm_context_,
- base::BindRepeating(&CallbackHelper::OnCdmAttached,
- base::Unretained(&callbacks_)));
+ base::BindOnce(&CallbackHelper::OnCdmAttached,
+ base::Unretained(&callbacks_)));
base::RunLoop().RunUntilIdle();
}
@@ -275,8 +275,8 @@ class PipelineImplTest : public ::testing::Test {
}
void DoSeek(const base::TimeDelta& seek_time) {
- pipeline_->Seek(seek_time, base::Bind(&CallbackHelper::OnSeek,
- base::Unretained(&callbacks_)));
+ pipeline_->Seek(seek_time, base::BindOnce(&CallbackHelper::OnSeek,
+ base::Unretained(&callbacks_)));
base::RunLoop().RunUntilIdle();
}
@@ -287,8 +287,8 @@ class PipelineImplTest : public ::testing::Test {
}
void DoSuspend() {
- pipeline_->Suspend(
- base::Bind(&CallbackHelper::OnSuspend, base::Unretained(&callbacks_)));
+ pipeline_->Suspend(base::BindOnce(&CallbackHelper::OnSuspend,
+ base::Unretained(&callbacks_)));
base::RunLoop().RunUntilIdle();
ResetRenderer();
}
@@ -320,8 +320,8 @@ class PipelineImplTest : public ::testing::Test {
}
void DoResume(const base::TimeDelta& seek_time) {
- pipeline_->Resume(seek_time, base::Bind(&CallbackHelper::OnResume,
- base::Unretained(&callbacks_)));
+ pipeline_->Resume(seek_time, base::BindOnce(&CallbackHelper::OnResume,
+ base::Unretained(&callbacks_)));
base::RunLoop().RunUntilIdle();
}
@@ -546,7 +546,7 @@ TEST_F(PipelineImplTest, EncryptedStream_SetCdmAfterStart) {
.WillOnce(RunClosure(run_loop.QuitClosure()));
pipeline_->Start(
Pipeline::StartType::kNormal, demuxer_.get(), &callbacks_,
- base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)));
+ base::BindOnce(&CallbackHelper::OnStart, base::Unretained(&callbacks_)));
run_loop.Run();
ExpectRendererInitialization();
@@ -584,7 +584,7 @@ TEST_F(PipelineImplTest, SeekAfterError) {
EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_INVALID_STATE));
pipeline_->Seek(
base::TimeDelta::FromMilliseconds(100),
- base::Bind(&CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
+ base::BindOnce(&CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
base::RunLoop().RunUntilIdle();
}
@@ -740,8 +740,8 @@ TEST_F(PipelineImplTest, ErrorDuringSeek) {
.WillOnce(RunOnceCallback<1>(PIPELINE_ERROR_READ));
EXPECT_CALL(*demuxer_, Stop());
- pipeline_->Seek(seek_time, base::Bind(&CallbackHelper::OnSeek,
- base::Unretained(&callbacks_)));
+ pipeline_->Seek(seek_time, base::BindOnce(&CallbackHelper::OnSeek,
+ base::Unretained(&callbacks_)));
EXPECT_CALL(callbacks_, OnSeek(PIPELINE_ERROR_READ))
.WillOnce(Stop(pipeline_.get()));
base::RunLoop().RunUntilIdle();
@@ -822,8 +822,8 @@ TEST_F(PipelineImplTest, GetMediaTimeAfterSeek) {
// notified of the seek (via media thread).
base::TimeDelta kSeekTime = kMediaTime - base::TimeDelta::FromSeconds(1);
ExpectSeek(kSeekTime, false);
- pipeline_->Seek(kSeekTime, base::Bind(&CallbackHelper::OnSeek,
- base::Unretained(&callbacks_)));
+ pipeline_->Seek(kSeekTime, base::BindOnce(&CallbackHelper::OnSeek,
+ base::Unretained(&callbacks_)));
// Verify pipeline returns the seek time in spite of renderer returning the
// stale media time.
@@ -997,7 +997,7 @@ class PipelineTeardownTest : public PipelineImplTest {
pipeline_->Seek(
base::TimeDelta::FromSeconds(10),
- base::Bind(&CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
+ base::BindOnce(&CallbackHelper::OnSeek, base::Unretained(&callbacks_)));
base::RunLoop().RunUntilIdle();
}
diff --git a/chromium/media/base/player_tracker.h b/chromium/media/base/player_tracker.h
index 57c59ab5bfd..8c7bf35f9f5 100644
--- a/chromium/media/base/player_tracker.h
+++ b/chromium/media/base/player_tracker.h
@@ -22,8 +22,8 @@ class MEDIA_EXPORT PlayerTracker {
// - |cdm_unset_cb| is fired when the CDM is detached from the player. The
// player should stop using the CDM and release any ref-count to the CDM.
// Returns a registration ID which can be used to unregister a player.
- virtual int RegisterPlayer(const base::Closure& new_key_cb,
- const base::Closure& cdm_unset_cb) = 0;
+ virtual int RegisterPlayer(base::RepeatingClosure new_key_cb,
+ base::RepeatingClosure cdm_unset_cb) = 0;
// Unregisters a previously registered player. This should be called when
// the CDM is detached from the player (e.g. setMediaKeys(0)), or when the
diff --git a/chromium/media/base/provision_fetcher.h b/chromium/media/base/provision_fetcher.h
index ed08751078a..e63b4786be2 100644
--- a/chromium/media/base/provision_fetcher.h
+++ b/chromium/media/base/provision_fetcher.h
@@ -34,7 +34,8 @@ class ProvisionFetcher {
ResponseCB response_cb) = 0;
};
-using CreateFetcherCB = base::Callback<std::unique_ptr<ProvisionFetcher>()>;
+using CreateFetcherCB =
+ base::RepeatingCallback<std::unique_ptr<ProvisionFetcher>()>;
} // namespace media
diff --git a/chromium/media/base/renderer_client.h b/chromium/media/base/renderer_client.h
index 249c5ee76da..f11f2132430 100644
--- a/chromium/media/base/renderer_client.h
+++ b/chromium/media/base/renderer_client.h
@@ -54,6 +54,11 @@ class MEDIA_EXPORT RendererClient {
// TODO(crbug.com/988535): Used by AudioRendererImpl. This can be removed
// when the bug is resolved.
virtual bool IsVideoStreamAvailable();
+
+ // Called when the bucketed frames per second has changed. |fps| will be
+ // unset if the frame rate is unstable. The duration used for the frame rate
+ // is based on the wall clock time, not the media time.
+ virtual void OnVideoFrameRateChange(base::Optional<int> fps) = 0;
};
} // namespace media
diff --git a/chromium/media/base/renderer_factory.h b/chromium/media/base/renderer_factory.h
index d362347e412..1001d7e0ff0 100644
--- a/chromium/media/base/renderer_factory.h
+++ b/chromium/media/base/renderer_factory.h
@@ -41,7 +41,7 @@ class MEDIA_EXPORT RendererFactory {
const scoped_refptr<base::TaskRunner>& worker_task_runner,
AudioRendererSink* audio_renderer_sink,
VideoRendererSink* video_renderer_sink,
- const RequestOverlayInfoCB& request_overlay_info_cb,
+ RequestOverlayInfoCB request_overlay_info_cb,
const gfx::ColorSpace& target_color_space) = 0;
// Returns the MediaResource::Type that should be used with the renderers
diff --git a/chromium/media/base/renderer_factory_selector_unittest.cc b/chromium/media/base/renderer_factory_selector_unittest.cc
index e93e8bbd2d4..c4900ab51e8 100644
--- a/chromium/media/base/renderer_factory_selector_unittest.cc
+++ b/chromium/media/base/renderer_factory_selector_unittest.cc
@@ -25,7 +25,7 @@ class RendererFactorySelectorTest : public testing::Test {
const scoped_refptr<base::TaskRunner>& worker_task_runner,
AudioRendererSink* audio_renderer_sink,
VideoRendererSink* video_renderer_sink,
- const RequestOverlayInfoCB& request_overlay_info_cb,
+ RequestOverlayInfoCB request_overlay_info_cb,
const gfx::ColorSpace& target_color_space) override {
return nullptr;
}
diff --git a/chromium/media/base/serial_runner.cc b/chromium/media/base/serial_runner.cc
index 176a9c9f722..3bc61077257 100644
--- a/chromium/media/base/serial_runner.cc
+++ b/chromium/media/base/serial_runner.cc
@@ -103,9 +103,9 @@ void SerialRunner::RunNextInSeries(PipelineStatus last_status) {
BoundPipelineStatusCallback bound_fn = bound_fns_.Pop();
std::move(bound_fn).Run(
- base::BindRepeating(&RunOnTaskRunner, task_runner_,
- base::BindRepeating(&SerialRunner::RunNextInSeries,
- weak_factory_.GetWeakPtr())));
+ base::BindOnce(&RunOnTaskRunner, task_runner_,
+ base::BindRepeating(&SerialRunner::RunNextInSeries,
+ weak_factory_.GetWeakPtr())));
}
} // namespace media
diff --git a/chromium/media/base/serial_runner_unittest.cc b/chromium/media/base/serial_runner_unittest.cc
index f619951a8be..4d7b4435b6a 100644
--- a/chromium/media/base/serial_runner_unittest.cc
+++ b/chromium/media/base/serial_runner_unittest.cc
@@ -100,10 +100,9 @@ class SerialRunnerTest : public ::testing::Test {
void StartRunnerInternal(SerialRunner::Queue bound_fns) {
inside_start_ = true;
- runner_ =
- SerialRunner::Run(std::move(bound_fns),
- base::BindRepeating(&SerialRunnerTest::DoneCallback,
- base::Unretained(this)));
+ runner_ = SerialRunner::Run(std::move(bound_fns),
+ base::BindOnce(&SerialRunnerTest::DoneCallback,
+ base::Unretained(this)));
inside_start_ = false;
}
diff --git a/chromium/media/base/silent_sink_suspender_unittest.cc b/chromium/media/base/silent_sink_suspender_unittest.cc
index e6b2c851c47..3d8316bedfc 100644
--- a/chromium/media/base/silent_sink_suspender_unittest.cc
+++ b/chromium/media/base/silent_sink_suspender_unittest.cc
@@ -2,19 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "media/base/silent_sink_suspender.h"
+
#include "base/run_loop.h"
+#include "base/test/gmock_callback_support.h"
#include "base/test/test_message_loop.h"
#include "media/base/fake_audio_render_callback.h"
#include "media/base/mock_audio_renderer_sink.h"
-#include "media/base/silent_sink_suspender.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace media {
+using base::test::RunClosure;
-ACTION_P(RunClosure, closure) {
- closure.Run();
-}
+namespace media {
class SilentSinkSuspenderTest : public testing::Test {
public:
@@ -184,4 +184,4 @@ TEST_F(SilentSinkSuspenderTest, MultipleResume) {
0);
}
-} // namespace content
+} // namespace media
diff --git a/chromium/media/base/sinc_resampler.cc b/chromium/media/base/sinc_resampler.cc
index b3dd4fd7fcc..d9965ca9ec2 100644
--- a/chromium/media/base/sinc_resampler.cc
+++ b/chromium/media/base/sinc_resampler.cc
@@ -310,6 +310,14 @@ void SincResampler::Flush() {
UpdateRegions(false);
}
+int SincResampler::GetMaxInputFramesRequested(
+ int output_frames_requested) const {
+ const int num_chunks = static_cast<int>(
+ std::ceil(static_cast<float>(output_frames_requested) / chunk_size_));
+
+ return num_chunks * request_frames_;
+}
+
double SincResampler::BufferedFrames() const {
return buffer_primed_ ? request_frames_ - virtual_source_idx_ : 0;
}
diff --git a/chromium/media/base/sinc_resampler.h b/chromium/media/base/sinc_resampler.h
index 42e2161257a..b8f42d691a2 100644
--- a/chromium/media/base/sinc_resampler.h
+++ b/chromium/media/base/sinc_resampler.h
@@ -61,6 +61,10 @@ class MEDIA_EXPORT SincResampler {
// kKernelSize / (2 * io_sample_rate_ratio). See the .cc file for details.
int ChunkSize() const { return chunk_size_; }
+ // Returns the max number of frames that could be requested (via multiple
+ // calls to |read_cb_|) during one Resample(|output_frames_requested|) call.
+ int GetMaxInputFramesRequested(int output_frames_requested) const;
+
// Guarantees that ChunkSize() will not change between calls by initializing
// the input buffer with silence. Note, this will cause the first few samples
// of output to be biased towards silence. Must be called again after Flush().
diff --git a/chromium/media/base/sinc_resampler_unittest.cc b/chromium/media/base/sinc_resampler_unittest.cc
index d10b5f0e1a6..0197ffdec6d 100644
--- a/chromium/media/base/sinc_resampler_unittest.cc
+++ b/chromium/media/base/sinc_resampler_unittest.cc
@@ -408,4 +408,46 @@ INSTANTIATE_TEST_SUITE_P(
std::make_tuple(96000, 192000, kResamplingRMSError, -73.52),
std::make_tuple(192000, 192000, kResamplingRMSError, -73.52)));
+// Verify the resampler properly reports the max number of input frames it would
+// request.
+TEST(SincResamplerTest, GetMaxInputFramesRequestedTest) {
+ SincResampler resampler(kSampleRateRatio, SincResampler::kDefaultRequestSize,
+ SincResampler::ReadCB());
+
+ EXPECT_EQ(SincResampler::kDefaultRequestSize,
+ resampler.GetMaxInputFramesRequested(resampler.ChunkSize()));
+
+ // Request sizes smaller than ChunkSize should still trigger 1 read.
+ EXPECT_EQ(SincResampler::kDefaultRequestSize,
+ resampler.GetMaxInputFramesRequested(resampler.ChunkSize() - 10));
+
+ // Request sizes bigger than ChunkSize can trigger multiple reads.
+ EXPECT_EQ(2 * SincResampler::kDefaultRequestSize,
+ resampler.GetMaxInputFramesRequested(resampler.ChunkSize() + 10));
+
+ // The number of input frames requested should grow proportionally to the
+ // output frames requested.
+ EXPECT_EQ(
+ 5 * SincResampler::kDefaultRequestSize,
+ resampler.GetMaxInputFramesRequested(4 * resampler.ChunkSize() + 10));
+
+ const int kCustomRequestSize = SincResampler::kDefaultRequestSize + 128;
+ SincResampler custom_size_resampler(kSampleRateRatio, kCustomRequestSize,
+ SincResampler::ReadCB());
+
+ // The input frames requested should be a multiple of the request size.
+ EXPECT_EQ(2 * kCustomRequestSize,
+ custom_size_resampler.GetMaxInputFramesRequested(
+ custom_size_resampler.ChunkSize() + 10));
+
+ // Verify we get results with both downsampling and upsampling ratios.
+ SincResampler inverse_ratio_resampler(1.0 / kSampleRateRatio,
+ SincResampler::kDefaultRequestSize,
+ SincResampler::ReadCB());
+
+ EXPECT_EQ(2 * SincResampler::kDefaultRequestSize,
+ inverse_ratio_resampler.GetMaxInputFramesRequested(
+ inverse_ratio_resampler.ChunkSize() + 10));
+}
+
} // namespace media
diff --git a/chromium/media/base/speech_recognition_client.h b/chromium/media/base/speech_recognition_client.h
new file mode 100644
index 00000000000..1290cd88c25
--- /dev/null
+++ b/chromium/media/base/speech_recognition_client.h
@@ -0,0 +1,28 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_BASE_SPEECH_RECOGNITION_CLIENT_H_
+#define MEDIA_BASE_SPEECH_RECOGNITION_CLIENT_H_
+
+#include <memory>
+
+#include "media/base/audio_buffer.h"
+#include "media/base/media_export.h"
+
+namespace media {
+
+// The interface for the speech recognition client used to transcribe audio into
+// captions.
+class MEDIA_EXPORT SpeechRecognitionClient {
+ public:
+ virtual ~SpeechRecognitionClient() = default;
+
+ virtual void AddAudio(scoped_refptr<AudioBuffer> buffer) = 0;
+
+ virtual bool IsSpeechRecognitionAvailable() = 0;
+};
+
+} // namespace media
+
+#endif // MEDIA_BASE_SPEECH_RECOGNITION_CLIENT_H_
diff --git a/chromium/media/base/status.cc b/chromium/media/base/status.cc
new file mode 100644
index 00000000000..003b6575330
--- /dev/null
+++ b/chromium/media/base/status.cc
@@ -0,0 +1,76 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/base/status.h"
+
+#include <memory>
+#include "media/base/media_serializers.h"
+
+namespace media {
+
+Status::Status() = default;
+
+Status::Status(StatusCode code,
+ base::StringPiece message,
+ const base::Location& location) {
+ DCHECK(code != StatusCode::kOk);
+ data_ = std::make_unique<StatusInternal>(code, message.as_string());
+ AddFrame(location);
+}
+
+// Copy Constructor
+Status::Status(const Status& copy) {
+ *this = copy;
+}
+
+Status& Status::operator=(const Status& copy) {
+ if (copy.is_ok()) {
+ data_.reset();
+ return *this;
+ }
+
+ data_ = std::make_unique<StatusInternal>(copy.code(), copy.message());
+ for (const base::Value& frame : copy.data_->frames)
+ data_->frames.push_back(frame.Clone());
+ for (const Status& err : copy.data_->causes)
+ data_->causes.push_back(err);
+ data_->data = copy.data_->data.Clone();
+ return *this;
+}
+
+// Allow move.
+Status::Status(Status&&) = default;
+Status& Status::operator=(Status&&) = default;
+
+Status::~Status() = default;
+
+Status::StatusInternal::StatusInternal(StatusCode code, std::string message)
+ : code(code),
+ message(std::move(message)),
+ data(base::Value(base::Value::Type::DICTIONARY)) {}
+
+Status::StatusInternal::~StatusInternal() = default;
+
+Status&& Status::AddHere(const base::Location& location) && {
+ DCHECK(data_);
+ AddFrame(location);
+ return std::move(*this);
+}
+
+Status&& Status::AddCause(Status&& cause) && {
+ DCHECK(data_ && cause.data_);
+ data_->causes.push_back(std::move(cause));
+ return std::move(*this);
+}
+
+void Status::AddFrame(const base::Location& location) {
+ DCHECK(data_);
+ data_->frames.push_back(MediaSerialize(location));
+}
+
+Status OkStatus() {
+ return Status();
+}
+
+} // namespace media
diff --git a/chromium/media/base/status.h b/chromium/media/base/status.h
new file mode 100644
index 00000000000..c06635b27a8
--- /dev/null
+++ b/chromium/media/base/status.h
@@ -0,0 +1,214 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_BASE_STATUS_H_
+#define MEDIA_BASE_STATUS_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/location.h"
+#include "base/strings/string_piece.h"
+#include "base/values.h"
+#include "media/base/media_export.h"
+#include "media/base/media_serializers_base.h"
+#include "media/base/status_codes.h"
+
+// Mojo namespaces for serialization friend declarations.
+namespace mojo {
+template <typename T, typename U>
+struct StructTraits;
+} // namespace mojo
+
+namespace media {
+
+namespace mojom {
+class StatusDataView;
+}
+
+// Status is meant to be a relatively small (sizeof(void*) bytes) object
+// that can be returned as a status value from functions or passed to callbacks
+// that want a report of status. Status allows attaching of arbitrary named
+// data, other Status' as causes, and stack frames, which can all be logged
+// and reported throughout the media stack. The status code and message are
+// immutable and can be used to give a stable numeric ID for any error
+// generated by media code.
+// There is also an OK state which can't hold any data and is only for
+// successful returns.
+class MEDIA_EXPORT Status {
+ public:
+ // Default constructor can be used for OkStatus();
+ Status();
+
+ // Constructor to create a new Status from a numeric code & message.
+ // These are immutable; if you'd like to change them, then you likely should
+ // create a new Status. {} or OkStatus() should be used to create a
+ // success status.
+ // NOTE: This should never be given a location parameter when called - It is
+ // defaulted in order to grab the caller location.
+ Status(StatusCode code,
+ base::StringPiece message = "",
+ const base::Location& location = base::Location::Current());
+
+ // Copy Constructor & assignment. (Mojo uses both of these)
+ Status(const Status&);
+ Status& operator=(const Status&);
+
+ // Allows move.
+ Status(Status&&);
+ Status& operator=(Status&&);
+
+ // Needs an out of line destructor...
+ ~Status();
+
+ bool is_ok() const { return !data_; }
+
+ // Getters for internal fields
+ const std::string& message() const {
+ DCHECK(data_);
+ return data_->message;
+ }
+
+ StatusCode code() const { return data_ ? data_->code : StatusCode::kOk; }
+
+ // Adds the current location to Status as it’s passed upwards.
+ // This does not need to be called at every location that touches it, but
+ // should be called for those locations where the path is ambiguous or
+ // critical. This can be especially helpful across IPC boundaries. This will
+ // fail on an OK status.
+ // NOTE: This should never be given a parameter when called - It is defaulted
+ // in order to grab the caller location.
+ Status&& AddHere(
+ const base::Location& location = base::Location::Current()) &&;
+
+ // Add |cause| as the error that triggered this one. For example,
+ // DecoderStream might return kDecoderSelectionFailed with one or more causes
+ // that are the specific errors from the decoders that it tried.
+ Status&& AddCause(Status&& cause) &&;
+ void AddCause(Status&& cause) &;
+
+ // Allows us to append any datatype which can be converted to
+ // an int/bool/string/base::Value. Any existing data associated with |key|
+ // will be overwritten by |value|. This will fail on an OK status.
+ template <typename T>
+ Status&& WithData(const char* key, const T& value) && {
+ DCHECK(data_);
+ data_->data.SetKey(key, MediaSerialize(value));
+ return std::move(*this);
+ }
+
+ template <typename T>
+ void WithData(const char* key, const T& value) & {
+ DCHECK(data_);
+ data_->data.SetKey(key, MediaSerialize(value));
+ }
+
+ private:
+ // Private helper to add the current stack frame to the error trace.
+ void AddFrame(const base::Location& location);
+
+ // Keep the internal data in a unique ptr to minimize size of OK errors.
+ struct MEDIA_EXPORT StatusInternal {
+ StatusInternal(StatusCode code, std::string message);
+ ~StatusInternal();
+
+ // The current error code
+ StatusCode code = StatusCode::kOk;
+
+ // The current error message (Can be used for
+ // https://developer.mozilla.org/en-US/docs/Web/API/Status)
+ std::string message;
+
+ // Stack frames
+ std::vector<base::Value> frames;
+
+ // Causes
+ std::vector<Status> causes;
+
+ // Data attached to the error
+ base::Value data;
+ };
+
+ // Allow self-serialization
+ friend struct internal::MediaSerializer<Status>;
+
+ // Allow mojo-serialization
+ friend struct mojo::StructTraits<media::mojom::StatusDataView, Status>;
+
+ // A null internals is an implicit OK.
+ std::unique_ptr<StatusInternal> data_;
+};
+
+// Convenience function to return |kOk|.
+// OK won't have a message, trace, or data associated with them, and DCHECK
+// if they are added.
+MEDIA_EXPORT Status OkStatus();
+
+// Helper class to allow returning a |T| or a Status. Typical usage:
+//
+// ErrorOr<std::unique_ptr<MyObject>> FactoryFn() {
+// if (success)
+// return std::make_unique<MyObject>();
+// return Status(StatusCodes::kSomethingBadHappened);
+// }
+//
+// auto result = FactoryFn();
+// if (result.has_error()) return std::move(result.error());
+// my_object_ = std::move(result.value());
+//
+// Also useful if one would like to get an enum class return value, unless an
+// error occurs:
+//
+// enum class ResultType { kNeedMoreInput, kOutputIsReady, kFormatChanged };
+//
+// ErrorOr<ResultType> Foo() { ... }
+//
+// auto result = Foo();
+// if (result.has_error()) return std::move(result.error());
+// switch (result.value()) {
+// case ResultType::kNeedMoreInput:
+// ...
+// }
+template <typename T>
+class ErrorOr {
+ public:
+ // All of these may be implicit, so that one may just return Status or
+ // the value in question.
+ ErrorOr(Status&& error) : error_(std::move(error)) {}
+ ErrorOr(const Status& error) : error_(error) {}
+ ErrorOr(T&& value) : value_(std::move(value)) {}
+ ErrorOr(const T& value) : value_(value) {}
+
+ ~ErrorOr() = default;
+
+ // Move- and copy- construction and assignment are okay.
+ ErrorOr(const ErrorOr&) = default;
+ ErrorOr(ErrorOr&&) = default;
+ ErrorOr& operator=(ErrorOr&) = default;
+ ErrorOr& operator=(ErrorOr&&) = default;
+
+ // Do we have a value?
+ bool has_value() const { return value_.has_value(); }
+
+ // Since we often test for errors, provide this too.
+ bool has_error() const { return !has_value(); }
+
+ // Return the error, if we have one. Up to the caller to make sure that we
+ // have one via |!has_value()|.
+ Status& error() { return *error_; }
+
+ // Return a ref to the value. It's up to the caller to verify that we have a
+ // value before calling this.
+ T& value() { return *value_; }
+
+ private:
+ base::Optional<Status> error_;
+ base::Optional<T> value_;
+};
+
+} // namespace media
+
+#endif // MEDIA_BASE_STATUS_H_
diff --git a/chromium/media/base/status_codes.cc b/chromium/media/base/status_codes.cc
new file mode 100644
index 00000000000..2aba1c20da3
--- /dev/null
+++ b/chromium/media/base/status_codes.cc
@@ -0,0 +1,15 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/base/status_codes.h"
+
+namespace media {
+
+// TODO(tmathmeyer) consider a way to get the names, since we don't have
+// the easy c++20 way yet.
+std::ostream& operator<<(std::ostream& os, const StatusCode& code) {
+ return os << std::hex << static_cast<StatusCodeType>(code);
+}
+
+} // namespace media
diff --git a/chromium/media/base/status_codes.h b/chromium/media/base/status_codes.h
new file mode 100644
index 00000000000..3f161c20316
--- /dev/null
+++ b/chromium/media/base/status_codes.h
@@ -0,0 +1,81 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_BASE_STATUS_CODES_H_
+#define MEDIA_BASE_STATUS_CODES_H_
+
+#include <cstdint>
+#include <limits>
+#include <ostream>
+
+#include "media/base/media_export.h"
+
+namespace media {
+
+using StatusCodeType = int32_t;
+// TODO(tmathmeyer, liberato, xhwang) These numbers are not yet finalized:
+// DO NOT use them for reporting statistics, and DO NOT report them to any
+// user-facing feature, including media log.
+
+// Codes are grouped with a bitmask:
+// 0xFFFFFFFF
+// └─┬┘├┘└┴ enumeration within the group
+// │ └─ group code
+// └─ reserved for now
+// 256 groups is more than anyone will ever need on a computer.
+enum class StatusCode : StatusCodeType {
+ kOk = 0,
+
+ // Decoder Errors: 0x01
+ kDecoderInitializeNeverCompleted = 0x00000101,
+ kDecoderFailedDecode = 0x00000102,
+ kDecoderUnsupportedProfile = 0x00000103,
+ kDecoderUnsupportedCodec = 0x00000104,
+ kDecoderUnsupportedConfig = 0x00000105,
+ kEncryptedContentUnsupported = 0x00000106,
+ kClearContentUnsupported = 0x00000107,
+ kDecoderMissingCdmForEncryptedContent = 0x00000108,
+ kDecoderFailedInitialization = 0x00000109,
+ kDecoderCantChangeCodec = 0x0000010A,
+ kDecoderFailedCreation = 0x0000010B,
+ kInitializationUnspecifiedFailure = 0x0000010C,
+
+ // Windows Errors: 0x02
+ kWindowsWrappedHresult = 0x00000201,
+ kWindowsApiNotAvailible = 0x00000202,
+
+ // D3D11VideoDecoder Errors: 0x03
+ kCantMakeContextCurrent = 0x00000301,
+ kCantPostTexture = 0x00000302,
+ kCantPostAcquireStream = 0x00000303,
+
+ // MojoDecoder Errors: 0x04
+ kMojoDecoderNoWrappedDecoder = 0x00000401,
+ kMojoDecoderStoppedBeforeInitDone = 0x00000402,
+ kMojoDecoderUnsupported = 0x00000403,
+ kMojoDecoderNoConnection = 0x00000404,
+ kMojoDecoderDeletedWithoutInitialization = 0x00000405,
+
+ // Chromeos Errors: 0x05
+ kChromeOSVideoDecoderNoDecoders = 0x00000501,
+ kV4l2NoDevice = 0x00000502,
+ kV4l2FailedToStopStreamQueue = 0x00000503,
+ kV4l2NoDecoder = 0x00000504,
+ kV4l2FailedFileCapabilitiesCheck = 0x00000505,
+ kV4l2FailedResourceAllocation = 0x00000506,
+ kV4l2BadFormat = 0x00000507,
+ kVaapiReinitializedDuringDecode = 0x00000508,
+ kVaapiFailedAcceleratorCreation = 0x00000509,
+
+ // Special codes
+ kGenericErrorPleaseRemove = 0x79999999,
+ kCodeOnlyForTesting = std::numeric_limits<StatusCodeType>::max(),
+ kMaxValue = kCodeOnlyForTesting,
+};
+
+MEDIA_EXPORT std::ostream& operator<<(std::ostream& os, const StatusCode& code);
+
+} // namespace media
+
+#endif // MEDIA_BASE_STATUS_CODES_H_
diff --git a/chromium/media/base/status_unittest.cc b/chromium/media/base/status_unittest.cc
new file mode 100644
index 00000000000..b9e6604c7ac
--- /dev/null
+++ b/chromium/media/base/status_unittest.cc
@@ -0,0 +1,246 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <sstream>
+#include <string>
+
+#include "base/json/json_writer.h"
+#include "base/macros.h"
+#include "media/base/media_serializers.h"
+#include "media/base/status.h"
+#include "media/base/test_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::HasSubstr;
+
+namespace media {
+
+class UselessThingToBeSerialized {
+ public:
+ explicit UselessThingToBeSerialized(const char* name) : name_(name) {}
+ const char* name_;
+};
+
+namespace internal {
+
+template <>
+struct MediaSerializer<UselessThingToBeSerialized> {
+ static base::Value Serialize(const UselessThingToBeSerialized& t) {
+ return base::Value(t.name_);
+ }
+};
+
+} // namespace internal
+
+// Friend class of MediaLog for access to internal constants.
+class StatusTest : public testing::Test {
+ public:
+ Status DontFail() { return OkStatus(); }
+
+ Status FailEasily() {
+ return Status(StatusCode::kCodeOnlyForTesting, "Message");
+ }
+
+ Status FailRecursively(unsigned int count) {
+ if (!count) {
+ return FailEasily();
+ }
+ return FailRecursively(count - 1).AddHere();
+ }
+
+ template <typename T>
+ Status FailWithData(const char* key, const T& t) {
+ return Status(StatusCode::kCodeOnlyForTesting, "Message", FROM_HERE)
+ .WithData(key, t);
+ }
+
+ Status FailWithCause() {
+ Status err = FailEasily();
+ return FailEasily().AddCause(std::move(err));
+ }
+
+ Status DoSomethingGiveItBack(Status me) {
+ me.WithData("data", "Hey you! psst! Help me outta here! I'm trapped!");
+ return me;
+ }
+
+ // Make sure that the typical usage of ErrorOr actually compiles.
+ ErrorOr<std::unique_ptr<int>> TypicalErrorOrUsage(bool succeed) {
+ if (succeed)
+ return std::make_unique<int>(123);
+ return Status(StatusCode::kCodeOnlyForTesting);
+ }
+};
+
+TEST_F(StatusTest, StaticOKMethodGivesCorrectSerialization) {
+ Status ok = DontFail();
+ base::Value actual = MediaSerialize(ok);
+ ASSERT_EQ(actual.GetString(), "Ok");
+}
+
+TEST_F(StatusTest, SingleLayerError) {
+ Status failed = FailEasily();
+ base::Value actual = MediaSerialize(failed);
+ ASSERT_EQ(actual.DictSize(), 5ul);
+ ASSERT_EQ(actual.FindIntPath("status_code"),
+ static_cast<int32_t>(StatusCode::kCodeOnlyForTesting));
+ ASSERT_EQ(*actual.FindStringPath("status_message"), "Message");
+ ASSERT_EQ(actual.FindListPath("stack")->GetList().size(), 1ul);
+ ASSERT_EQ(actual.FindListPath("causes")->GetList().size(), 0ul);
+ ASSERT_EQ(actual.FindDictPath("data")->DictSize(), 0ul);
+
+ const auto& stack = actual.FindListPath("stack")->GetList();
+ ASSERT_EQ(stack[0].DictSize(), 2ul); // line and file
+
+ // This is a bit fragile, since it's dependent on the file layout.
+ ASSERT_EQ(stack[0].FindIntPath("line").value_or(-1), 42);
+ ASSERT_THAT(*stack[0].FindStringPath("file"),
+ HasSubstr("status_unittest.cc"));
+}
+
+TEST_F(StatusTest, MultipleErrorLayer) {
+ Status failed = FailRecursively(3);
+ base::Value actual = MediaSerialize(failed);
+ ASSERT_EQ(actual.DictSize(), 5ul);
+ ASSERT_EQ(actual.FindIntPath("status_code").value_or(-1),
+ static_cast<int32_t>(StatusCode::kCodeOnlyForTesting));
+ ASSERT_EQ(*actual.FindStringPath("status_message"), "Message");
+ ASSERT_EQ(actual.FindListPath("stack")->GetList().size(), 4ul);
+ ASSERT_EQ(actual.FindListPath("causes")->GetList().size(), 0ul);
+ ASSERT_EQ(actual.FindDictPath("data")->DictSize(), 0ul);
+
+ const auto& stack = actual.FindListPath("stack")->GetList();
+ ASSERT_EQ(stack[0].DictSize(), 2ul); // line and file
+}
+
+TEST_F(StatusTest, CanHaveData) {
+ Status failed = FailWithData("example", "data");
+ base::Value actual = MediaSerialize(failed);
+ ASSERT_EQ(actual.DictSize(), 5ul);
+ ASSERT_EQ(actual.FindIntPath("status_code").value_or(-1),
+ static_cast<int32_t>(StatusCode::kCodeOnlyForTesting));
+ ASSERT_EQ(*actual.FindStringPath("status_message"), "Message");
+ ASSERT_EQ(actual.FindListPath("stack")->GetList().size(), 1ul);
+ ASSERT_EQ(actual.FindListPath("causes")->GetList().size(), 0ul);
+ ASSERT_EQ(actual.FindDictPath("data")->DictSize(), 1ul);
+
+ const auto& stack = actual.FindListPath("stack")->GetList();
+ ASSERT_EQ(stack[0].DictSize(), 2ul); // line and file
+
+ ASSERT_EQ(*actual.FindDictPath("data")->FindStringPath("example"), "data");
+}
+
+TEST_F(StatusTest, CanUseCustomSerializer) {
+ Status failed = FailWithData("example", UselessThingToBeSerialized("F"));
+ base::Value actual = MediaSerialize(failed);
+ ASSERT_EQ(actual.DictSize(), 5ul);
+ ASSERT_EQ(actual.FindIntPath("status_code"),
+ static_cast<int32_t>(StatusCode::kCodeOnlyForTesting));
+ ASSERT_EQ(*actual.FindStringPath("status_message"), "Message");
+ ASSERT_EQ(actual.FindListPath("stack")->GetList().size(), 1ul);
+ ASSERT_EQ(actual.FindListPath("causes")->GetList().size(), 0ul);
+ ASSERT_EQ(actual.FindDictPath("data")->DictSize(), 1ul);
+
+ const auto& stack = actual.FindListPath("stack")->GetList();
+ ASSERT_EQ(stack[0].DictSize(), 2ul); // line and file
+
+ ASSERT_EQ(*actual.FindDictPath("data")->FindStringPath("example"), "F");
+}
+
+TEST_F(StatusTest, CausedByHasVector) {
+ Status causal = FailWithCause();
+ base::Value actual = MediaSerialize(causal);
+ ASSERT_EQ(actual.DictSize(), 5ul);
+ ASSERT_EQ(actual.FindIntPath("status_code").value_or(-1),
+ static_cast<int32_t>(StatusCode::kCodeOnlyForTesting));
+ ASSERT_EQ(*actual.FindStringPath("status_message"), "Message");
+ ASSERT_EQ(actual.FindListPath("stack")->GetList().size(), 1ul);
+ ASSERT_EQ(actual.FindListPath("causes")->GetList().size(), 1ul);
+ ASSERT_EQ(actual.FindDictPath("data")->DictSize(), 0ul);
+
+ base::Value& nested = actual.FindListPath("causes")->GetList()[0];
+ ASSERT_EQ(nested.DictSize(), 5ul);
+ ASSERT_EQ(nested.FindIntPath("status_code").value_or(-1),
+ static_cast<int32_t>(StatusCode::kCodeOnlyForTesting));
+ ASSERT_EQ(*nested.FindStringPath("status_message"), "Message");
+ ASSERT_EQ(nested.FindListPath("stack")->GetList().size(), 1ul);
+ ASSERT_EQ(nested.FindListPath("causes")->GetList().size(), 0ul);
+ ASSERT_EQ(nested.FindDictPath("data")->DictSize(), 0ul);
+}
+
+TEST_F(StatusTest, CanCopyEasily) {
+ Status failed = FailEasily();
+ Status withData = DoSomethingGiveItBack(failed);
+
+ base::Value actual = MediaSerialize(failed);
+ ASSERT_EQ(actual.DictSize(), 5ul);
+ ASSERT_EQ(actual.FindIntPath("status_code"),
+ static_cast<int32_t>(StatusCode::kCodeOnlyForTesting));
+ ASSERT_EQ(*actual.FindStringPath("status_message"), "Message");
+ ASSERT_EQ(actual.FindListPath("stack")->GetList().size(), 1ul);
+ ASSERT_EQ(actual.FindListPath("causes")->GetList().size(), 0ul);
+ ASSERT_EQ(actual.FindDictPath("data")->DictSize(), 0ul);
+
+ actual = MediaSerialize(withData);
+ ASSERT_EQ(actual.DictSize(), 5ul);
+ ASSERT_EQ(actual.FindIntPath("status_code"),
+ static_cast<int32_t>(StatusCode::kCodeOnlyForTesting));
+ ASSERT_EQ(*actual.FindStringPath("status_message"), "Message");
+ ASSERT_EQ(actual.FindListPath("stack")->GetList().size(), 1ul);
+ ASSERT_EQ(actual.FindListPath("causes")->GetList().size(), 0ul);
+ ASSERT_EQ(actual.FindDictPath("data")->DictSize(), 1ul);
+}
+
+TEST_F(StatusTest, ErrorOrTypicalUsage) {
+ // Mostly so we have some code coverage on the default usage.
+ EXPECT_TRUE(TypicalErrorOrUsage(true).has_value());
+ EXPECT_FALSE(TypicalErrorOrUsage(true).has_error());
+ EXPECT_FALSE(TypicalErrorOrUsage(false).has_value());
+ EXPECT_TRUE(TypicalErrorOrUsage(false).has_error());
+}
+
+TEST_F(StatusTest, ErrorOrWithMoveOnlyType) {
+ ErrorOr<std::unique_ptr<int>> error_or(std::make_unique<int>(123));
+ EXPECT_TRUE(error_or.has_value());
+ EXPECT_FALSE(error_or.has_error());
+ std::unique_ptr<int> result = std::move(error_or.value());
+ EXPECT_EQ(error_or.value(), nullptr);
+ EXPECT_NE(result.get(), nullptr);
+ EXPECT_EQ(*result, 123);
+}
+
+TEST_F(StatusTest, ErrorOrWithCopyableType) {
+ ErrorOr<int> error_or(123);
+ EXPECT_TRUE(error_or.has_value());
+ EXPECT_FALSE(error_or.has_error());
+ int result = std::move(error_or.value());
+ EXPECT_EQ(result, 123);
+ // Should be unaffected by the move.
+ EXPECT_EQ(error_or.value(), 123);
+}
+
+TEST_F(StatusTest, ErrorOrMoveConstructionAndAssignment) {
+ // Make sure that we can move-construct and move-assign a move-only value.
+ ErrorOr<std::unique_ptr<int>> error_or_0(std::make_unique<int>(123));
+
+ ErrorOr<std::unique_ptr<int>> error_or_1(std::move(error_or_0));
+ EXPECT_EQ(error_or_0.value(), nullptr);
+
+ ErrorOr<std::unique_ptr<int>> error_or_2 = std::move(error_or_1);
+ EXPECT_EQ(error_or_1.value(), nullptr);
+
+ // |error_or_2| should have gotten the original.
+ std::unique_ptr<int> value = std::move(error_or_2.value());
+ EXPECT_EQ(*value, 123);
+}
+
+TEST_F(StatusTest, ErrorOrCopyWorks) {
+ // Make sure that we can move-construct and move-assign a move-only value.
+ ErrorOr<int> error_or_0(123);
+ ErrorOr<int> error_or_1(std::move(error_or_0));
+ ErrorOr<int> error_or_2 = std::move(error_or_1);
+ EXPECT_EQ(error_or_2.value(), 123);
+}
+
+} // namespace media
diff --git a/chromium/media/base/supported_types.cc b/chromium/media/base/supported_types.cc
index 0a9ff944f0c..19266cf96d8 100644
--- a/chromium/media/base/supported_types.cc
+++ b/chromium/media/base/supported_types.cc
@@ -185,7 +185,7 @@ bool IsAudioCodecProprietary(AudioCodec codec) {
}
bool IsDefaultSupportedAudioType(const AudioType& type) {
- if (type.spatialRendering)
+ if (type.spatial_rendering)
return false;
#if !BUILDFLAG(USE_PROPRIETARY_CODECS)
@@ -195,6 +195,15 @@ bool IsDefaultSupportedAudioType(const AudioType& type) {
switch (type.codec) {
case kCodecAAC:
+ if (type.profile != AudioCodecProfile::kXHE_AAC)
+ return true;
+#if defined(OS_ANDROID)
+ return base::android::BuildInfo::GetInstance()->sdk_int() >=
+ base::android::SDK_VERSION_P;
+#else
+ return false;
+#endif
+
case kCodecFLAC:
case kCodecMP3:
case kCodecOpus:
@@ -258,13 +267,15 @@ bool IsDefaultSupportedVideoType(const VideoType& type) {
// If the AV1 decoder is enabled, or if we're on Q or later, yes.
#if BUILDFLAG(ENABLE_AV1_DECODER)
return IsColorSpaceSupported(type.color_space);
-#elif defined(OS_ANDROID)
+#else
+#if defined(OS_ANDROID)
if (base::android::BuildInfo::GetInstance()->is_at_least_q() &&
IsColorSpaceSupported(type.color_space)) {
return true;
}
#endif
return false;
+#endif
case kCodecVP9:
// Color management required for HDR to not look terrible.
diff --git a/chromium/media/base/supported_types_unittest.cc b/chromium/media/base/supported_types_unittest.cc
index 24d5ea882ae..764561440d6 100644
--- a/chromium/media/base/supported_types_unittest.cc
+++ b/chromium/media/base/supported_types_unittest.cc
@@ -4,8 +4,13 @@
#include "media/base/supported_types.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_ANDROID)
+#include "base/android/build_info.h"
+#endif
+
namespace media {
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
@@ -168,36 +173,71 @@ TEST(SupportedTypesTest, IsSupportedAudioTypeWithSpatialRenderingBasics) {
const bool is_spatial_rendering = true;
// Dolby Atmos = E-AC3 (Dolby Digital Plus) + spatialRendering. Currently not
// supported.
- EXPECT_FALSE(IsSupportedAudioType({media::kCodecEAC3, is_spatial_rendering}));
+ EXPECT_FALSE(IsSupportedAudioType(
+ {media::kCodecEAC3, AudioCodecProfile::kUnknown, is_spatial_rendering}));
// Expect non-support for codecs with which there is no spatial audio format.
- EXPECT_FALSE(IsSupportedAudioType({media::kCodecAAC, is_spatial_rendering}));
- EXPECT_FALSE(IsSupportedAudioType({media::kCodecMP3, is_spatial_rendering}));
- EXPECT_FALSE(IsSupportedAudioType({media::kCodecPCM, is_spatial_rendering}));
- EXPECT_FALSE(
- IsSupportedAudioType({media::kCodecVorbis, is_spatial_rendering}));
- EXPECT_FALSE(IsSupportedAudioType({media::kCodecFLAC, is_spatial_rendering}));
- EXPECT_FALSE(
- IsSupportedAudioType({media::kCodecAMR_NB, is_spatial_rendering}));
+ EXPECT_FALSE(IsSupportedAudioType(
+ {media::kCodecAAC, AudioCodecProfile::kUnknown, is_spatial_rendering}));
+ EXPECT_FALSE(IsSupportedAudioType(
+ {media::kCodecMP3, AudioCodecProfile::kUnknown, is_spatial_rendering}));
+ EXPECT_FALSE(IsSupportedAudioType(
+ {media::kCodecPCM, AudioCodecProfile::kUnknown, is_spatial_rendering}));
EXPECT_FALSE(
- IsSupportedAudioType({media::kCodecAMR_WB, is_spatial_rendering}));
+ IsSupportedAudioType({media::kCodecVorbis, AudioCodecProfile::kUnknown,
+ is_spatial_rendering}));
+ EXPECT_FALSE(IsSupportedAudioType(
+ {media::kCodecFLAC, AudioCodecProfile::kUnknown, is_spatial_rendering}));
EXPECT_FALSE(
- IsSupportedAudioType({media::kCodecPCM_MULAW, is_spatial_rendering}));
+ IsSupportedAudioType({media::kCodecAMR_NB, AudioCodecProfile::kUnknown,
+ is_spatial_rendering}));
EXPECT_FALSE(
- IsSupportedAudioType({media::kCodecGSM_MS, is_spatial_rendering}));
+ IsSupportedAudioType({media::kCodecAMR_WB, AudioCodecProfile::kUnknown,
+ is_spatial_rendering}));
EXPECT_FALSE(
- IsSupportedAudioType({media::kCodecPCM_S16BE, is_spatial_rendering}));
+ IsSupportedAudioType({media::kCodecPCM_MULAW, AudioCodecProfile::kUnknown,
+ is_spatial_rendering}));
EXPECT_FALSE(
- IsSupportedAudioType({media::kCodecPCM_S24BE, is_spatial_rendering}));
- EXPECT_FALSE(IsSupportedAudioType({media::kCodecOpus, is_spatial_rendering}));
+ IsSupportedAudioType({media::kCodecGSM_MS, AudioCodecProfile::kUnknown,
+ is_spatial_rendering}));
EXPECT_FALSE(
- IsSupportedAudioType({media::kCodecPCM_ALAW, is_spatial_rendering}));
- EXPECT_FALSE(IsSupportedAudioType({media::kCodecALAC, is_spatial_rendering}));
- EXPECT_FALSE(IsSupportedAudioType({media::kCodecAC3, is_spatial_rendering}));
+ IsSupportedAudioType({media::kCodecPCM_S16BE, AudioCodecProfile::kUnknown,
+ is_spatial_rendering}));
EXPECT_FALSE(
- IsSupportedAudioType({media::kCodecMpegHAudio, is_spatial_rendering}));
+ IsSupportedAudioType({media::kCodecPCM_S24BE, AudioCodecProfile::kUnknown,
+ is_spatial_rendering}));
+ EXPECT_FALSE(IsSupportedAudioType(
+ {media::kCodecOpus, AudioCodecProfile::kUnknown, is_spatial_rendering}));
EXPECT_FALSE(
- IsSupportedAudioType({media::kUnknownAudioCodec, is_spatial_rendering}));
+ IsSupportedAudioType({media::kCodecPCM_ALAW, AudioCodecProfile::kUnknown,
+ is_spatial_rendering}));
+ EXPECT_FALSE(IsSupportedAudioType(
+ {media::kCodecALAC, AudioCodecProfile::kUnknown, is_spatial_rendering}));
+ EXPECT_FALSE(IsSupportedAudioType(
+ {media::kCodecAC3, AudioCodecProfile::kUnknown, is_spatial_rendering}));
+ EXPECT_FALSE(IsSupportedAudioType({media::kCodecMpegHAudio,
+ AudioCodecProfile::kUnknown,
+ is_spatial_rendering}));
+ EXPECT_FALSE(IsSupportedAudioType({media::kUnknownAudioCodec,
+ AudioCodecProfile::kUnknown,
+ is_spatial_rendering}));
+}
+
+TEST(SupportedTypesTest, XHE_AACSupportedOnAndroidOnly) {
+ // TODO(dalecurtis): Update this test if we ever have support elsewhere.
+#if defined(OS_ANDROID)
+ const bool is_supported =
+ kPropCodecsEnabled &&
+ base::android::BuildInfo::GetInstance()->sdk_int() >=
+ base::android::SDK_VERSION_P;
+
+ EXPECT_EQ(is_supported,
+ IsSupportedAudioType(
+ {media::kCodecAAC, AudioCodecProfile::kXHE_AAC, false}));
+#else
+ EXPECT_FALSE(IsSupportedAudioType(
+ {media::kCodecAAC, AudioCodecProfile::kXHE_AAC, false}));
+#endif
}
} // namespace media
diff --git a/chromium/media/base/test_data_util.cc b/chromium/media/base/test_data_util.cc
index 469be49afea..d849db56af1 100644
--- a/chromium/media/base/test_data_util.cc
+++ b/chromium/media/base/test_data_util.cc
@@ -40,6 +40,7 @@ const char kMp4Vp9Profile2Video[] =
"video/mp4; codecs=\"vp09.02.10.10.01.02.02.02.00\"";
const char kMp4Vp9Video[] =
"video/mp4; codecs=\"vp09.00.10.08.01.02.02.02.00\"";
+const char kMp4XheAacAudio[] = "audio/mp4; codecs=\"mp4a.40.42\"";
// WebM
const char kWebMAv110bitVideo[] = "video/webm; codecs=\"av01.0.04M.10\"";
const char kWebMAv1Video[] = "video/webm; codecs=\"av01.0.04M.08\"";
@@ -139,6 +140,7 @@ const FileToMimeTypeMap& GetFileToMimeTypeMap() {
{"bear-vp9.webm", kWebMVp9Video},
{"frame_size_change-av_enc-v.webm", kWebMVorbisAudioVp8Video},
{"icy_sfx.mp3", kMp3Audio},
+ {"noise-xhe-aac.mp4", kMp4XheAacAudio},
{"opus-trimming-test.mp4", kMp4OpusAudio},
{"opus-trimming-test.webm", kWebMOpusAudio},
{"sfx-flac_frag.mp4", kMp4FlacAudio},
diff --git a/chromium/media/base/test_helpers.cc b/chromium/media/base/test_helpers.cc
index 97bca27c607..c815328ee39 100644
--- a/chromium/media/base/test_helpers.cc
+++ b/chromium/media/base/test_helpers.cc
@@ -45,22 +45,22 @@ class MockCallback : public base::RefCountedThreadSafe<MockCallback> {
MockCallback::MockCallback() = default;
MockCallback::~MockCallback() = default;
-base::Closure NewExpectedClosure() {
+base::OnceClosure NewExpectedClosure() {
StrictMock<MockCallback>* callback = new StrictMock<MockCallback>();
EXPECT_CALL(*callback, Run());
- return base::Bind(&MockCallback::Run, WrapRefCounted(callback));
+ return base::BindOnce(&MockCallback::Run, WrapRefCounted(callback));
}
-base::Callback<void(bool)> NewExpectedBoolCB(bool success) {
+base::OnceCallback<void(bool)> NewExpectedBoolCB(bool success) {
StrictMock<MockCallback>* callback = new StrictMock<MockCallback>();
EXPECT_CALL(*callback, RunWithBool(success));
- return base::Bind(&MockCallback::RunWithBool, WrapRefCounted(callback));
+ return base::BindOnce(&MockCallback::RunWithBool, WrapRefCounted(callback));
}
-PipelineStatusCB NewExpectedStatusCB(PipelineStatus status) {
+PipelineStatusCallback NewExpectedStatusCB(PipelineStatus status) {
StrictMock<MockCallback>* callback = new StrictMock<MockCallback>();
EXPECT_CALL(*callback, RunWithStatus(status));
- return base::Bind(&MockCallback::RunWithStatus, WrapRefCounted(callback));
+ return base::BindOnce(&MockCallback::RunWithStatus, WrapRefCounted(callback));
}
WaitableMessageLoopEvent::WaitableMessageLoopEvent()
@@ -73,17 +73,16 @@ WaitableMessageLoopEvent::~WaitableMessageLoopEvent() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
-base::Closure WaitableMessageLoopEvent::GetClosure() {
+base::OnceClosure WaitableMessageLoopEvent::GetClosure() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return BindToCurrentLoop(base::Bind(
- &WaitableMessageLoopEvent::OnCallback, base::Unretained(this),
- PIPELINE_OK));
+ return BindToCurrentLoop(base::BindOnce(&WaitableMessageLoopEvent::OnCallback,
+ base::Unretained(this), PIPELINE_OK));
}
-PipelineStatusCB WaitableMessageLoopEvent::GetPipelineStatusCB() {
+PipelineStatusCallback WaitableMessageLoopEvent::GetPipelineStatusCB() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return BindToCurrentLoop(base::Bind(
- &WaitableMessageLoopEvent::OnCallback, base::Unretained(this)));
+ return BindToCurrentLoop(base::BindOnce(&WaitableMessageLoopEvent::OnCallback,
+ base::Unretained(this)));
}
void WaitableMessageLoopEvent::RunAndWait() {
@@ -100,9 +99,9 @@ void WaitableMessageLoopEvent::RunAndWaitForStatus(PipelineStatus expected) {
run_loop_.reset(new base::RunLoop());
base::OneShotTimer timer;
- timer.Start(
- FROM_HERE, timeout_,
- base::Bind(&WaitableMessageLoopEvent::OnTimeout, base::Unretained(this)));
+ timer.Start(FROM_HERE, timeout_,
+ base::BindOnce(&WaitableMessageLoopEvent::OnTimeout,
+ base::Unretained(this)));
run_loop_->Run();
EXPECT_TRUE(signaled_);
diff --git a/chromium/media/base/test_helpers.h b/chromium/media/base/test_helpers.h
index b2caa61094b..8e97cdc778d 100644
--- a/chromium/media/base/test_helpers.h
+++ b/chromium/media/base/test_helpers.h
@@ -19,6 +19,7 @@
#include "media/base/media_log.h"
#include "media/base/pipeline_status.h"
#include "media/base/sample_format.h"
+#include "media/base/status.h"
#include "media/base/video_decoder_config.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "ui/gfx/geometry/size.h"
@@ -36,9 +37,9 @@ class DecoderBuffer;
class MockDemuxerStream;
// Return a callback that expects to be run once.
-base::Closure NewExpectedClosure();
-base::Callback<void(bool)> NewExpectedBoolCB(bool success);
-PipelineStatusCB NewExpectedStatusCB(PipelineStatus status);
+base::OnceClosure NewExpectedClosure();
+base::OnceCallback<void(bool)> NewExpectedBoolCB(bool success);
+PipelineStatusCallback NewExpectedStatusCB(PipelineStatus status);
// Helper class for running a message loop until a callback has run. Useful for
// testing classes that run on more than a single thread.
@@ -51,8 +52,8 @@ class WaitableMessageLoopEvent {
~WaitableMessageLoopEvent();
// Returns a thread-safe closure that will signal |this| when executed.
- base::Closure GetClosure();
- PipelineStatusCB GetPipelineStatusCB();
+ base::OnceClosure GetClosure();
+ PipelineStatusCallback GetPipelineStatusCB();
// Runs the current message loop until |this| has been signaled.
//
@@ -199,6 +200,20 @@ bool VerifyFakeVideoBufferForTest(const DecoderBuffer& buffer,
std::unique_ptr<::testing::StrictMock<MockDemuxerStream>>
CreateMockDemuxerStream(DemuxerStream::Type type, bool encrypted);
+// Compares two media::Status by StatusCode only.
+MATCHER_P(SameStatusCode, status, "") {
+ return arg.code() == status.code();
+}
+
+// Compares two an |arg| Status to a StatusCode provided
+MATCHER_P(HasStatusCode, status_code, "") {
+ return arg.code() == status_code;
+}
+
+MATCHER(IsOkStatus, "") {
+ return arg.is_ok();
+}
+
// Compares two {Audio|Video}DecoderConfigs
MATCHER_P(DecoderConfigEq, config, "") {
return arg.Matches(config);
diff --git a/chromium/media/base/text_renderer.cc b/chromium/media/base/text_renderer.cc
index fa57294773c..aa1e5a34d1e 100644
--- a/chromium/media/base/text_renderer.cc
+++ b/chromium/media/base/text_renderer.cc
@@ -34,7 +34,7 @@ TextRenderer::~TextRenderer() {
std::move(pause_cb_).Run();
}
-void TextRenderer::Initialize(const base::Closure& ended_cb) {
+void TextRenderer::Initialize(const base::RepeatingClosure& ended_cb) {
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(ended_cb);
DCHECK_EQ(kUninitialized, state_) << "state_ " << state_;
@@ -65,22 +65,22 @@ void TextRenderer::StartPlaying() {
state_ = kPlaying;
}
-void TextRenderer::Pause(const base::Closure& callback) {
+void TextRenderer::Pause(base::OnceClosure callback) {
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(state_ == kPlaying || state_ == kEnded) << "state_ " << state_;
DCHECK_GE(pending_read_count_, 0);
if (pending_read_count_ == 0) {
state_ = kPaused;
- task_runner_->PostTask(FROM_HERE, callback);
+ task_runner_->PostTask(FROM_HERE, std::move(callback));
return;
}
- pause_cb_ = callback;
+ pause_cb_ = std::move(callback);
state_ = kPausePending;
}
-void TextRenderer::Flush(const base::Closure& callback) {
+void TextRenderer::Flush(base::OnceClosure callback) {
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK_EQ(pending_read_count_, 0);
DCHECK(state_ == kPaused) << "state_ " << state_;
@@ -91,7 +91,7 @@ void TextRenderer::Flush(const base::Closure& callback) {
itr->second->text_ranges_.Reset();
}
DCHECK_EQ(pending_eos_set_.size(), text_track_state_map_.size());
- task_runner_->PostTask(FROM_HERE, callback);
+ task_runner_->PostTask(FROM_HERE, std::move(callback));
}
void TextRenderer::AddTextStream(DemuxerStream* text_stream,
@@ -103,12 +103,11 @@ void TextRenderer::AddTextStream(DemuxerStream* text_stream,
DCHECK(pending_eos_set_.find(text_stream) ==
pending_eos_set_.end());
- AddTextTrackDoneCB done_cb =
- BindToCurrentLoop(base::Bind(&TextRenderer::OnAddTextTrackDone,
- weak_factory_.GetWeakPtr(),
- text_stream));
+ AddTextTrackDoneCB done_cb = BindToCurrentLoop(
+ base::BindOnce(&TextRenderer::OnAddTextTrackDone,
+ weak_factory_.GetWeakPtr(), text_stream));
- add_text_track_cb_.Run(config, done_cb);
+ add_text_track_cb_.Run(config, std::move(done_cb));
}
void TextRenderer::RemoveTextStream(DemuxerStream* text_stream) {
diff --git a/chromium/media/base/text_renderer.h b/chromium/media/base/text_renderer.h
index e8348bd9c02..52fef826088 100644
--- a/chromium/media/base/text_renderer.h
+++ b/chromium/media/base/text_renderer.h
@@ -45,17 +45,17 @@ class MEDIA_EXPORT TextRenderer {
// |ended_cb| is executed when all of the text tracks have reached
// end of stream, following a play request.
- void Initialize(const base::Closure& ended_cb);
+ void Initialize(const base::RepeatingClosure& ended_cb);
// Starts text track cue decoding and rendering.
void StartPlaying();
// Temporarily suspends decoding and rendering, executing |callback| when
// playback has been suspended.
- void Pause(const base::Closure& callback);
+ void Pause(base::OnceClosure callback);
// Discards any text data, executing |callback| when completed.
- void Flush(const base::Closure& callback);
+ void Flush(base::OnceClosure callback);
// Adds new |text_stream|, having the indicated |config|, to the text stream
// collection managed by this text renderer.
@@ -106,10 +106,10 @@ class MEDIA_EXPORT TextRenderer {
const AddTextTrackCB add_text_track_cb_;
// Callbacks provided during Initialize().
- base::Closure ended_cb_;
+ base::RepeatingClosure ended_cb_;
// Callback provided to Pause().
- base::Closure pause_cb_;
+ base::OnceClosure pause_cb_;
// Simple state tracking variable.
enum State {
diff --git a/chromium/media/base/text_renderer_unittest.cc b/chromium/media/base/text_renderer_unittest.cc
index a9fa4872e83..d6ab92c4733 100644
--- a/chromium/media/base/text_renderer_unittest.cc
+++ b/chromium/media/base/text_renderer_unittest.cc
@@ -29,9 +29,9 @@ namespace media {
// Local implementation of the TextTrack interface.
class FakeTextTrack : public TextTrack {
public:
- FakeTextTrack(const base::Closure& destroy_cb, const TextTrackConfig& config)
- : destroy_cb_(destroy_cb), config_(config) {}
- ~FakeTextTrack() override { destroy_cb_.Run(); }
+ FakeTextTrack(base::OnceClosure destroy_cb, const TextTrackConfig& config)
+ : destroy_cb_(std::move(destroy_cb)), config_(config) {}
+ ~FakeTextTrack() override { std::move(destroy_cb_).Run(); }
MOCK_METHOD5(addWebVTTCue,
void(base::TimeDelta start,
@@ -40,7 +40,7 @@ class FakeTextTrack : public TextTrack {
const std::string& content,
const std::string& settings));
- const base::Closure destroy_cb_;
+ base::OnceClosure destroy_cb_;
const TextTrackConfig config_;
private:
@@ -54,11 +54,12 @@ class TextRendererTest : public testing::Test {
void CreateTextRenderer() {
DCHECK(!text_renderer_);
- text_renderer_.reset(new TextRenderer(
- task_environment_.GetMainThreadTaskRunner(),
- base::Bind(&TextRendererTest::OnAddTextTrack, base::Unretained(this))));
+ text_renderer_.reset(
+ new TextRenderer(task_environment_.GetMainThreadTaskRunner(),
+ base::BindRepeating(&TextRendererTest::OnAddTextTrack,
+ base::Unretained(this))));
text_renderer_->Initialize(
- base::Bind(&TextRendererTest::OnEnd, base::Unretained(this)));
+ base::BindRepeating(&TextRendererTest::OnEnd, base::Unretained(this)));
}
void Destroy() {
@@ -87,16 +88,16 @@ class TextRendererTest : public testing::Test {
}
void OnAddTextTrack(const TextTrackConfig& config,
- const AddTextTrackDoneCB& done_cb) {
- base::Closure destroy_cb =
- base::Bind(&TextRendererTest::OnDestroyTextTrack,
- base::Unretained(this), text_tracks_.size());
+ AddTextTrackDoneCB done_cb) {
+ base::OnceClosure destroy_cb =
+ base::BindOnce(&TextRendererTest::OnDestroyTextTrack,
+ base::Unretained(this), text_tracks_.size());
// Text track objects are owned by the text renderer, but we cache them
// here so we can inspect them. They get removed from our cache when the
// text renderer deallocates them.
- text_tracks_.push_back(new FakeTextTrack(destroy_cb, config));
+ text_tracks_.push_back(new FakeTextTrack(std::move(destroy_cb), config));
std::unique_ptr<TextTrack> text_track(text_tracks_.back());
- done_cb.Run(std::move(text_track));
+ std::move(done_cb).Run(std::move(text_track));
}
void RemoveTextTrack(unsigned idx) {
@@ -171,14 +172,14 @@ class TextRendererTest : public testing::Test {
void Pause() {
text_renderer_->Pause(
- base::Bind(&TextRendererTest::OnPause, base::Unretained(this)));
+ base::BindOnce(&TextRendererTest::OnPause, base::Unretained(this)));
base::RunLoop().RunUntilIdle();
}
void Flush() {
EXPECT_CALL(*this, OnFlush());
text_renderer_->Flush(
- base::Bind(&TextRendererTest::OnFlush, base::Unretained(this)));
+ base::BindOnce(&TextRendererTest::OnFlush, base::Unretained(this)));
}
void ExpectRead(size_t idx) {
@@ -205,9 +206,10 @@ class TextRendererTest : public testing::Test {
};
TEST_F(TextRendererTest, CreateTextRendererNoInit) {
- text_renderer_.reset(new TextRenderer(
- task_environment_.GetMainThreadTaskRunner(),
- base::Bind(&TextRendererTest::OnAddTextTrack, base::Unretained(this))));
+ text_renderer_.reset(
+ new TextRenderer(task_environment_.GetMainThreadTaskRunner(),
+ base::BindRepeating(&TextRendererTest::OnAddTextTrack,
+ base::Unretained(this))));
text_renderer_.reset();
}
diff --git a/chromium/media/base/text_track.h b/chromium/media/base/text_track.h
index f7ee5ee36d6..4d594a0bc50 100644
--- a/chromium/media/base/text_track.h
+++ b/chromium/media/base/text_track.h
@@ -25,10 +25,11 @@ class TextTrack {
const std::string& settings) = 0;
};
-using AddTextTrackDoneCB = base::Callback<void(std::unique_ptr<TextTrack>)>;
+using AddTextTrackDoneCB = base::OnceCallback<void(std::unique_ptr<TextTrack>)>;
-using AddTextTrackCB = base::Callback<void(const TextTrackConfig& config,
- const AddTextTrackDoneCB& done_cb)>;
+using AddTextTrackCB =
+ base::RepeatingCallback<void(const TextTrackConfig& config,
+ AddTextTrackDoneCB done_cb)>;
} // namespace media
diff --git a/chromium/media/base/time_source.h b/chromium/media/base/time_source.h
index 9d478d17340..92d6528d909 100644
--- a/chromium/media/base/time_source.h
+++ b/chromium/media/base/time_source.h
@@ -18,8 +18,8 @@ class MEDIA_EXPORT TimeSource {
public:
// Helper alias for converting media timestamps into a wall clock timestamps.
using WallClockTimeCB =
- base::Callback<bool(const std::vector<base::TimeDelta>&,
- std::vector<base::TimeTicks>*)>;
+ base::RepeatingCallback<bool(const std::vector<base::TimeDelta>&,
+ std::vector<base::TimeTicks>*)>;
TimeSource() {}
virtual ~TimeSource() {}
diff --git a/chromium/media/base/video_codecs.h b/chromium/media/base/video_codecs.h
index bf7e4bc9282..f81a273096a 100644
--- a/chromium/media/base/video_codecs.h
+++ b/chromium/media/base/video_codecs.h
@@ -96,10 +96,13 @@ enum VideoCodecProfile {
VIDEO_CODEC_PROFILE_MAX = DOLBYVISION_PROFILE9,
};
+using VideoCodecLevel = uint32_t;
+constexpr VideoCodecLevel kNoVideoCodecLevel = 0;
+
struct CodecProfileLevel {
VideoCodec codec;
VideoCodecProfile profile;
- int level;
+ VideoCodecLevel level;
};
std::string MEDIA_EXPORT GetCodecName(VideoCodec codec);
diff --git a/chromium/media/base/video_decoder.h b/chromium/media/base/video_decoder.h
index 52753e8c17e..bbb0b11b151 100644
--- a/chromium/media/base/video_decoder.h
+++ b/chromium/media/base/video_decoder.h
@@ -13,6 +13,7 @@
#include "media/base/decode_status.h"
#include "media/base/media_export.h"
#include "media/base/pipeline_status.h"
+#include "media/base/status.h"
#include "media/base/waiting.h"
#include "ui/gfx/geometry/size.h"
@@ -26,7 +27,7 @@ class VideoFrame;
class MEDIA_EXPORT VideoDecoder {
public:
// Callback for VideoDecoder initialization.
- using InitCB = base::OnceCallback<void(bool success)>;
+ using InitCB = base::OnceCallback<void(Status status)>;
// Callback for VideoDecoder to return a decoded frame whenever it becomes
// available. Only non-EOS frames should be returned via this callback.
diff --git a/chromium/media/base/video_decoder_config.cc b/chromium/media/base/video_decoder_config.cc
index dfe1f7500f0..e9c54664dfc 100644
--- a/chromium/media/base/video_decoder_config.cc
+++ b/chromium/media/base/video_decoder_config.cc
@@ -8,6 +8,7 @@
#include <vector>
#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
#include "media/base/limits.h"
#include "media/base/media_util.h"
#include "media/base/video_types.h"
@@ -67,11 +68,7 @@ VideoCodec VideoCodecProfileToVideoCodec(VideoCodecProfile profile) {
return kUnknownVideoCodec;
}
-VideoDecoderConfig::VideoDecoderConfig()
- : codec_(kUnknownVideoCodec),
- profile_(VIDEO_CODEC_PROFILE_UNKNOWN),
- alpha_mode_(AlphaMode::kIsOpaque),
- transformation_(kNoTransformation) {}
+VideoDecoderConfig::VideoDecoderConfig() = default;
VideoDecoderConfig::VideoDecoderConfig(VideoCodec codec,
VideoCodecProfile profile,
@@ -92,23 +89,6 @@ VideoDecoderConfig::VideoDecoderConfig(const VideoDecoderConfig& other) =
VideoDecoderConfig::~VideoDecoderConfig() = default;
-void VideoDecoderConfig::set_color_space_info(
- const VideoColorSpace& color_space) {
- color_space_info_ = color_space;
-}
-
-const VideoColorSpace& VideoDecoderConfig::color_space_info() const {
- return color_space_info_;
-}
-
-void VideoDecoderConfig::set_hdr_metadata(const HDRMetadata& hdr_metadata) {
- hdr_metadata_ = hdr_metadata;
-}
-
-const base::Optional<HDRMetadata>& VideoDecoderConfig::hdr_metadata() const {
- return hdr_metadata_;
-}
-
void VideoDecoderConfig::Initialize(VideoCodec codec,
VideoCodecProfile profile,
AlphaMode alpha_mode,
@@ -147,13 +127,16 @@ bool VideoDecoderConfig::Matches(const VideoDecoderConfig& config) const {
extra_data() == config.extra_data() &&
encryption_scheme() == config.encryption_scheme() &&
color_space_info() == config.color_space_info() &&
- hdr_metadata() == config.hdr_metadata();
+ hdr_metadata() == config.hdr_metadata() && level() == config.level();
}
std::string VideoDecoderConfig::AsHumanReadableString() const {
std::ostringstream s;
s << "codec: " << GetCodecName(codec())
- << ", profile: " << GetProfileName(profile()) << ", alpha_mode: "
+ << ", profile: " << GetProfileName(profile()) << ", level: "
+ << (level() > kNoVideoCodecLevel ? base::NumberToString(level())
+ : "not available")
+ << ", alpha_mode: "
<< (alpha_mode() == AlphaMode::kHasAlpha ? "has_alpha" : "is_opaque")
<< ", coded size: [" << coded_size().width() << "," << coded_size().height()
<< "]"
@@ -166,6 +149,7 @@ std::string VideoDecoderConfig::AsHumanReadableString() const {
<< ", rotation: " << VideoRotationToString(video_transformation().rotation)
<< ", flipped: " << video_transformation().mirrored
<< ", color space: " << color_space_info().ToGfxColorSpace().ToString();
+
if (hdr_metadata().has_value()) {
s << std::setprecision(4) << ", luminance range: "
<< hdr_metadata()->mastering_metadata.luminance_min << "-"
@@ -179,6 +163,7 @@ std::string VideoDecoderConfig::AsHumanReadableString() const {
<< hdr_metadata()->mastering_metadata.white_point.x() << ","
<< hdr_metadata()->mastering_metadata.white_point.y() << ")";
}
+
return s.str();
}
diff --git a/chromium/media/base/video_decoder_config.h b/chromium/media/base/video_decoder_config.h
index e9ca2795a61..405be9f8102 100644
--- a/chromium/media/base/video_decoder_config.h
+++ b/chromium/media/base/video_decoder_config.h
@@ -78,8 +78,6 @@ class MEDIA_EXPORT VideoDecoderConfig {
std::string GetHumanReadableCodecName() const;
- static std::string GetHumanReadableProfile(VideoCodecProfile profile);
-
VideoCodec codec() const { return codec_; }
VideoCodecProfile profile() const { return profile_; }
AlphaMode alpha_mode() const { return alpha_mode_; }
@@ -148,24 +146,38 @@ class MEDIA_EXPORT VideoDecoderConfig {
EncryptionScheme encryption_scheme() const { return encryption_scheme_; }
// Color space of the image data.
- void set_color_space_info(const VideoColorSpace& color_space);
- const VideoColorSpace& color_space_info() const;
+ void set_color_space_info(const VideoColorSpace& color_space) {
+ color_space_info_ = color_space;
+ }
+ const VideoColorSpace& color_space_info() const { return color_space_info_; }
// Dynamic range of the image data.
- void set_hdr_metadata(const HDRMetadata& hdr_metadata);
- const base::Optional<HDRMetadata>& hdr_metadata() const;
+ void set_hdr_metadata(const HDRMetadata& hdr_metadata) {
+ hdr_metadata_ = hdr_metadata;
+ }
+ const base::Optional<HDRMetadata>& hdr_metadata() const {
+ return hdr_metadata_;
+ }
+
+ // Codec level.
+ void set_level(VideoCodecLevel level) { level_ = level; }
+ VideoCodecLevel level() const { return level_; }
// Sets the config to be encrypted or not encrypted manually. This can be
// useful for decryptors that decrypts an encrypted stream to a clear stream.
void SetIsEncrypted(bool is_encrypted);
private:
- VideoCodec codec_;
- VideoCodecProfile profile_;
+ VideoCodec codec_ = kUnknownVideoCodec;
+ VideoCodecProfile profile_ = VIDEO_CODEC_PROFILE_UNKNOWN;
+
+ // Optional video codec level. kNoVideoCodecLevel means the field is not
+ // available.
+ VideoCodecLevel level_ = kNoVideoCodecLevel;
- AlphaMode alpha_mode_;
+ AlphaMode alpha_mode_ = AlphaMode::kIsOpaque;
- VideoTransformation transformation_;
+ VideoTransformation transformation_ = kNoTransformation;
// Deprecated. TODO(wolenetz): Remove. See https://crbug.com/665539.
gfx::Size coded_size_;
diff --git a/chromium/media/base/video_frame.cc b/chromium/media/base/video_frame.cc
index b3e63e70521..0bb025a1d5f 100644
--- a/chromium/media/base/video_frame.cc
+++ b/chromium/media/base/video_frame.cc
@@ -131,6 +131,7 @@ gfx::Size VideoFrame::SampleSize(VideoPixelFormat format, size_t plane) {
case PIXEL_FORMAT_P016LE:
return gfx::Size(2, 2);
+ case PIXEL_FORMAT_UYVY:
case PIXEL_FORMAT_UNKNOWN:
case PIXEL_FORMAT_YUY2:
case PIXEL_FORMAT_ARGB:
@@ -193,6 +194,7 @@ static bool RequiresEvenSizeAllocation(VideoPixelFormat format) {
case PIXEL_FORMAT_YUV422P12:
case PIXEL_FORMAT_YUV444P12:
case PIXEL_FORMAT_I420A:
+ case PIXEL_FORMAT_UYVY:
case PIXEL_FORMAT_P016LE:
return true;
case PIXEL_FORMAT_UNKNOWN:
@@ -732,8 +734,7 @@ scoped_refptr<VideoFrame> VideoFrame::WrapVideoFrame(
if (frame->storage_type() == STORAGE_SHMEM) {
DCHECK(frame->shm_region_ && frame->shm_region_->IsValid());
- wrapping_frame->BackWithSharedMemory(frame->shm_region_,
- frame->shared_memory_offset());
+ wrapping_frame->BackWithSharedMemory(frame->shm_region_);
}
wrapping_frame->wrapped_frame_ = std::move(frame);
@@ -864,6 +865,7 @@ int VideoFrame::BytesPerElement(VideoPixelFormat format, size_t plane) {
case PIXEL_FORMAT_RGB24:
return 3;
case PIXEL_FORMAT_Y16:
+ case PIXEL_FORMAT_UYVY:
case PIXEL_FORMAT_YUY2:
case PIXEL_FORMAT_YUV420P9:
case PIXEL_FORMAT_YUV422P9:
@@ -941,8 +943,7 @@ void VideoFrame::HashFrameForTesting(base::MD5Context* context,
}
}
-void VideoFrame::BackWithSharedMemory(base::UnsafeSharedMemoryRegion* region,
- size_t offset) {
+void VideoFrame::BackWithSharedMemory(base::UnsafeSharedMemoryRegion* region) {
DCHECK(!shm_region_);
DCHECK(!owned_shm_region_.IsValid());
// Either we should be backing a frame created with WrapExternal*, or we are
@@ -953,13 +954,11 @@ void VideoFrame::BackWithSharedMemory(base::UnsafeSharedMemoryRegion* region,
DCHECK(region && region->IsValid());
storage_type_ = STORAGE_SHMEM;
shm_region_ = region;
- shared_memory_offset_ = offset;
}
void VideoFrame::BackWithOwnedSharedMemory(
base::UnsafeSharedMemoryRegion region,
- base::WritableSharedMemoryMapping mapping,
- size_t offset) {
+ base::WritableSharedMemoryMapping mapping) {
DCHECK(!shm_region_);
DCHECK(!owned_shm_region_.IsValid());
// We should be backing a frame created with WrapExternal*. We cannot be
@@ -969,7 +968,6 @@ void VideoFrame::BackWithOwnedSharedMemory(
owned_shm_region_ = std::move(region);
shm_region_ = &owned_shm_region_;
owned_shm_mapping_ = std::move(mapping);
- shared_memory_offset_ = offset;
}
bool VideoFrame::IsMappable() const {
@@ -1006,6 +1004,17 @@ gfx::GpuMemoryBuffer* VideoFrame::GetGpuMemoryBuffer() const {
: gpu_memory_buffer_.get();
}
+bool VideoFrame::IsSameAllocation(VideoPixelFormat format,
+ const gfx::Size& coded_size,
+ const gfx::Rect& visible_rect,
+ const gfx::Size& natural_size) const {
+ // CreateFrameInternal() changes coded_size to new_coded_size. Match that
+ // behavior here.
+ const gfx::Size new_coded_size = DetermineAlignedSize(format, coded_size);
+ return this->format() == format && this->coded_size() == new_coded_size &&
+ visible_rect_ == visible_rect && natural_size_ == natural_size;
+}
+
gfx::ColorSpace VideoFrame::ColorSpace() const {
return color_space_;
}
@@ -1109,7 +1118,7 @@ gpu::SyncToken VideoFrame::UpdateReleaseSyncToken(SyncTokenClient* client) {
return release_sync_token_;
}
-std::string VideoFrame::AsHumanReadableString() {
+std::string VideoFrame::AsHumanReadableString() const {
if (metadata()->IsTrue(VideoFrameMetadata::END_OF_STREAM))
return "end of stream";
@@ -1201,7 +1210,7 @@ scoped_refptr<VideoFrame> VideoFrame::CreateFrameInternal(
// line up on sample boundaries. See discussion at http://crrev.com/1240833003
const gfx::Size new_coded_size = DetermineAlignedSize(format, coded_size);
auto layout = VideoFrameLayout::CreateWithStrides(
- format, new_coded_size, ComputeStrides(format, coded_size));
+ format, new_coded_size, ComputeStrides(format, new_coded_size));
if (!layout) {
DLOG(ERROR) << "Invalid layout.";
return nullptr;
diff --git a/chromium/media/base/video_frame.h b/chromium/media/base/video_frame.h
index 9ea6ceba22d..6b1a5b455a7 100644
--- a/chromium/media/base/video_frame.h
+++ b/chromium/media/base/video_frame.h
@@ -112,8 +112,7 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
DISALLOW_COPY_AND_ASSIGN(SyncTokenClient);
};
- // Call prior to CreateFrame to ensure validity of frame configuration. Called
- // automatically by VideoDecoderConfig::IsValidConfig().
+ // Returns true if frame configuration is valid.
static bool IsValidConfig(VideoPixelFormat format,
StorageType storage_type,
const gfx::Size& coded_size,
@@ -312,6 +311,10 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
static size_t AllocationSize(VideoPixelFormat format,
const gfx::Size& coded_size);
+ // Returns |dimensions| adjusted to appropriate boundaries based on |format|.
+ static gfx::Size DetermineAlignedSize(VideoPixelFormat format,
+ const gfx::Size& dimensions);
+
// Returns the plane gfx::Size (in bytes) for a plane of the given coded size
// and format.
static gfx::Size PlaneSize(VideoPixelFormat format,
@@ -370,21 +373,12 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
//
// The region is NOT owned by the video frame. Both the region and its
// associated mapping must outlive this instance.
- void BackWithSharedMemory(base::UnsafeSharedMemoryRegion* region,
- size_t offset = 0);
+ void BackWithSharedMemory(base::UnsafeSharedMemoryRegion* region);
// As above, but the VideoFrame owns the shared memory region as well as the
// mapping. They will be destroyed with their VideoFrame.
void BackWithOwnedSharedMemory(base::UnsafeSharedMemoryRegion region,
- base::WritableSharedMemoryMapping mapping,
- size_t offset = 0);
-
- // Returns the offset into the shared memory where the frame data begins. Only
- // valid if the frame is backed by shared memory.
- size_t shared_memory_offset() const {
- DCHECK(IsValidSharedMemoryFrame());
- return shared_memory_offset_;
- }
+ base::WritableSharedMemoryMapping mapping);
// Valid for shared memory backed VideoFrames.
base::UnsafeSharedMemoryRegion* shm_region() {
@@ -411,6 +405,12 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
// Gets the GpuMemoryBuffer backing the VideoFrame.
gfx::GpuMemoryBuffer* GetGpuMemoryBuffer() const;
+ // Returns true if the video frame was created with the given parameters.
+ bool IsSameAllocation(VideoPixelFormat format,
+ const gfx::Size& coded_size,
+ const gfx::Rect& visible_rect,
+ const gfx::Size& natural_size) const;
+
// Returns the color space of this frame's content.
gfx::ColorSpace ColorSpace() const;
void set_color_space(const gfx::ColorSpace& color_space) {
@@ -544,7 +544,7 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
gpu::SyncToken UpdateReleaseSyncToken(SyncTokenClient* client);
// Returns a human-readable string describing |*this|.
- std::string AsHumanReadableString();
+ std::string AsHumanReadableString() const;
// Unique identifier for this video frame; generated at construction time and
// guaranteed to be unique within a single process.
@@ -579,10 +579,6 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
const gfx::Rect& visible_rect,
const gfx::Size& natural_size);
- // Returns |dimensions| adjusted to appropriate boundaries based on |format|.
- static gfx::Size DetermineAlignedSize(VideoPixelFormat format,
- const gfx::Size& dimensions);
-
void set_data(size_t plane, uint8_t* ptr) {
DCHECK(IsValidPlane(format(), plane));
DCHECK(ptr);
@@ -650,10 +646,6 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe<VideoFrame> {
// to is unowned.
base::UnsafeSharedMemoryRegion* shm_region_ = nullptr;
- // If this is a STORAGE_SHMEM frame, the offset of the data within the shared
- // memory.
- size_t shared_memory_offset_ = 0;
-
// Used if this is a STORAGE_SHMEM frame with owned shared memory. In that
// case, shm_region_ will refer to this region.
base::UnsafeSharedMemoryRegion owned_shm_region_;
diff --git a/chromium/media/base/video_frame_layout.cc b/chromium/media/base/video_frame_layout.cc
index 51e06ff8f95..b7210ce1126 100644
--- a/chromium/media/base/video_frame_layout.cc
+++ b/chromium/media/base/video_frame_layout.cc
@@ -43,6 +43,7 @@ std::vector<ColorPlaneLayout> PlanesFromStrides(
// static
size_t VideoFrameLayout::NumPlanes(VideoPixelFormat format) {
switch (format) {
+ case PIXEL_FORMAT_UYVY:
case PIXEL_FORMAT_YUY2:
case PIXEL_FORMAT_ARGB:
case PIXEL_FORMAT_BGRA:
diff --git a/chromium/media/base/video_frame_layout.h b/chromium/media/base/video_frame_layout.h
index c7f59083cff..aeb0ceaeef5 100644
--- a/chromium/media/base/video_frame_layout.h
+++ b/chromium/media/base/video_frame_layout.h
@@ -38,11 +38,10 @@ class MEDIA_EXPORT VideoFrameLayout {
static constexpr size_t kBufferAddressAlignment = 32;
// Factory functions.
- // |format| and |coded_size| must be specified.
- // |is_single_planar| is optional. It describes planes can be stored (although
- // not always) in multiple buffers. It is specified only in HW decoder code.
+ // |format| and |coded_size| must always be specified.
// |planes| info is also optional but useful to represent the layout of a
- // video frame buffer correctly.
+ // video frame buffer correctly. When omitted, its information is all set
+ // to zero, so clients should be wary not to use this information.
// |buffer_addr_align| can be specified to request a specific buffer memory
// alignment.
// |modifier| is the additional information of |format|. It will become some
@@ -50,17 +49,24 @@ class MEDIA_EXPORT VideoFrameLayout {
// buffer format is different from a standard |format| due to tiling.
// The returned base::Optional will be base::nullopt if the configured values
// are invalid.
+
+ // Create a layout suitable for |format| at |coded_size|. The stride, offsets
+ // and size of all planes are set to 0, since that information cannot reliably
+ // be infered from the arguments.
static base::Optional<VideoFrameLayout> Create(VideoPixelFormat format,
const gfx::Size& coded_size);
- // The size of |strides| must be NumPlanes(|format|). Planes' offset will be
- // 0.
+ // Create a layout suitable for |format| at |coded_size|, with the |strides|
+ // for each plane specified. The offsets and size of all planes are set to 0.
+ // The size of |strides| must be equal to NumPlanes(|format|).
static base::Optional<VideoFrameLayout> CreateWithStrides(
VideoPixelFormat format,
const gfx::Size& coded_size,
std::vector<int32_t> strides);
- // The size of |planes| must be NumPlanes(|format|).
+ // Create a layout suitable for |format| at |coded_size|, with the |planes|
+ // fully provided.
+ // The size of |planes| must be equal to NumPlanes(|format|).
static base::Optional<VideoFrameLayout> CreateWithPlanes(
VideoPixelFormat format,
const gfx::Size& coded_size,
diff --git a/chromium/media/base/video_frame_metadata.cc b/chromium/media/base/video_frame_metadata.cc
index 0257844c9cc..1b403379bd0 100644
--- a/chromium/media/base/video_frame_metadata.cc
+++ b/chromium/media/base/video_frame_metadata.cc
@@ -50,33 +50,23 @@ void VideoFrameMetadata::SetRotation(Key key, VideoRotation value) {
}
void VideoFrameMetadata::SetString(Key key, const std::string& value) {
- dictionary_.SetWithoutPathExpansion(
+ dictionary_.SetKey(
ToInternalKey(key),
- // Using BinaryValue since we don't want the |value| interpreted as having
+
+ // Using BlobStorage since we don't want the |value| interpreted as having
// any particular character encoding (e.g., UTF-8) by
// base::DictionaryValue.
- base::Value::CreateWithCopiedBuffer(value.data(), value.size()));
+ base::Value(base::Value::BlobStorage(value.begin(), value.end())));
}
-namespace {
-template<class TimeType>
-void SetTimeValue(VideoFrameMetadata::Key key,
- const TimeType& value,
- base::DictionaryValue* dictionary) {
- const int64_t internal_value = value.ToInternalValue();
- dictionary->SetWithoutPathExpansion(
- ToInternalKey(key), base::Value::CreateWithCopiedBuffer(
- reinterpret_cast<const char*>(&internal_value),
- sizeof(internal_value)));
-}
-} // namespace
-
void VideoFrameMetadata::SetTimeDelta(Key key, const base::TimeDelta& value) {
- SetTimeValue(key, value, &dictionary_);
+ dictionary_.SetKey(ToInternalKey(key), base::CreateTimeDeltaValue(value));
}
void VideoFrameMetadata::SetTimeTicks(Key key, const base::TimeTicks& value) {
- SetTimeValue(key, value, &dictionary_);
+ // Serialize TimeTicks as TimeDeltas.
+ dictionary_.SetKey(ToInternalKey(key),
+ base::CreateTimeDeltaValue(value - base::TimeTicks()));
}
void VideoFrameMetadata::SetUnguessableToken(
@@ -90,72 +80,76 @@ void VideoFrameMetadata::SetRect(Key key, const gfx::Rect& value) {
base::Value init[] = {base::Value(value.x()), base::Value(value.y()),
base::Value(value.width()),
base::Value(value.height())};
- SetValue(key, std::make_unique<base::ListValue>(base::Value::ListStorage{
- std::make_move_iterator(std::begin(init)),
- std::make_move_iterator(std::end(init))}));
-}
-
-void VideoFrameMetadata::SetValue(Key key, std::unique_ptr<base::Value> value) {
- dictionary_.SetWithoutPathExpansion(ToInternalKey(key), std::move(value));
+ dictionary_.SetKey(ToInternalKey(key),
+ base::Value(base::Value::ListStorage(
+ std::make_move_iterator(std::begin(init)),
+ std::make_move_iterator(std::end(init)))));
}
bool VideoFrameMetadata::GetBoolean(Key key, bool* value) const {
DCHECK(value);
- return dictionary_.GetBooleanWithoutPathExpansion(ToInternalKey(key), value);
+ auto opt_bool = dictionary_.FindBoolKey(ToInternalKey(key));
+ if (opt_bool)
+ *value = opt_bool.value();
+
+ return opt_bool.has_value();
}
bool VideoFrameMetadata::GetInteger(Key key, int* value) const {
DCHECK(value);
- return dictionary_.GetIntegerWithoutPathExpansion(ToInternalKey(key), value);
+ auto opt_int = dictionary_.FindIntKey(ToInternalKey(key));
+ if (opt_int)
+ *value = opt_int.value();
+
+ return opt_int.has_value();
}
bool VideoFrameMetadata::GetDouble(Key key, double* value) const {
DCHECK(value);
- return dictionary_.GetDoubleWithoutPathExpansion(ToInternalKey(key), value);
+ auto opt_double = dictionary_.FindDoubleKey(ToInternalKey(key));
+ if (opt_double)
+ *value = opt_double.value();
+
+ return opt_double.has_value();
}
bool VideoFrameMetadata::GetRotation(Key key, VideoRotation* value) const {
DCHECK_EQ(ROTATION, key);
DCHECK(value);
- int int_value;
- const bool rv = dictionary_.GetIntegerWithoutPathExpansion(ToInternalKey(key),
- &int_value);
- if (rv)
- *value = static_cast<VideoRotation>(int_value);
- return rv;
+ auto opt_int = dictionary_.FindIntKey(ToInternalKey(key));
+ if (opt_int)
+ *value = static_cast<VideoRotation>(opt_int.value());
+ return opt_int.has_value();
}
bool VideoFrameMetadata::GetString(Key key, std::string* value) const {
DCHECK(value);
- const base::Value* const binary_value = GetBinaryValue(key);
- if (binary_value)
- value->assign(binary_value->GetBlob().begin(),
- binary_value->GetBlob().end());
- return !!binary_value;
-}
+ const base::Value::BlobStorage* const binary_value =
+ dictionary_.FindBlobKey(ToInternalKey(key));
-namespace {
-template <class TimeType>
-bool ToTimeValue(const base::Value& binary_value, TimeType* value) {
- DCHECK(value);
- int64_t internal_value;
- if (binary_value.GetBlob().size() != sizeof(internal_value))
- return false;
- memcpy(&internal_value, binary_value.GetBlob().data(),
- sizeof(internal_value));
- *value = TimeType::FromInternalValue(internal_value);
- return true;
+ if (!!binary_value)
+ value->assign(binary_value->begin(), binary_value->end());
+
+ return !!binary_value;
}
-} // namespace
bool VideoFrameMetadata::GetTimeDelta(Key key, base::TimeDelta* value) const {
- const base::Value* const binary_value = GetBinaryValue(key);
- return binary_value && ToTimeValue(*binary_value, value);
+ const base::Value* internal_value = dictionary_.FindKey(ToInternalKey(key));
+ if (!internal_value)
+ return false;
+ return base::GetValueAsTimeDelta(*internal_value, value);
}
bool VideoFrameMetadata::GetTimeTicks(Key key, base::TimeTicks* value) const {
- const base::Value* const binary_value = GetBinaryValue(key);
- return binary_value && ToTimeValue(*binary_value, value);
+ // Deserialize TimeTicks from TimeDelta.
+ const base::Value* internal_value = dictionary_.FindKey(ToInternalKey(key));
+ base::TimeDelta delta;
+
+ if (!internal_value || !base::GetValueAsTimeDelta(*internal_value, &delta))
+ return false;
+
+ *value = base::TimeTicks() + delta;
+ return true;
}
bool VideoFrameMetadata::GetUnguessableToken(
@@ -168,7 +162,8 @@ bool VideoFrameMetadata::GetUnguessableToken(
}
bool VideoFrameMetadata::GetRect(Key key, gfx::Rect* value) const {
- const base::ListValue* internal_value = GetList(key);
+ const base::Value* internal_value =
+ dictionary_.FindListKey(ToInternalKey(key));
if (!internal_value || internal_value->GetList().size() != 4)
return false;
*value = gfx::Rect(internal_value->GetList()[0].GetInt(),
@@ -178,32 +173,14 @@ bool VideoFrameMetadata::GetRect(Key key, gfx::Rect* value) const {
return true;
}
-const base::ListValue* VideoFrameMetadata::GetList(Key key) const {
- return static_cast<const base::ListValue*>(
- dictionary_.FindKeyOfType(ToInternalKey(key), base::Value::Type::LIST));
-}
-
-const base::Value* VideoFrameMetadata::GetValue(Key key) const {
- return dictionary_.FindKey(ToInternalKey(key));
-}
-
bool VideoFrameMetadata::IsTrue(Key key) const {
bool value = false;
return GetBoolean(key, &value) && value;
}
-std::unique_ptr<base::DictionaryValue> VideoFrameMetadata::CopyInternalValues()
- const {
- return dictionary_.CreateDeepCopy();
-}
-
void VideoFrameMetadata::MergeInternalValuesFrom(const base::Value& in) {
- const base::DictionaryValue* dict;
- if (!in.GetAsDictionary(&dict)) {
- NOTREACHED();
- return;
- }
- dictionary_.MergeDictionary(dict);
+ // This function CHECKs if |in| is a dictionary.
+ dictionary_.MergeDictionary(&in);
}
void VideoFrameMetadata::MergeMetadataFrom(
@@ -211,11 +188,4 @@ void VideoFrameMetadata::MergeMetadataFrom(
dictionary_.MergeDictionary(&metadata_source->dictionary_);
}
-const base::Value* VideoFrameMetadata::GetBinaryValue(Key key) const {
- const base::Value* internal_value = dictionary_.FindKey(ToInternalKey(key));
- if (internal_value && (internal_value->type() == base::Value::Type::BINARY))
- return internal_value;
- return nullptr;
-}
-
} // namespace media
diff --git a/chromium/media/base/video_frame_metadata.h b/chromium/media/base/video_frame_metadata.h
index 8ae0303db90..4e873e4152d 100644
--- a/chromium/media/base/video_frame_metadata.h
+++ b/chromium/media/base/video_frame_metadata.h
@@ -177,6 +177,18 @@ class MEDIA_EXPORT VideoFrameMetadata {
// https://w3c.github.io/webrtc-pc/#dom-rtcrtpcontributingsource
RTP_TIMESTAMP,
+ // For video frames coming from a remote source, this is the time the
+ // encoded frame was received by the platform, i.e., the time at
+ // which the last packet belonging to this frame was received over the
+ // network.
+ RECEIVE_TIME,
+
+ // If present, this field represents the duration this frame is ideally
+ // expected to spend on the screen during playback. Unlike FRAME_DURATION
+ // this field takes into account current playback rate.
+ // Use Get/SetTimeDelta() for this key.
+ WALLCLOCK_FRAME_DURATION,
+
NUM_KEYS
};
@@ -197,7 +209,6 @@ class MEDIA_EXPORT VideoFrameMetadata {
void SetTimeTicks(Key key, const base::TimeTicks& value);
void SetUnguessableToken(Key key, const base::UnguessableToken& value);
void SetRect(Key key, const gfx::Rect& value);
- void SetValue(Key key, std::unique_ptr<base::Value> value);
// Getters. Returns true if |key| is present, and its value has been set.
bool GetBoolean(Key key, bool* value) const WARN_UNUSED_RESULT;
@@ -210,16 +221,11 @@ class MEDIA_EXPORT VideoFrameMetadata {
bool GetUnguessableToken(Key key, base::UnguessableToken* value) const
WARN_UNUSED_RESULT;
bool GetRect(Key key, gfx::Rect* value) const WARN_UNUSED_RESULT;
- // Returns null if |key| was not present or value was not a ListValue.
- const base::ListValue* GetList(Key key) const WARN_UNUSED_RESULT;
- // Returns null if |key| was not present.
- const base::Value* GetValue(Key key) const WARN_UNUSED_RESULT;
// Convenience method that returns true if |key| exists and is set to true.
bool IsTrue(Key key) const WARN_UNUSED_RESULT;
// For serialization.
- std::unique_ptr<base::DictionaryValue> CopyInternalValues() const;
void MergeInternalValuesFrom(const base::Value& in);
const base::Value& GetInternalValues() const { return dictionary_; }
@@ -227,8 +233,6 @@ class MEDIA_EXPORT VideoFrameMetadata {
void MergeMetadataFrom(const VideoFrameMetadata* metadata_source);
private:
- const base::Value* GetBinaryValue(Key key) const;
-
base::DictionaryValue dictionary_;
DISALLOW_COPY_AND_ASSIGN(VideoFrameMetadata);
diff --git a/chromium/media/base/video_frame_pool.cc b/chromium/media/base/video_frame_pool.cc
index 37dd36ad513..1d029f054b6 100644
--- a/chromium/media/base/video_frame_pool.cc
+++ b/chromium/media/base/video_frame_pool.cc
@@ -85,14 +85,12 @@ scoped_refptr<VideoFrame> VideoFramePool::PoolImpl::CreateFrame(
DCHECK(!is_shutdown_);
scoped_refptr<VideoFrame> frame;
- while (!frame && !frames_.empty()) {
+ while (!frames_.empty()) {
scoped_refptr<VideoFrame> pool_frame = std::move(frames_.back().frame);
frames_.pop_back();
- if (pool_frame->format() == format &&
- pool_frame->coded_size() == coded_size &&
- pool_frame->visible_rect() == visible_rect &&
- pool_frame->natural_size() == natural_size) {
+ if (pool_frame->IsSameAllocation(format, coded_size, visible_rect,
+ natural_size)) {
frame = pool_frame;
frame->set_timestamp(timestamp);
frame->metadata()->Clear();
diff --git a/chromium/media/base/video_frame_pool_unittest.cc b/chromium/media/base/video_frame_pool_unittest.cc
index 231f58c8099..1588e9d919b 100644
--- a/chromium/media/base/video_frame_pool_unittest.cc
+++ b/chromium/media/base/video_frame_pool_unittest.cc
@@ -5,14 +5,17 @@
#include <stddef.h>
#include <stdint.h>
#include <memory>
+#include <tuple>
+#include "base/bits.h"
#include "base/test/simple_test_tick_clock.h"
#include "media/base/video_frame_pool.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace media {
-class VideoFramePoolTest : public ::testing::TestWithParam<VideoPixelFormat> {
+class VideoFramePoolTest
+ : public ::testing::TestWithParam<std::tuple<VideoPixelFormat, gfx::Size>> {
public:
VideoFramePoolTest() : pool_(new VideoFramePool()) {
// Seed test clock with some dummy non-zero value to avoid confusion with
@@ -22,8 +25,8 @@ class VideoFramePoolTest : public ::testing::TestWithParam<VideoPixelFormat> {
}
scoped_refptr<VideoFrame> CreateFrame(VideoPixelFormat format,
+ const gfx::Size& coded_size,
int timestamp_ms) {
- gfx::Size coded_size(320,240);
gfx::Rect visible_rect(coded_size);
gfx::Size natural_size(coded_size);
@@ -34,7 +37,13 @@ class VideoFramePoolTest : public ::testing::TestWithParam<VideoPixelFormat> {
EXPECT_EQ(format, frame->format());
EXPECT_EQ(base::TimeDelta::FromMilliseconds(timestamp_ms),
frame->timestamp());
- EXPECT_EQ(coded_size, frame->coded_size());
+ if (format == PIXEL_FORMAT_ARGB) {
+ EXPECT_EQ(coded_size, frame->coded_size());
+ } else {
+ const gfx::Size adjusted(base::bits::Align(coded_size.width(), 2),
+ base::bits::Align(coded_size.height(), 2));
+ EXPECT_EQ(adjusted, frame->coded_size());
+ }
EXPECT_EQ(visible_rect, frame->visible_rect());
EXPECT_EQ(natural_size, frame->natural_size());
@@ -51,34 +60,44 @@ class VideoFramePoolTest : public ::testing::TestWithParam<VideoPixelFormat> {
};
TEST_P(VideoFramePoolTest, FrameInitializedAndZeroed) {
- scoped_refptr<VideoFrame> frame = CreateFrame(GetParam(), 10);
+ scoped_refptr<VideoFrame> frame =
+ CreateFrame(std::get<0>(GetParam()), std::get<1>(GetParam()), 10);
// Verify that frame is initialized with zeros.
for (size_t i = 0; i < VideoFrame::NumPlanes(frame->format()); ++i)
EXPECT_EQ(0, frame->data(i)[0]);
}
-INSTANTIATE_TEST_SUITE_P(All,
- VideoFramePoolTest,
- testing::Values(PIXEL_FORMAT_I420,
- PIXEL_FORMAT_NV12,
- PIXEL_FORMAT_ARGB));
-
-TEST_F(VideoFramePoolTest, SimpleFrameReuse) {
- scoped_refptr<VideoFrame> frame = CreateFrame(PIXEL_FORMAT_I420, 10);
+TEST_P(VideoFramePoolTest, FrameReuse) {
+ scoped_refptr<VideoFrame> frame =
+ CreateFrame(std::get<0>(GetParam()), std::get<1>(GetParam()), 10);
const uint8_t* old_y_data = frame->data(VideoFrame::kYPlane);
// Clear frame reference to return the frame to the pool.
frame.reset();
// Verify that the next frame from the pool uses the same memory.
- scoped_refptr<VideoFrame> new_frame = CreateFrame(PIXEL_FORMAT_I420, 20);
+ scoped_refptr<VideoFrame> new_frame =
+ CreateFrame(std::get<0>(GetParam()), std::get<1>(GetParam()), 20);
EXPECT_EQ(old_y_data, new_frame->data(VideoFrame::kYPlane));
}
+INSTANTIATE_TEST_SUITE_P(All,
+ VideoFramePoolTest,
+ ::testing::Combine(testing::Values(PIXEL_FORMAT_I420,
+ PIXEL_FORMAT_NV12,
+ PIXEL_FORMAT_ARGB),
+ testing::Values(gfx::Size(320, 240),
+ gfx::Size(321, 240),
+ gfx::Size(320, 241),
+ gfx::Size(321,
+ 241))));
+
TEST_F(VideoFramePoolTest, SimpleFormatChange) {
- scoped_refptr<VideoFrame> frame_a = CreateFrame(PIXEL_FORMAT_I420, 10);
- scoped_refptr<VideoFrame> frame_b = CreateFrame(PIXEL_FORMAT_I420, 10);
+ scoped_refptr<VideoFrame> frame_a =
+ CreateFrame(PIXEL_FORMAT_I420, gfx::Size(320, 240), 10);
+ scoped_refptr<VideoFrame> frame_b =
+ CreateFrame(PIXEL_FORMAT_I420, gfx::Size(320, 240), 10);
// Clear frame references to return the frames to the pool.
frame_a.reset();
@@ -89,12 +108,14 @@ TEST_F(VideoFramePoolTest, SimpleFormatChange) {
// Verify that requesting a frame with a different format causes the pool
// to get drained.
- scoped_refptr<VideoFrame> new_frame = CreateFrame(PIXEL_FORMAT_I420A, 10);
+ scoped_refptr<VideoFrame> new_frame =
+ CreateFrame(PIXEL_FORMAT_I420A, gfx::Size(320, 240), 10);
CheckPoolSize(0u);
}
TEST_F(VideoFramePoolTest, FrameValidAfterPoolDestruction) {
- scoped_refptr<VideoFrame> frame = CreateFrame(PIXEL_FORMAT_I420, 10);
+ scoped_refptr<VideoFrame> frame =
+ CreateFrame(PIXEL_FORMAT_I420, gfx::Size(320, 240), 10);
// Destroy the pool.
pool_.reset();
@@ -106,8 +127,10 @@ TEST_F(VideoFramePoolTest, FrameValidAfterPoolDestruction) {
}
TEST_F(VideoFramePoolTest, StaleFramesAreExpired) {
- scoped_refptr<VideoFrame> frame_1 = CreateFrame(PIXEL_FORMAT_I420, 10);
- scoped_refptr<VideoFrame> frame_2 = CreateFrame(PIXEL_FORMAT_I420, 10);
+ scoped_refptr<VideoFrame> frame_1 =
+ CreateFrame(PIXEL_FORMAT_I420, gfx::Size(320, 240), 10);
+ scoped_refptr<VideoFrame> frame_2 =
+ CreateFrame(PIXEL_FORMAT_I420, gfx::Size(320, 240), 10);
EXPECT_NE(frame_1.get(), frame_2.get());
CheckPoolSize(0u);
diff --git a/chromium/media/base/video_frame_unittest.cc b/chromium/media/base/video_frame_unittest.cc
index 88024574d37..17a1b972c64 100644
--- a/chromium/media/base/video_frame_unittest.cc
+++ b/chromium/media/base/video_frame_unittest.cc
@@ -353,33 +353,6 @@ TEST(VideoFrame, WrapSharedMemory) {
EXPECT_EQ(frame->data(media::VideoFrame::kYPlane)[0], 0xff);
}
-// Create a frame that wraps shared memory with an offset.
-TEST(VideoFrame, WrapUnsafeSharedMemoryWithOffset) {
- const size_t kOffset = 64;
- const size_t kDataSize = 2 * 256 * 256;
- base::UnsafeSharedMemoryRegion region =
- base::UnsafeSharedMemoryRegion::Create(kDataSize + kOffset);
- ASSERT_TRUE(region.IsValid());
- base::WritableSharedMemoryMapping mapping = region.Map();
- ASSERT_TRUE(mapping.IsValid());
- gfx::Size coded_size(256, 256);
- gfx::Rect visible_rect(coded_size);
- CreateTestY16Frame(
- coded_size, visible_rect,
- mapping.GetMemoryAsSpan<uint8_t>().subspan(kOffset).data());
- auto timestamp = base::TimeDelta::FromMilliseconds(1);
- auto frame = VideoFrame::WrapExternalData(
- media::PIXEL_FORMAT_Y16, coded_size, visible_rect, visible_rect.size(),
- mapping.GetMemoryAsSpan<uint8_t>().subspan(kOffset).data(), kDataSize,
- timestamp);
- frame->BackWithSharedMemory(&region, kOffset);
-
- EXPECT_EQ(frame->coded_size(), coded_size);
- EXPECT_EQ(frame->visible_rect(), visible_rect);
- EXPECT_EQ(frame->timestamp(), timestamp);
- EXPECT_EQ(frame->data(media::VideoFrame::kYPlane)[0], 0xff);
-}
-
TEST(VideoFrame, WrapExternalGpuMemoryBuffer) {
gfx::Size coded_size = gfx::Size(256, 256);
gfx::Rect visible_rect(coded_size);
@@ -630,6 +603,7 @@ TEST(VideoFrame, AllocationSize_OddSize) {
EXPECT_EQ(72u, VideoFrame::AllocationSize(format, size))
<< VideoPixelFormatToString(format);
break;
+ case PIXEL_FORMAT_UYVY:
case PIXEL_FORMAT_YUY2:
case PIXEL_FORMAT_I422:
EXPECT_EQ(48u, VideoFrame::AllocationSize(format, size))
@@ -708,29 +682,44 @@ TEST(VideoFrameMetadata, SetAndThenGetAllKeysForAllTypes) {
metadata.Clear();
EXPECT_FALSE(metadata.HasKey(key));
- metadata.SetTimeDelta(key, base::TimeDelta::FromInternalValue(42 + i));
+ base::TimeDelta reference_delta = base::TimeDelta::FromMilliseconds(42 + i);
+ metadata.SetTimeDelta(key, reference_delta);
EXPECT_TRUE(metadata.HasKey(key));
base::TimeDelta delta_value;
EXPECT_TRUE(metadata.GetTimeDelta(key, &delta_value));
- EXPECT_EQ(base::TimeDelta::FromInternalValue(42 + i), delta_value);
+ EXPECT_EQ(reference_delta, delta_value);
metadata.Clear();
EXPECT_FALSE(metadata.HasKey(key));
- metadata.SetTimeTicks(key, base::TimeTicks::FromInternalValue(~(0LL) + i));
+ base::TimeTicks reference_ticks =
+ base::TimeTicks() + base::TimeDelta::FromMilliseconds(1234 + i);
+ metadata.SetTimeTicks(key, reference_ticks);
EXPECT_TRUE(metadata.HasKey(key));
base::TimeTicks ticks_value;
EXPECT_TRUE(metadata.GetTimeTicks(key, &ticks_value));
- EXPECT_EQ(base::TimeTicks::FromInternalValue(~(0LL) + i), ticks_value);
+ EXPECT_EQ(reference_ticks, ticks_value);
metadata.Clear();
EXPECT_FALSE(metadata.HasKey(key));
- metadata.SetValue(key, std::make_unique<base::Value>());
+ gfx::Rect reference_rect = gfx::Rect(3, 5, 240, 360);
+ metadata.SetRect(key, reference_rect);
EXPECT_TRUE(metadata.HasKey(key));
- const base::Value* const null_value = metadata.GetValue(key);
- EXPECT_TRUE(null_value);
- EXPECT_EQ(base::Value::Type::NONE, null_value->type());
+ gfx::Rect rect_value;
+ EXPECT_TRUE(metadata.GetRect(key, &rect_value));
+ EXPECT_EQ(reference_rect, rect_value);
metadata.Clear();
}
+
+ // The Get/SetRotation methods only accept ROTATION as a key.
+ auto rot_key = VideoFrameMetadata::Key::ROTATION;
+ EXPECT_FALSE(metadata.HasKey(rot_key));
+ VideoRotation reference_rot = VideoRotation::VIDEO_ROTATION_270;
+ metadata.SetRotation(rot_key, reference_rot);
+ EXPECT_TRUE(metadata.HasKey(rot_key));
+ VideoRotation rot_value;
+ EXPECT_TRUE(metadata.GetRotation(rot_key, &rot_value));
+ EXPECT_EQ(reference_rot, rot_value);
+ metadata.Clear();
}
TEST(VideoFrameMetadata, PassMetadataViaIntermediary) {
@@ -749,6 +738,16 @@ TEST(VideoFrameMetadata, PassMetadataViaIntermediary) {
EXPECT_TRUE(result.GetInteger(key, &value));
EXPECT_EQ(i, value);
}
+
+ result.Clear();
+ result.MergeInternalValuesFrom(expected.GetInternalValues());
+
+ for (int i = 0; i < VideoFrameMetadata::NUM_KEYS; ++i) {
+ const VideoFrameMetadata::Key key = static_cast<VideoFrameMetadata::Key>(i);
+ int value = -1;
+ EXPECT_TRUE(result.GetInteger(key, &value));
+ EXPECT_EQ(i, value);
+ }
}
} // namespace media
diff --git a/chromium/media/base/video_renderer.h b/chromium/media/base/video_renderer.h
index c8268c571f4..bfbc676c856 100644
--- a/chromium/media/base/video_renderer.h
+++ b/chromium/media/base/video_renderer.h
@@ -7,6 +7,7 @@
#include "base/callback_forward.h"
#include "base/macros.h"
+#include "base/optional.h"
#include "media/base/media_export.h"
#include "media/base/pipeline_status.h"
#include "media/base/time_source.h"
@@ -42,7 +43,7 @@ class MEDIA_EXPORT VideoRenderer {
CdmContext* cdm_context,
RendererClient* client,
const TimeSource::WallClockTimeCB& wall_clock_time_cb,
- const PipelineStatusCB& init_cb) = 0;
+ PipelineStatusCallback init_cb) = 0;
// Discards any video data and stops reading from |stream|, executing
// |callback| when completed.
@@ -63,6 +64,12 @@ class MEDIA_EXPORT VideoRenderer {
virtual void OnTimeProgressing() = 0;
virtual void OnTimeStopped() = 0;
+ // Sets a hint indicating target latency. See comment in header for
+ // media::Renderer::SetLatencyHint().
+ // |latency_hint| may be nullopt to indicate the hint has been cleared
+ // (restore UA default).
+ virtual void SetLatencyHint(base::Optional<base::TimeDelta> latency_hint) = 0;
+
private:
DISALLOW_COPY_AND_ASSIGN(VideoRenderer);
};
diff --git a/chromium/media/base/video_thumbnail_decoder.cc b/chromium/media/base/video_thumbnail_decoder.cc
index d6f67b05f69..130813a00fb 100644
--- a/chromium/media/base/video_thumbnail_decoder.cc
+++ b/chromium/media/base/video_thumbnail_decoder.cc
@@ -29,15 +29,15 @@ void VideoThumbnailDecoder::Start(VideoFrameCallback video_frame_callback) {
DCHECK(video_frame_callback_);
decoder_->Initialize(
config_, false, nullptr,
- base::BindRepeating(&VideoThumbnailDecoder::OnVideoDecoderInitialized,
- weak_factory_.GetWeakPtr()),
+ base::BindOnce(&VideoThumbnailDecoder::OnVideoDecoderInitialized,
+ weak_factory_.GetWeakPtr()),
base::BindRepeating(&VideoThumbnailDecoder::OnVideoFrameDecoded,
weak_factory_.GetWeakPtr()),
base::DoNothing());
}
-void VideoThumbnailDecoder::OnVideoDecoderInitialized(bool success) {
- if (!success) {
+void VideoThumbnailDecoder::OnVideoDecoderInitialized(Status status) {
+ if (!status.is_ok()) {
NotifyComplete(nullptr);
return;
}
@@ -45,8 +45,8 @@ void VideoThumbnailDecoder::OnVideoDecoderInitialized(bool success) {
auto buffer =
DecoderBuffer::CopyFrom(&encoded_data_[0], encoded_data_.size());
encoded_data_.clear();
- decoder_->Decode(
- buffer, base::BindRepeating(&VideoThumbnailDecoder::OnVideoBufferDecoded,
+ decoder_->Decode(buffer,
+ base::BindOnce(&VideoThumbnailDecoder::OnVideoBufferDecoded,
weak_factory_.GetWeakPtr()));
}
@@ -57,10 +57,9 @@ void VideoThumbnailDecoder::OnVideoBufferDecoded(DecodeStatus status) {
}
// Enqueue eos since only one video frame is needed for thumbnail.
- decoder_->Decode(
- DecoderBuffer::CreateEOSBuffer(),
- base::BindRepeating(&VideoThumbnailDecoder::OnEosBufferDecoded,
- weak_factory_.GetWeakPtr()));
+ decoder_->Decode(DecoderBuffer::CreateEOSBuffer(),
+ base::BindOnce(&VideoThumbnailDecoder::OnEosBufferDecoded,
+ weak_factory_.GetWeakPtr()));
}
void VideoThumbnailDecoder::OnEosBufferDecoded(DecodeStatus status) {
diff --git a/chromium/media/base/video_thumbnail_decoder.h b/chromium/media/base/video_thumbnail_decoder.h
index 363006f1208..69f0c4faf76 100644
--- a/chromium/media/base/video_thumbnail_decoder.h
+++ b/chromium/media/base/video_thumbnail_decoder.h
@@ -38,7 +38,7 @@ class MEDIA_EXPORT VideoThumbnailDecoder {
void Start(VideoFrameCallback video_frame_callback);
private:
- void OnVideoDecoderInitialized(bool success);
+ void OnVideoDecoderInitialized(Status status);
void OnVideoBufferDecoded(DecodeStatus status);
void OnEosBufferDecoded(DecodeStatus status);
diff --git a/chromium/media/base/video_thumbnail_decoder_unittest.cc b/chromium/media/base/video_thumbnail_decoder_unittest.cc
index 57550ae10bd..93e343345b9 100644
--- a/chromium/media/base/video_thumbnail_decoder_unittest.cc
+++ b/chromium/media/base/video_thumbnail_decoder_unittest.cc
@@ -85,8 +85,8 @@ class VideoThumbnailDecoderTest : public testing::Test {
TEST_F(VideoThumbnailDecoderTest, Success) {
auto expected_frame = CreateFrame();
EXPECT_CALL(*mock_video_decoder(), Initialize_(_, _, _, _, _, _))
- .WillOnce(
- DoAll(RunOnceCallback<3>(true), RunCallback<4>(expected_frame)));
+ .WillOnce(DoAll(RunOnceCallback<3>(OkStatus()),
+ RunCallback<4>(expected_frame)));
EXPECT_CALL(*mock_video_decoder(), Decode_(_, _))
.Times(2)
.WillRepeatedly(RunOnceCallback<1>(DecodeStatus::OK));
@@ -99,7 +99,7 @@ TEST_F(VideoThumbnailDecoderTest, Success) {
TEST_F(VideoThumbnailDecoderTest, InitializationFailed) {
auto expected_frame = CreateFrame();
EXPECT_CALL(*mock_video_decoder(), Initialize_(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<3>(false));
+ .WillOnce(RunOnceCallback<3>(StatusCode::kCodeOnlyForTesting));
Start();
EXPECT_FALSE(frame());
@@ -109,7 +109,7 @@ TEST_F(VideoThumbnailDecoderTest, InitializationFailed) {
TEST_F(VideoThumbnailDecoderTest, DecodingFailed) {
auto expected_frame = CreateFrame();
EXPECT_CALL(*mock_video_decoder(), Initialize_(_, _, _, _, _, _))
- .WillOnce(RunOnceCallback<3>(true));
+ .WillOnce(RunOnceCallback<3>(OkStatus()));
EXPECT_CALL(*mock_video_decoder(), Decode_(_, _))
.WillOnce(RunOnceCallback<1>(DecodeStatus::DECODE_ERROR));
diff --git a/chromium/media/base/video_types.cc b/chromium/media/base/video_types.cc
index 624f89deff0..6f23ea771a0 100644
--- a/chromium/media/base/video_types.cc
+++ b/chromium/media/base/video_types.cc
@@ -27,6 +27,8 @@ std::string VideoPixelFormatToString(VideoPixelFormat format) {
return "PIXEL_FORMAT_NV12";
case PIXEL_FORMAT_NV21:
return "PIXEL_FORMAT_NV21";
+ case PIXEL_FORMAT_UYVY:
+ return "PIXEL_FORMAT_UYVY";
case PIXEL_FORMAT_YUY2:
return "PIXEL_FORMAT_YUY2";
case PIXEL_FORMAT_ARGB:
@@ -112,6 +114,7 @@ bool IsYuvPlanar(VideoPixelFormat format) {
return true;
case PIXEL_FORMAT_UNKNOWN:
+ case PIXEL_FORMAT_UYVY:
case PIXEL_FORMAT_YUY2:
case PIXEL_FORMAT_ARGB:
case PIXEL_FORMAT_XRGB:
@@ -138,6 +141,7 @@ bool IsOpaque(VideoPixelFormat format) {
case PIXEL_FORMAT_NV12:
case PIXEL_FORMAT_NV21:
case PIXEL_FORMAT_YUY2:
+ case PIXEL_FORMAT_UYVY:
case PIXEL_FORMAT_XRGB:
case PIXEL_FORMAT_RGB24:
case PIXEL_FORMAT_MJPEG:
@@ -178,6 +182,7 @@ size_t BitDepth(VideoPixelFormat format) {
case PIXEL_FORMAT_NV12:
case PIXEL_FORMAT_NV21:
case PIXEL_FORMAT_YUY2:
+ case PIXEL_FORMAT_UYVY:
case PIXEL_FORMAT_ARGB:
case PIXEL_FORMAT_XRGB:
case PIXEL_FORMAT_RGB24:
diff --git a/chromium/media/base/video_types.h b/chromium/media/base/video_types.h
index 8fda6d85b19..2205036a07c 100644
--- a/chromium/media/base/video_types.h
+++ b/chromium/media/base/video_types.h
@@ -37,7 +37,8 @@ enum VideoPixelFormat {
6, // 12bpp with Y plane followed by a 2x2 interleaved UV plane.
PIXEL_FORMAT_NV21 =
7, // 12bpp with Y plane followed by a 2x2 interleaved VU plane.
- /* PIXEL_FORMAT_UYVY = 8, Deprecated */
+ PIXEL_FORMAT_UYVY =
+ 8, // 16bpp interleaved 2x1 U, 1x1 Y, 2x1 V, 1x1 Y samples.
PIXEL_FORMAT_YUY2 =
9, // 16bpp interleaved 1x1 Y, 2x1 U, 1x1 Y, 2x1 V samples.
PIXEL_FORMAT_ARGB = 10, // 32bpp BGRA (byte-order), 1 plane.
diff --git a/chromium/media/base/video_util.cc b/chromium/media/base/video_util.cc
index e97350aaf81..bc4c55619d3 100644
--- a/chromium/media/base/video_util.cc
+++ b/chromium/media/base/video_util.cc
@@ -382,6 +382,10 @@ gfx::Size ScaleSizeToEncompassTarget(const gfx::Size& size,
return ScaleSizeToTarget(size, target, false);
}
+gfx::Size GetRectSizeFromOrigin(const gfx::Rect& rect) {
+ return gfx::Size(rect.right(), rect.bottom());
+}
+
gfx::Size PadToMatchAspectRatio(const gfx::Size& size,
const gfx::Size& target) {
if (target.IsEmpty())
diff --git a/chromium/media/base/video_util.h b/chromium/media/base/video_util.h
index b40331c0293..42e060a25b7 100644
--- a/chromium/media/base/video_util.h
+++ b/chromium/media/base/video_util.h
@@ -114,6 +114,17 @@ MEDIA_EXPORT gfx::Size ScaleSizeToFitWithinTarget(const gfx::Size& size,
MEDIA_EXPORT gfx::Size ScaleSizeToEncompassTarget(const gfx::Size& size,
const gfx::Size& target);
+// Returns the size of a rectangle whose upper left corner is at the origin (0,
+// 0) and whose bottom right corner is the same as that of |rect|. This is
+// useful to get the size of a buffer that contains the visible rectangle plus
+// the non-visible area above and to the left of the visible rectangle.
+//
+// An example to illustrate: suppose the visible rectangle of a decoded frame is
+// 10,10,100,100. The size of this rectangle is 90x90. However, we need to
+// create a texture of size 100x100 because the client will want to sample from
+// the texture starting with uv coordinates corresponding to 10,10.
+MEDIA_EXPORT gfx::Size GetRectSizeFromOrigin(const gfx::Rect& rect);
+
// Returns |size| with only one of its dimensions increased such that the result
// matches the aspect ratio of |target|. This is different from
// ScaleSizeToEncompassTarget() in two ways: 1) The goal is to match the aspect
diff --git a/chromium/media/base/video_util_unittest.cc b/chromium/media/base/video_util_unittest.cc
index b4b5513b35d..79af565e5b0 100644
--- a/chromium/media/base/video_util_unittest.cc
+++ b/chromium/media/base/video_util_unittest.cc
@@ -458,6 +458,12 @@ TEST_F(VideoUtilTest, ComputeLetterboxRegion) {
gfx::Size(40000, 30000)));
EXPECT_TRUE(ComputeLetterboxRegion(gfx::Rect(0, 0, 2000000000, 2000000000),
gfx::Size(0, 0)).IsEmpty());
+
+ // Some operations in the internal ScaleSizeToTarget() use rounded division
+ // and might lose some precision, this expectation codifies that.
+ EXPECT_EQ(
+ gfx::Rect(0, 0, 1279, 720),
+ ComputeLetterboxRegion(gfx::Rect(0, 0, 1280, 720), gfx::Size(1057, 595)));
}
// Tests the ComputeLetterboxRegionForI420 function.
diff --git a/chromium/media/base/win/BUILD.gn b/chromium/media/base/win/BUILD.gn
index d851563429a..c4d20d2fed4 100644
--- a/chromium/media/base/win/BUILD.gn
+++ b/chromium/media/base/win/BUILD.gn
@@ -45,12 +45,8 @@ jumbo_component("media_foundation_util") {
}
source_set("d3d11") {
- sources = [
- "d3d11_create_device_cb.h",
- ]
- deps = [
- "//base",
- ]
+ sources = [ "d3d11_create_device_cb.h" ]
+ deps = [ "//base" ]
}
source_set("d3d11_test_support") {
diff --git a/chromium/media/base/win/d3d11_mocks.cc b/chromium/media/base/win/d3d11_mocks.cc
index 4dddc97321d..b921f2551e8 100644
--- a/chromium/media/base/win/d3d11_mocks.cc
+++ b/chromium/media/base/win/d3d11_mocks.cc
@@ -18,12 +18,21 @@ D3D11BufferMock::~D3D11BufferMock() = default;
D3D11DeviceMock::D3D11DeviceMock() = default;
D3D11DeviceMock::~D3D11DeviceMock() = default;
+DXGIFactoryMock::DXGIFactoryMock() = default;
+DXGIFactoryMock::~DXGIFactoryMock() = default;
+
DXGIDeviceMock::DXGIDeviceMock() = default;
DXGIDeviceMock::~DXGIDeviceMock() = default;
DXGIDevice2Mock::DXGIDevice2Mock() = default;
DXGIDevice2Mock::~DXGIDevice2Mock() = default;
+DXGIOutputMock::DXGIOutputMock() = default;
+DXGIOutputMock::~DXGIOutputMock() = default;
+
+DXGIOutput6Mock::DXGIOutput6Mock() = default;
+DXGIOutput6Mock::~DXGIOutput6Mock() = default;
+
DXGIAdapterMock::DXGIAdapterMock() = default;
DXGIAdapterMock::~DXGIAdapterMock() = default;
diff --git a/chromium/media/base/win/d3d11_mocks.h b/chromium/media/base/win/d3d11_mocks.h
index 81169c0dbdb..fef030f6ca5 100644
--- a/chromium/media/base/win/d3d11_mocks.h
+++ b/chromium/media/base/win/d3d11_mocks.h
@@ -8,6 +8,7 @@
#include <d3d11.h>
#include <d3d11_1.h>
#include <dxgi1_4.h>
+#include <dxgi1_6.h>
#include <wrl/client.h>
#include <wrl/implements.h>
@@ -286,6 +287,28 @@ class D3D11DeviceMock
MOCK_STDCALL_METHOD0(GetExceptionMode, UINT());
};
+class DXGIFactoryMock
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
+ IDXGIFactory> {
+ public:
+ DXGIFactoryMock();
+ ~DXGIFactoryMock() override;
+ MOCK_STDCALL_METHOD2(CreateSoftwareAdapter, HRESULT(HMODULE, IDXGIAdapter**));
+ MOCK_STDCALL_METHOD3(CreateSwapChain,
+ HRESULT(IUnknown*,
+ DXGI_SWAP_CHAIN_DESC*,
+ IDXGISwapChain**));
+ MOCK_STDCALL_METHOD2(EnumAdapters, HRESULT(UINT, IDXGIAdapter**));
+ MOCK_STDCALL_METHOD1(GetWindowAssociation, HRESULT(HWND*));
+ MOCK_STDCALL_METHOD2(MakeWindowAssociation, HRESULT(HWND, UINT));
+ MOCK_STDCALL_METHOD3(SetPrivateData, HRESULT(REFGUID, UINT, const void*));
+ MOCK_STDCALL_METHOD2(SetPrivateDataInterface,
+ HRESULT(REFGUID, const IUnknown*));
+ MOCK_STDCALL_METHOD2(GetParent, HRESULT(REFIID, void**));
+ MOCK_STDCALL_METHOD3(GetPrivateData, HRESULT(REFGUID, UINT*, void*));
+};
+
class DXGIDeviceMock
: public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
@@ -417,7 +440,112 @@ class DXGIAdapterMock
HRESULT(REFGUID, const IUnknown*));
};
-// TODO(crbug.com/788880): This may not be necessary. Tyr out and see if
+class DXGIOutputMock
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
+ IDXGIOutput> {
+ public:
+ DXGIOutputMock();
+ ~DXGIOutputMock() override;
+ MOCK_STDCALL_METHOD3(FindClosestMatchingMode,
+ HRESULT(const DXGI_MODE_DESC*,
+ DXGI_MODE_DESC*,
+ IUnknown*));
+ MOCK_STDCALL_METHOD1(GetDesc, HRESULT(DXGI_OUTPUT_DESC*));
+ MOCK_STDCALL_METHOD4(GetDisplayModeList,
+ HRESULT(DXGI_FORMAT, UINT, UINT*, DXGI_MODE_DESC*));
+ MOCK_STDCALL_METHOD1(GetDisplaySurfaceData, HRESULT(IDXGISurface*));
+ MOCK_STDCALL_METHOD1(GetFrameStatistics, HRESULT(DXGI_FRAME_STATISTICS*));
+ MOCK_STDCALL_METHOD1(GetGammaControl, HRESULT(DXGI_GAMMA_CONTROL*));
+ MOCK_STDCALL_METHOD1(GetGammaControlCapabilities,
+ HRESULT(DXGI_GAMMA_CONTROL_CAPABILITIES*));
+ MOCK_STDCALL_METHOD0(ReleaseOwnership, void());
+ MOCK_STDCALL_METHOD1(SetDisplaySurface, HRESULT(IDXGISurface*));
+ MOCK_STDCALL_METHOD1(SetGammaControl, HRESULT(const DXGI_GAMMA_CONTROL*));
+ MOCK_STDCALL_METHOD2(TakeOwnership, HRESULT(IUnknown*, BOOL));
+ MOCK_STDCALL_METHOD0(WaitForVBlank, HRESULT());
+
+ MOCK_STDCALL_METHOD3(SetPrivateData, HRESULT(REFGUID, UINT, const void*));
+ MOCK_STDCALL_METHOD2(SetPrivateDataInterface,
+ HRESULT(REFGUID, const IUnknown*));
+ MOCK_STDCALL_METHOD2(GetParent, HRESULT(REFIID, void**));
+ MOCK_STDCALL_METHOD3(GetPrivateData, HRESULT(REFGUID, UINT*, void*));
+
+ // IUnknown
+ MOCK_STDCALL_METHOD2(QueryInterface, HRESULT(REFIID riid, void** ppv));
+};
+
+class DXGIOutput6Mock
+ : public Microsoft::WRL::RuntimeClass<
+ Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
+ IDXGIOutput6> {
+ public:
+ DXGIOutput6Mock();
+ ~DXGIOutput6Mock() override;
+
+ // IDXGIOutput6
+ MOCK_STDCALL_METHOD1(GetDesc1, HRESULT(DXGI_OUTPUT_DESC1*));
+ MOCK_STDCALL_METHOD1(CheckHardwareCompositionSupport, HRESULT(UINT*));
+
+ // IDXGIOutput5
+ MOCK_STDCALL_METHOD5(DuplicateOutput1,
+ HRESULT(IUnknown*,
+ UINT,
+ UINT,
+ const DXGI_FORMAT*,
+ IDXGIOutputDuplication**));
+
+ // IDXGIOutput4
+ MOCK_STDCALL_METHOD4(
+ CheckOverlayColorSpaceSupport,
+ HRESULT(DXGI_FORMAT, DXGI_COLOR_SPACE_TYPE, IUnknown*, UINT*));
+
+ // IDXGIOutput3
+ MOCK_STDCALL_METHOD3(CheckOverlaySupport,
+ HRESULT(DXGI_FORMAT, IUnknown*, UINT*));
+
+ // IDXGIOutput2
+ MOCK_STDCALL_METHOD0(SupportsOverlays, BOOL());
+
+ // IDXGIOutput1
+ MOCK_STDCALL_METHOD2(DuplicateOutput,
+ HRESULT(IUnknown*, IDXGIOutputDuplication**));
+ MOCK_STDCALL_METHOD3(FindClosestMatchingMode1,
+ HRESULT(const DXGI_MODE_DESC1*,
+ DXGI_MODE_DESC1*,
+ IUnknown*));
+ MOCK_STDCALL_METHOD4(GetDisplayModeList1,
+ HRESULT(DXGI_FORMAT, UINT, UINT*, DXGI_MODE_DESC1*));
+ MOCK_STDCALL_METHOD1(GetDisplaySurfaceData1, HRESULT(IDXGIResource*));
+
+ // IDXGIOutput
+ MOCK_STDCALL_METHOD3(FindClosestMatchingMode,
+ HRESULT(const DXGI_MODE_DESC*,
+ DXGI_MODE_DESC*,
+ IUnknown*));
+ MOCK_STDCALL_METHOD1(GetDesc, HRESULT(DXGI_OUTPUT_DESC*));
+ MOCK_STDCALL_METHOD4(GetDisplayModeList,
+ HRESULT(DXGI_FORMAT, UINT, UINT*, DXGI_MODE_DESC*));
+ MOCK_STDCALL_METHOD1(GetDisplaySurfaceData, HRESULT(IDXGISurface*));
+ MOCK_STDCALL_METHOD1(GetFrameStatistics, HRESULT(DXGI_FRAME_STATISTICS*));
+ MOCK_STDCALL_METHOD1(GetGammaControl, HRESULT(DXGI_GAMMA_CONTROL*));
+ MOCK_STDCALL_METHOD1(GetGammaControlCapabilities,
+ HRESULT(DXGI_GAMMA_CONTROL_CAPABILITIES*));
+ MOCK_STDCALL_METHOD0(ReleaseOwnership, void());
+ MOCK_STDCALL_METHOD1(SetDisplaySurface, HRESULT(IDXGISurface*));
+ MOCK_STDCALL_METHOD1(SetGammaControl, HRESULT(const DXGI_GAMMA_CONTROL*));
+ MOCK_STDCALL_METHOD2(TakeOwnership, HRESULT(IUnknown*, BOOL));
+ MOCK_STDCALL_METHOD0(WaitForVBlank, HRESULT());
+
+ // IDXGIObject
+ MOCK_STDCALL_METHOD3(SetPrivateData, HRESULT(REFGUID, UINT, const void*));
+ MOCK_STDCALL_METHOD2(SetPrivateDataInterface,
+ HRESULT(REFGUID, const IUnknown*));
+ MOCK_STDCALL_METHOD2(GetParent, HRESULT(REFIID, void**));
+ MOCK_STDCALL_METHOD3(GetPrivateData, HRESULT(REFGUID, UINT*, void*));
+};
+
+// TODO(crbug.com/788880): This may not be necessary. Try out and see if
// D3D11VideoDevice1Mock is sufficient. and if so, remove this.
class D3D11VideoDeviceMock
: public Microsoft::WRL::RuntimeClass<
diff --git a/chromium/media/base/win/dxgi_device_scope_handle_unittest.cc b/chromium/media/base/win/dxgi_device_scope_handle_unittest.cc
new file mode 100644
index 00000000000..5058d1bfd31
--- /dev/null
+++ b/chromium/media/base/win/dxgi_device_scope_handle_unittest.cc
@@ -0,0 +1,91 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <d3d11.h>
+#include <mfapi.h>
+
+#include "base/win/windows_version.h"
+#include "media/base/test_helpers.h"
+#include "media/base/win/mf_helpers.h"
+#include "media/base/win/mf_initializer.h"
+
+namespace media {
+
+using Microsoft::WRL::ComPtr;
+
+class DXGIDeviceScopedHandleTest : public testing::Test {
+ public:
+ DXGIDeviceScopedHandleTest()
+ : test_supported_(base::win::GetVersion() >= base::win::Version::WIN10) {}
+ ~DXGIDeviceScopedHandleTest() override = default;
+
+ protected:
+ void SetUp() override {
+ if (!test_supported_)
+ return;
+
+ ASSERT_NE(nullptr, session_ = InitializeMediaFoundation());
+
+ // Get a shared DXGI Device Manager from Media Foundation.
+ ASSERT_HRESULT_SUCCEEDED(
+ MFLockDXGIDeviceManager(&device_reset_token_, &dxgi_device_man_));
+
+ // |dxgi_device_man_| does not create the device, creates Direct3D device.
+ ComPtr<ID3D11Device> d3d11_device;
+ UINT creation_flags =
+ (D3D11_CREATE_DEVICE_VIDEO_SUPPORT | D3D11_CREATE_DEVICE_BGRA_SUPPORT |
+ D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS);
+ static const D3D_FEATURE_LEVEL feature_levels[] = {
+ D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1,
+ D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3, D3D_FEATURE_LEVEL_9_2,
+ D3D_FEATURE_LEVEL_9_1};
+ ASSERT_HRESULT_SUCCEEDED(
+ D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, 0, creation_flags,
+ feature_levels, ARRAYSIZE(feature_levels),
+ D3D11_SDK_VERSION, &d3d11_device, nullptr, nullptr));
+
+ ComPtr<ID3D10Multithread> multithreaded_device;
+ ASSERT_HRESULT_SUCCEEDED(d3d11_device.As(&multithreaded_device));
+ multithreaded_device->SetMultithreadProtected(TRUE);
+
+ // Set Direct3D device to the device manager.
+ ASSERT_HRESULT_SUCCEEDED(
+ dxgi_device_man_->ResetDevice(d3d11_device.Get(), device_reset_token_));
+ }
+
+ void TearDown() override {
+ if (test_supported_) {
+ ASSERT_HRESULT_SUCCEEDED(MFUnlockDXGIDeviceManager());
+ }
+ }
+
+ MFSessionLifetime session_;
+ Microsoft::WRL::ComPtr<IMFDXGIDeviceManager> dxgi_device_man_ = nullptr;
+ UINT device_reset_token_ = 0;
+ const bool test_supported_;
+};
+
+TEST_F(DXGIDeviceScopedHandleTest, UseDXGIDeviceScopedHandle) {
+ if (!test_supported_)
+ return;
+
+ {
+ // Create DXGIDeviceScopedHandle in an inner scope without LockDevice
+ // call.
+ DXGIDeviceScopedHandle device_handle_1(dxgi_device_man_.Get());
+ }
+ {
+ // Create DXGIDeviceScopedHandle in an inner scope with LockDevice call.
+ DXGIDeviceScopedHandle device_handle_2(dxgi_device_man_.Get());
+ ComPtr<ID3D11Device> device2;
+ ASSERT_HRESULT_SUCCEEDED(
+ device_handle_2.LockDevice(IID_PPV_ARGS(&device2)));
+ }
+ // Use the device in an outer scope.
+ DXGIDeviceScopedHandle device_handle_3(dxgi_device_man_.Get());
+ ComPtr<ID3D11Device> device3;
+ ASSERT_HRESULT_SUCCEEDED(device_handle_3.LockDevice(IID_PPV_ARGS(&device3)));
+}
+
+} // namespace media \ No newline at end of file
diff --git a/chromium/media/base/win/mf_helpers.cc b/chromium/media/base/win/mf_helpers.cc
index cb331bb4473..fce7ada08e4 100644
--- a/chromium/media/base/win/mf_helpers.cc
+++ b/chromium/media/base/win/mf_helpers.cc
@@ -4,25 +4,15 @@
#include "media/base/win/mf_helpers.h"
-#include "base/metrics/histogram_functions.h"
-
namespace media {
-namespace mf {
-
-void LogDXVAError(int line) {
- LOG(ERROR) << "Error in dxva_video_decode_accelerator_win.cc on line "
- << line;
- base::UmaHistogramSparse("Media.DXVAVDA.ErrorLine", line);
-}
-
Microsoft::WRL::ComPtr<IMFSample> CreateEmptySampleWithBuffer(
uint32_t buffer_length,
int align) {
CHECK_GT(buffer_length, 0U);
Microsoft::WRL::ComPtr<IMFSample> sample;
- HRESULT hr = MFCreateSample(sample.GetAddressOf());
+ HRESULT hr = MFCreateSample(&sample);
RETURN_ON_HR_FAILURE(hr, "MFCreateSample failed",
Microsoft::WRL::ComPtr<IMFSample>());
@@ -30,10 +20,9 @@ Microsoft::WRL::ComPtr<IMFSample> CreateEmptySampleWithBuffer(
if (align == 0) {
// Note that MFCreateMemoryBuffer is same as MFCreateAlignedMemoryBuffer
// with the align argument being 0.
- hr = MFCreateMemoryBuffer(buffer_length, buffer.GetAddressOf());
+ hr = MFCreateMemoryBuffer(buffer_length, &buffer);
} else {
- hr = MFCreateAlignedMemoryBuffer(buffer_length, align - 1,
- buffer.GetAddressOf());
+ hr = MFCreateAlignedMemoryBuffer(buffer_length, align - 1, &buffer);
}
RETURN_ON_HR_FAILURE(hr, "Failed to create memory buffer for sample",
Microsoft::WRL::ComPtr<IMFSample>());
@@ -60,6 +49,32 @@ MediaBufferScopedPointer::~MediaBufferScopedPointer() {
CHECK(SUCCEEDED(hr));
}
-} // namespace mf
+DXGIDeviceScopedHandle::DXGIDeviceScopedHandle(
+ IMFDXGIDeviceManager* device_manager)
+ : device_manager_(device_manager) {}
+
+DXGIDeviceScopedHandle::~DXGIDeviceScopedHandle() {
+ if (device_handle_ != INVALID_HANDLE_VALUE) {
+ HRESULT hr = device_manager_->CloseDeviceHandle(device_handle_);
+ CHECK(SUCCEEDED(hr));
+ device_handle_ = INVALID_HANDLE_VALUE;
+ }
+}
+
+HRESULT DXGIDeviceScopedHandle::LockDevice(REFIID riid, void** device_out) {
+ HRESULT hr;
+ if (device_handle_ == INVALID_HANDLE_VALUE) {
+ hr = device_manager_->OpenDeviceHandle(&device_handle_);
+ if (FAILED(hr)) {
+ return hr;
+ }
+ }
+ // see
+ // https://docs.microsoft.com/en-us/windows/win32/api/mfobjects/nf-mfobjects-imfdxgidevicemanager-lockdevice
+ // for details of LockDevice call.
+ hr = device_manager_->LockDevice(device_handle_, riid, device_out,
+ /*block=*/FALSE);
+ return hr;
+}
} // namespace media
diff --git a/chromium/media/base/win/mf_helpers.h b/chromium/media/base/win/mf_helpers.h
index 56b661d0874..ac163084247 100644
--- a/chromium/media/base/win/mf_helpers.h
+++ b/chromium/media/base/win/mf_helpers.h
@@ -15,37 +15,34 @@
namespace media {
-namespace mf {
-
-#define RETURN_ON_FAILURE(result, log, ret) \
- do { \
- if (!(result)) { \
- DLOG(ERROR) << log; \
- mf::LogDXVAError(__LINE__); \
- return ret; \
- } \
+// Macros that contain return statements can make code harder to read. Only use
+// these when necessary, e.g. in places where we deal with a lot of Windows API
+// calls, for each of which we have to check the returned HRESULT.
+// See discussion thread at:
+// https://groups.google.com/a/chromium.org/d/msg/cxx/zw5Xmcs--S4/r7Fwb-TsCAAJ
+
+#define RETURN_IF_FAILED(expr) \
+ do { \
+ HRESULT hresult = (expr); \
+ if (FAILED(hresult)) { \
+ DLOG(ERROR) << __func__ << ": failed with \"" \
+ << logging::SystemErrorCodeToString(hresult) << "\""; \
+ return hresult; \
+ } \
} while (0)
-#define RETURN_ON_HR_FAILURE(result, log, ret) \
- RETURN_ON_FAILURE(SUCCEEDED(result), \
- log << ", HRESULT: 0x" << std::hex << result, ret);
-
-#define RETURN_AND_NOTIFY_ON_FAILURE(result, log, error_code, ret) \
- do { \
- if (!(result)) { \
- DVLOG(1) << log; \
- mf::LogDXVAError(__LINE__); \
- StopOnError(error_code); \
- return ret; \
- } \
+#define RETURN_ON_FAILURE(success, log, ret) \
+ do { \
+ if (!(success)) { \
+ DLOG(ERROR) << log; \
+ return ret; \
+ } \
} while (0)
-#define RETURN_AND_NOTIFY_ON_HR_FAILURE(result, log, error_code, ret) \
- RETURN_AND_NOTIFY_ON_FAILURE(SUCCEEDED(result), \
- log << ", HRESULT: 0x" << std::hex << result, \
- error_code, ret);
-
-MF_INITIALIZER_EXPORT void LogDXVAError(int line);
+#define RETURN_ON_HR_FAILURE(hresult, log, ret) \
+ RETURN_ON_FAILURE(SUCCEEDED(hresult), \
+ log << ", " << logging::SystemErrorCodeToString(hresult), \
+ ret);
// Creates a Media Foundation sample with one buffer of length |buffer_length|
// on a |align|-byte boundary. Alignment must be a perfect power of 2 or 0.
@@ -71,7 +68,20 @@ class MF_INITIALIZER_EXPORT MediaBufferScopedPointer {
DISALLOW_COPY_AND_ASSIGN(MediaBufferScopedPointer);
};
-} // namespace mf
+// Wrap around the usage of device handle from |device_manager|.
+class MF_INITIALIZER_EXPORT DXGIDeviceScopedHandle {
+ public:
+ explicit DXGIDeviceScopedHandle(IMFDXGIDeviceManager* device_manager);
+
+ ~DXGIDeviceScopedHandle();
+
+ HRESULT LockDevice(REFIID riid, void** device_out);
+
+ private:
+ Microsoft::WRL::ComPtr<IMFDXGIDeviceManager> device_manager_;
+
+ HANDLE device_handle_ = INVALID_HANDLE_VALUE;
+};
} // namespace media
diff --git a/chromium/media/base/win/mf_initializer.cc b/chromium/media/base/win/mf_initializer.cc
index 47d78225c91..a19f79f6ff4 100644
--- a/chromium/media/base/win/mf_initializer.cc
+++ b/chromium/media/base/win/mf_initializer.cc
@@ -8,13 +8,19 @@
#include "base/logging.h"
+#include "base/optional.h"
+
namespace media {
-bool InitializeMediaFoundation() {
- static const bool success = MFStartup(MF_VERSION, MFSTARTUP_LITE) == S_OK;
- DVLOG_IF(1, !success)
- << "Media Foundation unavailable or it failed to initialize";
- return success;
+MFSessionLifetime InitializeMediaFoundation() {
+ if (MFStartup(MF_VERSION, MFSTARTUP_LITE) == S_OK)
+ return std::make_unique<MFSession>();
+ DVLOG(1) << "Media Foundation unavailable or it failed to initialize";
+ return nullptr;
+}
+
+MFSession::~MFSession() {
+ MFShutdown();
}
} // namespace media
diff --git a/chromium/media/base/win/mf_initializer.h b/chromium/media/base/win/mf_initializer.h
index 982cdc6c01b..f1e1bd06a6c 100644
--- a/chromium/media/base/win/mf_initializer.h
+++ b/chromium/media/base/win/mf_initializer.h
@@ -5,15 +5,25 @@
#ifndef MEDIA_BASE_WIN_MF_INITIALIZER_H_
#define MEDIA_BASE_WIN_MF_INITIALIZER_H_
+#include <mfapi.h>
+
+#include "base/logging.h"
#include "media/base/win/mf_initializer_export.h"
namespace media {
-// Makes sure MFStartup() is called exactly once. Returns true if Media
-// Foundation is available and has been initialized successfully. Note that it
-// is expected to return false on an "N" edition of Windows, see
-// https://en.wikipedia.org/wiki/Windows_7_editions#Special-purpose_editions.
-MF_INITIALIZER_EXPORT bool InitializeMediaFoundation();
+// Handy-dandy wrapper struct that kills MediaFoundation on destruction.
+struct MF_INITIALIZER_EXPORT MFSession {
+ ~MFSession();
+};
+
+using MFSessionLifetime = std::unique_ptr<MFSession>;
+
+// Make sure that MFShutdown is called for each MFStartup that is successful.
+// The public documentation stating that it needs to have a corresponding
+// shutdown for all startups (even failed ones) is wrong.
+MF_INITIALIZER_EXPORT MFSessionLifetime InitializeMediaFoundation()
+ WARN_UNUSED_RESULT;
} // namespace media