[mob][photos] Handle/fix issues with media dimensions (#2580)
## Description - Stopped updating image width and height in public metadata since the these could be incorrect (width and height inverted to be precise). - Parse `rotation` metadata from video metadata when parsing video properties with `ffprobe` to get the correct video width and height considering `rotation`.
This commit is contained in:
@@ -28,7 +28,7 @@ class FFProbeKeys {
|
||||
static const date = 'date';
|
||||
static const disposition = 'disposition';
|
||||
static const duration = 'duration';
|
||||
static const quickTimeLocation ="com.apple.quicktime.location.ISO6709";
|
||||
static const quickTimeLocation = "com.apple.quicktime.location.ISO6709";
|
||||
static const durationMicros = 'duration_us';
|
||||
static const encoder = 'encoder';
|
||||
static const extraDataSize = 'extradata_size';
|
||||
@@ -70,6 +70,8 @@ class FFProbeKeys {
|
||||
static const vendorId = 'vendor_id';
|
||||
static const width = 'width';
|
||||
static const xiaomiSlowMoment = 'com.xiaomi.slow_moment';
|
||||
static const sideDataList = 'side_data_list';
|
||||
static const rotation = 'rotation';
|
||||
}
|
||||
|
||||
class MediaStreamTypes {
|
||||
|
||||
@@ -18,20 +18,56 @@ class FFProbeProps {
|
||||
String? bitrate;
|
||||
String? majorBrand;
|
||||
String? fps;
|
||||
String? codecWidth;
|
||||
String? codecHeight;
|
||||
String? _codecWidth;
|
||||
String? _codecHeight;
|
||||
int? _rotation;
|
||||
|
||||
// dot separated bitrate, fps, codecWidth, codecHeight. Ignore null value
|
||||
String get videoInfo {
|
||||
final List<String> info = [];
|
||||
if (bitrate != null) info.add('$bitrate');
|
||||
if (fps != null) info.add('ƒ/$fps');
|
||||
if (codecWidth != null && codecHeight != null) {
|
||||
info.add('$codecWidth x $codecHeight');
|
||||
if (_codecWidth != null && _codecHeight != null) {
|
||||
info.add('$_codecWidth x $_codecHeight');
|
||||
}
|
||||
return info.join(' * ');
|
||||
}
|
||||
|
||||
int? get width {
|
||||
if (_codecWidth == null || _codecHeight == null) return null;
|
||||
final intCodecWidth = int.tryParse(_codecWidth!);
|
||||
if (_rotation == null) {
|
||||
return intCodecWidth;
|
||||
} else {
|
||||
if ((_rotation! ~/ 90).isEven) {
|
||||
return intCodecWidth;
|
||||
} else {
|
||||
return int.tryParse(_codecHeight!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int? get height {
|
||||
if (_codecWidth == null || _codecHeight == null) return null;
|
||||
final intCodecHeight = int.tryParse(_codecHeight!);
|
||||
if (_rotation == null) {
|
||||
return intCodecHeight;
|
||||
} else {
|
||||
if ((_rotation! ~/ 90).isEven) {
|
||||
return intCodecHeight;
|
||||
} else {
|
||||
return int.tryParse(_codecWidth!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double? get aspectRatio {
|
||||
if (width == null || height == null || height == 0 || width == 0) {
|
||||
return null;
|
||||
}
|
||||
return width! / height!;
|
||||
}
|
||||
|
||||
// toString() method
|
||||
@override
|
||||
String toString() {
|
||||
@@ -132,11 +168,13 @@ class FFProbeProps {
|
||||
result.fps = _formatFPS(stream[key]);
|
||||
parsedData[key] = result.fps;
|
||||
} else if (key == FFProbeKeys.codedWidth) {
|
||||
result.codecWidth = stream[key].toString();
|
||||
parsedData[key] = result.codecWidth;
|
||||
result._codecWidth = stream[key].toString();
|
||||
parsedData[key] = result._codecWidth;
|
||||
} else if (key == FFProbeKeys.codedHeight) {
|
||||
result.codecHeight = stream[key].toString();
|
||||
parsedData[key] = result.codecHeight;
|
||||
result._codecHeight = stream[key].toString();
|
||||
parsedData[key] = result._codecHeight;
|
||||
} else if (key == FFProbeKeys.sideDataList) {
|
||||
result._rotation = stream[key][0][FFProbeKeys.rotation];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@ import 'package:photos/events/files_updated_event.dart';
|
||||
import 'package:photos/events/local_photos_updated_event.dart';
|
||||
import "package:photos/models/file/extensions/file_props.dart";
|
||||
import 'package:photos/models/file/file.dart';
|
||||
import "package:photos/models/metadata/file_magic.dart";
|
||||
import "package:photos/services/file_magic_service.dart";
|
||||
import "package:photos/ui/actions/file/file_actions.dart";
|
||||
import 'package:photos/ui/common/loading_widget.dart';
|
||||
import 'package:photos/utils/file_util.dart';
|
||||
@@ -31,12 +29,12 @@ class ZoomableImage extends StatefulWidget {
|
||||
|
||||
const ZoomableImage(
|
||||
this.photo, {
|
||||
Key? key,
|
||||
super.key,
|
||||
this.shouldDisableScroll,
|
||||
required this.tagPrefix,
|
||||
this.backgroundDecoration,
|
||||
this.shouldCover = false,
|
||||
}) : super(key: key);
|
||||
});
|
||||
|
||||
@override
|
||||
State<ZoomableImage> createState() => _ZoomableImageState();
|
||||
@@ -359,29 +357,6 @@ class _ZoomableImageState extends State<ZoomableImage> {
|
||||
if (finalImageInfo == null && canUpdateMetadata && !_photo.hasDimensions) {
|
||||
finalImageInfo = await getImageInfo(finalImageProvider);
|
||||
}
|
||||
if (finalImageInfo != null && canUpdateMetadata) {
|
||||
_updateAspectRatioIfNeeded(_photo, finalImageInfo).ignore();
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback logic to finish back fill and update aspect
|
||||
// ratio if needed.
|
||||
Future<void> _updateAspectRatioIfNeeded(
|
||||
EnteFile enteFile,
|
||||
ImageInfo imageInfo,
|
||||
) async {
|
||||
final int h = imageInfo.image.height, w = imageInfo.image.width;
|
||||
if (h != enteFile.height || w != enteFile.width) {
|
||||
final logMessage =
|
||||
'Updating aspect ratio for from ${enteFile.height}x${enteFile.width} to ${h}x$w';
|
||||
_logger.info(logMessage);
|
||||
await FileMagicService.instance.updatePublicMagicMetadata([
|
||||
enteFile,
|
||||
], {
|
||||
heightKey: h,
|
||||
widthKey: w,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool _isGIF() => _photo.displayName.toLowerCase().endsWith(".gif");
|
||||
|
||||
Reference in New Issue
Block a user