[mob][photos] Show accurate height and width in file info for a video
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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(() {});
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user