我的视频的 naturalSize 仅为 (4.0, 3.0) 像素,这也是提取的帧大小
Posted
技术标签:
【中文标题】我的视频的 naturalSize 仅为 (4.0, 3.0) 像素,这也是提取的帧大小【英文标题】:My videos have a naturalSize of only (4.0, 3.0) pixels, which is also extracted frame size 【发布时间】:2021-03-12 09:54:02 【问题描述】:上下文
我正在处理 1280x920 的视频文件,这是它们在 QuickTime 中显示或什至在我的 AVPlayer 中播放时的实际像素大小。
我的文件夹中有一堆视频,我需要将它们放在AVMutableComposition
上并播放。
我还需要为每个视频提取最后一帧。
到目前为止,我所做的是在我的个人 AVAsset
上使用 AVAssetImageGenerator
,并且无论我使用的是 generateCGImagesAsynchronously
还是 copyCGImage
,它都有效。
但我认为在我的作曲资产上运行 generateCGImagesAsynchronously
会更有效,所以我只有一个调用,而不是循环每个原始轨道。
而不是:
v-Get Frame
AVAsset1 |---------|
AVAsset2 |---------|
AVAsset3 |---------|
我想做:
v----------v----------v- Get Frames
AVMutableComposition: |---------||---------||---------|
问题
这是实际问题:
import AVKit
var video1URL = URL(fileReferenceLiteralResourceName: "video_bad.mp4") // One of my video file
let asset1 = AVAsset(url: video1URL)
let track1 = asset1.tracks(withMediaType: .video).first!
_ = track1.naturalSize // w 4 h 3
var video2URL = URL(fileReferenceLiteralResourceName: "video_ok.mp4") // Some mp4 I got from internet
let asset2 = AVAsset(url: video2URL)
let track2 = asset2.tracks(withMediaType: .video).first!
_ = track2.naturalSize // w 1920 h 1080
这是操场的实际截图(您可以下载here):
还有其他的:
查看 QuickTime 检查器中的“当前比例”信息。视频显示很好,但显示为被放大了(注意没有像素模糊或任何东西,它与一些元数据有关)
我在 QuickTime 中使用的视频文件:
来自网络的视频文件:
问题
这些信息是什么元数据以及如何处理它? 为什么它在原始轨道上与放在不同乐曲上时不同? 如何在此类视频中提取帧?【问题讨论】:
【参考方案1】:因此,如果您偶然发现这篇文章,可能是您正在尝试弄清楚特斯拉的视频编写方式。
该问题没有简单的解决方案,这是由 Tesla 软件错误地设置 .mov
视频文件中的元数据引起的。我向 Apple 提出了一个事件,他们能够证实这一点。
所以我写了一些代码,通过重写指示视频轨道大小的字节来实际修复视频文件。
我们开始吧,它很丑,但为了完整起见,我想在这里发布一个解决方案,如果不是最好的。
import Foundation
struct VideoFixer
var url: URL
private var fh: FileHandle?
static func fix(_ url: URL)
var fixer = VideoFixer(url)
fixer.fix()
init(_ url: URL)
self.url = url
mutating func fix()
guard let fh = try? FileHandle(forUpdating: url) else
return
var atom = Atom(fh)
atom.seekTo(AtomType.moov)
atom.enter()
if atom.atom_type != AtomType.trak
atom.seekTo(AtomType.trak)
atom.enter()
if atom.atom_type != AtomType.tkhd
atom.seekTo(AtomType.tkhd)
atom.seekTo(AtomType.tkhd)
let data = atom.data()
let width = data?.withUnsafeBytes $0.load(fromByteOffset: 76, as: UInt16.self).bigEndian
let height = data?.withUnsafeBytes $0.load(fromByteOffset: 80, as: UInt16.self).bigEndian
if width==4 && height==3
guard let offset = try? fh.offset() else
return
try? fh.seek(toOffset: offset+76)
//1280x960
var newWidth = UInt16(1280).byteSwapped
var newHeight = UInt16(960).byteSwapped
let dataWidth = Data(bytes: &newWidth, count: 2)
let dataHeight = Data(bytes: &newHeight, count: 2)
fh.write(dataWidth)
try? fh.seek(toOffset: offset+80)
fh.write(dataHeight)
try? fh.close()
typealias AtomType = UInt32
extension UInt32
static var ftyp = UInt32(1718909296)
static var mdat = UInt32(1835295092)
static var free = UInt32(1718773093)
static var moov = UInt32(1836019574)
static var trak = UInt32(1953653099)
static var tkhd = UInt32(1953196132)
struct Atom
var fh: FileHandle
var atom_size: UInt32 = 0
var atom_type: UInt32 = 0
init(_ fh: FileHandle)
self.fh = fh
self.read()
mutating func seekTo(_ type:AtomType)
while self.atom_type != type
self.next()
mutating func next()
guard var offset = try? fh.offset() else
return
offset = offset-8+UInt64(atom_size)
if (try? self.fh.seek(toOffset: UInt64(offset))) == nil
return
self.read()
mutating func read()
self.atom_size = fh.nextUInt32().bigEndian
self.atom_type = fh.nextUInt32().bigEndian
mutating func enter()
self.atom_size = fh.nextUInt32().bigEndian
self.atom_type = fh.nextUInt32().bigEndian
func data() -> Data?
guard let offset = try? fh.offset() else
return nil
let data = fh.readData(ofLength: Int(self.atom_size))
try? fh.seek(toOffset: offset)
return data
extension FileHandle
func nextUInt32() -> UInt32
let data = self.readData(ofLength: 4)
let i32array = data.withUnsafeBytes $0.load(as: UInt32.self)
//print(i32array)
return i32array
【讨论】:
以上是关于我的视频的 naturalSize 仅为 (4.0, 3.0) 像素,这也是提取的帧大小的主要内容,如果未能解决你的问题,请参考以下文章
如何仅为从 iOS 中的照片库中选择的视频设置 UIImagePickerController 的allowEditing?