Created
September 28, 2022 16:10
-
-
Save fredldotme/4c594c4b1164e8f02cd55333930f1bf1 to your computer and use it in GitHub Desktop.
QtWebEngine + OMX video decoding on libhybris
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/qtwebengine-chromium/chromium/content/gpu/BUILD.gn b/qtwebengine-chromium/chromium/content/gpu/BUILD.gn | |
index 872ddb841..2c2c1e8d2 100644 | |
--- a/qtwebengine-chromium/chromium/content/gpu/BUILD.gn | |
+++ b/qtwebengine-chromium/chromium/content/gpu/BUILD.gn | |
@@ -92,7 +92,8 @@ target(link_target_type, "gpu_sources") { | |
"//ui/gl", | |
"//ui/gl/init", | |
"//ui/latency/ipc", | |
- ] | |
+ "//components/services/quarantine/public/mojom", | |
+ ] | |
if (is_android) { | |
deps += [ | |
diff --git a/qtwebengine-chromium/chromium/media/gpu/BUILD.gn b/qtwebengine-chromium/chromium/media/gpu/BUILD.gn | |
index b1a84b1ad..52cf59d05 100644 | |
--- a/qtwebengine-chromium/chromium/media/gpu/BUILD.gn | |
+++ b/qtwebengine-chromium/chromium/media/gpu/BUILD.gn | |
@@ -94,6 +94,17 @@ component("gpu") { | |
public_deps += [ "//media/gpu/mac" ] | |
} | |
+ if (is_linux) { | |
+ defines += [ "ENABLE_HYBRIS_MEDIA" ] | |
+ sources += [ | |
+ "hybris/video_decoder_hybris.cc", | |
+ "hybris/video_decoder_hybris.h", | |
+ "hybris/media.c", | |
+ "//media/base/android/extract_sps_and_pps.cc", | |
+ "//media/base/android/extract_sps_and_pps.h", | |
+ ] | |
+ } | |
+ | |
if (is_android) { | |
sources += [ | |
"android/android_video_surface_chooser.cc", | |
diff --git a/qtwebengine-chromium/chromium/media/gpu/hybris/media.c b/qtwebengine-chromium/chromium/media/gpu/hybris/media.c | |
new file mode 100644 | |
index 000000000..175833e8a | |
--- /dev/null | |
+++ b/qtwebengine-chromium/chromium/media/gpu/hybris/media.c | |
@@ -0,0 +1,443 @@ | |
+/* | |
+ * Copyright (C) 2013-2014 Canonical Ltd | |
+ * | |
+ * Licensed under the Apache License, Version 2.0 (the "License"); | |
+ * you may not use this file except in compliance with the License. | |
+ * You may obtain a copy of the License at | |
+ * | |
+ * http://www.apache.org/licenses/LICENSE-2.0 | |
+ * | |
+ * Unless required by applicable law or agreed to in writing, software | |
+ * distributed under the License is distributed on an "AS IS" BASIS, | |
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ * | |
+ * Authored by: Jim Hodapp <jim.hodapp@canonical.com> | |
+ * Ricardo Salveti de Araujo <ricardo.salveti@canonical.com> | |
+ */ | |
+ | |
+#include <assert.h> | |
+#include <dlfcn.h> | |
+#include <stddef.h> | |
+#include <stdbool.h> | |
+ | |
+#include <hybris/common/binding.h> | |
+//#include <hybris/media/decoding_service.h> | |
+#include <hybris/media/media_compatibility_layer.h> | |
+#include <hybris/media/media_codec_layer.h> | |
+#include <hybris/media/media_codec_list.h> | |
+#include <hybris/media/media_format_layer.h> | |
+#include <hybris/media/media_recorder_layer.h> | |
+#include <hybris/media/surface_texture_client_hybris.h> | |
+#include <hybris/media/media_codec_source_layer.h> | |
+#include <hybris/media/media_buffer_layer.h> | |
+ | |
+ | |
+#define COMPAT_LIBRARY_PATH "libmedia_compat_layer.so" | |
+ | |
+#ifdef __ARM_PCS_VFP | |
+#define FP_ATTRIB __attribute__((pcs("aapcs"))) | |
+#else | |
+#define FP_ATTRIB | |
+#endif | |
+ | |
+HYBRIS_LIBRARY_INITIALIZE(media, COMPAT_LIBRARY_PATH); | |
+ | |
+int media_compat_check_availability() | |
+{ | |
+ /* Both are defined via HYBRIS_LIBRARY_INITIALIZE */ | |
+ hybris_media_initialize(); | |
+ return media_handle ? 1 : 0; | |
+} | |
+ | |
+unsigned int hybris_media_get_version() | |
+{ | |
+ static unsigned int (*f)() FP_ATTRIB = NULL; | |
+ HYBRIS_DLSYSM(media, &f, "hybris_media_get_version"); | |
+ | |
+ /* When the method is not available we return zero here | |
+ * rather than crashing to indicate the client the | |
+ * Android side implementation is not versioned yet. */ | |
+ if (!f) | |
+ return 0; | |
+ | |
+ return f(); | |
+} | |
+ | |
+HYBRIS_IMPLEMENT_FUNCTION0(media, struct MediaPlayerWrapper*, | |
+ android_media_new_player); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, android_media_update_surface_texture, | |
+ struct MediaPlayerWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_media_play, | |
+ struct MediaPlayerWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_media_pause, | |
+ struct MediaPlayerWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_media_stop, | |
+ struct MediaPlayerWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, bool, android_media_is_playing, | |
+ struct MediaPlayerWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_seek_to, | |
+ struct MediaPlayerWrapper*, int); | |
+ | |
+// Setters | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_set_data_source, | |
+ struct MediaPlayerWrapper*, const char*); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_set_preview_texture, | |
+ struct MediaPlayerWrapper*, int); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_set_volume, | |
+ struct MediaPlayerWrapper*, int); | |
+ | |
+// Getters | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, android_media_surface_texture_get_transformation_matrix, | |
+ struct MediaPlayerWrapper*, float*); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_get_current_position, | |
+ struct MediaPlayerWrapper*, int*); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_get_duration, | |
+ struct MediaPlayerWrapper*, int*); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_media_get_volume, | |
+ struct MediaPlayerWrapper*, int*); | |
+ | |
+// Callbacks | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_video_size_cb, | |
+ struct MediaPlayerWrapper*, on_msg_set_video_size, void*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_video_texture_needs_update_cb, | |
+ struct MediaPlayerWrapper*, on_video_texture_needs_update, void*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_error_cb, | |
+ struct MediaPlayerWrapper*, on_msg_error, void*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_playback_complete_cb, | |
+ struct MediaPlayerWrapper*, on_playback_complete, void*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_set_media_prepared_cb, | |
+ struct MediaPlayerWrapper*, on_media_prepared, void*); | |
+ | |
+// DecodingService | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION0(media, decoding_service_init); | |
+HYBRIS_IMPLEMENT_FUNCTION0(media, IGBCWrapperHybris, | |
+ decoding_service_get_igraphicbufferconsumer); | |
+HYBRIS_IMPLEMENT_FUNCTION0(media, IGraphicBufferProducerHybris, | |
+ decoding_service_get_igraphicbufferproducer); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, DSSessionWrapperHybris, | |
+ decoding_service_create_session, uint32_t); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, decoding_service_set_client_death_cb, | |
+ DecodingClientDeathCbHybris, uint32_t, void*); | |
+ | |
+// Media Codecs | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaCodecDelegate, | |
+ media_codec_create_by_codec_name, const char*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_delegate_destroy, | |
+ MediaCodecDelegate); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_delegate_ref, | |
+ MediaCodecDelegate); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_delegate_unref, | |
+ MediaCodecDelegate); | |
+ | |
+#ifdef SIMPLE_PLAYER | |
+HYBRIS_IMPLEMENT_FUNCTION4(media, int, media_codec_configure, | |
+ MediaCodecDelegate, MediaFormat, void*, uint32_t); | |
+#else | |
+HYBRIS_IMPLEMENT_FUNCTION4(media, int, media_codec_configure, | |
+ MediaCodecDelegate, MediaFormat, SurfaceTextureClientHybris, uint32_t); | |
+#endif | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, media_codec_set_surface_texture_client, | |
+ MediaCodecDelegate, SurfaceTextureClientHybris); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, media_codec_queue_csd, | |
+ MediaCodecDelegate, MediaFormat); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_codec_start, | |
+ MediaCodecDelegate); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_codec_stop, | |
+ MediaCodecDelegate); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_codec_release, | |
+ MediaCodecDelegate); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_codec_flush, | |
+ MediaCodecDelegate); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_codec_get_input_buffers_size, | |
+ MediaCodecDelegate); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, uint8_t*, media_codec_get_nth_input_buffer, | |
+ MediaCodecDelegate, size_t); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_get_nth_input_buffer_capacity, | |
+ MediaCodecDelegate, size_t); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_codec_get_output_buffers_size, | |
+ MediaCodecDelegate); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, uint8_t*, media_codec_get_nth_output_buffer, | |
+ MediaCodecDelegate, size_t); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_get_nth_output_buffer_capacity, | |
+ MediaCodecDelegate, size_t); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_dequeue_output_buffer, | |
+ MediaCodecDelegate, MediaCodecBufferInfo*, int64_t); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, media_codec_queue_input_buffer, | |
+ MediaCodecDelegate, const MediaCodecBufferInfo*); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_dequeue_input_buffer, | |
+ MediaCodecDelegate, size_t*, int64_t); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_release_output_buffer, | |
+ MediaCodecDelegate, size_t, uint8_t); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaFormat, media_codec_get_output_format, | |
+ MediaCodecDelegate); | |
+ | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, ssize_t, media_codec_list_find_codec_by_type, | |
+ const char*, bool, size_t); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, ssize_t, media_codec_list_find_codec_by_name, | |
+ const char *); | |
+HYBRIS_IMPLEMENT_FUNCTION0(media, size_t, media_codec_list_count_codecs); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_list_get_codec_info_at_id, | |
+ size_t); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, const char*, media_codec_list_get_codec_name, | |
+ size_t); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, bool, media_codec_list_is_encoder, | |
+ size_t); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_codec_list_get_num_supported_types, | |
+ size_t); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_list_get_nth_supported_type_len, | |
+ size_t, size_t); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_list_get_nth_supported_type, | |
+ size_t, char *, size_t); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_list_get_num_profile_levels, | |
+ size_t, const char*); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, size_t, media_codec_list_get_num_color_formats, | |
+ size_t, const char*); | |
+HYBRIS_IMPLEMENT_FUNCTION4(media, int, media_codec_list_get_nth_codec_profile_level, | |
+ size_t, const char*, profile_level*, size_t); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, media_codec_list_get_codec_color_formats, | |
+ size_t, const char*, uint32_t*); | |
+ | |
+HYBRIS_IMPLEMENT_FUNCTION5(media, MediaFormat, media_format_create_video_format, | |
+ const char*, int32_t, int32_t, int64_t, int32_t); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_format_destroy, | |
+ MediaFormat); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_format_ref, | |
+ MediaFormat); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_format_unref, | |
+ MediaFormat); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION4(media, media_format_set_byte_buffer, | |
+ MediaFormat, const char*, uint8_t*, size_t); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, const char*, media_format_get_mime, | |
+ MediaFormat); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int64_t, media_format_get_duration_us, | |
+ MediaFormat); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_width, | |
+ MediaFormat); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_height, | |
+ MediaFormat); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_max_input_size, | |
+ MediaFormat); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_stride, | |
+ MediaFormat); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_slice_height, | |
+ MediaFormat); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_color_format, | |
+ MediaFormat); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_crop_left, | |
+ MediaFormat); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_crop_right, | |
+ MediaFormat); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_crop_top, | |
+ MediaFormat); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int32_t, media_format_get_crop_bottom, | |
+ MediaFormat); | |
+ | |
+// SurfaceTextureClientHybris | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, SurfaceTextureClientHybris, | |
+ surface_texture_client_create, EGLNativeWindowType); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, SurfaceTextureClientHybris, | |
+ surface_texture_client_create_by_id, unsigned int); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, SurfaceTextureClientHybris, | |
+ surface_texture_client_create_by_igbp, IGBPWrapperHybris); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, GLConsumerWrapperHybris, | |
+ gl_consumer_create_by_id_with_igbc, unsigned int, IGBCWrapperHybris); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, | |
+ gl_consumer_set_frame_available_cb, GLConsumerWrapperHybris, FrameAvailableCbHybris, void*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, gl_consumer_get_transformation_matrix, | |
+ GLConsumerWrapperHybris, GLfloat*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, gl_consumer_update_texture, | |
+ GLConsumerWrapperHybris); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, uint8_t, | |
+ surface_texture_client_is_ready_for_rendering, SurfaceTextureClientHybris); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, uint8_t, | |
+ surface_texture_client_hardware_rendering, SurfaceTextureClientHybris); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, surface_texture_client_set_hardware_rendering, | |
+ SurfaceTextureClientHybris, uint8_t); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, surface_texture_client_get_transformation_matrix, | |
+ SurfaceTextureClientHybris, GLfloat*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, surface_texture_client_update_texture, | |
+ SurfaceTextureClientHybris); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, surface_texture_client_destroy, | |
+ SurfaceTextureClientHybris); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, surface_texture_client_ref, | |
+ SurfaceTextureClientHybris); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, surface_texture_client_unref, | |
+ SurfaceTextureClientHybris); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, surface_texture_client_set_surface_texture, | |
+ SurfaceTextureClientHybris, EGLNativeWindowType); | |
+ | |
+// Recorder Observer | |
+HYBRIS_IMPLEMENT_FUNCTION0(media, struct MediaRecorderObserver*, | |
+ android_media_recorder_observer_new); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_media_recorder_observer_set_cb, | |
+ struct MediaRecorderObserver*, media_recording_started_cb, void*); | |
+ | |
+// Recorder | |
+HYBRIS_IMPLEMENT_FUNCTION0(media, struct MediaRecorderWrapper*, | |
+ android_media_new_recorder); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_initCheck, | |
+ struct MediaRecorderWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setCamera, | |
+ struct MediaRecorderWrapper*, struct CameraControl*); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setVideoSource, | |
+ struct MediaRecorderWrapper*, VideoSource); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setAudioSource, | |
+ struct MediaRecorderWrapper*, AudioSource); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setOutputFormat, | |
+ struct MediaRecorderWrapper*, OutputFormat); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setVideoEncoder, | |
+ struct MediaRecorderWrapper*, VideoEncoder); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setAudioEncoder, | |
+ struct MediaRecorderWrapper*, AudioEncoder); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setOutputFile, | |
+ struct MediaRecorderWrapper*, int); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, int, android_recorder_setVideoSize, | |
+ struct MediaRecorderWrapper*, int, int); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setVideoFrameRate, | |
+ struct MediaRecorderWrapper*, int); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, int, android_recorder_setParameters, | |
+ struct MediaRecorderWrapper*, const char*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_start, | |
+ struct MediaRecorderWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_stop, | |
+ struct MediaRecorderWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_prepare, | |
+ struct MediaRecorderWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_reset, | |
+ struct MediaRecorderWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_close, | |
+ struct MediaRecorderWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, android_recorder_release, | |
+ struct MediaRecorderWrapper*); | |
+ | |
+// Recorder Callbacks | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_recorder_set_error_cb, | |
+ struct MediaRecorderWrapper*, on_recorder_msg_error, void*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, android_recorder_set_audio_read_cb, | |
+ struct MediaRecorderWrapper*, on_recorder_read_audio, void*); | |
+ | |
+// Media Message | |
+HYBRIS_IMPLEMENT_FUNCTION0(media, MediaMessageWrapper*, media_message_create); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_message_release, MediaMessageWrapper*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_message_clear, MediaMessageWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, const char*, media_message_dump, MediaMessageWrapper*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_message_set_int32, MediaMessageWrapper*, | |
+ const char*, int32_t); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_message_set_int64, MediaMessageWrapper*, | |
+ const char*, int64_t); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_message_set_size, MediaMessageWrapper*, | |
+ const char*, size_t); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_message_set_float, MediaMessageWrapper*, | |
+ const char*, float); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_message_set_double, MediaMessageWrapper*, | |
+ const char*, double); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION4(media, media_message_set_string, MediaMessageWrapper*, | |
+ const char*, const char*, ssize_t); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, bool, media_message_contains, MediaMessageWrapper*, | |
+ const char*); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_message_find_int32, MediaMessageWrapper*, | |
+ const char*, int32_t*); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_message_find_int64, MediaMessageWrapper*, | |
+ const char*, int64_t*); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_message_find_size, MediaMessageWrapper*, | |
+ const char*, size_t*); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_message_find_float, MediaMessageWrapper*, | |
+ const char*, float*); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_message_find_double, MediaMessageWrapper*, | |
+ const char*, double*); | |
+ | |
+// Media Meta Data | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, uint32_t, media_meta_data_get_key_id, int); | |
+HYBRIS_IMPLEMENT_FUNCTION0(media, MediaMetaDataWrapper*, media_meta_data_create); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_meta_data_release, MediaMetaDataWrapper*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_meta_data_clear, MediaMetaDataWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, bool, media_meta_data_remove, MediaMetaDataWrapper*, | |
+ uint32_t); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_set_cstring, MediaMetaDataWrapper*, | |
+ uint32_t, const char*); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_set_int32, MediaMetaDataWrapper*, | |
+ uint32_t, int32_t); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_set_int64, MediaMetaDataWrapper*, | |
+ uint32_t, int64_t); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_set_float, MediaMetaDataWrapper*, | |
+ uint32_t, float); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_set_pointer, MediaMetaDataWrapper*, | |
+ uint32_t, void*); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_find_cstring, MediaMetaDataWrapper*, | |
+ uint32_t, const char**); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_find_int32, MediaMetaDataWrapper*, | |
+ uint32_t, int32_t*); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_find_int64, MediaMetaDataWrapper*, | |
+ uint32_t, int64_t*); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_find_float, MediaMetaDataWrapper*, | |
+ uint32_t, float*); | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, bool, media_meta_data_find_pointer, MediaMetaDataWrapper*, | |
+ uint32_t, void**); | |
+ | |
+// Media Buffer | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaBufferWrapper*, media_buffer_create, size_t); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_buffer_destroy, MediaBufferWrapper*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_buffer_release, MediaBufferWrapper*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_buffer_ref, MediaBufferWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, int, media_buffer_get_refcount, MediaBufferWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, void*, media_buffer_get_data, MediaBufferWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_buffer_get_size, MediaBufferWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_buffer_get_range_offset, MediaBufferWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_buffer_get_range_length, MediaBufferWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaMetaDataWrapper*, media_buffer_get_meta_data, MediaBufferWrapper*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_buffer_set_return_callback, MediaBufferWrapper*, | |
+ MediaBufferReturnCallback, void*); | |
+ | |
+// Media ABuffer | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaABufferWrapper*, media_abuffer_create, | |
+ size_t); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, MediaABufferWrapper*, media_abuffer_create_with_data, | |
+ uint8_t*, size_t); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_abuffer_set_range, | |
+ MediaABufferWrapper*, size_t, size_t); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, media_abuffer_set_media_buffer_base, | |
+ MediaABufferWrapper*, MediaBufferWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaBufferWrapper*, media_abuffer_get_media_buffer_base, | |
+ MediaABufferWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, void*, media_abuffer_get_data, | |
+ MediaABufferWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_abuffer_get_size, | |
+ MediaABufferWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_abuffer_get_range_offset, | |
+ MediaABufferWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, size_t, media_abuffer_get_capacity, | |
+ MediaABufferWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaMessageWrapper*, media_abuffer_get_meta, | |
+ MediaABufferWrapper*); | |
+ | |
+// Media Codec Source | |
+HYBRIS_IMPLEMENT_FUNCTION3(media, MediaCodecSourceWrapper*, media_codec_source_create, | |
+ MediaMessageWrapper*, MediaSourceWrapper*, int); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_codec_source_release, MediaCodecSourceWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, void*, media_codec_source_get_native_window_handle, | |
+ MediaCodecSourceWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, MediaMetaDataWrapper*, media_codec_source_get_format, | |
+ MediaCodecSourceWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, bool, media_codec_source_start, MediaCodecSourceWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, bool, media_codec_source_stop, MediaCodecSourceWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, bool, media_codec_source_pause, MediaCodecSourceWrapper*); | |
+HYBRIS_IMPLEMENT_FUNCTION2(media, bool, media_codec_source_read, MediaCodecSourceWrapper*, | |
+ MediaBufferWrapper**); | |
+HYBRIS_IMPLEMENT_FUNCTION1(media, bool, media_codec_source_request_idr_frame, | |
+ MediaCodecSourceWrapper*); | |
+ | |
+// Media Source | |
+HYBRIS_IMPLEMENT_FUNCTION0(media, MediaSourceWrapper*, media_source_create); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION1(media, media_source_release, MediaSourceWrapper*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION2(media, media_source_set_format, MediaSourceWrapper*, | |
+ MediaMetaDataWrapper*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_source_set_start_callback, | |
+ MediaSourceWrapper*, MediaSourceStartCallback, void*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_source_set_stop_callback, | |
+ MediaSourceWrapper*, MediaSourceStopCallback, void*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_source_set_read_callback, | |
+ MediaSourceWrapper*, MediaSourceReadCallback, void*); | |
+HYBRIS_IMPLEMENT_VOID_FUNCTION3(media, media_source_set_pause_callback, | |
+ MediaSourceWrapper*, MediaSourcePauseCallback, void*); | |
diff --git a/qtwebengine-chromium/chromium/media/gpu/hybris/video_decoder_hybris.cc b/qtwebengine-chromium/chromium/media/gpu/hybris/video_decoder_hybris.cc | |
new file mode 100644 | |
index 000000000..3739bba38 | |
--- /dev/null | |
+++ b/qtwebengine-chromium/chromium/media/gpu/hybris/video_decoder_hybris.cc | |
@@ -0,0 +1,780 @@ | |
+// Copyright 2022 Alfred Neumayer. 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/gpu/hybris/video_decoder_hybris.h" | |
+#include "media/formats/mp4/box_definitions.h" | |
+#include "base/task/task_traits.h" | |
+#include "base/task/thread_pool.h" | |
+#include "gpu/ipc/service/command_buffer_stub.h" | |
+#include "ui/gl/gl_bindings.h" | |
+#include "ui/gl/gl_context.h" | |
+#include "ui/gl/gl_implementation.h" | |
+#include "ui/gl/gl_surface.h" | |
+#include "ui/gl/scoped_binders.h" | |
+#include "ui/gl/init/gl_factory.h" | |
+ | |
+#define BUFFER_FLAG_KEY_FRAME 1 | |
+#define BUFFER_FLAG_CODEC_CONFIG 2 | |
+#define BUFFER_FLAG_END_OF_STREAM 4 | |
+#define INFO_TRY_AGAIN_LATER -1 | |
+#define INFO_OUTPUT_FORMAT_CHANGED -2 | |
+#define INFO_OUTPUT_BUFFERS_CHANGED -4 | |
+ | |
+extern "C" { | |
+int media_compat_check_availability(); | |
+} | |
+ | |
+namespace media { | |
+ | |
+static const char* kVideoMimeTypeH264 = "video/avc"; | |
+static const char* kVideoMimeTypeVP8 = "video/x-vnd.on2.vp8"; | |
+static const char* kVideoMimeTypeVP9 = "video/x-vnd.on2.vp9"; | |
+ | |
+std::vector<SupportedVideoDecoderConfig> HybrisMediaCodecVideoDecoder::GetSupportedConfigs() { | |
+ static const auto configs = GetSupportedConfigsInternal(); | |
+ return configs; | |
+} | |
+ | |
+std::vector<SupportedVideoDecoderConfig> HybrisMediaCodecVideoDecoder::GetSupportedConfigsInternal() { | |
+ std::vector<SupportedVideoDecoderConfig> supported_configs; | |
+ | |
+ if (IsSupported(VP8PROFILE_MIN)) { | |
+ supported_configs.emplace_back(VP8PROFILE_ANY, VP8PROFILE_ANY, | |
+ gfx::Size(480, 360), gfx::Size(3840, 2160), | |
+ false, // allow_encrypted | |
+ false); // require_encrypted | |
+ // Encrypted content must be decoded by MediaCodec. | |
+ supported_configs.emplace_back(VP8PROFILE_ANY, VP8PROFILE_ANY, | |
+ gfx::Size(0, 0), gfx::Size(3840, 2160), | |
+ true, // allow_encrypted | |
+ true); // require_encrypted | |
+ } | |
+ | |
+ if (IsSupported(VP9PROFILE_MIN)) { | |
+ std::vector<CodecProfileLevel> profiles; | |
+ | |
+ profiles.push_back({kCodecVP9, VP9PROFILE_PROFILE0, 0}); | |
+ | |
+ for (const auto& p : profiles) { | |
+ if (p.codec != kCodecVP9) | |
+ continue; | |
+ | |
+ // We don't compile support into libvpx for these profiles, so allow them | |
+ // for all resolutions. See notes on H264 profiles below for more detail. | |
+ if (p.profile > VP9PROFILE_PROFILE1) { | |
+ supported_configs.emplace_back(p.profile, p.profile, gfx::Size(0, 0), | |
+ gfx::Size(3840, 2160), | |
+ true, // allow_encrypted | |
+ false); // require_encrypted | |
+ supported_configs.emplace_back(p.profile, p.profile, gfx::Size(0, 0), | |
+ gfx::Size(2160, 3840), | |
+ true, // allow_encrypted | |
+ false); // require_encrypted | |
+ continue; | |
+ } | |
+ | |
+ // Encrypted content must be decoded by MediaCodec. | |
+ supported_configs.emplace_back(p.profile, p.profile, gfx::Size(0, 0), | |
+ gfx::Size(3840, 2160), | |
+ true, // allow_encrypted | |
+ true); // require_encrypted | |
+ supported_configs.emplace_back(p.profile, p.profile, gfx::Size(0, 0), | |
+ gfx::Size(2160, 3840), | |
+ true, // allow_encrypted | |
+ true); // require_encrypted | |
+ } | |
+ } | |
+ | |
+ supported_configs.emplace_back(H264PROFILE_MIN, H264PROFILE_MAX, | |
+ gfx::Size(0, 0), gfx::Size(3840, 2160), | |
+ true, // allow_encrypted | |
+ false); // require_encrypted | |
+ supported_configs.emplace_back(H264PROFILE_MIN, H264PROFILE_MAX, | |
+ gfx::Size(0, 0), gfx::Size(2160, 3840), | |
+ true, // allow_encrypted | |
+ false); // require_encrypted | |
+ | |
+//#if BUILDFLAG(ENABLE_PLATFORM_HEVC) | |
+#if 0 | |
+ supported_configs.emplace_back(HEVCPROFILE_MIN, HEVCPROFILE_MAX, | |
+ gfx::Size(0, 0), gfx::Size(3840, 2160), | |
+ true, // allow_encrypted | |
+ false); // require_encrypted | |
+#endif | |
+ | |
+ return supported_configs; | |
+} | |
+ | |
+ HybrisMediaCodecVideoDecoder::HybrisMediaCodecVideoDecoder( | |
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner, | |
+ scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner, | |
+ GetStubCB stub_cb) : | |
+ running_(false), | |
+ n_buffers_in_(0), | |
+ n_buffers_out_(0), | |
+ queue_timeout_(10000), | |
+ is_draining_(false), | |
+ is_flushing_(false), | |
+ media_codec_(nullptr), | |
+ media_format_(nullptr), | |
+ stc_(nullptr), | |
+ igbp_(nullptr), | |
+ igbc_(nullptr), | |
+ gl_texture(nullptr), | |
+ pending_input_runner_(base::ThreadPool::CreateSingleThreadTaskRunner( | |
+ {base::WithBaseSyncPrimitives(), base::TaskPriority::USER_VISIBLE}, | |
+ base::SingleThreadTaskRunnerThreadMode::DEDICATED)), | |
+ pending_output_runner_(base::ThreadPool::CreateSingleThreadTaskRunner( | |
+ {base::WithBaseSyncPrimitives(), base::TaskPriority::USER_VISIBLE}, | |
+ base::SingleThreadTaskRunnerThreadMode::DEDICATED)), | |
+ task_runner_(task_runner), | |
+ gpu_task_runner_(gpu_task_runner) { | |
+ gpu::CommandBufferStub* stub = std::move(stub_cb).Run(); | |
+ decoder_context_ = stub->decoder_context(); | |
+ decoder_helper_ = GLES2DecoderHelper::Create(decoder_context_); | |
+ } | |
+ | |
+ HybrisMediaCodecVideoDecoder::~HybrisMediaCodecVideoDecoder() { | |
+ Destroy(); | |
+ } | |
+ | |
+ bool HybrisMediaCodecVideoDecoder::IsSupportedProfile(VideoCodecProfile type) | |
+ { | |
+ if (!((type >= H264PROFILE_MIN && type <= H264PROFILE_MAX) || | |
+ (type >= VP8PROFILE_MIN && type <= VP8PROFILE_MAX) || | |
+ (type >= VP9PROFILE_MIN && type <= VP9PROFILE_MAX))) { | |
+ return false; | |
+ } | |
+ return true; | |
+ } | |
+ | |
+ bool HybrisMediaCodecVideoDecoder::IsSupported(VideoCodecProfile type) | |
+ { | |
+ if (!IsSupportedProfile(type)) { | |
+ return false; | |
+ } | |
+ | |
+ const char* hybris_codec_type = MimeTypeForCodecType(type); | |
+ if (!hybris_codec_type) { | |
+ return false; | |
+ } | |
+ | |
+ std::string codec_type = std::string(hybris_codec_type); | |
+ std::string hybris_codec_name = FindSuitableCodec(codec_type, true); | |
+ if (hybris_codec_name.length() == 0) { | |
+ hybris_codec_name = FindSuitableCodec(codec_type, false); | |
+ } | |
+ return (hybris_codec_name.length() > 0); | |
+ } | |
+ | |
+ const char* HybrisMediaCodecVideoDecoder::MimeTypeForCodecType(VideoCodecProfile type) { | |
+ if (type >= H264PROFILE_MIN && type <= H264PROFILE_MAX) { | |
+ return kVideoMimeTypeH264; | |
+ } else if (type >= VP8PROFILE_MIN && type <= VP8PROFILE_MAX) { | |
+ return kVideoMimeTypeVP8; | |
+ } else if (type >= VP9PROFILE_MIN && type <= VP9PROFILE_MAX) { | |
+ return kVideoMimeTypeVP9; | |
+ } | |
+ return nullptr; | |
+ } | |
+ | |
+ std::string HybrisMediaCodecVideoDecoder::FindSuitableCodec(const std::string& codec_type, const bool hwCodecOnly) { | |
+ std::string hybris_codec_name; | |
+ | |
+ // Find a decoder corresponding to our requested type | |
+ const size_t media_codec_num = media_codec_list_count_codecs(); | |
+ for (size_t media_codec_pos = 0; media_codec_pos < media_codec_num; media_codec_pos++) { | |
+ media_codec_list_get_codec_info_at_id(media_codec_pos); | |
+ | |
+ if (media_codec_list_is_encoder(media_codec_pos)) | |
+ continue; | |
+ | |
+ const char* codec_name_ptr = media_codec_list_get_codec_name(media_codec_pos); | |
+ if (!codec_name_ptr) | |
+ continue; | |
+ | |
+ std::string codec_name(codec_name_ptr); | |
+ | |
+ if (hwCodecOnly) { | |
+ if (codec_name.rfind("OMX.google.", 0) == 0) | |
+ continue; | |
+ } | |
+ | |
+ LOG(INFO) << "Inspecting codec: " << codec_name; | |
+ | |
+ const size_t num_supported_types = media_codec_list_get_num_supported_types(media_codec_pos); | |
+ for (size_t supported_type_pos = 0; supported_type_pos < num_supported_types; supported_type_pos++) { | |
+ const size_t mime_len = media_codec_list_get_nth_supported_type_len(media_codec_pos, supported_type_pos); | |
+ if (mime_len == 0) | |
+ continue; | |
+ | |
+ char* potential_mime = new char[mime_len + 1](); | |
+ media_codec_list_get_nth_supported_type(media_codec_pos, potential_mime, supported_type_pos); | |
+ if (!potential_mime) | |
+ continue; | |
+ | |
+ potential_mime[mime_len] = '\0'; | |
+ std::string potential_type(potential_mime); | |
+ LOG(ERROR) << "Type: " << potential_type; | |
+ | |
+ if (potential_type == codec_type) { | |
+ LOG(INFO) << "Found codec for type " << potential_type << ", called " << codec_name; | |
+ hybris_codec_name = codec_name; | |
+ delete[] potential_mime; | |
+ break; | |
+ } | |
+ | |
+ delete[] potential_mime; | |
+ } | |
+ | |
+ if (hybris_codec_name.length() > 0) | |
+ break; | |
+ } | |
+ | |
+ return hybris_codec_name; | |
+ } | |
+ | |
+void HybrisMediaCodecVideoDecoder::Initialize( | |
+ const VideoDecoderConfig& config, | |
+ bool low_delay, | |
+ CdmContext* cdm_context, | |
+ InitCB init_cb, | |
+ const OutputCB& output_cb, | |
+ const WaitingCB& waiting_cb) { | |
+ if (!IsSupportedProfile(config.profile())) { | |
+ return; | |
+ } | |
+ | |
+ // Initialize hybris compat layer | |
+ const char* hybris_codec_type = MimeTypeForCodecType(config.profile()); | |
+ if (!hybris_codec_type) { | |
+ return; | |
+ } | |
+ | |
+ codec_type_ = std::string(hybris_codec_type); | |
+ | |
+ // Look for hardware-codecs first | |
+ std::string hybris_codec_name = FindSuitableCodec(codec_type_, true); | |
+ if (hybris_codec_name.length() == 0) { | |
+ hybris_codec_name = FindSuitableCodec(codec_type_, false); | |
+ } | |
+ | |
+ if (hybris_codec_name.length() == 0) { | |
+ return; | |
+ } | |
+ | |
+ media_codec_ = media_codec_create_by_codec_name(hybris_codec_name.c_str()); | |
+ if (!media_codec_) { | |
+ return; | |
+ } | |
+ | |
+ output_cb_ = output_cb; | |
+ config_ = config; | |
+ | |
+ gpu_task_runner_->PostTask( | |
+ FROM_HERE, | |
+ base::BindOnce(&HybrisMediaCodecVideoDecoder::Reconfigure, | |
+ base::Unretained(this), config, std::move(init_cb))); | |
+} | |
+ | |
+void HybrisMediaCodecVideoDecoder::Drain() { | |
+ std::unique_lock<decltype(drain_mutex_)> lk(drain_mutex_); | |
+ is_draining_ = true; | |
+ QueuedBuffer eos_buffer { DecoderBuffer::CreateEOSBuffer(), base::DoNothing() }; | |
+ ProcessInput(eos_buffer); | |
+ drain_condition_.wait(lk, [this]{ return !is_draining_; }); | |
+ LOG(INFO) << "Queue drained"; | |
+} | |
+ | |
+void HybrisMediaCodecVideoDecoder::Flush() { | |
+ std::unique_lock<decltype(drain_mutex_)> lk(flush_mutex_); | |
+ is_flushing_ = true; | |
+ media_codec_flush(media_codec_); | |
+ is_flushing_ = false; | |
+ flush_condition_.notify_all(); | |
+ LOG(INFO) << "Queue flushed"; | |
+} | |
+ | |
+void HybrisMediaCodecVideoDecoder::EnqueueOrderedInput( | |
+ scoped_refptr<DecoderBuffer> buffer, | |
+ DecodeCB decode_cb) { | |
+ LOG(INFO) << __func__; | |
+ while (!pending_inputs_.empty()) { | |
+ QueuedBuffer dequeued_buffer = std::move(pending_inputs_.front()); | |
+ pending_inputs_.pop_front(); | |
+ if (!ProcessInput(dequeued_buffer)) { | |
+ pending_inputs_.push_front(std::move(dequeued_buffer)); | |
+ break; | |
+ } | |
+ } | |
+ | |
+ QueuedBuffer next_input { buffer, std::move(decode_cb) }; | |
+ if (pending_inputs_.empty()) { | |
+ if (!ProcessInput(next_input)) { | |
+ pending_inputs_.push_back(std::move(next_input)); | |
+ } | |
+ } else { | |
+ pending_inputs_.push_back(std::move(next_input)); | |
+ } | |
+} | |
+ | |
+bool HybrisMediaCodecVideoDecoder::ProcessInput( | |
+ QueuedBuffer& in_flight_buffer) { | |
+ LOG(INFO) << __func__; | |
+ | |
+ int32_t flags_for_input = 0; | |
+ if (in_flight_buffer.buffer->is_key_frame()) { | |
+ flags_for_input |= BUFFER_FLAG_KEY_FRAME; | |
+ } | |
+ if (in_flight_buffer.buffer->end_of_stream()) { | |
+ flags_for_input |= BUFFER_FLAG_END_OF_STREAM; | |
+ } | |
+ | |
+ size_t offset = SkipForbiddenNALUs(in_flight_buffer.buffer->data(), | |
+ in_flight_buffer.buffer->data_size()); | |
+ if (offset > 0) { | |
+ flags_for_input |= BUFFER_FLAG_CODEC_CONFIG; | |
+ } | |
+ | |
+ size_t buf_index; | |
+ uint8_t* input_ptr = nullptr; | |
+ int ret; | |
+ int dequeue_attempts = 25; | |
+ | |
+ while (!input_ptr && dequeue_attempts-- > 0) { | |
+ ret = media_codec_dequeue_input_buffer(media_codec_, &buf_index, queue_timeout_); | |
+ if (ret >= 0) { | |
+ input_ptr = codec_input_buffers_[buf_index].data; | |
+ } | |
+ } | |
+ | |
+ if (!input_ptr) { | |
+ LOG(ERROR) << "Error in " << __func__ << ":" << __LINE__; | |
+ return false; | |
+ } | |
+ | |
+ // Fill the input buffer | |
+ const size_t capacity = codec_input_buffers_[buf_index].size; | |
+ const size_t mem_size = std::min<size_t>(in_flight_buffer.buffer->data_size(), capacity); | |
+ LOG(INFO) << "Capacity " << capacity << " vs mem_size " << mem_size; | |
+ if (mem_size > 0) { | |
+ memcpy(input_ptr, in_flight_buffer.buffer->data(), mem_size); | |
+ } | |
+ | |
+ const int64_t presentation_time = | |
+ in_flight_buffer.buffer->timestamp().InMicroseconds(); | |
+ const int64_t presentation_duration = | |
+ in_flight_buffer.buffer->duration().InMicroseconds(); | |
+ | |
+ // Queue it into the decoder | |
+ MediaCodecBufferInfo buffer_info; | |
+ memset(&buffer_info, 0, sizeof(buffer_info)); | |
+ buffer_info.index = buf_index; | |
+ buffer_info.size = mem_size; | |
+ buffer_info.flags = flags_for_input; | |
+ buffer_info.presentation_time_us = std::max<size_t>(1, presentation_time + presentation_duration); | |
+ buffer_info.offset = 0; | |
+ ret = media_codec_queue_input_buffer(media_codec_, &buffer_info); | |
+ | |
+ if (ret < 0) { | |
+ LOG(ERROR) << "Error in " << __func__ << ":" << __LINE__; | |
+ return false; | |
+ } | |
+ | |
+ pending_outputs_.push_back(std::move(in_flight_buffer)); | |
+ return true; | |
+} | |
+ | |
+void HybrisMediaCodecVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) { | |
+ LOG(INFO) << __func__; | |
+ | |
+ if (!buffer) { | |
+ return; | |
+ } | |
+ | |
+ if (buffer->end_of_stream()) { | |
+ std::lock_guard<decltype(running_mutex_)> lk(running_mutex_); | |
+ running_ = false; | |
+ eos_decode_cb_ = std::move(decode_cb); | |
+ return; | |
+ } | |
+ | |
+ pending_input_runner_->PostTask( | |
+ FROM_HERE, | |
+ base::BindOnce(&HybrisMediaCodecVideoDecoder::EnqueueOrderedInput, | |
+ base::Unretained(this), buffer, std::move(decode_cb))); | |
+} | |
+ | |
+void HybrisMediaCodecVideoDecoder::OnFrameAvailable(GLConsumerWrapperHybris, void* data) { | |
+ LOG(INFO) << "OnFrameAvailable"; | |
+ HybrisMediaCodecVideoDecoder* thiz = static_cast<HybrisMediaCodecVideoDecoder*>(data); | |
+ if (!thiz) { | |
+ return; | |
+ } | |
+ thiz->FrameAvailable(); | |
+} | |
+ | |
+void HybrisMediaCodecVideoDecoder::FrameAvailable() { | |
+ gpu_task_runner_->PostTask( | |
+ FROM_HERE, base::BindOnce(&HybrisMediaCodecVideoDecoder::RedrawTexture, base::Unretained(this))); | |
+} | |
+ | |
+void HybrisMediaCodecVideoDecoder::RedrawTexture() { | |
+ while (!pending_redraws_.empty()) { | |
+ LOG(ERROR) << "1"; | |
+ std::lock_guard<decltype(redraw_mutex_)> lk(redraw_mutex_); | |
+ QueuedDrawOperation& draw_operation = pending_redraws_.front(); | |
+ | |
+ LOG(ERROR) << "2"; | |
+ decoder_context_->MakeCurrent(); | |
+ gl_consumer_update_texture(gl_texture_consumer_); | |
+ | |
+ LOG(ERROR) << "3"; | |
+ base::TimeDelta timestamp = base::TimeDelta::FromMicroseconds(draw_operation.timestamp); | |
+ VideoPixelFormat pixel_format = PIXEL_FORMAT_ABGR; | |
+ | |
+ LOG(ERROR) << "4"; | |
+ gpu::Mailbox mailbox = decoder_helper_->CreateMailbox(gl_texture.get()); | |
+ gpu::SyncToken sync_token = gpu::SyncToken(); | |
+ gpu::MailboxHolder mailbox_holders_[VideoFrame::kMaxPlanes]; | |
+ mailbox_holders_[0] = gpu::MailboxHolder(mailbox, sync_token, GL_TEXTURE_EXTERNAL_OES); | |
+ | |
+ LOG(ERROR) << "5"; | |
+ auto frame = VideoFrame::WrapNativeTextures( | |
+ pixel_format, mailbox_holders_, VideoFrame::ReleaseMailboxCB(), | |
+ coded_size_, visible_rect_, natural_size_, timestamp); | |
+ | |
+ LOG(ERROR) << "6"; | |
+ std::move(draw_operation.decode_cb).Run(DecodeStatus::OK); | |
+ pending_redraws_.pop_front(); | |
+ | |
+ if (!frame) { | |
+ return; | |
+ } | |
+ | |
+ LOG(ERROR) << "7"; | |
+ frame->metadata()->power_efficient = true; | |
+ output_cb_.Run(frame); | |
+ | |
+ // We can safely reduce the timeout for de-/queueing now | |
+ //queue_timeout_ = 10000; | |
+ } | |
+} | |
+ | |
+ void HybrisMediaCodecVideoDecoder::Destroy() { | |
+ if (media_codec_) { | |
+ running_ = false; | |
+ media_codec_flush(media_codec_); | |
+ media_codec_stop(media_codec_); | |
+ media_codec_delegate_destroy(media_codec_); | |
+ media_codec_ = nullptr; | |
+ } | |
+ /*if (media_format_) { | |
+ media_format_destroy(media_format_); | |
+ media_format_ = nullptr; | |
+ } | |
+ if (stc_) { | |
+ surface_texture_client_destroy(stc_); | |
+ stc_ = nullptr; | |
+ }*/ | |
+ } | |
+ | |
+ void HybrisMediaCodecVideoDecoder::Reset(base::OnceClosure closure) { | |
+ std::lock_guard<decltype(running_mutex_)> lk(running_mutex_); | |
+ running_ = false; | |
+ media_codec_flush(media_codec_); | |
+ media_codec_stop(media_codec_); | |
+ std::move(closure).Run(); | |
+ } | |
+ | |
+ bool HybrisMediaCodecVideoDecoder::NeedsBitstreamConversion() const { | |
+ return false; | |
+ } | |
+ | |
+ bool HybrisMediaCodecVideoDecoder::CanReadWithoutStalling() const { | |
+ return false; | |
+ } | |
+ | |
+ int HybrisMediaCodecVideoDecoder::GetMaxDecodeRequests() const { | |
+ return n_buffers_in_; | |
+ } | |
+ | |
+ std::string HybrisMediaCodecVideoDecoder::GetDisplayName() const { | |
+ return "HybrisMediaCodecVideoDecoder"; | |
+ } | |
+ | |
+ void HybrisMediaCodecVideoDecoder::Reconfigure(const VideoDecoderConfig config, InitCB init_cb) { | |
+ LOG(INFO) << "Configuring decoder: " << config.AsHumanReadableString(); | |
+ | |
+ const int32_t width = config.coded_size().width(); | |
+ const int32_t height = config.coded_size().height(); | |
+ const int32_t buf_size = width * height; | |
+ | |
+ decoder_context_->MakeCurrent(); | |
+ gl_texture = decoder_helper_->CreateTexture(GL_TEXTURE_EXTERNAL_OES, GL_RGBA, width, height, GL_RGBA, GL_UNSIGNED_BYTE); | |
+ | |
+ igbp_ = decoding_service_get_igraphicbufferproducer(); | |
+ if (!igbp_) { | |
+ std::move(init_cb).Run(StatusCode::kDecoderInitializationFailed); | |
+ return; | |
+ } | |
+ | |
+ igbc_ = decoding_service_get_igraphicbufferconsumer(); | |
+ if (!igbc_) { | |
+ std::move(init_cb).Run(StatusCode::kDecoderInitializationFailed); | |
+ return; | |
+ } | |
+ | |
+ gl_texture_consumer_ = gl_consumer_create_by_id_with_igbc(gl_texture->service_id(), igbc_); | |
+ if (!gl_texture_consumer_) { | |
+ std::move(init_cb).Run(StatusCode::kDecoderInitializationFailed); | |
+ return; | |
+ } | |
+ | |
+/* | |
+ gl_consumer_set_frame_available_cb(gl_texture_consumer_, | |
+ HybrisMediaCodecVideoDecoder::OnFrameAvailable, | |
+ this); | |
+*/ | |
+ | |
+ stc_ = surface_texture_client_create_by_igbp(igbp_); | |
+ if (!stc_) { | |
+ std::move(init_cb).Run(StatusCode::kDecoderInitializationFailed); | |
+ return; | |
+ } | |
+ | |
+ surface_texture_client_set_hardware_rendering(stc_, true); | |
+ media_format_ = media_format_create_video_format(codec_type_.c_str(), width, height, 0, buf_size); | |
+ | |
+ if (config.codec() == kCodecH264) { | |
+ ExtractSpsAndPps(config.extra_data(), &csd0_, &csd1_); | |
+ media_format_set_byte_buffer(media_format_, "csd-0", csd0_.data(), csd0_.size()); | |
+ media_format_set_byte_buffer(media_format_, "csd-1", csd1_.data(), csd1_.size()); | |
+ } | |
+ | |
+ int ret = media_codec_configure(media_codec_, media_format_, stc_, 0); | |
+ media_format_destroy(media_format_); | |
+ media_format_ = nullptr; | |
+ | |
+ if (ret > 0) { | |
+ LOG(ERROR) << "Error in " << __func__ << ":" << __LINE__; | |
+ std::move(init_cb).Run(StatusCode::kDecoderInitializationFailed); | |
+ return; | |
+ } | |
+ | |
+ // RecreateGeometry(); | |
+ | |
+ if (!running_) { | |
+ ret = media_codec_start(media_codec_); | |
+ if (ret < 0) { | |
+ LOG(ERROR) << "Error in " << __func__ << ":" << __LINE__; | |
+ std::move(init_cb).Run(StatusCode::kDecoderInitializationFailed); | |
+ return; | |
+ } | |
+ } | |
+ | |
+ running_ = true; | |
+ pending_output_runner_->PostTask(FROM_HERE, | |
+ base::Bind(&HybrisMediaCodecVideoDecoder::RunPipeline, | |
+ base::Unretained(this))); | |
+ | |
+ //LOG(INFO) << "Queue CSD: " << media_codec_queue_csd(media_codec_, media_format_); | |
+ | |
+/* | |
+ Drain(); | |
+ Flush(); | |
+ | |
+ { | |
+ std::unique_lock<decltype(flush_mutex_)> lk(flush_mutex_); | |
+ flush_condition_.wait(lk, [this]{ return !is_flushing_; }); | |
+ } | |
+*/ | |
+ | |
+ if (!RecreateInputBuffers()) { | |
+ media_codec_stop(media_codec_); | |
+ std::move(init_cb).Run(StatusCode::kDecoderInitializationFailed); | |
+ return; | |
+ } | |
+ | |
+ if (!RecreateOutputBuffers()) { | |
+ media_codec_stop(media_codec_); | |
+ std::move(init_cb).Run(StatusCode::kDecoderInitializationFailed); | |
+ return; | |
+ } | |
+ | |
+ std::move(init_cb).Run(OkStatus()); | |
+ LOG(INFO) << "Codec configured"; | |
+ return; | |
+ } | |
+ | |
+void HybrisMediaCodecVideoDecoder::ExtractSpsAndPps( | |
+ const std::vector<uint8_t>& avcc, | |
+ std::vector<uint8_t>* sps_out, | |
+ std::vector<uint8_t>* pps_out) { | |
+ if (avcc.empty()) | |
+ return; | |
+ | |
+ mp4::AVCDecoderConfigurationRecord record; | |
+ if (!record.Parse(avcc.data(), avcc.size())) { | |
+ DVLOG(1) << "Failed to extract SPS and PPS"; | |
+ return; | |
+ } | |
+ | |
+ constexpr std::array<uint8_t, 4> prefix = {{0, 0, 0, 1}}; | |
+ for (const std::vector<uint8_t>& sps : record.sps_list) { | |
+ sps_out->insert(sps_out->end(), prefix.begin(), prefix.end()); | |
+ sps_out->insert(sps_out->end(), sps.begin(), sps.end()); | |
+ } | |
+ | |
+ for (const std::vector<uint8_t>& pps : record.pps_list) { | |
+ pps_out->insert(pps_out->end(), prefix.begin(), prefix.end()); | |
+ pps_out->insert(pps_out->end(), pps.begin(), pps.end()); | |
+ } | |
+} | |
+ | |
+void HybrisMediaCodecVideoDecoder::RunPipeline() { | |
+ int ret = 0; | |
+ | |
+ while (running_) { | |
+ std::lock_guard<decltype(running_mutex_)> lk(running_mutex_); | |
+ | |
+ // Get the decoded frame | |
+ MediaCodecBufferInfo buffer_info_out; | |
+ memset(&buffer_info_out, 0, sizeof(buffer_info_out)); | |
+ | |
+ ret = media_codec_dequeue_output_buffer(media_codec_, &buffer_info_out, queue_timeout_); | |
+ LOG(INFO) << "buffer_into_out.flags: " << buffer_info_out.flags << ", ret: " << ret; | |
+ const bool is_eos = (buffer_info_out.flags & BUFFER_FLAG_END_OF_STREAM); | |
+ | |
+ if (is_eos) { | |
+ bool notify = false; | |
+ { | |
+ std::lock_guard<decltype(drain_mutex_)> lk(drain_mutex_); | |
+ if (is_draining_) { | |
+ is_draining_ = false; | |
+ notify = true; | |
+ } | |
+ } | |
+ if (notify) { | |
+ drain_condition_.notify_all(); | |
+ } | |
+ } | |
+ | |
+ if (ret == INFO_TRY_AGAIN_LATER) { | |
+ continue; | |
+ } else if (ret == INFO_OUTPUT_BUFFERS_CHANGED + 1) { | |
+ RecreateOutputBuffers(); | |
+ continue; | |
+ } else if (ret == INFO_OUTPUT_FORMAT_CHANGED) { | |
+ RecreateGeometry(); | |
+ continue; | |
+ } else { | |
+ QueuedBuffer& pending_output = pending_outputs_.front(); | |
+ | |
+ std::lock_guard<decltype(redraw_mutex_)> lk(redraw_mutex_); | |
+ pending_redraws_.push_back({ buffer_info_out.presentation_time_us, std::move(pending_output.decode_cb) }); | |
+ ret = media_codec_release_output_buffer(media_codec_, buffer_info_out.index, !is_eos); | |
+ if (ret < 0) { | |
+ LOG(ERROR) << "Error in " << __func__ << ":" << __LINE__; | |
+ std::move(pending_redraws_.back().decode_cb).Run(DecodeStatus::DECODE_ERROR); | |
+ pending_redraws_.pop_back(); | |
+ } else { | |
+ FrameAvailable(); | |
+ } | |
+ | |
+ pending_outputs_.pop_front(); | |
+ } | |
+ } | |
+ | |
+ if (eos_decode_cb_) { | |
+ std::lock_guard<decltype(running_mutex_)> lk(running_mutex_); | |
+ std::move(eos_decode_cb_).Run(DecodeStatus::OK); | |
+ } | |
+} | |
+ | |
+bool HybrisMediaCodecVideoDecoder::RecreateInputBuffers() { | |
+ codec_input_buffers_.clear(); | |
+ n_buffers_in_ = media_codec_get_input_buffers_size(media_codec_); | |
+ if (n_buffers_in_ <= 0) { | |
+ return false; | |
+ } | |
+ | |
+ for (size_t i = 0; i < n_buffers_in_; i++) { | |
+ MediaCodecBuffer media_codec_buffer; | |
+ media_codec_buffer.data = media_codec_get_nth_input_buffer(media_codec_, i); | |
+ media_codec_buffer.size = media_codec_get_nth_input_buffer_capacity(media_codec_, i); | |
+ codec_input_buffers_.push_back(media_codec_buffer); | |
+ } | |
+ | |
+ return true; | |
+} | |
+ | |
+bool HybrisMediaCodecVideoDecoder::RecreateOutputBuffers() { | |
+ n_buffers_out_ = media_codec_get_output_buffers_size(media_codec_); | |
+ if (n_buffers_out_ <= 0) { | |
+ return false; | |
+ } | |
+ for (size_t i = 0; i < n_buffers_out_; i++) { | |
+ media_codec_get_nth_output_buffer(media_codec_, i); | |
+ media_codec_get_nth_output_buffer_capacity(media_codec_, i); | |
+ } | |
+ return true; | |
+} | |
+ | |
+void HybrisMediaCodecVideoDecoder::RecreateGeometry() | |
+{ | |
+ MediaFormat output_format = media_codec_get_output_format(media_codec_); | |
+ | |
+ const int width = media_format_get_width(output_format); | |
+ const int height = media_format_get_height(output_format); | |
+ const int crop_left = media_format_get_crop_left(output_format); | |
+ const int crop_right = media_format_get_crop_right(output_format); | |
+ const int crop_bottom = media_format_get_crop_bottom(output_format); | |
+ const int crop_top = media_format_get_crop_top(output_format); | |
+ | |
+ media_format_destroy(output_format); | |
+ | |
+ gfx::Size coded_size(width, height); | |
+ gfx::Rect visible_rect(crop_left, crop_top, width - crop_right - crop_left, height - crop_bottom - crop_top); | |
+ gfx::Size natural_size(width, height); | |
+ | |
+ coded_size_ = coded_size; | |
+ visible_rect_ = visible_rect; | |
+ natural_size_ = natural_size; | |
+} | |
+ | |
+size_t HybrisMediaCodecVideoDecoder::SkipForbiddenNALUs(const uint8_t* data, size_t size) | |
+{ | |
+ size_t new_offset = 0; | |
+ | |
+ if (config_.codec() == VideoCodec::kCodecH264) { | |
+ LOG(INFO) << "H264"; | |
+ if (size > 4 && | |
+ data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x01) { | |
+ LOG(INFO) << "NAL header"; | |
+ return 1; | |
+ } else if (size > 5 && | |
+ data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x00 && data[3] == 0x01) { | |
+ LOG(INFO) << "NAL header"; | |
+ return 1; | |
+ } | |
+ } else if (config_.codec() == VideoCodec::kCodecHEVC) { | |
+ | |
+ } | |
+ | |
+ return new_offset; | |
+} | |
+ | |
+bool HybrisVideoDecoder::IsSupported() { | |
+ return (media_compat_check_availability() == 1); | |
+} | |
+ | |
+std::unique_ptr<VideoDecoder> HybrisVideoDecoder::Create( | |
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner, | |
+ scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner, | |
+ GetStubCB stub_cb) { | |
+ return std::unique_ptr<VideoDecoder>(new HybrisMediaCodecVideoDecoder(task_runner, gpu_task_runner, stub_cb)); | |
+} | |
+ | |
+} // namespace media | |
diff --git a/qtwebengine-chromium/chromium/media/gpu/hybris/video_decoder_hybris.h b/qtwebengine-chromium/chromium/media/gpu/hybris/video_decoder_hybris.h | |
new file mode 100644 | |
index 000000000..05b96a7bf | |
--- /dev/null | |
+++ b/qtwebengine-chromium/chromium/media/gpu/hybris/video_decoder_hybris.h | |
@@ -0,0 +1,179 @@ | |
+// Copyright 2022 Alfred Neumayer. 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_GPU_VIDEO_DECODE_HYBRIS_ACCELERATOR_OVERRIDE_H_ | |
+#define MEDIA_GPU_VIDEO_DECODE_HYBRIS_ACCELERATOR_OVERRIDE_H_ | |
+ | |
+#include "media/base/video_decoder.h" | |
+#include "media/base/video_decoder_config.h" | |
+#include "media/gpu/media_gpu_export.h" | |
+#include "media/video/supported_video_decoder_config.h" | |
+#include "base/memory/ptr_util.h" | |
+#include "base/timer/timer.h" | |
+#include "gpu/config/gpu_preferences.h" | |
+#include "media/gpu/gles2_decoder_helper.h" | |
+#include "gpu/command_buffer/service/mailbox_manager.h" | |
+#include "gpu/command_buffer/service/texture_manager.h" | |
+#include "media/base/video_frame.h" | |
+ | |
+#include <memory> | |
+#include <set> | |
+#include <vector> | |
+#include <chrono> | |
+#include <mutex> | |
+#include <condition_variable> | |
+ | |
+#include <hybris/media/media_codec_list.h> | |
+#include <hybris/media/media_codec_layer.h> | |
+#include <hybris/media/media_format_layer.h> | |
+#include <hybris/media/surface_texture_client_hybris.h> | |
+ | |
+namespace gpu { | |
+class CommandBufferStub; | |
+} | |
+ | |
+namespace media { | |
+ | |
+using GetStubCB = base::RepeatingCallback<gpu::CommandBufferStub*()>; | |
+typedef std::function<void(int)> BufferDoneCB; | |
+ | |
+class MEDIA_GPU_EXPORT HybrisMediaCodecVideoDecoder : public VideoDecoder | |
+{ | |
+public: | |
+ static std::vector<SupportedVideoDecoderConfig> GetSupportedConfigs(); | |
+ | |
+ HybrisMediaCodecVideoDecoder( | |
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner, | |
+ scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner, | |
+ GetStubCB stub_cb); | |
+ | |
+protected: | |
+ ~HybrisMediaCodecVideoDecoder() override; | |
+ | |
+private: | |
+ static std::vector<SupportedVideoDecoderConfig> GetSupportedConfigsInternal(); | |
+ static bool IsSupportedProfile(VideoCodecProfile type); | |
+ static bool IsSupported(VideoCodecProfile type); | |
+ static const char* MimeTypeForCodecType(VideoCodecProfile type); | |
+ static std::string FindSuitableCodec(const std::string& codec_type, const bool hwCodecOnly); | |
+ static void OnFrameAvailable(GLConsumerWrapperHybris, void* data); | |
+ | |
+public: | |
+ void Initialize(const VideoDecoderConfig& config, | |
+ bool low_delay, | |
+ CdmContext* cdm_context, | |
+ InitCB init_cb, | |
+ const OutputCB& output_cb, | |
+ const WaitingCB& waiting_cb) override; | |
+ | |
+ void Decode(scoped_refptr<DecoderBuffer> buffer, DecodeCB decode_cb) override; | |
+ void FrameAvailable(); | |
+ void RedrawTexture(); | |
+ void Destroy(); | |
+ void Reset(base::OnceClosure closure) override; | |
+ bool NeedsBitstreamConversion() const override; | |
+ bool CanReadWithoutStalling() const override; | |
+ int GetMaxDecodeRequests() const override; | |
+ std::string GetDisplayName() const override; | |
+ | |
+private: | |
+ struct QueuedBuffer { | |
+ scoped_refptr<DecoderBuffer> buffer; | |
+ DecodeCB decode_cb; | |
+ }; | |
+ | |
+ struct QueuedDrawOperation { | |
+ int64_t timestamp; | |
+ DecodeCB decode_cb; | |
+ }; | |
+ | |
+ struct MediaCodecBuffer { | |
+ uint8_t* data; | |
+ size_t size; | |
+ }; | |
+ | |
+ void Reconfigure(const VideoDecoderConfig config, InitCB init_cb); | |
+ void Drain(); | |
+ void Flush(); | |
+ bool ProcessInput( | |
+ QueuedBuffer& in_flight_buffer); | |
+ void EnqueueOrderedInput( | |
+ scoped_refptr<DecoderBuffer> buffer, | |
+ DecodeCB decode_cb); | |
+ void RunPipeline(); | |
+ void ExtractSpsAndPps( | |
+ const std::vector<uint8_t>& avcc, | |
+ std::vector<uint8_t>* sps_out, | |
+ std::vector<uint8_t>* pps_out); | |
+ bool RecreateInputBuffers(); | |
+ bool RecreateOutputBuffers(); | |
+ void RecreateGeometry(); | |
+ | |
+ size_t SkipForbiddenNALUs(const uint8_t* data, size_t size); | |
+ | |
+ OutputCB output_cb_; | |
+ DecodeCB eos_decode_cb_; | |
+ | |
+ bool running_; | |
+ | |
+ int32_t n_buffers_in_; | |
+ int32_t n_buffers_out_; | |
+ | |
+ std::vector<MediaCodecBuffer> codec_input_buffers_; | |
+ | |
+ std::deque<QueuedBuffer> pending_inputs_; | |
+ std::deque<QueuedBuffer> pending_outputs_; | |
+ std::deque<QueuedDrawOperation> pending_redraws_; | |
+ int32_t queue_timeout_; | |
+ | |
+ std::mutex drain_mutex_; | |
+ std::condition_variable drain_condition_; | |
+ bool is_draining_; | |
+ | |
+ std::mutex flush_mutex_; | |
+ std::condition_variable flush_condition_; | |
+ bool is_flushing_; | |
+ | |
+ std::mutex redraw_mutex_; | |
+ std::mutex running_mutex_; | |
+ | |
+ MediaCodecDelegate media_codec_; | |
+ MediaFormat media_format_; | |
+ SurfaceTextureClientHybris stc_; | |
+ IGBPWrapperHybris igbp_; | |
+ IGBCWrapperHybris igbc_; | |
+ GLConsumerWrapperHybris gl_texture_consumer_; | |
+ | |
+ gpu::DecoderContext* decoder_context_; | |
+ std::unique_ptr<GLES2DecoderHelper> decoder_helper_; | |
+ std::unique_ptr<gpu::gles2::AbstractTexture> gl_texture; | |
+ | |
+ std::string codec_type_; | |
+ VideoDecoderConfig config_; | |
+ | |
+ scoped_refptr<base::SingleThreadTaskRunner> pending_input_runner_; | |
+ scoped_refptr<base::SingleThreadTaskRunner> pending_output_runner_; | |
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | |
+ scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_; | |
+ base::RepeatingTimer pump_codec_timer_; | |
+ | |
+ gfx::Size coded_size_; | |
+ gfx::Rect visible_rect_; | |
+ gfx::Size natural_size_; | |
+ std::vector<uint8_t> csd0_; | |
+ std::vector<uint8_t> csd1_; | |
+}; | |
+ | |
+class MEDIA_GPU_EXPORT HybrisVideoDecoder { | |
+ public: | |
+ static bool IsSupported(); | |
+ static std::unique_ptr<VideoDecoder> Create( | |
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner, | |
+ scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner, | |
+ GetStubCB stub_cb); | |
+}; | |
+ | |
+} // namespace media | |
+ | |
+#endif // MEDIA_GPU_VIDEO_DECODE_HYBRIS_ACCELERATOR_OVERRIDE_H_ | |
diff --git a/qtwebengine-chromium/chromium/media/media_options.gni b/qtwebengine-chromium/chromium/media/media_options.gni | |
index acacfcd62..852d9b745 100644 | |
--- a/qtwebengine-chromium/chromium/media/media_options.gni | |
+++ b/qtwebengine-chromium/chromium/media/media_options.gni | |
@@ -213,7 +213,7 @@ if (is_chromecast) { | |
"video_decoder", | |
] | |
_default_mojo_media_host = "gpu" | |
-} else if (is_chromeos || is_mac || is_win || (is_linux && use_vaapi)) { | |
+} else if (is_chromeos || is_mac || is_win || is_linux) { | |
_default_mojo_media_services = [ "video_decoder" ] | |
_default_mojo_media_host = "gpu" | |
} | |
diff --git a/qtwebengine-chromium/chromium/media/mojo/services/BUILD.gn b/qtwebengine-chromium/chromium/media/mojo/services/BUILD.gn | |
index 0782f9fd2..efa3220b4 100644 | |
--- a/qtwebengine-chromium/chromium/media/mojo/services/BUILD.gn | |
+++ b/qtwebengine-chromium/chromium/media/mojo/services/BUILD.gn | |
@@ -4,9 +4,14 @@ | |
import("//build/config/chromecast_build.gni") | |
import("//build/config/jumbo.gni") | |
+import("//build/config/linux/pkg_config.gni") | |
import("//media/media_options.gni") | |
import("//testing/test.gni") | |
+pkg_config("libmedia") { | |
+ packages = [ "libmedia" ] | |
+} | |
+ | |
jumbo_component("services") { | |
output_name = "media_mojo_services" | |
sources = [ | |
@@ -144,6 +149,9 @@ jumbo_component("services") { | |
deps += | |
[ "//chromeos/components/cdm_factory_daemon:cdm_factory_daemon_gpu" ] | |
} | |
+ if (is_linux) { | |
+ defines += [ "ENABLE_HYBRIS_MEDIA" ] | |
+ } | |
} | |
source_set("unit_tests") { | |
diff --git a/qtwebengine-chromium/chromium/media/mojo/services/gpu_mojo_media_client.cc b/qtwebengine-chromium/chromium/media/mojo/services/gpu_mojo_media_client.cc | |
index b1f553ce7..4d53d0c05 100644 | |
--- a/qtwebengine-chromium/chromium/media/mojo/services/gpu_mojo_media_client.cc | |
+++ b/qtwebengine-chromium/chromium/media/mojo/services/gpu_mojo_media_client.cc | |
@@ -40,6 +40,10 @@ | |
#include "media/mojo/services/mojo_provision_fetcher.h" | |
#endif // defined(OS_ANDROID) | |
+#if defined(ENABLE_HYBRIS_MEDIA) | |
+#include "media/gpu/hybris/video_decoder_hybris.h" | |
+#endif | |
+ | |
#if defined(OS_WIN) | |
#include "media/gpu/windows/d3d11_video_decoder.h" | |
#include "ui/gl/direct_composition_surface_win.h" | |
@@ -168,9 +172,16 @@ GpuMojoMediaClient::GetSupportedVideoDecoderConfigs() { | |
MediaCodecVideoDecoder::GetSupportedConfigs()}, | |
}; | |
return supported_configs; | |
+ | |
+#elif defined(ENABLE_HYBRIS_MEDIA) | |
+ static SupportedVideoDecoderConfigMap supported_configs{ | |
+ {VideoDecoderImplementation::kDefault, | |
+ HybrisMediaCodecVideoDecoder::GetSupportedConfigs()}, | |
+ }; | |
+ return supported_configs; | |
+ | |
#else | |
SupportedVideoDecoderConfigMap supported_config_map; | |
- | |
#if defined(OS_WIN) | |
// Start with the configurations supported by D3D11VideoDecoder. | |
// VdaVideoDecoder is still used as a fallback. | |
@@ -305,13 +316,23 @@ std::unique_ptr<VideoDecoder> GpuMojoMediaClient::CreateVideoDecoder( | |
if (gpu_workarounds_.disable_dxva_video_decoder) | |
return nullptr; | |
#endif // defined(OS_WIN) | |
- video_decoder = VdaVideoDecoder::Create( | |
- task_runner, gpu_task_runner_, media_log->Clone(), target_color_space, | |
- gpu_preferences_, gpu_workarounds_, | |
- base::BindRepeating(&GetCommandBufferStub, gpu_task_runner_, | |
- media_gpu_channel_manager_, | |
- command_buffer_id->channel_token, | |
- command_buffer_id->route_id)); | |
+#if defined(ENABLE_HYBRIS_MEDIA) | |
+ if (HybrisVideoDecoder::IsSupported()) | |
+ video_decoder = HybrisVideoDecoder::Create( | |
+ task_runner, gpu_task_runner_, | |
+ base::BindRepeating(&GetCommandBufferStub, gpu_task_runner_, | |
+ media_gpu_channel_manager_, | |
+ command_buffer_id->channel_token, | |
+ command_buffer_id->route_id)); | |
+ else | |
+#endif // defined(ENABLE_HYBRIS_MEDIA) | |
+ video_decoder = VdaVideoDecoder::Create( | |
+ task_runner, gpu_task_runner_, media_log->Clone(), target_color_space, | |
+ gpu_preferences_, gpu_workarounds_, | |
+ base::BindRepeating(&GetCommandBufferStub, gpu_task_runner_, | |
+ media_gpu_channel_manager_, | |
+ command_buffer_id->channel_token, | |
+ command_buffer_id->route_id)); | |
#endif // defined(OS_ANDROID) | |
} break; | |
diff --git a/src/core/core_module.pro b/src/core/core_module.pro | |
index 5e8f8d96f..21702ef2c 100644 | |
--- a/src/core/core_module.pro | |
+++ b/src/core/core_module.pro | |
@@ -7,7 +7,7 @@ api_library_name = qtwebenginecoreapi$$qtPlatformTargetSuffix() | |
api_library_path = $$OUT_PWD/api/$$getConfigDir() | |
LIBS_PRIVATE += -L$$api_library_path | |
linux:LIBS_PRIVATE += -landroid-properties | |
-linux:LIBS_PRIVATE += -lhybris-common -lcamera | |
+linux:LIBS_PRIVATE += -lhybris-common -lcamera -lmedia | |
CONFIG *= no_smart_library_merge | |
osx { | |
LIBS_PRIVATE += -Wl,-force_load,$${api_library_path}$${QMAKE_DIR_SEP}lib$${api_library_name}.a | |
diff --git a/src/core/gn_run.pro b/src/core/gn_run.pro | |
index 3d6fda80e..6e9f5b9d9 100644 | |
--- a/src/core/gn_run.pro | |
+++ b/src/core/gn_run.pro | |
@@ -33,6 +33,8 @@ build_pass|!debug_and_release { | |
gn_args += "qtwebengine_target=\"$$system_path($$OUT_PWD/$$getConfigDir()):QtWebEngineCore\"" | |
+ gn_args += "mojo_media_host=\"utility\" mojo_media_services=[\"video_decoder\"]" | |
+ | |
!qtConfig(webengine-system-gn) { | |
gn_binary = $$system_quote($$system_path($$gnPath())) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note: Might be missing some parts and is very unclean, has has various experiments behind it.
Maybe someone else can finish this for more than just VP8 & VP9.