使用AVAssetReader从远程资产读取(stream)
我的主要目标是从服务器stream式传输video,并在stream式传输时逐帧剪切(以便OpenGL可以使用)。 为此,我使用了在互联网上随处可见的代码(我记得它来自Apple的GLVideoFrame示例代码):
NSArray * tracks = [asset tracks]; NSLog(@"%d", tracks.count); for(AVAssetTrack* track in tracks) { NSLog(@"type: %@", [track mediaType]); initialFPS = track.nominalFrameRate; width = (GLuint)track.naturalSize.width; height = (GLuint)track.naturalSize.height; NSError * error = nil; // _movieReader is a member variable @try { self._movieReader = [[[AVAssetReader alloc] initWithAsset:asset error:&error] autorelease]; } @catch (NSException *exception) { NSLog(@"%@ -- %@", [exception name], [exception reason]); NSLog(@"skipping track"); continue; } if (error) { NSLog(@"CODE:%d\nDOMAIN:%@\nDESCRIPTION:%@\nFAILURE_REASON:%@", [error code], [error domain], error.localizedDescription, [error localizedFailureReason]); continue; } NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey; NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA]; NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:value forKey:key]; [_movieReader addOutput:[AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:track outputSettings:videoSettings]]; [_movieReader startReading]; [self performSelectorOnMainThread:@selector(frameStarter) withObject:nil waitUntilDone:NO]; }
但是我总是在[[AVAssetReader alloc] initWithAsset:error:]
得到这个exception。
NSInvalidArgumentException -- *** -[AVAssetReader initWithAsset:error:] Cannot initialize an instance of AVAssetReader with an asset at non-local URL 'http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8'
所以我的两个问题是:
- 这个exception真的告诉我,
AVAssetReader
必须有一个本地URL? 它可以用于stream(就像AVFoundation
类的其余部分)? - 如果
AVFoundation
方法不起作用,还有什么其他的build议可以同时stream式传输video和分割帧?
非常感谢你的帮助。
@Cocoanetics,我无法评论由于低代表。 但是你所说的话似乎并不完全正确。 AVFoundation在本地和非本地文件之间似乎没有区别,就像它在所使用的一些文件或协议之间所做的那样。 使用mp4 / mov与使用通过m3u8的HTTP Livestream协议之间有一个非常明显的区别,但是使用本地或远程mp4的差别有点模糊。
展开上面的内容:
a)如果您的“远程”资产是M3U8(也就是说,您正在使用HTTP“实时”stream式传输),那么没有任何机会。 无论M3U8是在您的本地文件系统还是在远程服务器上,由于AVAssetReader和所有与AVAsset相关的function都不起作用。 However, AVPlayer, AVPlayerItem etc would work just fine.
b)如果是MP4 / MOV,则需要进一步调查。 Local MP4/MOV's work flawlessly.
而在远程MP4 / MOV的情况下,我能够创build(或从AVPlayerItem或AVPlayer或AVAssetTracks检索)AVURLAsset,有时我可以成功地初始化一个AVAssetReader(我将展开'有时'以及,很快)。 但是, copyNextSampleBuffer always returns nil in case of remote MP4's
, copyNextSampleBuffer always returns nil in case of remote MP4's
。 由于几件事情调用copyNextSampleBuffer的工作点,我不是100%确定如果:
i)在所有其他步骤已经成功之后,copyNextSampleBuffer不起作用于远程mp4的function。
ii)“其他步骤”对于远程MP4似乎都起作用,这是苹果公司实施的一个偶然事件,当我们碰到copyNextSampleBuffer时,这种不兼容性就显得很突出了…………..这些“其他的步骤”是什么,我马上就会详细介绍。
iii)我试图调用copyNextSampleBuffer远程MP4的时候做错了。
所以@Paula你可以尝试远程MOV / MP4进一步调查。
作为参考,以下是我尝试从video中捕获帧的方法:
一个)
直接从videourl创build一个AVURLAsset。
使用[asset tracksWithMediaType:AVMediaTypeVideo]检索video轨道
准备AVAssetReaderTrackOutput使用video轨道作为来源。
使用AVURLAsset创build一个AVAssetReader。
将AVAssetReaderTrackOutput添加到AVAssetReader和startReading。
使用copyNextSampleBuffer检索图像。
b)
从videourl创build一个AVPlayerItem,然后从它创build一个AVPlayer(或直接从URL创buildAVPlayer)。
检索AVPlayer的“资产”属性并使用“loadValuesAsynchronouslyForKeys:”加载其“轨道”。
分开AVMediaTypeVideotypes的轨道(或者只需在轨道加载后在资产上调用tracksWithMediaType:),然后使用video轨道创buildAVAssetReaderTrackOutput。
使用AVPlayer的'asset','startReading'创buildAVAssetReader,然后使用copyNextSampleBuffer检索图像。
C)
直接从videourl创build一个AVPlayerItem + AVPlayer或AVPlayer。
KVO AVPlayerItem的“音轨”属性,一旦加载音轨,分开AVMediaTypeVideotypes的AVAssetTracks。
从AVPlayerItem / AVPlayer / AVAssetTrack的“资产”属性中检索AVAsset。
其余步骤与(b)类似。
d)
直接从videourl创build一个AVPlayerItem + AVPlayer或AVPlayer。
KVO AVPlayerItem的“轨道”属性,一旦加载轨道,分开AVMediaTypeVideotypes。
创buildAVMutableComposition,并初始化AVMediaTypeVideotypes的关联AVMutableCompositionTrack。
从先前检索的video轨道插入适当的CMTimeRange到这个AVMutableCompositionTrack。
与(b)和(c)类似,现在创build您的AVAssetReader和AVAssetReaderTrackOutput,但不同之处在于您使用AVMutableComposition作为初始化AVAssetReader的基础AVAsset,并使用AVMutableCompositionTrack作为AVAssetReaderTrackOutput的基础AVAssetTrack。
'startReading'并使用copyNextSampleBuffer从AVAssetReader获取帧。
PS:我在这里尝试了方法(d),以避免直接从AVPlayerItem或AVPlayer检索AVAsset不起作用的事实。 所以我想从我手头已经有的AVAssetTrack创build一个新的AVAsset。 无可否认,也许毫无意义(如果不是最初的AVAsset,最终将从哪里获得曲目信息?),但无论如何,这是值得一试的尝试。
以下是不同types文件的结果摘要:
1)本地MOV / MP4的 – 所有4个方法完美地工作。
2)远程MOV / MP4的 – 在方法(b)到(d)中资产和轨道被正确地检索,并且AVAssetReader也被初始化,但copyNextSampleBuffer总是返回nil。 在(a)的情况下,创buildAVAssetReader本身失败,出现“未知错误”NSOSStatusErrorDomain -12407。
3)本地M3U8(通过应用内/本地HTTP服务器访问) – 方法(a),(b)和(c)失败,试图获取任何形状或forms的AVURLAsset / AVAsset通过M3U8stream传输的文件一个傻瓜差事。
在(a)的情况下,根本不创build资产,并且AVURLAsset上的initWithURL:调用失败,并出现“未知错误”AVFoundationErrorDomain -11800。
在(b)和(c)的情况下,从AVPlayer / AVPlayerItem或AVAssetTracks中检索AVURLAsset会返回SOME对象,但是访问它的'tracks'属性总是返回一个空的数组。
在(d)的情况下,我能够成功地检索和隔离video轨道,但是在尝试创buildAVMutableCompositionTrack时,尝试从源轨道插入AVMutableCompositionTrack中插入CMTimeRange失败,出现“未知错误” NSOSStatusErrorDomain -12780。
4)遥控M3U8,与当地的M3U8完全一样。
我没有完全了解为什么这些差异存在,或不能被苹果减轻。 但是,你去了。
@科学,那不是真的。 你可以在AVMutableCompositionTrack上获得一个远程文件
AVURLAsset* soundTrackAsset = [[AVURLAsset alloc]initWithURL:[NSURL URLWithString:@"http://www.yoururl.com/yourfile.mp3"] options:nil]; AVMutableCompositionTrack *compositionAudioSoundTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; [compositionAudioSoundTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAsset.duration) ofTrack:[[soundTrackAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil];
但是,这种方法对MP4等压缩比较高的文件并不适用
目前AVFoundation不可能使用非本地URL,至less不是直接的。
- 核心数据,当NSFetchRequest返回NSDictionaryResultType时如何获取NSManagedObject的ObjectId?
- AFNetworking 2.0跟踪file upload进度
- 远程的MP3文件需要花费很多时间在迅速的ios中播放
- 将Swift UnsafePointer <AudioStreamBasicDescription>转换为字典?
- AVAssetResourceLoaderDelegate方法不能在设备上工作
- CMSampleBufferSetDataBufferFromAudioBufferList返回错误12731
- 如何使用AVCaptureStillImageOutput拍摄照片
- AVPlayer停止播放,不再恢复
- 如何正确地停止和删除iOS11中的audioTapProcessor
- 如何loggingvideo并保持音乐在后台播放?
- iOS从.mov文件中提取audio