import '../contracts/library.dart'; import '../../shared/utils/app_logger.dart'; import 'media_range_detector.dart'; enum VideoRangeCategory { dolbyVision, hdr10, hlg, sdr, unknown } class MediaCapability { final VideoRangeCategory rangeCategory; final String? codec; const MediaCapability({required this.rangeCategory, this.codec}); } class ProbeResult { final String? videoCodec; final String? videoRange; final String? videoRangeType; const ProbeResult({this.videoCodec, this.videoRange, this.videoRangeType}); } class MediaCapabilityAnalyzer { static const _tag = 'MediaCap'; static MediaCapability analyze( EmbyRawMediaSource? source, { ProbeResult? probeResult, }) { if (source == null && probeResult == null) { AppLogger.debug(_tag, 'analyze: source=null probeResult=null -> unknown'); return const MediaCapability(rangeCategory: VideoRangeCategory.unknown); } final codec = _resolveCodec(source, probeResult); final videoRange = _resolveVideoRange(source, probeResult); final videoRangeType = _resolveVideoRangeType(source, probeResult); final isDV = _checkDolbyVision( source, probeResult, codec, videoRange, videoRangeType, ); final isHdrDetected = _checkHdr( source, probeResult, videoRange, videoRangeType, ); final VideoRangeCategory rangeCategory; if (isDV) { rangeCategory = VideoRangeCategory.dolbyVision; } else if (isHdrDetected) { rangeCategory = _classifyHdr(videoRangeType, videoRange); } else { rangeCategory = VideoRangeCategory.sdr; } AppLogger.debug( _tag, 'analyze: codec=$codec ' 'videoRange=$videoRange videoRangeType=$videoRangeType ' '-> rangeCategory=${rangeCategory.name}', ); return MediaCapability(rangeCategory: rangeCategory, codec: codec); } static String? _resolveCodec(EmbyRawMediaSource? source, ProbeResult? probe) { if (probe?.videoCodec != null) return probe!.videoCodec; if (source == null) return null; final video = findVideoStream(source); return video?.Codec; } static String? _resolveVideoRange( EmbyRawMediaSource? source, ProbeResult? probe, ) { if (probe?.videoRange != null) return probe!.videoRange; if (source == null) return null; final video = findVideoStream(source); return video?.extra['VideoRange'] as String?; } static String? _resolveVideoRangeType( EmbyRawMediaSource? source, ProbeResult? probe, ) { if (probe?.videoRangeType != null) return probe!.videoRangeType; if (source == null) return null; final video = findVideoStream(source); return video?.extra['VideoRangeType'] as String?; } static bool _checkDolbyVision( EmbyRawMediaSource? source, ProbeResult? probe, String? codec, String? videoRange, String? videoRangeType, ) { if (probe != null) { final lCodec = codec?.toLowerCase() ?? ''; final lRange = videoRange?.toLowerCase() ?? ''; final lRangeType = videoRangeType?.toLowerCase() ?? ''; if (lRangeType.contains('dovi') || lRangeType.contains('dolby')) { return true; } if (lRange.contains('dovi') || lRange.contains('dolby')) return true; if (lCodec.contains('dvh') || lCodec.contains('dovi')) return true; if (videoRange != null || videoRangeType != null) return false; } if (source != null) return isDolbyVision(source); return false; } static bool _checkHdr( EmbyRawMediaSource? source, ProbeResult? probe, String? videoRange, String? videoRangeType, ) { if (probe != null) { final lRange = videoRange?.toLowerCase() ?? ''; final lRangeType = videoRangeType?.toLowerCase() ?? ''; final hasHdrSignal = lRange.contains('hdr') || lRange.contains('dovi') || lRangeType.contains('hdr') || lRangeType.contains('dovi') || lRangeType.contains('hlg'); if (hasHdrSignal) return true; if (videoRange != null || videoRangeType != null) return false; } if (source != null) { if (isHdr(source)) return true; final video = findVideoStream(source); if (video != null) { final rangeType = (video.extra['VideoRangeType'] as String? ?? '') .toLowerCase(); if (rangeType.contains('hlg')) return true; } return false; } return false; } static VideoRangeCategory _classifyHdr( String? videoRangeType, String? videoRange, ) { final lRangeType = videoRangeType?.toLowerCase() ?? ''; if (lRangeType.contains('hlg')) return VideoRangeCategory.hlg; if (lRangeType.contains('hdr10')) return VideoRangeCategory.hdr10; if (lRangeType.contains('hdr')) return VideoRangeCategory.hdr10; final lRange = videoRange?.toLowerCase() ?? ''; if (lRange.contains('hlg')) return VideoRangeCategory.hlg; if (lRange.contains('hdr')) return VideoRangeCategory.hdr10; return VideoRangeCategory.unknown; } }