ディスクへの書き込み中に AVAssetWriter の生の出力を読み取るために、いくつかのトリックを使用しています。個々のファイルを連結して再構築すると、結果のファイルは AVAssetWriter の出力ファイルとまったく同じバイト数になります。ただし、再構築されたファイルは、データが破損しているため、QuickTime で再生したり、FFmpeg で解析したりできません。あちこちで数バイトが変更されているため、結果のファイルは使用できなくなります。これは各読み取りの EOF 境界で発生していると思いますが、一貫した破損ではありません。
最終的にはこれに似たコードを使用して、エンコーダーから個々の H.264 NAL ユニットを解析し、それらをパケット化して RTP 経由で送信する予定ですが、ディスクから読み取られるデータを信頼できない場合は、別のソリューションを使用する必要があるかもしれません.
このデータ破損の説明/修正はありますか? NALユニットを解析してRTPでパケット化する方法について見つけた他のリソース/リンクはありますか?
完全なコードはこちら: AVAppleEncoder.m
// Modified from
// http://www.davidhamrick.com/2011/10/13/Monitoring-Files-With-GCD-Being-Edited-With-A-Text-Editor.html
- (void)watchOutputFileHandle
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
int fildes = open([[movieURL path] UTF8String], O_EVTONLY);
source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE,fildes,
DISPATCH_VNODE_DELETE | DISPATCH_VNODE_WRITE | DISPATCH_VNODE_EXTEND | DISPATCH_VNODE_ATTRIB | DISPATCH_VNODE_LINK | DISPATCH_VNODE_RENAME | DISPATCH_VNODE_REVOKE,
queue);
dispatch_source_set_event_handler(source, ^
{
unsigned long flags = dispatch_source_get_data(source);
if(flags & DISPATCH_VNODE_DELETE)
{
dispatch_source_cancel(source);
//[blockSelf watchStyleSheet:path];
}
if(flags & DISPATCH_VNODE_EXTEND)
{
//NSLog(@"File size changed");
NSError *error = nil;
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingFromURL:movieURL error:&error];
if (error) {
[self showError:error];
}
[fileHandle seekToFileOffset:fileOffset];
NSData *newData = [fileHandle readDataToEndOfFile];
if ([newData length] > 0) {
NSLog(@"newData (%lld): %d bytes", fileOffset, [newData length]);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
NSString *movieName = [NSString stringWithFormat:@"%d.%lld.%d.mp4", fileNumber, fileOffset, [newData length]];
NSString *path = [NSString stringWithFormat:@"%@/%@", basePath, movieName];
[newData writeToFile:path atomically:NO];
fileNumber++;
fileOffset = [fileHandle offsetInFile];
}
}
});
dispatch_source_set_cancel_handler(source, ^(void)
{
close(fildes);
});
dispatch_resume(source);
}
ここに私が見つけたいくつかの同様の質問がありますが、私の質問に正確には答えていません:
- iOS AVAssetWriter によって生成された生の H264 mdat から PTS を取得します
- iPhone からビデオをストリーミング
- QuickTime MOV ファイルからの h.264 NAL ユニットの解析
- iPhone から別のデバイス (ブラウザ、または iPhone) へのリアルタイム オーディオ/ビデオ ストリーミング
最終的にこれを理解したら、将来これを行おうとする人々を支援するために、オープンソース ライブラリをリリースします。
ありがとうございました!
更新:破損は EOF 境界では発生しません。が呼び出された後、ファイルの一部が書き換えられているようですfinishWriting
。この最初のファイルは 4KB でチャンク化されているため、変更された領域は EOF 境界のどこにもありません。movieFragmentInterval
有効にすると、新しい「moov」要素の近くでも破損しているようです。
左が正しいファイル、右が壊れたファイル。