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';