video: OGV support
This commit is contained in:
parent
dc4db4c4e3
commit
752e34b765
9 changed files with 44 additions and 6 deletions
Binary file not shown.
|
@ -100,7 +100,7 @@ class SourceEntry {
|
||||||
private val hasDuration: Boolean
|
private val hasDuration: Boolean
|
||||||
get() = durationMillis ?: 0 > 0
|
get() = durationMillis ?: 0 > 0
|
||||||
|
|
||||||
private val isVideo: Boolean
|
val isVideo: Boolean
|
||||||
get() = MimeTypes.isVideo(sourceMimeType)
|
get() = MimeTypes.isVideo(sourceMimeType)
|
||||||
|
|
||||||
val isSvg: Boolean
|
val isSvg: Boolean
|
||||||
|
|
|
@ -65,7 +65,7 @@ internal class ContentImageProvider : ImageProvider() {
|
||||||
}
|
}
|
||||||
|
|
||||||
val entry = SourceEntry(map).fillPreCatalogMetadata(context)
|
val entry = SourceEntry(map).fillPreCatalogMetadata(context)
|
||||||
if (entry.isSized || entry.isSvg) {
|
if (entry.isSized || entry.isSvg || entry.isVideo) {
|
||||||
callback.onSuccess(entry.toMap())
|
callback.onSuccess(entry.toMap())
|
||||||
} else {
|
} else {
|
||||||
callback.onFailure(Exception("entry has no size"))
|
callback.onFailure(Exception("entry has no size"))
|
||||||
|
|
|
@ -27,7 +27,7 @@ internal class FileImageProvider : ImageProvider() {
|
||||||
}
|
}
|
||||||
entry.fillPreCatalogMetadata(context)
|
entry.fillPreCatalogMetadata(context)
|
||||||
|
|
||||||
if (entry.isSized || entry.isSvg) {
|
if (entry.isSized || entry.isSvg || entry.isVideo) {
|
||||||
callback.onSuccess(entry.toMap())
|
callback.onSuccess(entry.toMap())
|
||||||
} else {
|
} else {
|
||||||
callback.onFailure(Exception("entry has no size"))
|
callback.onFailure(Exception("entry has no size"))
|
||||||
|
|
|
@ -40,6 +40,7 @@ object MimeTypes {
|
||||||
private const val MP2T = "video/mp2t"
|
private const val MP2T = "video/mp2t"
|
||||||
private const val MP2TS = "video/mp2ts"
|
private const val MP2TS = "video/mp2ts"
|
||||||
const val MP4 = "video/mp4"
|
const val MP4 = "video/mp4"
|
||||||
|
private const val OGV = "video/ogg"
|
||||||
private const val WEBM = "video/webm"
|
private const val WEBM = "video/webm"
|
||||||
|
|
||||||
fun isImage(mimeType: String?) = mimeType != null && mimeType.startsWith(IMAGE)
|
fun isImage(mimeType: String?) = mimeType != null && mimeType.startsWith(IMAGE)
|
||||||
|
@ -71,7 +72,7 @@ object MimeTypes {
|
||||||
|
|
||||||
// as of `metadata-extractor` v2.14.0
|
// as of `metadata-extractor` v2.14.0
|
||||||
fun isSupportedByMetadataExtractor(mimeType: String) = when (mimeType) {
|
fun isSupportedByMetadataExtractor(mimeType: String) = when (mimeType) {
|
||||||
DJVU, WBMP, MP2T, MP2TS, WEBM -> false
|
DJVU, WBMP, MP2T, MP2TS, OGV, WEBM -> false
|
||||||
else -> true
|
else -> true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:aves/model/entry_cache.dart';
|
||||||
import 'package:aves/model/favourites.dart';
|
import 'package:aves/model/favourites.dart';
|
||||||
import 'package:aves/model/metadata.dart';
|
import 'package:aves/model/metadata.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
|
import 'package:aves/model/video/metadata.dart';
|
||||||
import 'package:aves/ref/mime_types.dart';
|
import 'package:aves/ref/mime_types.dart';
|
||||||
import 'package:aves/services/geocoding_service.dart';
|
import 'package:aves/services/geocoding_service.dart';
|
||||||
import 'package:aves/services/service_policy.dart';
|
import 'package:aves/services/service_policy.dart';
|
||||||
|
@ -33,7 +34,7 @@ class AvesEntry {
|
||||||
// `dateModifiedSecs` can be missing in viewer mode
|
// `dateModifiedSecs` can be missing in viewer mode
|
||||||
int? _dateModifiedSecs;
|
int? _dateModifiedSecs;
|
||||||
final int? sourceDateTakenMillis;
|
final int? sourceDateTakenMillis;
|
||||||
final int? durationMillis;
|
int? durationMillis;
|
||||||
int? _catalogDateMillis;
|
int? _catalogDateMillis;
|
||||||
CatalogMetadata? _catalogMetadata;
|
CatalogMetadata? _catalogMetadata;
|
||||||
AddressDetails? _addressDetails;
|
AddressDetails? _addressDetails;
|
||||||
|
@ -432,6 +433,11 @@ class AvesEntry {
|
||||||
}
|
}
|
||||||
catalogMetadata = CatalogMetadata(contentId: contentId);
|
catalogMetadata = CatalogMetadata(contentId: contentId);
|
||||||
} else {
|
} else {
|
||||||
|
if (isVideo && (!isSized || durationMillis == 0)) {
|
||||||
|
// exotic video that is not sized during loading
|
||||||
|
final fields = await VideoMetadataFormatter.getCatalogMetadata(this);
|
||||||
|
await _applyNewFields(fields, persist: persist);
|
||||||
|
}
|
||||||
catalogMetadata = await metadataService.getCatalogMetadata(this, background: background);
|
catalogMetadata = await metadataService.getCatalogMetadata(this, background: background);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -552,6 +558,8 @@ class AvesEntry {
|
||||||
if (width is int) this.width = width;
|
if (width is int) this.width = width;
|
||||||
final height = newFields['height'];
|
final height = newFields['height'];
|
||||||
if (height is int) this.height = height;
|
if (height is int) this.height = height;
|
||||||
|
final durationMillis = newFields['durationMillis'];
|
||||||
|
if (durationMillis is int) this.durationMillis = durationMillis;
|
||||||
|
|
||||||
final dateModifiedSecs = newFields['dateModifiedSecs'];
|
final dateModifiedSecs = newFields['dateModifiedSecs'];
|
||||||
if (dateModifiedSecs is int) this.dateModifiedSecs = dateModifiedSecs;
|
if (dateModifiedSecs is int) this.dateModifiedSecs = dateModifiedSecs;
|
||||||
|
|
|
@ -38,6 +38,7 @@ class Keys {
|
||||||
static const selectedAudioStream = 'audio';
|
static const selectedAudioStream = 'audio';
|
||||||
static const selectedTextStream = 'timedtext';
|
static const selectedTextStream = 'timedtext';
|
||||||
static const selectedVideoStream = 'video';
|
static const selectedVideoStream = 'video';
|
||||||
|
static const sourceOshash = 'source_oshash';
|
||||||
static const startMicros = 'start_us';
|
static const startMicros = 'start_us';
|
||||||
static const statisticsTags = '_statistics_tags';
|
static const statisticsTags = '_statistics_tags';
|
||||||
static const statisticsWritingApp = '_statistics_writing_app';
|
static const statisticsWritingApp = '_statistics_writing_app';
|
||||||
|
|
|
@ -44,6 +44,31 @@ class VideoMetadataFormatter {
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<Map<String, int>> getCatalogMetadata(AvesEntry entry) async {
|
||||||
|
final mediaInfo = await getVideoMetadata(entry);
|
||||||
|
final fields = <String, int>{};
|
||||||
|
|
||||||
|
final streams = mediaInfo[Keys.streams];
|
||||||
|
if (streams is List) {
|
||||||
|
final allStreamInfo = streams.cast<Map>();
|
||||||
|
final sizedStream = allStreamInfo.firstWhereOrNull((stream) => stream.containsKey(Keys.width) && stream.containsKey(Keys.height));
|
||||||
|
if (sizedStream != null) {
|
||||||
|
final width = sizedStream[Keys.width];
|
||||||
|
final height = sizedStream[Keys.height];
|
||||||
|
if (width is int && height is int) {
|
||||||
|
fields['width'] = width;
|
||||||
|
fields['height'] = height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final durationMicros = mediaInfo[Keys.durationMicros];
|
||||||
|
if (durationMicros is num) {
|
||||||
|
fields['durationMillis'] = (durationMicros / 1000).round();
|
||||||
|
}
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
// pattern to extract optional language code suffix, e.g. 'location-eng'
|
// pattern to extract optional language code suffix, e.g. 'location-eng'
|
||||||
static final keyWithLanguagePattern = RegExp(r'^(.*)-([a-z]{3})$');
|
static final keyWithLanguagePattern = RegExp(r'^(.*)-([a-z]{3})$');
|
||||||
|
|
||||||
|
@ -198,6 +223,9 @@ class VideoMetadataFormatter {
|
||||||
// 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');
|
||||||
break;
|
break;
|
||||||
|
case Keys.sourceOshash:
|
||||||
|
save('Source OSHash', value);
|
||||||
|
break;
|
||||||
case Keys.startMicros:
|
case Keys.startMicros:
|
||||||
if (value != 0) save('Start', formatPreciseDuration(Duration(microseconds: value)));
|
if (value != 0) save('Start', formatPreciseDuration(Duration(microseconds: value)));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -218,7 +218,7 @@ packages:
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: aves
|
ref: aves
|
||||||
resolved-ref: "789162b567e2eaef4d6047cb85e77d9c915e1bed"
|
resolved-ref: "40da97eb749d28c476601cb868a10e6c8bf7e569"
|
||||||
url: "git://github.com/deckerst/fijkplayer.git"
|
url: "git://github.com/deckerst/fijkplayer.git"
|
||||||
source: git
|
source: git
|
||||||
version: "0.9.0"
|
version: "0.9.0"
|
||||||
|
|
Loading…
Reference in a new issue