#716 video: fail fast instead of corrupting file when editing fragmented mp4

This commit is contained in:
Thibault Deckers 2023-08-20 20:04:04 +02:00
parent 7b30c7235b
commit 0fc2710e62
6 changed files with 19 additions and 12 deletions

View file

@ -52,6 +52,9 @@ object Mp4ParserHelper {
} }
// creating `IsoFile` with a `File` or a `File.inputStream()` yields `No such device` // creating `IsoFile` with a `File` or a `File.inputStream()` yields `No such device`
IsoFile(channel, boxParser).use { isoFile -> IsoFile(channel, boxParser).use { isoFile ->
val fragmented = isoFile.boxes.any { box -> box is MovieFragmentBox || box is SegmentIndexBox }
if (fragmented) throw Exception("editing fragmented movies is not supported")
val lastContentBox = isoFile.boxes.reversed().firstOrNull { box -> val lastContentBox = isoFile.boxes.reversed().firstOrNull { box ->
when { when {
box == isoFile.movieBox -> false box == isoFile.movieBox -> false
@ -60,7 +63,7 @@ object Mp4ParserHelper {
else -> true else -> true
} }
} }
lastContentBox ?: throw Exception("failed to find last context box") lastContentBox ?: throw Exception("failed to find last content box")
val oldFileSize = isoFile.size val oldFileSize = isoFile.size
var appendOffset = (isoFile.getBoxOffset { box -> box == lastContentBox })!! + lastContentBox.size var appendOffset = (isoFile.getBoxOffset { box -> box == lastContentBox })!! + lastContentBox.size
@ -97,7 +100,6 @@ object Mp4ParserHelper {
if (trailing > 0) { if (trailing > 0) {
addFreeBoxEdit(appendOffset, trailing) addFreeBoxEdit(appendOffset, trailing)
} }
return edits return edits
} }
} }
@ -277,7 +279,9 @@ object Mp4ParserHelper {
// creating `IsoFile` with a `File` or a `File.inputStream()` yields `No such device` // creating `IsoFile` with a `File` or a `File.inputStream()` yields `No such device`
IsoFile(channel, metadataBoxParser()).use { isoFile -> IsoFile(channel, metadataBoxParser()).use { isoFile ->
val userDataBox = Path.getPath<UserDataBox>(isoFile.movieBox, UserDataBox.TYPE) val userDataBox = Path.getPath<UserDataBox>(isoFile.movieBox, UserDataBox.TYPE)
fields.putAll(extractBoxFields(userDataBox)) if (userDataBox != null) {
fields.putAll(extractBoxFields(userDataBox))
}
} }
} }
} }

View file

@ -356,6 +356,8 @@ class VideoMetadataFormatter {
final sarDen = info[Keys.sarDen]; final sarDen = info[Keys.sarDen];
// skip common square pixels (1:1) // skip common square pixels (1:1)
if (sarNum != sarDen) save('SAR', '$sarNum:$sarDen'); if (sarNum != sarDen) save('SAR', '$sarNum:$sarDen');
case Keys.segmentCount:
save('Segment Count', value);
case Keys.sourceOshash: case Keys.sourceOshash:
save('Source OSHash', value); save('Source OSHash', value);
case Keys.startMicros: case Keys.startMicros:

View file

@ -149,7 +149,7 @@ class _MetadataTabState extends State<MetadataTab> {
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
child: SingleChildScrollView( child: SingleChildScrollView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
child: Text(data), child: SelectableText(data),
), ),
) )
], ],

View file

@ -82,6 +82,7 @@ class Keys {
static const streams = 'streams'; static const streams = 'streams';
static const tbrDen = 'tbr_den'; static const tbrDen = 'tbr_den';
static const tbrNum = 'tbr_num'; static const tbrNum = 'tbr_num';
static const segmentCount = 'segment_count';
static const streamType = 'type'; static const streamType = 'type';
static const title = 'title'; static const title = 'title';
static const timeBase = 'time_base'; static const timeBase = 'time_base';

View file

@ -172,10 +172,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: media_kit name: media_kit
sha256: "0a89e7037002a62701ec319c375586849f9ef8e681820e1dd4a4ff7b843f7542" sha256: d7a827080fb28f0ba4e8a7ab3f3e3f868fa817f0a94499640466ade84a1c31c9
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.4+1" version: "1.1.5"
media_kit_libs_android_video: media_kit_libs_android_video:
dependency: "direct main" dependency: "direct main"
description: description:
@ -196,10 +196,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: media_kit_video name: media_kit_video
sha256: e7fcbe426d42a78ad6696f8f557adb9cbdc012177829026d04992cc106a1c815 sha256: d4143a96d97965d025bbb8b88db0ebf301e3c4cfa10c7e2ad7fd47c86a7febae
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.5" version: "1.1.6"
meta: meta:
dependency: transitive dependency: transitive
description: description:

View file

@ -835,10 +835,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: media_kit name: media_kit
sha256: "0a89e7037002a62701ec319c375586849f9ef8e681820e1dd4a4ff7b843f7542" sha256: d7a827080fb28f0ba4e8a7ab3f3e3f868fa817f0a94499640466ade84a1c31c9
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.4+1" version: "1.1.5"
media_kit_libs_android_video: media_kit_libs_android_video:
dependency: transitive dependency: transitive
description: description:
@ -859,10 +859,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: media_kit_video name: media_kit_video
sha256: e7fcbe426d42a78ad6696f8f557adb9cbdc012177829026d04992cc106a1c815 sha256: d4143a96d97965d025bbb8b88db0ebf301e3c4cfa10c7e2ad7fd47c86a7febae
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.5" version: "1.1.6"
meta: meta:
dependency: transitive dependency: transitive
description: description: