Initial commit
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user