[mob][photos] Show accurate height and width in file info for a video

This commit is contained in:
ashilkn
2024-08-05 15:09:16 +05:30
parent 7c202a4edb
commit e1713851b3
4 changed files with 49 additions and 36 deletions

View File

@@ -12,7 +12,7 @@ import "package:photos/models/ffmpeg/mp4.dart";
import "package:photos/models/location/location.dart";
class FFProbeProps {
Map<String, dynamic>? prodData;
Map<String, dynamic>? propData;
Location? location;
DateTime? creationTimeUTC;
String? bitrate;
@@ -72,8 +72,8 @@ class FFProbeProps {
@override
String toString() {
final buffer = StringBuffer();
for (final key in prodData!.keys) {
final value = prodData![key];
for (final key in propData!.keys) {
final value = propData![key];
if (value != null) {
buffer.writeln('$key: $value');
}
@@ -169,33 +169,33 @@ class FFProbeProps {
parsedData[key] = result.fps;
} else if (key == FFProbeKeys.codedWidth) {
final width = stream[key];
if (width != null || width != "0") {
if (width != null && width != 0) {
result._width = width.toString();
parsedData[key] = result._width;
}
} else if (key == FFProbeKeys.codedHeight) {
final height = stream[key];
if (height != null && height != "0") {
if (height != null && height != 0) {
result._height = height.toString();
parsedData[key] = result._height;
}
} else if (key == FFProbeKeys.width) {
final width = stream[key];
if (width != null || width != "0") {
if (width != null && width != 0) {
result._width = width.toString();
parsedData[FFProbeKeys.width] = result._width;
}
} else if (key == FFProbeKeys.height) {
final height = stream[key];
if (height != null && height != "0") {
if (height != null && height != 0) {
result._height = height.toString();
parsedData[FFProbeKeys.width] = result._height;
parsedData[FFProbeKeys.height] = result._height;
}
} else if (key == FFProbeKeys.sideDataList) {
// result._rotation = stream[key][0][FFProbeKeys.rotation];
for (Map sideData in stream[key]) {
if (sideData["side_data_type"] == "Display Matrix") {
result._rotation = sideData[FFProbeKeys.rotation];
parsedData[FFProbeKeys.rotation] = result._rotation;
}
}
}
@@ -205,7 +205,7 @@ class FFProbeProps {
newStreams.add(metadata);
}
parsedData["streams"] = newStreams;
result.prodData = parsedData;
result.propData = parsedData;
return result;
}

View File

@@ -128,7 +128,7 @@ class _FileDetailsWidgetState extends State<FileDetailsWidget> {
_videoMetadataNotifier.value = properties;
if (kDebugMode) {
log("videoCustomProps ${properties.toString()}");
log("PropData ${properties?.prodData.toString()}");
log("PropData ${properties?.propData.toString()}");
}
setState(() {});
}

View File

@@ -1,12 +1,13 @@
import 'package:flutter/material.dart';
import "package:photos/l10n/l10n.dart";
import "package:photos/models/ffmpeg/ffprobe_keys.dart";
import "package:photos/models/ffmpeg/ffprobe_props.dart";
import "package:photos/theme/ente_theme.dart";
class VideoExifDialog extends StatelessWidget {
final Map<String, dynamic> probeData;
final FFProbeProps props;
const VideoExifDialog({Key? key, required this.probeData}) : super(key: key);
const VideoExifDialog({Key? key, required this.props}) : super(key: key);
@override
Widget build(BuildContext context) {
@@ -48,23 +49,23 @@ class VideoExifDialog extends StatelessWidget {
context.l10n.videoInfo,
style: getEnteTextTheme(context).large,
),
_buildInfoRow(context, 'Creation Time', probeData, 'creation_time'),
_buildInfoRow(context, 'Duration', probeData, 'duration'),
_buildInfoRow(context, context.l10n.location, probeData, 'location'),
_buildInfoRow(context, 'Bitrate', probeData, 'bitrate'),
_buildInfoRow(context, 'Frame Rate', probeData, FFProbeKeys.rFrameRate),
_buildInfoRow(context, 'Width', probeData, FFProbeKeys.codedWidth),
_buildInfoRow(context, 'Height', probeData, FFProbeKeys.codedHeight),
_buildInfoRow(context, 'Model', probeData, 'com.apple.quicktime.model'),
_buildInfoRow(context, 'OS', probeData, 'com.apple.quicktime.software'),
_buildInfoRow(context, 'Major Brand', probeData, 'major_brand'),
_buildInfoRow(context, 'Format', probeData, 'format'),
_buildInfoRow(context, 'Creation Time', props, 'creation_time'),
_buildInfoRow(context, 'Duration', props, 'duration'),
_buildInfoRow(context, context.l10n.location, props, 'location'),
_buildInfoRow(context, 'Bitrate', props, 'bitrate'),
_buildInfoRow(context, 'Frame Rate', props, FFProbeKeys.rFrameRate),
_buildInfoRow(context, 'Width', props, null),
_buildInfoRow(context, 'Height', props, null),
_buildInfoRow(context, 'Model', props, 'com.apple.quicktime.model'),
_buildInfoRow(context, 'OS', props, 'com.apple.quicktime.software'),
_buildInfoRow(context, 'Major Brand', props, 'major_brand'),
_buildInfoRow(context, 'Format', props, 'format'),
],
);
}
Widget _buildStreamsList(BuildContext context) {
final List<dynamic> streams = probeData['streams'];
final List<dynamic> streams = props.propData!['streams'];
final List<Map<String, dynamic>> data = [];
for (final stream in streams) {
final Map<String, dynamic> streamData = {};
@@ -113,7 +114,12 @@ class VideoExifDialog extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: stream.entries
.map(
(entry) => _buildInfoRow(context, entry.key, stream, entry.key),
(entry) => _buildInfoRow(
context,
entry.key,
FFProbeProps()..propData = stream,
entry.key,
),
)
.toList(),
),
@@ -124,15 +130,23 @@ class VideoExifDialog extends StatelessWidget {
Widget _buildInfoRow(
BuildContext context,
String rowName,
Map<String, dynamic> data,
String dataKey,
FFProbeProps data,
String? dataKey,
) {
final propData = data.propData;
rowName = rowName.replaceAll('_', ' ');
rowName = rowName[0].toUpperCase() + rowName.substring(1);
try {
final value = data[dataKey];
dynamic value;
if (rowName == 'Width' || rowName == 'Height') {
rowName == 'Width' ? value = data.width : value = data.height;
} else {
value = propData![dataKey];
}
if (value == null) {
return Container(); // Return an empty container if there's no data for the key.
return const SizedBox.shrink();
}
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),

View File

@@ -35,8 +35,7 @@ class _VideoProbeInfoState extends State<VideoExifRowItem> {
return InfoItemWidget(
leadingIcon: Icons.text_snippet_outlined,
title: S.of(context).videoInfo,
subtitleSection:
_exifButton(context, widget.file, widget.props?.prodData),
subtitleSection: _exifButton(context, widget.file, widget.props),
onTap: _onTap,
);
}
@@ -44,20 +43,20 @@ class _VideoProbeInfoState extends State<VideoExifRowItem> {
Future<List<Widget>> _exifButton(
BuildContext context,
EnteFile file,
Map<String, dynamic>? exif,
FFProbeProps? props,
) async {
late final String label;
late final VoidCallback? onTap;
if (exif == null) {
if (props?.propData == null) {
label = S.of(context).loadingExifData;
onTap = null;
} else if (exif.isNotEmpty) {
} else if (props!.propData!.isNotEmpty) {
label = "${widget.props?.videoInfo ?? ''} ..";
onTap = () => showBarModalBottomSheet(
context: context,
builder: (BuildContext context) {
return VideoExifDialog(
probeData: exif,
props: props,
);
},
shape: const RoundedRectangleBorder(