iOS偶尔会生成空的视频文件

3
我有一个Movie类,其中包含一个UIImage数组,我将其写入H264文件。这可行,但有时会写入不包含任何内容的视频文件,但文件大小仍设置为非零大小。
下面是我进行写入的代码。我对iOS开发还比较陌生,所以这段代码是从互联网复制来的,可能没有完全理解它在做什么。希望有人能建议更好的方法来解决这个问题。
frame是循环中的UIImage实例。
func writeAnimationToMovie() {
    var error: NSError?

    writer.startWriting()
    writer.startSessionAtSourceTime(kCMTimeZero)

    var buffer: CVPixelBufferRef

    var frameCount = 0
    for frame in self.photos {
        buffer = createPixelBufferFromCGImage(frame.CGImage)

        var appendOk = false
        var j = 0
        while (!appendOk && j < 30) {
            if pixelBufferAdaptor.assetWriterInput.readyForMoreMediaData {
                let frameTime = CMTimeMake(Int64(frameCount), Int32(fps))
                appendOk = pixelBufferAdaptor.appendPixelBuffer(buffer, withPresentationTime: frameTime)
                // appendOk will always be false
                NSThread.sleepForTimeInterval(0.05)
            } else {
                NSThread.sleepForTimeInterval(0.1)
            }
            j++
        }
        if (!appendOk) {
            println("Doh, frame \(frame) at offset \(frameCount) failed to append")
        }

        frameCount++
    }

    input.markAsFinished()

    writer.finishWritingWithCompletionHandler({
        if self.writer.status == AVAssetWriterStatus.Failed {
            println("oh noes, an error: \(self.writer.error.description)")
        } else {
            let content = NSFileManager.defaultManager().contentsAtPath(self.fileURL.path!)
            println("wrote video: \(self.fileURL.path) at size: \(content?.length)")
        }
    })
}

func createPixelBufferFromCGImage(image: CGImageRef) -> CVPixelBufferRef {
    let options = [
        "kCVPixelBufferCGImageCompatibilityKey": true,
        "kCVPixelBufferCGBitmapContextCompatibilityKey": true
    ]

    let frameSize = CGSizeMake(CGFloat(CGImageGetWidth(image)), CGFloat(CGImageGetHeight(image)))

    var pixelBufferPointer = UnsafeMutablePointer<Unmanaged<CVPixelBuffer>?>.alloc(1)

    var status:CVReturn = CVPixelBufferCreate(
        kCFAllocatorDefault,
        UInt(frameSize.width),
        UInt(frameSize.height),
        OSType(kCVPixelFormatType_32ARGB),
        options,
        pixelBufferPointer
    )

    var lockStatus:CVReturn = CVPixelBufferLockBaseAddress(pixelBufferPointer.memory?.takeUnretainedValue(), 0)

    var pxData:UnsafeMutablePointer<(Void)> = CVPixelBufferGetBaseAddress(pixelBufferPointer.memory?.takeUnretainedValue())
    let bitmapinfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.NoneSkipFirst.rawValue)
    let rgbColorSpace:CGColorSpace = CGColorSpaceCreateDeviceRGB()

    var context:CGContextRef = CGBitmapContextCreate(
        pxData,
        UInt(frameSize.width),
        UInt(frameSize.height),
        8,
        4 * CGImageGetWidth(image),
        rgbColorSpace,
        bitmapinfo
    )

    CGContextDrawImage(context, CGRectMake(0, 0, frameSize.width, frameSize.height), image)

    CVPixelBufferUnlockBaseAddress(pixelBufferPointer.memory?.takeUnretainedValue(), 0)

    return pixelBufferPointer.memory!.takeUnretainedValue()
}

编辑 那些似乎没有任何内容的文件无法像其他正常工作的电影一样播放。如果我使用exiftool查看一个正常工作的文件,我会得到以下结果:

$ exiftool 20242697651186-o.mp4

ExifTool Version Number         : 9.76
File Name                       : 20242697651186-o.mp4
Directory                       : .
File Size                       : 74 kB
File Modification Date/Time     : 2014:12:05 11:07:29-05:00
File Access Date/Time           : 2014:12:08 10:12:29-05:00
File Inode Change Date/Time     : 2014:12:05 11:07:29-05:00
File Permissions                : rw-r--r--
File Type                       : MP4
MIME Type                       : video/mp4
Major Brand                     : MP4 v2 [ISO 14496-14]
Minor Version                   : 0.0.1
Compatible Brands               : mp41, mp42, isom
Movie Data Size                 : 74741
Movie Data Offset               : 44
Movie Header Version            : 0
Create Date                     : 2014:12:05 16:07:32
Modify Date                     : 2014:12:05 16:07:32
Time Scale                      : 600
Duration                        : 0.50 s
Preferred Rate                  : 1
Preferred Volume                : 100.00%
Preview Time                    : 0 s
Preview Duration                : 0 s
Poster Time                     : 0 s
Selection Time                  : 0 s
Selection Duration              : 0 s
Current Time                    : 0 s
Next Track ID                   : 2
Track Header Version            : 0
Track Create Date               : 2014:12:05 16:07:32
Track Modify Date               : 2014:12:05 16:07:32
Track ID                        : 1
Track Duration                  : 0.50 s
Track Layer                     : 0
Track Volume                    : 0.00%
Matrix Structure                : 1 0 0 0 1 0 0 0 1
Image Width                     : 640
Image Height                    : 480
Media Header Version            : 0
Media Create Date               : 2014:12:05 16:07:32
Media Modify Date               : 2014:12:05 16:07:32
Media Time Scale                : 600
Media Duration                  : 0.50 s
Media Language Code             : und
Handler Type                    : Video Track
Handler Description             : Core Media Video
Graphics Mode                   : srcCopy
Op Color                        : 0 0 0
Compressor ID                   : avc1
Source Image Width              : 640
Source Image Height             : 480
X Resolution                    : 72
Y Resolution                    : 72
Bit Depth                       : 24
Video Frame Rate                : 8
Avg Bitrate                     : 1.2 Mbps
Image Size                      : 640x480
Rotation                        : 0

这里有一个无法正常使用的文件,它没有包含所有元数据。

$ exiftool 20242891987099-o.mp4

ExifTool Version Number         : 9.76
File Name                       : 20242891987099-o.mp4
Directory                       : .
File Size                       : 75 kB
File Modification Date/Time     : 2014:12:05 11:07:37-05:00
File Access Date/Time           : 2014:12:08 10:12:36-05:00
File Inode Change Date/Time     : 2014:12:05 11:07:37-05:00
File Permissions                : rw-r--r--
File Type                       : MP4
MIME Type                       : video/mp4
Major Brand                     : MP4 v2 [ISO 14496-14]
Minor Version                   : 0.0.1
Compatible Brands               : mp41, mp42, isom
Movie Data Size                 : 76856
Movie Data Offset               : 44

“不包含任何内容”是什么意思?我测试了代码,它对我来说总是有效的,也许您可以展示更多的代码。 - gabbler
@gabbler 我添加了更多信息,希望有所帮助。你对代码做了我没有的更改吗? - Brandon
也许你可以展示一下你的代码,创建一个虚拟项目。我认为除了初始化“writer”和“input”之外,我没有更多对代码的修改了。你在设备上还是模拟器上测试过它? - gabbler
我建议您将writer的初始化添加到writeAnimationToMovie()中,以便每次运行writeAnimationToMovie()时都有一个单独的writer - LorikMalorik
1个回答

0

你有一些问题。我不确定你所说的“不包含任何内容”具体指什么,但希望以下其中之一能够帮到你(如果不能,你也应该实现它们):

  1. 你的调用 sleepForTimeInterval() 阻塞了线程,可能会导致问题。这个答案 建议使用运行循环而不是睡眠,这是一个稍微更好的解决方案,但是 readyForMoreMediaData 文档 提供了一个更好的建议:

    可以使用键值观察来观察此属性(请参阅键值观察编程指南)。观察者不应假设它们将在特定线程上收到更改通知。

    不要运行循环并询问是否可用,只需使用 KVO 让对象在准备好更多数据时告诉你即可。

  2. 在你的 createPixelBufferFromCGImage 方法中,你没有在任何时候检查失败。例如,你应该处理 pixelBufferPointer.memory? 可能为 nil 的情况。

基本上,我假设以下情况之一正在发生:

  • j 达到 30,但由于线程被阻塞,尚未写入任何内容。在这种情况下,您将写入一个具有正确文件大小的空文件。
  • createPixelBufferFromCGImage 返回意外数据,然后您将其写入磁盘。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接