diff --git a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc index 3acfcf5749..45b18d4203 100644 --- a/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc +++ b/content/renderer/media/gpu/gpu_video_accelerator_factories_impl.cc @@ -183,6 +183,9 @@ void GpuVideoAcceleratorFactoriesImpl::DestroyContext() { } bool GpuVideoAcceleratorFactoriesImpl::IsGpuVideoDecodeAcceleratorEnabled() { +#if BUILDFLAG(IS_AMLOGIC_MEDIA) + return true; +#endif return video_decode_accelerator_enabled_; } bool GpuVideoAcceleratorFactoriesImpl::IsGpuVideoEncodeAcceleratorEnabled() { diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index c848b7f8f7..e2b5215d17 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc @@ -1,3 +1,4 @@ +#include "media/mojo/buildflags.h" // Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -1026,8 +1027,10 @@ media::GpuVideoAcceleratorFactories* RenderThreadImpl::GetGpuFactories() { // Currently, VideoResourceUpdater can't convert hardware resources to // software resources in software compositing mode. So, fall back to software // video decoding if gpu compositing is off. +#if !BUILDFLAG(IS_AMLOGIC_MEDIA) if (is_gpu_compositing_disabled_) return nullptr; +#endif // This context is only used to create textures and mailbox them, so // use lower limits than the default. gpu::SharedMemoryLimits limits = gpu::SharedMemoryLimits::ForMailboxContext(); @@ -1045,6 +1048,9 @@ media::GpuVideoAcceleratorFactories* RenderThreadImpl::GetGpuFactories() { viz::command_buffer_metrics::ContextType::MEDIA, kGpuStreamIdMedia, kGpuStreamPriorityMedia); +#if BUILDFLAG(IS_AMLOGIC_MEDIA) + const bool enable_video_decode_accelerator = true; +#else const bool enable_video_decode_accelerator = #if BUILDFLAG(IS_LINUX) base::FeatureList::IsEnabled(media::kAcceleratedVideoDecodeLinux) && @@ -1053,6 +1059,7 @@ media::GpuVideoAcceleratorFactories* RenderThreadImpl::GetGpuFactories() { (gpu_channel_host->gpu_feature_info() .status_values[gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE] == gpu::kGpuFeatureStatusEnabled); +#endif const bool enable_video_encode_accelerator = #if BUILDFLAG(IS_LINUX) diff --git a/media/base/format_utils.cc b/media/base/format_utils.cc index 0e1080e0a6..98a221b2f4 100644 --- a/media/base/format_utils.cc +++ b/media/base/format_utils.cc @@ -65,6 +65,9 @@ std::optional VideoPixelFormatToGfxBufferFormat( case PIXEL_FORMAT_NV12: return gfx::BufferFormat::YUV_420_BIPLANAR; + case PIXEL_FORMAT_NV21: + return gfx::BufferFormat::YUV_420_BIPLANAR; + case PIXEL_FORMAT_NV12A: return gfx::BufferFormat::YUVA_420_TRIPLANAR; diff --git a/media/base/supported_types.cc b/media/base/supported_types.cc index 34e1ecb868..bc0cd98fee 100644 --- a/media/base/supported_types.cc +++ b/media/base/supported_types.cc @@ -315,7 +315,7 @@ bool IsDecoderAACSupported(const AudioType& type) { return true; } #if BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER) && \ - (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)) + (BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_AMLOGIC_MEDIA)) return GetSupplementalDecoderAudioTypeCache()->IsProfileSupported(type); #else return false; @@ -350,12 +350,13 @@ bool IsDecoderDolbyAc3Eac3Supported(const AudioType& type) { bool IsDecoderDolbyAc4Supported(const AudioType& type) { #if BUILDFLAG(ENABLE_PLATFORM_AC4_AUDIO) && \ - BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER) && BUILDFLAG(IS_WIN) + BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER) && (BUILDFLAG(IS_WIN) || BUILDFLAG(IS_AMLOGIC_MEDIA)) return GetSupplementalDecoderAudioTypeCache()->IsProfileSupported(type); #else return false; #endif // BUILDFLAG(ENABLE_PLATFORM_AC4_AUDIO) && - // BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER) && BUILDFLAG(IS_WIN) + // BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER) && (BUILDFLAG(IS_WIN) || + // BUILDFLAG(IS_AMLOGIC_MEDIA)) } bool IsEncoderH264ProfileSupported(const VideoType& type) { @@ -579,6 +580,11 @@ bool IsDefaultEncoderSupportedVideoType(const VideoType& type) { } bool IsDecoderBuiltInVideoCodec(VideoCodec codec) { +#if BUILDFLAG(IS_AMLOGIC_MEDIA) + // On Amlogic platforms, all codecs are treated as built-in since the + // hardware decoders are used. + return true; +#endif // BUILDFLAG(IS_AMLOGIC_MEDIA) #if BUILDFLAG(ENABLE_FFMPEG_VIDEO_DECODERS) && BUILDFLAG(USE_PROPRIETARY_CODECS) if (codec == VideoCodec::kH264 && base::FeatureList::IsEnabled(kBuiltInH264Decoder)) { diff --git a/media/gpu/chromeos/mailbox_video_frame_converter.cc b/media/gpu/chromeos/mailbox_video_frame_converter.cc index 6cbc6d89f5..21994b5f34 100644 --- a/media/gpu/chromeos/mailbox_video_frame_converter.cc +++ b/media/gpu/chromeos/mailbox_video_frame_converter.cc @@ -389,10 +389,22 @@ void MailboxVideoFrameConverter::WrapSharedImageAndVideoFrameAndOutput( frame->metadata().needs_detiling ? frame->coded_size() : GetRectSizeFromOrigin(frame->visible_rect()); + // AML: NV21 and NV12 have identical layout for GPU texture import. + // WrapSharedImage doesn't support NV21, so use NV12 instead. + VideoPixelFormat wrap_format = frame->format(); + if (wrap_format == PIXEL_FORMAT_NV21) + wrap_format = PIXEL_FORMAT_NV12; scoped_refptr mailbox_frame = VideoFrame::WrapSharedImage( - frame->format(), shared_image, shared_image_sync_token, + wrap_format, shared_image, shared_image_sync_token, std::move(release_mailbox_cb), coded_size, frame->visible_rect(), frame->natural_size(), frame->timestamp()); + if (!mailbox_frame) { + DVLOG(3) << "[AML-CONV] WrapSharedImage returned null! format=" + << VideoPixelFormatToString(frame->format()) + << " coded=" << coded_size.ToString() + << " visible=" << frame->visible_rect().ToString(); + return; + } mailbox_frame->set_color_space(frame->ColorSpace()); mailbox_frame->set_hdr_metadata(frame->hdr_metadata()); mailbox_frame->set_metadata(frame->metadata()); @@ -496,8 +508,13 @@ bool MailboxVideoFrameConverter::GenerateSharedImageOnGPUThread( } auto gpu_memory_buffer_handle = origin_frame->CreateGpuMemoryBufferHandle(); - DCHECK(!gpu_memory_buffer_handle.is_null()); - DCHECK_EQ(gpu_memory_buffer_handle.type, gfx::NATIVE_PIXMAP); + DVLOG(3) << "[AML-CONV] CreateGpuMemoryBufferHandle: null=" + << gpu_memory_buffer_handle.is_null() + << " type=" << gpu_memory_buffer_handle.type + << " planes=" << gpu_memory_buffer_handle.native_pixmap_handle.planes.size() + << " fmt=" << VideoPixelFormatToString(origin_frame->format()) + << " size=" << origin_frame->coded_size().ToString(); + if (gpu_memory_buffer_handle.is_null()) return false; // The SharedImage size ultimately must correspond to the size used to import // the decoded frame into a graphics API (e.g., the EGL image size when using @@ -531,18 +548,18 @@ bool MailboxVideoFrameConverter::GenerateSharedImageOnGPUThread( shared_image_usage |= gpu::SHARED_IMAGE_USAGE_WEBGPU_READ; } + DVLOG(3) << "[AML-CONV] About to CreateSharedImage size=" << shared_image_size.ToString(); scoped_refptr client_shared_image = gpu_delegate_->CreateSharedImage(std::move(gpu_memory_buffer_handle), GetSharedImageFormat(*buffer_format), shared_image_size, src_color_space, kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, shared_image_usage); + DVLOG(3) << "[AML-CONV] CreateSharedImage result: " << (client_shared_image ? "OK" : "FAIL"); if (!client_shared_image) { OnError(FROM_HERE, "Failed to create shared image."); return false; } - // There's no need to UpdateSharedImage() after CreateSharedImage(). - shared_image->Reset(std::move(client_shared_image)); return true; } diff --git a/media/gpu/chromeos/native_pixmap_frame_resource.cc b/media/gpu/chromeos/native_pixmap_frame_resource.cc index 09c763a7e8..5ac815656b 100644 --- a/media/gpu/chromeos/native_pixmap_frame_resource.cc +++ b/media/gpu/chromeos/native_pixmap_frame_resource.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "media/gpu/chromeos/native_pixmap_frame_resource.h" +#include #include "atomic" @@ -130,10 +131,8 @@ scoped_refptr NativePixmapFrameResource::Create( std::move(dmabuf_fds[i])); } - // This is only ever called with V4L2-allocated buffers, so |layout.modifier| - // is expected to be kNoModifier. - CHECK_EQ(layout.modifier(), gfx::NativePixmapHandle::kNoModifier); - handle.modifier = layout.modifier(); + // Keep kNoModifier for V4L2 MMAP buffers. + handle.modifier = gfx::NativePixmapHandle::kNoModifier; // AML: force no modifier for V4L2 MMAP // Note: |buffer_usage| is not set. As a result, the constructed // NativePixmapFrameResource cannot be converted to a VideoFrame with the diff --git a/media/gpu/chromeos/video_decoder_pipeline.cc b/media/gpu/chromeos/video_decoder_pipeline.cc --- a/media/gpu/chromeos/video_decoder_pipeline.cc +++ b/media/gpu/chromeos/video_decoder_pipeline.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "media/gpu/chromeos/video_decoder_pipeline.h" +#include "media/mojo/buildflags.h" #include #include @@ -571,6 +572,7 @@ // Make sure that the configuration requested is supported by the driver, // which must provide such information. +#if !BUILDFLAG(IS_AMLOGIC_MEDIA) const auto supported_configs = supported_configs_for_testing_.empty() ? VideoDecoderPipeline::GetSupportedConfigs(GetDecoderType(), @@ -588,6 +590,7 @@ std::move(init_cb).Run(DecoderStatus::Codes::kUnsupportedConfig); return; } +#endif // !BUILDFLAG(IS_AMLOGIC_MEDIA) constexpr auto kVideoCodecProfileCount = media::VIDEO_CODEC_PROFILE_MAX + 1; base::UmaHistogramEnumeration( "Media.PlatformVideoDecoding.VideoCodecProfile", config.profile(), @@ -647,8 +650,10 @@ get_original_frame_cb = base::BindRepeating( &OOPVideoDecoder::GetOriginalFrame, base::Unretained(static_cast(decoder_.get()))); + } else if (!main_frame_pool_) { + // AML: PickDecoderOutputFormat() drops the pool in V4L2 MMAP mode. + get_original_frame_cb = base::NullCallback(); } else { - CHECK(main_frame_pool_); PlatformVideoFramePool* platform_video_frame_pool = main_frame_pool_->AsPlatformVideoFramePool(); // The only |frame_converter_| that needs the GetOriginalFrameCB callback @@ -1058,6 +1063,15 @@ // vector (CAPCM*1_Sand_E.h264). CHECK_LE(num_codec_reference_frames, 32u); + DVLOG(3) << "[AML-PIPE] PickDecoderOutputFormat: candidates=" << candidates.size() + << " renderable=" << renderable_fourccs_.size(); + for (const auto& c : candidates) { + DVLOG(3) << "[AML-PIPE] candidate: " << c.fourcc.ToString() + << " size=" << c.size.ToString(); + } + for (const auto& f : renderable_fourccs_) { + DVLOG(3) << "[AML-PIPE] renderable: " << f.ToString(); + } if (candidates.empty()) return CroStatus::Codes::kNoDecoderOutputFormatCandidates; @@ -1069,6 +1083,8 @@ // provided by the frame pool matches the one supported by the |decoder_|, we // don't need an image processor. std::optional viable_candidate; + DVLOG(3) << "[AML-PIPE] output_size=" << (output_size ? output_size->ToString() : "none") + << " decoder_visible=" << decoder_visible_rect.ToString(); if (!output_size || *output_size == decoder_visible_rect.size()) { for (const auto& fourcc : renderable_fourccs_) { for (const auto& candidate : candidates) { @@ -1108,14 +1124,9 @@ *allocator, VideoFrame::STORAGE_DMABUFS); #elif BUILDFLAG(IS_LINUX) && BUILDFLAG(USE_V4L2_CODEC) // Linux w/ V4L2 should not use a custom allocator - // Only tested with video_decode_accelerator_tests - // TODO(wenst@) Test with full Chromium Browser CHECK(!allocator.has_value()); if (viable_candidate) { - // Instead, let V4L2 allocate the buffers if it can decode directly - // to the preferred formats. There's no need to allocate frames. - // This is not compatible with VdVideoDecodeAccelerator, which - // expects GPU buffers in VdVideoDecodeAccelerator::GetPicture() + // Let V4L2 allocate the buffers (MMAP mode) frame_converter_->set_get_original_frame_cb(base::NullCallback()); main_frame_pool_.reset(); return *viable_candidate; diff --git a/media/gpu/v4l2/legacy/v4l2_video_decoder_backend_stateful.cc b/media/gpu/v4l2/legacy/v4l2_video_decoder_backend_stateful.cc --- a/media/gpu/v4l2/legacy/v4l2_video_decoder_backend_stateful.cc +++ b/media/gpu/v4l2/legacy/v4l2_video_decoder_backend_stateful.cc @@ -464,7 +464,17 @@ // Wrap the frame into another one so we can be signaled when the // consumer is done with it and reuse the V4L2 buffer. scoped_refptr origin_frame = buffer->GetFrameResource(); + DVLOG(3) << "[AML-V4L2] OnOutputBufferDequeued: origin_frame=" + << (origin_frame ? "valid" : "NULL") + << " memory=" << output_queue_->GetMemoryType(); + if (!origin_frame) { + // Queue was reset (resolution change). Skip this buffer. + return; + } frame = origin_frame->CreateWrappingFrame(); + if (!frame) { + return; + } frame->AddDestructionObserver(base::BindOnce( &V4L2StatefulVideoDecoderBackend::ReuseOutputBufferThunk, task_runner_, weak_this_, buffer)); @@ -761,6 +771,8 @@ #endif // BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER) V4L2_PIX_FMT_VP8, V4L2_PIX_FMT_VP9, + // AML: without AV01 here every AV1 stream is rejected in Initialize(). + V4L2_PIX_FMT_AV1, }; auto device = base::MakeRefCounted(); VideoDecodeAccelerator::SupportedProfiles profiles = diff --git a/media/gpu/v4l2/v4l2_queue.cc b/media/gpu/v4l2/v4l2_queue.cc index bd6b3f5278..4242e06e38 100644 --- a/media/gpu/v4l2/v4l2_queue.cc +++ b/media/gpu/v4l2/v4l2_queue.cc @@ -133,13 +133,12 @@ std::vector GetDmabufsForV4L2Buffer( expbuf.type = buf_type; expbuf.index = index; expbuf.plane = i; - expbuf.flags = O_CLOEXEC; + expbuf.flags = O_CLOEXEC | O_RDWR; // AML: Mali needs RW access if (ioctl_cb.Run(VIDIOC_EXPBUF, &expbuf) != 0) { RecordVidiocIoctlErrorUMA(VidiocIoctlRequests::kVidiocExpbuf); dmabuf_fds.clear(); break; } - dmabuf_fds.push_back(base::ScopedFD(expbuf.fd)); } @@ -268,6 +267,15 @@ bool V4L2Buffer::Query() { return false; } + // Log actual plane info from QUERYBUF + for (size_t pi = 0; pi < v4l2_buffer_.length; pi++) { + LOG(ERROR) << "[AML-QB] buf=" << v4l2_buffer_.index + << " plane" << pi + << " length=" << v4l2_planes_[pi].length + << " offset=" << v4l2_planes_[pi].m.mem_offset + << " bytesused=" << v4l2_planes_[pi].bytesused; + } + DCHECK(plane_mappings_.size() == v4l2_buffer_.length); return true; @@ -314,7 +322,10 @@ size_t V4L2Buffer::GetMemoryUsage() const { scoped_refptr V4L2Buffer::CreateFrame() { auto layout = V4L2FormatToVideoFrameLayout(format_); if (!layout) { - VLOGF(1) << "Cannot create frame layout for V4L2 buffers"; + DVLOG(3) << "[AML-V4L2] CreateFrame: layout failed, pixfmt=0x" + << std::hex << format_.fmt.pix_mp.pixelformat << std::dec + << " " << format_.fmt.pix_mp.width << "x" << format_.fmt.pix_mp.height + << " num_planes=" << format_.fmt.pix_mp.num_planes; return nullptr; } @@ -322,7 +333,8 @@ scoped_refptr V4L2Buffer::CreateFrame() { ioctl_cb_, v4l2_buffer_.index, v4l2_buffer_.length, static_cast(v4l2_buffer_.type)); if (dmabuf_fds.empty()) { - VLOGF(1) << "Failed to get DMABUFs of V4L2 buffer"; + DVLOG(3) << "[AML-V4L2] CreateFrame: GetDmabufs failed, index=" + << v4l2_buffer_.index << " length=" << v4l2_buffer_.length; return nullptr; } @@ -355,15 +367,19 @@ scoped_refptr V4L2Buffer::CreateFrame() { const scoped_refptr& V4L2Buffer::GetFrameResource() { // We can create the FrameResource only when using MMAP buffers. if (v4l2_buffer_.memory != V4L2_MEMORY_MMAP) { - VLOGF(1) << "Cannot create video frame from non-MMAP buffer"; - // Allow NOTREACHED() on invalid argument because this is an internal - // method. - NOTREACHED(); + DVLOG(3) << "[AML-V4L2] GetFrameResource: memory type is " + << v4l2_buffer_.memory << " (not MMAP=" << V4L2_MEMORY_MMAP << ")" + << " index=" << v4l2_buffer_.index; + static const scoped_refptr null_res; + return null_res; } // Create the video frame instance if requiring it for the first time. if (!frame_) { frame_ = CreateFrame(); + if (!frame_) { + DVLOG(3) << "[AML-V4L2] CreateFrame returned null for buffer " << v4l2_buffer_.index; + } } return frame_; @@ -1178,6 +1194,12 @@ size_t V4L2Queue::AllocateBuffers(size_t count, return 0; } planes_count_ = format->fmt.pix_mp.num_planes; + // AML 6.12: queue_setup returns 2 vb2 planes for NV21, but G_FMT + // reports num_planes=1. Force 2 so QUERYBUF gets correct length. + if (type_ == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && planes_count_ < 2) { + planes_count_ = 2; + format->fmt.pix_mp.num_planes = 2; + } DCHECK_LE(planes_count_, static_cast(VIDEO_MAX_PLANES)); __u8 flags = incoherent ? V4L2_MEMORY_FLAG_NON_COHERENT : 0; diff --git a/media/gpu/v4l2/v4l2_utils.cc b/media/gpu/v4l2/v4l2_utils.cc --- a/media/gpu/v4l2/v4l2_utils.cc +++ b/media/gpu/v4l2/v4l2_utils.cc @@ -17,6 +17,10 @@ #if BUILDFLAG(IS_CHROMEOS) #include #endif +// AML: the Debian uAPI headers predate the AV1 controls. +#ifndef V4L2_CID_MPEG_VIDEO_AV1_PROFILE +#define V4L2_CID_MPEG_VIDEO_AV1_PROFILE (V4L2_CID_CODEC_BASE + 656) +#endif #include "base/containers/contains.h" #include "base/metrics/histogram_functions.h" @@ -264,8 +268,17 @@ planes.reserve(num_color_planes); for (size_t i = 0; i < num_buffers; ++i) { const v4l2_plane_pix_format& plane_format = pix_mp.plane_fmt[i]; - planes.emplace_back(static_cast(plane_format.bytesperline), 0u, - plane_format.sizeimage); + int32_t stride = static_cast(plane_format.bytesperline); + size_t sizeimage = plane_format.sizeimage; + // AML: When num_planes was forced to 2 for NV21, plane_fmt[1] may + // have zero values. Fill stride/size from plane0. + // Each vb2 plane is a separate DMA-BUF allocation, so offset=0 for all. + if (i > 0 && stride == 0 && num_buffers == 2) { + stride = static_cast(pix_mp.plane_fmt[0].bytesperline); + sizeimage = stride * pix_mp.height / 2; + } + // AML: each EXPBUF plane is independent DMA-BUF, offset=0 for each + planes.emplace_back(stride, 0u, sizeimage); } // For the case that #color planes > #buffers, it fills stride of color // plane which does not map to buffer. @@ -338,10 +351,9 @@ {V4L2_PIX_FMT_VP8_FRAME, V4L2_CID_MPEG_VIDEO_VP8_PROFILE}, {V4L2_PIX_FMT_VP9, V4L2_CID_MPEG_VIDEO_VP9_PROFILE}, {V4L2_PIX_FMT_VP9_FRAME, V4L2_CID_MPEG_VIDEO_VP9_PROFILE}, -#if BUILDFLAG(IS_CHROMEOS) + // AML: needed on Linux too, or no AV1 profile is ever enumerated. {V4L2_PIX_FMT_AV1, V4L2_CID_MPEG_VIDEO_AV1_PROFILE}, {V4L2_PIX_FMT_AV1_FRAME, V4L2_CID_MPEG_VIDEO_AV1_PROFILE}, -#endif }; // Default VideoCodecProfiles associated to a V4L2 Codec Control ID. @@ -359,9 +371,8 @@ #endif // BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER) {V4L2_CID_MPEG_VIDEO_VP8_PROFILE, {VP8PROFILE_ANY}}, {V4L2_CID_MPEG_VIDEO_VP9_PROFILE, {VP9PROFILE_PROFILE0}}, -#if BUILDFLAG(IS_CHROMEOS) + // AML: fallback used when the driver has no AV1 profile control. {V4L2_CID_MPEG_VIDEO_AV1_PROFILE, {AV1PROFILE_PROFILE_MAIN}}, -#endif }; // Correspondence from a VideoCodecProfiles to V4L2 codec described @@ -379,10 +390,9 @@ {VP8PROFILE_ANY, MAKE_V4L2_CODEC_PAIR(V4L2_PIX_FMT_VP8, FRAME)}, {VP9PROFILE_PROFILE0, MAKE_V4L2_CODEC_PAIR(V4L2_PIX_FMT_VP9, FRAME)}, {VP9PROFILE_PROFILE2, MAKE_V4L2_CODEC_PAIR(V4L2_PIX_FMT_VP9, FRAME)}, -#if BUILDFLAG(IS_CHROMEOS) + // AML: the fourcc -> profile direction is not IS_CHROMEOS gated. {AV1PROFILE_PROFILE_MAIN, MAKE_V4L2_CODEC_PAIR(V4L2_PIX_FMT_AV1, FRAME)}, -#endif }; } // namespace @@ -545,8 +555,11 @@ uint32_t VideoCodecProfileToV4L2PixFmt(VideoCodecProfile profile, bool slice_based) { - CHECK(base::Contains(kVideoCodecProfileToV4L2CodecPixFmt, profile)) - << "Unsupported profile: " << GetProfileName(profile); + // AML: the header contract is INVALID for unmapped profiles, not a crash. + if (!base::Contains(kVideoCodecProfileToV4L2CodecPixFmt, profile)) { + VLOGF(1) << "Unsupported profile: " << GetProfileName(profile); + return V4L2_PIX_FMT_INVALID; + } const auto& v4l2_pix_fmt = kVideoCodecProfileToV4L2CodecPixFmt.at(profile); return slice_based ? v4l2_pix_fmt.first : v4l2_pix_fmt.second; diff --git a/media/gpu/v4l2/v4l2_vda_helpers.cc b/media/gpu/v4l2/v4l2_vda_helpers.cc --- a/media/gpu/v4l2/v4l2_vda_helpers.cc +++ b/media/gpu/v4l2/v4l2_vda_helpers.cc @@ -160,7 +160,8 @@ #endif // BUILDFLAG(ENABLE_HEVC_PARSER_AND_HW_DECODER) case VideoCodec::kVP8: case VideoCodec::kVP9: - // VP8/VP9 don't need any frame splitting, use the default implementation. + case VideoCodec::kAV1: + // AML: AV1 needs no frame splitting either, one buffer is one temporal unit. return std::make_unique(); default: LOG(ERROR) << "Unhandled profile: " << profile; diff --git a/media/media_options.gni b/media/media_options.gni index e235287ebb..36e13c3e91 100644 --- a/media/media_options.gni +++ b/media/media_options.gni @@ -347,6 +347,14 @@ declare_args() { chrome_wide_echo_cancellation_supported = is_win || is_mac || is_linux } +declare_args() { + is_amlogic_media=false +} + +declare_args() { + widevine_version=0 +} + # Do not expand this list without double-checking with OWNERS, this is a list of # all targets which roll up into the //media component. It controls visibility # of subcomponent targets and public_deps for //media. diff --git a/media/mojo/BUILD.gn b/media/mojo/BUILD.gn index 9573d77ba8..92ecf99112 100644 --- a/media/mojo/BUILD.gn +++ b/media/mojo/BUILD.gn @@ -55,6 +55,7 @@ buildflag_header("buildflags") { "ENABLE_MOJO_VIDEO_DECODER=$enable_mojo_video_decoder", "ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS=$enable_mojo_media_in_browser_process", "ENABLE_MOJO_MEDIA_IN_GPU_PROCESS=$enable_mojo_media_in_gpu_process", + "IS_AMLOGIC_MEDIA=$is_amlogic_media", ] } diff --git a/media/mojo/services/BUILD.gn b/media/mojo/services/BUILD.gn index 3e2dac7991..b3911dcf35 100644 --- a/media/mojo/services/BUILD.gn +++ b/media/mojo/services/BUILD.gn @@ -119,6 +119,11 @@ component("services") { sources += [ "gpu_mojo_media_client_mac.cc" ] } else if (is_win) { sources += [ "gpu_mojo_media_client_win.cc" ] + } else if (is_amlogic_media) { + sources += [ "gpu_mojo_media_client_amlogic.cc" ] + deps += [ + "//media/gpu/chromeos", + ] } else if (use_vaapi || use_v4l2_codec) { if (is_linux) { sources += [ "gpu_mojo_media_client_linux.cc" ] diff --git a/media/mojo/services/gpu_mojo_media_client.cc b/media/mojo/services/gpu_mojo_media_client.cc index 7a739e1d73..0475c34757 100644 --- a/media/mojo/services/gpu_mojo_media_client.cc +++ b/media/mojo/services/gpu_mojo_media_client.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "media/mojo/services/gpu_mojo_media_client.h" +#include "media/mojo/buildflags.h" #include #include @@ -156,12 +157,16 @@ GpuMojoMediaClient::GetSupportedVideoDecoderConfigs() { if (!supported_config_cache_) { // Only bother to query if accelerated video decoding is enabled. // (RenderMediaClient does not know about GPU features before it asks.) +#if BUILDFLAG(IS_AMLOGIC_MEDIA) + { +#else if (gpu_preferences_.disable_accelerated_video_decode || (gpu_feature_info_ .status_values[gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE] != gpu::kGpuFeatureStatusEnabled)) { supported_config_cache_ = SupportedVideoDecoderConfigs(); } else { +#endif supported_config_cache_ = GetPlatformSupportedVideoDecoderConfigs(); } @@ -230,12 +235,14 @@ std::unique_ptr GpuMojoMediaClient::CreateVideoDecoder( const gfx::ColorSpace& target_color_space, mojo::PendingRemote oop_video_decoder) { // Always respect GPU features. +#if !BUILDFLAG(IS_AMLOGIC_MEDIA) if (gpu_preferences_.disable_accelerated_video_decode || (gpu_feature_info_ .status_values[gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE] != gpu::kGpuFeatureStatusEnabled)) { return nullptr; } +#endif // All implementations require a command buffer. if (!command_buffer_id) return nullptr; diff --git a/ui/ozone/common/BUILD.gn b/ui/ozone/common/BUILD.gn index 7ce40f68de..1036e37a91 100644 --- a/ui/ozone/common/BUILD.gn +++ b/ui/ozone/common/BUILD.gn @@ -42,6 +42,7 @@ source_set("common") { "//ui/gfx/ipc/color", "//ui/gl", "//ui/gl:buildflags", + "//media/mojo:buildflags", ] data_deps = [ "//third_party/angle:includes" ] diff --git a/ui/ozone/common/native_pixmap_egl_binding.cc b/ui/ozone/common/native_pixmap_egl_binding.cc index b945e14226..b1b0dda89b 100644 --- a/ui/ozone/common/native_pixmap_egl_binding.cc +++ b/ui/ozone/common/native_pixmap_egl_binding.cc @@ -8,6 +8,7 @@ #endif #include "ui/ozone/common/native_pixmap_egl_binding.h" +#include "media/mojo/buildflags.h" #include "base/logging.h" #include "base/memory/scoped_refptr.h" @@ -70,7 +71,11 @@ EGLint FourCC(gfx::BufferFormat format) { case gfx::BufferFormat::YVU_420: return DRM_FORMAT_YVU420; case gfx::BufferFormat::YUV_420_BIPLANAR: +#if BUILDFLAG(IS_AMLOGIC_MEDIA) + return 0x3132564e; // DRM_FORMAT_NV21 - AML V4L2 outputs VU order +#else return DRM_FORMAT_NV12; +#endif case gfx::BufferFormat::P010: return DRM_FORMAT_P010; case gfx::BufferFormat::RGBA_F16: @@ -229,11 +234,19 @@ bool NativePixmapEGLBinding::InitializeFromNativePixmap( attrs.push_back(kPlaneOffsetAttrs[attrs_plane]); attrs.push_back(pixmap->GetDmaBufOffset(attrs_plane)); attrs.push_back(kPlanePitchAttrs[attrs_plane]); - attrs.push_back(pixmap->GetDmaBufPitch(attrs_plane)); + { + int p = pixmap->GetDmaBufPitch(attrs_plane); + if (attrs_plane > 0 && p == 0 && pixmap->GetNumberOfPlanes() == 2) + p = pixmap->GetDmaBufPitch(0); + attrs.push_back(p); + } uint64_t modifier = pixmap->GetBufferFormatModifier(); + // AML: skip modifier only for kNoModifier (V4L2 MMAP video buffers) + // GBM-allocated UI buffers have real modifiers and must pass them. if (has_dma_buf_import_modifier && - modifier != gfx::NativePixmapHandle::kNoModifier) { + modifier != gfx::NativePixmapHandle::kNoModifier && + modifier != 0) { DCHECK(attrs_plane < std::size(kPlaneLoModifierAttrs)); DCHECK(attrs_plane < std::size(kPlaneHiModifierAttrs)); attrs.push_back(kPlaneLoModifierAttrs[attrs_plane]); @@ -252,7 +265,12 @@ bool NativePixmapEGLBinding::InitializeFromNativePixmap( attrs.push_back(EGL_DMA_BUF_PLANE0_OFFSET_EXT); attrs.push_back(pixmap->GetDmaBufOffset(pixmap_plane)); attrs.push_back(EGL_DMA_BUF_PLANE0_PITCH_EXT); - attrs.push_back(pixmap->GetDmaBufPitch(pixmap_plane)); + { + int p = pixmap->GetDmaBufPitch(pixmap_plane); + if (pixmap_plane > 0 && p == 0) + p = pixmap->GetDmaBufPitch(0); + attrs.push_back(p); + } attrs.push_back(EGL_NONE); }