Skip to content
This repository has been archived by the owner on Sep 17, 2022. It is now read-only.

Commit

Permalink
fix: add support for media files without video
Browse files Browse the repository at this point in the history
  • Loading branch information
vzhd1701 committed Sep 7, 2022
1 parent 926f857 commit f0d84de
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 39 deletions.
106 changes: 67 additions & 39 deletions Sources/MarkersExtractor/Converters/MarkersToCSV.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,20 @@ func markersToCSV(
) throws {
let logger = Logger(label: "markersToCSV")

var videoPath: URL = videoPath
let videoPlaceholder: TemporaryMediaFile

let isVideoPresent = isVideoPresent(in: videoPath)
let isSingleFrame = !isVideoPresent && imageLabelFields.isEmpty && imageLabelCopyright == nil

if !isVideoPresent {
logger.info("Media file has no video track, using video placeholder for markers")

let markersDicts = markers.map { markerToDict($0, isVideoPresent ? imageFormat : nil) }
videoPlaceholder = try TemporaryMediaFile(withData: markerVideoPlaceholder)
videoPath = videoPlaceholder.url!
}

let markersDicts = markers.map { markerToDict($0, imageFormat, isSingleFrame) }

logger.info("Exporting marker icons")

Expand All @@ -32,41 +43,43 @@ func markersToCSV(
throw MarkersExtractorError.runtimeError("Failed to write marker icons")
}

if isVideoPresent {
logger.info("Generating \(imageFormat.rawValue.uppercased()) images for markers")
logger.info("Generating \(imageFormat.rawValue.uppercased()) images for markers")

let imageLabelText = makeImageLabelText(
markersDicts: markersDicts,
imageLabelFields: imageLabelFields,
imageLabelCopyright: imageLabelCopyright
)

let timeCodes = makeTimecodes(
markers: markers,
markersDicts: markersDicts,
isVideoPresent: isVideoPresent,
isSingleFrame: isSingleFrame
)

let imageLabelText = makeImageLabelText(
markersDicts: markersDicts,
imageLabelFields: imageLabelFields,
imageLabelCopyright: imageLabelCopyright
if imageFormat == .gif {
try timecodesToGIF(
timeCodes: timeCodes,
video: videoPath,
destPath: destPath,
gifFrameRate: gifFPS,
gifSpan: gifSpan,
gifDimensions: imageDimensions,
imageLabelText: imageLabelText,
imageLabelProperties: imageLabelProperties
)
let timeCodes = makeTimecodes(markers: markers, markersDicts: markersDicts)

if imageFormat == .gif {
try timecodesToGIF(
timeCodes: timeCodes,
video: videoPath,
destPath: destPath,
gifFrameRate: gifFPS,
gifSpan: gifSpan,
gifDimensions: imageDimensions,
imageLabelText: imageLabelText,
imageLabelProperties: imageLabelProperties
)
} else {
try timecodesToPIC(
timeCodes: timeCodes,
video: videoPath,
destPath: destPath,
imageFormat: imageFormat,
imageJPGQuality: imageQuality,
imageDimensions: imageDimensions,
imageLabelText: imageLabelText,
imageLabelProperties: imageLabelProperties
)
}
} else {
logger.info("No video track present in \(videoPath.path), skipping images processing")
try timecodesToPIC(
timeCodes: timeCodes,
video: videoPath,
destPath: destPath,
imageFormat: imageFormat,
imageJPGQuality: imageQuality,
imageDimensions: imageDimensions,
imageLabelText: imageLabelText,
imageLabelProperties: imageLabelProperties
)
}

let rows = dictsToRows(markersDicts)
Expand All @@ -76,7 +89,8 @@ func markersToCSV(

private func markerToDict(
_ marker: Marker,
_ imageFormat: MarkerImageFormat?
_ imageFormat: MarkerImageFormat,
_ isSingleFrame: Bool
) -> OrderedDictionary<MarkerHeader, String> {
[
.id: marker.id,
Expand All @@ -93,7 +107,8 @@ private func markerToDict(
.projectName: marker.parentProjectName,
.libraryName: marker.parentLibraryName,
.iconImage: marker.icon.fileName,
.imageName: imageFormat == nil ? "" : "\(marker.idPathSafe).\(imageFormat!)",
.imageName: isSingleFrame
? "marker-placeholder.\(imageFormat)" : "\(marker.idPathSafe).\(imageFormat)",
]
}

Expand Down Expand Up @@ -133,12 +148,25 @@ private func makeLabels(

private func makeTimecodes(
markers: [Marker],
markersDicts: [OrderedDictionary<MarkerHeader, String>]
markersDicts: [OrderedDictionary<MarkerHeader, String>],
isVideoPresent: Bool,
isSingleFrame: Bool
) -> OrderedDictionary<String, CMTime> {
let markerNames = markersDicts.map { $0[.imageName]! }
return OrderedDictionary(
uniqueKeysWithValues: zip(markerNames, markers).map { ($0, $1.position) }
)

// if no video - grabbing first frame from video placeholder
let markerTimecodes = markers.map {
isVideoPresent ? $0.position : CMTime(seconds: 0, preferredTimescale: 1)
}

var markerPairs = zip(markerNames, markerTimecodes).map { ($0, $1) }

// if no video and no labels - only one frame needed for all markers
if isSingleFrame {
markerPairs = [markerPairs[0]]
}

return OrderedDictionary(uniqueKeysWithValues: markerPairs)
}

private func dictsToRows(
Expand Down
6 changes: 6 additions & 0 deletions Sources/MarkersExtractor/Types/MarkerVideoPlaceholder.swift

Large diffs are not rendered by default.

37 changes: 37 additions & 0 deletions Sources/MarkersExtractor/Types/TemporaryMediaFile.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import AVKit
import Foundation

class TemporaryMediaFile {
var url: URL?

init(withData: Data) throws {
let directory = FileManager.default.temporaryDirectory
let fileName = "\(NSUUID().uuidString).mov"
let url = directory.appendingPathComponent(fileName)
do {
try withData.write(to: url)
self.url = url
} catch {
throw MarkersExtractorError.runtimeError("Error creating temporary file: \(error)")
}
}

public var avAsset: AVAsset? {
if let url = url {
return AVAsset(url: url)
}

return nil
}

public func deleteFile() {
if let url = url {
try? FileManager.default.removeItem(at: url)
self.url = nil
}
}

deinit {
deleteFile()
}
}

0 comments on commit f0d84de

Please sign in to comment.