我的主要目标是从服务器上流视频,并在流中逐帧切割它(这样OpenGL就可以使用它)。为此,我使用了在互联网上随处可见的代码(据我回忆,它来自苹果的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:]得到这个异常。
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'所以我的两个问题是:
AVAssetReader必须有一个本地URL吗?它能用于流(就像其他的AVFoundation类一样)吗?AVFoundation方法不能工作,还有什么建议可以同时流视频和分割它的帧?非常感谢你的帮助。
发布于 2011-06-20 10:06:05
AVFoundation似乎没有像区分所使用的文件或协议那样区分本地文件和非本地文件。使用mp4 /mov与使用通过m3u8的HTTP流协议之间有非常明确的区别,但使用本地或远程mp4的区别有点模糊。
扩大上述内容:
如果您的“远程”资产是M3U8 (也就是说,您使用的是HTTP 'live‘流),那么就没有任何可能。无论M3U8是在您的本地文件系统中还是在远程服务器上,由于多种原因,AVAssetReader和所有与AVAsset相关的功能都无法工作。However, AVPlayer, AVPlayerItem etc would work just fine.
( b)如果是MP4/MOV,则需要进一步调查。Local MP4/MOV's work flawlessly. --虽然在远程MP4/MOV的情况下,我可以创建(或从AVPlayerItem、AVPlayer或AVAssetTracks检索)一个AVURLAsset,有时我可以用它成功地初始化AVAssetReader (稍后,我还会对“有时”进行扩展)。然而,copyNextSampleBuffer always returns nil in case of remote MP4's.由于有几件事情需要调用copyNextSampleBuffer工作,所以我不能100%确定是否:
i)在所有其他步骤都成功之后,没有为远程MP4工作的copyNextSampleBuffer是预定的/预期的功能。
(二)“其他步骤”似乎完全适用于远程MP4,这是苹果的实现过程中的一个意外,当我们点击copyNextSampleBuffer..............what时,这种不兼容性就会浮出水面--这些‘其他步骤’,我很快就会详细介绍。
(3)当我试图为远程mp4的.调用copyNextSampleBuffer时,我做了一些错误的事情。
所以@Paula你可以试着用远程MOV/MP4做进一步的研究。
作为参考,下面是我尝试过的从视频中获取帧的方法:
a)
直接从视频URL创建一个AVURLAsset。
使用资产跟踪检索视频轨道-- tracksWithMediaType:AVMediaTypeVideo
准备一个使用视频轨道作为源的AVAssetReaderTrackOutput。
使用AVAssetReader创建一个AVURLAsset。
将AVAssetReaderTrackOutput添加到AVAssetReader和startReading中。
使用copyNextSampleBuffer检索图像。b)
从视频URL创建一个AVPlayerItem,然后从它创建一个AVPlayer (或者直接从这个URL创建AVPlayer )。
检索AVPlayer的‘资产’属性,并使用"loadValuesAsynchronouslyForKeys:“加载其”跟踪“。
分离AVMediaTypeVideo类型的音轨(或者在加载轨道后只在资产上调用tracksWithMediaType:),并使用视频轨道创建AVAssetReaderTrackOutput。
使用AVPlayer的“资产”、“AVAssetReader”创建AVAssetReader,然后使用copyNextSampleBuffer检索图像。c)
直接从视频URL创建AVPlayerItem+AVPlayer或AVPlayer。
KVO是AVPlayerItem的“磁道”属性,一旦加载了音轨,就将AVAssetTracks类型为AVMediaTypeVideo。
从AVPlayerItem/AVPlayer/AVAssetTrack的“资产”属性中检索AVAsset。
其余步骤与方法(b)相似。d)
直接从视频URL创建AVPlayerItem+AVPlayer或AVPlayer。
KVO是AVPlayerItem的“磁道”属性,一旦加载,就将AVMediaTypeVideo类型的音轨分开。
创建一个AVMutableComposition,并初始化一个类型为AVMediaTypeVideo的关联AVMutableCompositionTrack。
将先前检索到的视频轨道中的适当CMTimeRange插入到此AVMutableCompositionTrack中。
类似于(b)和(c),现在创建您的AVAssetReader和AVAssetReaderTrackOutput,但区别在于您使用AVMutableComposition作为初始化AVAssetReader的基本AVAsset,使用AVMutableCompositionTrack作为AVAssetReaderTrackOutput的基本AVAssetTrack。
“startReading”并使用copyNextSampleBuffer从AVAssetReader获取帧。
P.S:我在这里尝试了一种方法(d),以避开直接从AVPlayerItem或AVPlayer检索的AVPlayerItem或AVPlayer没有行为的事实。因此,我想从我手头已有的AVAsset中创建一个新的AVAssetTracks。诚然,这是无趣的,而且可能毫无意义(如果不是原始的AVAsset,那么跟踪信息最终会从哪里检索呢?)但无论如何都值得一试。
以下是不同类型文件的结果摘要:
1)本地MOV/MP4的所有4种方法都能完美地工作。
2)远程MOV/MP4--在方法(b)到(d)中正确检索资产和跟踪,AVAssetReader也被初始化,但copyNextSampleBuffer总是返回零。在(a)的情况下,AVAssetReader本身的创建将失败,出现“未知错误”NSOSStatusErrorDomain -12407。
3) Localm3u8(通过in / Local服务器访问)-- (a)、(b)和(c)方法不幸失败,因为试图为通过m3u 8传输的文件获取任何形式或形式的AVURLAsset/AVAsset都是愚蠢的错误。
在(a)的情况下,根本没有创建资产,initWithURL:调用AVURLAsset失败了,出现了“未知错误”AVFoundationErrorDomain -11800。
在(b)和(c)的情况下,从AVPlayer/AVPlayerItem或AVAssetTracks检索AVAssetTracks返回一些对象,但是访问其上的“tracks”属性总是返回一个空数组。
在(d)的情况下,我能够成功地检索和隔离视频轨道,但是当尝试创建AVMutableCompositionTrack时,当尝试将CMTimeRange从源轨道插入到AVMutableCompositionTrack中时,它会失败,其中包含一个“未知错误”NSOSStatusErrorDomain -12780。4)远程m3u8,其行为与本地m3u8完全相同。
我并没有完全了解这些差异存在的原因,也没有被苹果公司减轻。但就这样吧。
发布于 2011-09-29 21:50:46
您可以在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];但是,这种方法不能很好地处理像MP4s这样具有较高压缩能力的文件。
https://stackoverflow.com/questions/6242131
复制相似问题