2014-12-05 34 views
3

我有一個Movie類,它有一個UIImage的數組,我寫入H264文件。它可以工作,但偶爾它會寫入一個不包含任何內容的視頻文件,但文件大小仍然設置爲非零大小。iOS偶爾寫空視頻文件

這裏是我寫作的代碼。我對iOS開發很新,所以這是從互聯網複製的,所以我可能不完全明白它在做什麼。希望有人可以提出一個更好的方法來做到這一點。

frame是在循環

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() 
} 

編輯這似乎沒有任何內容會不喜歡這個工作,其他的電影播放的文件UIImage實例。如果我查看與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 
+0

你說的意思是'不包含任何content'?我測試了代碼,它總是爲我工作,也許你可以展示更多的代碼。 – gabbler 2014-12-08 06:01:47

+0

@ gabbler我添加了一些更多的信息,希望有助於。你有沒有對我沒有的代碼做更多的修改? – Brandon 2014-12-08 15:18:45

+0

也許你可以展示你的代碼,製作一個虛擬項目,除了初始化'writer','input'外,我不認爲我有更多的代碼更改。你在設備或模擬器上測試過它嗎? – gabbler 2014-12-08 15:25:08

回答

0

你有幾個問題。我不知道究竟你所說的「不包含任何內容」的意思,但這些希望有幫助(如果沒有,你無論如何都應該實現它們):

  1. 你阻塞線程撥打電話sleepForTimeInterval(),這可能會導致問題。 This answer建議沿,而不是睡覺,這是一個稍微好一點的解決方案移動運行循環,但the readyForMoreMediaData documentation有一個更好的建議:

    此屬性是可觀察到的使用鍵 - 值觀察(見Key-Value Observing Programming Guide)。觀察者不應該認爲他們會被通知某個特定線程的變化。

    而不是運行一個循環,並如果它是可用的,剛剛得到的對象告訴你當它準備使用KVO更多。

  2. 在您的createPixelBufferFromCGImage方法中,您不會檢查任何點的故障。例如,您應該處理pixelBufferPointer.memory?nil的可能性。

基本上,我假設到的是,這些東西一個正在發生的事情:因爲一個線程被阻塞

  • j命中30並沒有什麼一直沒有寫。在這種情況下,您可以使用正確的文件大小編寫一個空文件。
  • createPixelBufferFromCGImage被返回意外的數據,這你再寫入磁盤