From 5c4991362dd67cc13035534fe4108a0f041ea773 Mon Sep 17 00:00:00 2001 From: Doug Date: Wed, 11 Jan 2023 16:59:36 +0000 Subject: [PATCH] Fix playback of encrypted videos. Encrypted videos from Element iOS were being stored with a `.Video` extension which was confusing AVFoundation. --- .../RoomTimelineController.swift | 26 ++++++++++++++++--- changelog.d/419.bugfix | 1 + 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 changelog.d/419.bugfix diff --git a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift index c5d9017e9..7ae617ec6 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift @@ -17,6 +17,7 @@ import Combine import Foundation import UIKit +import UniformTypeIdentifiers class RoomTimelineController: RoomTimelineControllerProtocol { private let userId: String @@ -399,9 +400,8 @@ class RoomTimelineController: RoomTimelineControllerProtocol { guard let source = timelineItem.source else { return } - - // This is not great. We could better estimate file extension from the mimetype. - let fileExtension = String(timelineItem.text.split(separator: ".").last ?? "mp4") + + let fileExtension = movieFileExtension(for: timelineItem.text) switch await mediaProvider.loadFileFromSource(source, fileExtension: fileExtension) { case .success(let fileURL): guard let index = timelineItems.firstIndex(where: { $0.id == timelineItem.id }), @@ -415,6 +415,26 @@ class RoomTimelineController: RoomTimelineControllerProtocol { break } } + + /// Temporary method that generates a file extension for a video file name + /// using `UTType.movie` and falls back to .mp4 if anything goes wrong. + /// + /// Ideally Rust should be able to handle this for us, otherwise we should be + /// attempting to detect the file type from the data itself. + private func movieFileExtension(for text: String) -> String { + let fallbackExtension = "mp4" + + // This is not great. We could better estimate file extension from the mimetype. + guard let fileExtensionComponent = text.split(separator: ".").last else { return fallbackExtension } + let fileExtension = String(fileExtensionComponent) + + // We can't trust that the extension provided is an extension that AVFoundation will accept. + guard let fileType = UTType(filenameExtension: fileExtension), + fileType.isSubtype(of: .movie) + else { return fallbackExtension } + + return fileExtension + } private func loadFileForImageTimelineItem(_ timelineItem: ImageRoomTimelineItem) async { if timelineItem.cachedFileURL != nil { diff --git a/changelog.d/419.bugfix b/changelog.d/419.bugfix new file mode 100644 index 000000000..bc2b48f05 --- /dev/null +++ b/changelog.d/419.bugfix @@ -0,0 +1 @@ +Video playback: Fix playback of encrypted video files. \ No newline at end of file