diff --git a/CHANGELOG.md b/CHANGELOG.md index 08e2f89df..7be5efcfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Added + +- Cataloguing: detect/filter HDR videos + ### Changed - check Media Store changes when resuming app diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataFetchHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataFetchHandler.kt index 6b6d7d36d..b7e03b319 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataFetchHandler.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataFetchHandler.kt @@ -1,6 +1,7 @@ package deckers.thibault.aves.channel.calls import android.content.Context +import android.media.MediaFormat import android.media.MediaMetadataRetriever import android.net.Uri import android.os.Build @@ -559,7 +560,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { // identification of embedded gain map if (xmpMeta.hasHdrGainMap()) { - flags = flags or MASK_HAS_HDR_GAIN_MAP + flags = flags or MASK_IS_HDR } } catch (e: XMPException) { Log.w(LOG_TAG, "failed to read XMP directory for uri=$uri", e) @@ -797,6 +798,14 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { } } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + retriever.getSafeInt(MediaMetadataRetriever.METADATA_KEY_COLOR_TRANSFER) { + if (it == MediaFormat.COLOR_TRANSFER_ST2084 || it == MediaFormat.COLOR_TRANSFER_HLG) { + flags = flags or MASK_IS_HDR + } + } + } + metadataMap[KEY_FLAGS] = flags } catch (e: Exception) { Log.w(LOG_TAG, "failed to get catalog metadata by MediaMetadataRetriever for uri=$uri", e) @@ -1300,7 +1309,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { private const val MASK_IS_360 = 1 shl 3 private const val MASK_IS_MULTIPAGE = 1 shl 4 private const val MASK_IS_MOTION_PHOTO = 1 shl 5 - private const val MASK_HAS_HDR_GAIN_MAP = 1 shl 6 + private const val MASK_IS_HDR = 1 shl 6 // for images: embedded HDR gainmap, for videos: HDR color transfer private const val XMP_SUBJECTS_SEPARATOR = ";" // overlay metadata diff --git a/lib/model/entry/entry.dart b/lib/model/entry/entry.dart index 3d2060405..bdf810294 100644 --- a/lib/model/entry/entry.dart +++ b/lib/model/entry/entry.dart @@ -242,6 +242,11 @@ class AvesEntry with AvesEntryBase { return _bestDate; } + @override + bool get isAnimated => catalogMetadata?.isAnimated ?? false; + + bool get isHdr => _catalogMetadata?.isHdr ?? false; + int get rating => _catalogMetadata?.rating ?? 0; @override @@ -303,9 +308,6 @@ class AvesEntry with AvesEntryBase { return d == null ? null : DateTime(d.year, d.month, d.day); } - @override - bool get isAnimated => catalogMetadata?.isAnimated ?? false; - @override int? get durationMillis => _durationMillis; diff --git a/lib/model/entry/extensions/multipage.dart b/lib/model/entry/extensions/multipage.dart index e613583a6..a978ef0f6 100644 --- a/lib/model/entry/extensions/multipage.dart +++ b/lib/model/entry/extensions/multipage.dart @@ -13,8 +13,6 @@ extension ExtraAvesEntryMultipage on AvesEntry { bool get isMotionPhoto => catalogMetadata?.isMotionPhoto ?? false; - bool get isHdr => catalogMetadata?.hasHdrGainMap ?? false; - String? getBurstKey(List patterns) { final key = BurstPatterns.getKeyForName(filenameWithoutExtension, patterns); return key != null ? '$directory/$key' : null; diff --git a/lib/model/metadata/catalog.dart b/lib/model/metadata/catalog.dart index 157c348aa..2c668d334 100644 --- a/lib/model/metadata/catalog.dart +++ b/lib/model/metadata/catalog.dart @@ -4,7 +4,7 @@ import 'package:flutter/foundation.dart'; class CatalogMetadata { final int id; final int? dateMillis; - final bool isAnimated, isGeotiff, is360, isMultiPage, isMotionPhoto, hasHdrGainMap; + final bool isAnimated, isGeotiff, is360, isMultiPage, isMotionPhoto, isHdr; bool isFlipped; int? rotationDegrees; final String? mimeType, xmpSubjects, xmpTitle; @@ -21,7 +21,7 @@ class CatalogMetadata { static const _is360Mask = 1 << 3; static const _isMultiPageMask = 1 << 4; static const _isMotionPhotoMask = 1 << 5; - static const _hasHdrGainMapMask = 1 << 6; + static const _isHdr = 1 << 6; // for images: embedded HDR gainmap, for videos: HDR color transfer CatalogMetadata({ required this.id, @@ -33,7 +33,7 @@ class CatalogMetadata { this.is360 = false, this.isMultiPage = false, this.isMotionPhoto = false, - this.hasHdrGainMap = false, + this.isHdr = false, this.rotationDegrees, this.xmpSubjects, this.xmpTitle, @@ -75,7 +75,7 @@ class CatalogMetadata { is360: is360, isMultiPage: isMultiPage ?? this.isMultiPage, isMotionPhoto: isMotionPhoto, - hasHdrGainMap: hasHdrGainMap, + isHdr: isHdr, rotationDegrees: rotationDegrees ?? this.rotationDegrees, xmpSubjects: xmpSubjects, xmpTitle: xmpTitle, @@ -97,7 +97,7 @@ class CatalogMetadata { is360: flags & _is360Mask != 0, isMultiPage: flags & _isMultiPageMask != 0, isMotionPhoto: flags & _isMotionPhotoMask != 0, - hasHdrGainMap: flags & _hasHdrGainMapMask != 0, + isHdr: flags & _isHdr != 0, // `rotationDegrees` should default to `sourceRotationDegrees`, not 0 rotationDegrees: map['rotationDegrees'], xmpSubjects: map['xmpSubjects'] ?? '', @@ -112,7 +112,7 @@ class CatalogMetadata { 'id': id, 'mimeType': mimeType, 'dateMillis': dateMillis, - 'flags': (isAnimated ? _isAnimatedMask : 0) | (isFlipped ? _isFlippedMask : 0) | (isGeotiff ? _isGeotiffMask : 0) | (is360 ? _is360Mask : 0) | (isMultiPage ? _isMultiPageMask : 0) | (isMotionPhoto ? _isMotionPhotoMask : 0) | (hasHdrGainMap ? _hasHdrGainMapMask : 0), + 'flags': (isAnimated ? _isAnimatedMask : 0) | (isFlipped ? _isFlippedMask : 0) | (isGeotiff ? _isGeotiffMask : 0) | (is360 ? _is360Mask : 0) | (isMultiPage ? _isMultiPageMask : 0) | (isMotionPhoto ? _isMotionPhotoMask : 0) | (isHdr ? _isHdr : 0), 'rotationDegrees': rotationDegrees, 'xmpSubjects': xmpSubjects, 'xmpTitle': xmpTitle, diff --git a/lib/widgets/common/grid/theme.dart b/lib/widgets/common/grid/theme.dart index 1cf9498de..a9c4c73a7 100644 --- a/lib/widgets/common/grid/theme.dart +++ b/lib/widgets/common/grid/theme.dart @@ -91,12 +91,12 @@ class GridThemeData { if (located && showLocated) LocationIcon.located(), if (!located && showUnlocated) LocationIcon.unlocated(), if (entry.rating != 0 && showRating) RatingIcon(entry: entry), + if (entry.isHdr && showHdr) const HdrIcon(), if (entry.isPureVideo) VideoIcon(entry: entry) else if (entry.isAnimated) const AnimatedImageIcon() else ...[ - if (entry.isHdr && showHdr) const HdrIcon(), if (entry.isRaw && showRaw) const RawIcon(), if (entry.is360) const PanoramaIcon(), ], diff --git a/lib/widgets/viewer/controls/controller.dart b/lib/widgets/viewer/controls/controller.dart index 086929d98..0ee13ddbd 100644 --- a/lib/widgets/viewer/controls/controller.dart +++ b/lib/widgets/viewer/controls/controller.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:math'; import 'package:aves/model/entry/entry.dart'; -import 'package:aves/model/entry/extensions/multipage.dart'; import 'package:aves/services/common/services.dart'; import 'package:aves/theme/durations.dart'; import 'package:aves/widgets/viewer/controls/cast.dart';