跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • AVAssetReader 视频数据读取
未分類
5 2 月 2021

AVAssetReader 视频数据读取

AVAssetReader 视频数据读取

資深大佬 : zoule 9

AVAssetReader 介绍

可以通过 AVAssetReader 获取视频文件里媒体样本,可以直接从存储器中读取未解码的原始媒体样本,获得解码成可渲染形式的样本。 文档里说明 AVAssetrader 管道内部是多线程的。初始化之后,读取器在使用前加载并处理合理数量的样本数据,以 copyNextSampleBuffer ( AVAssetReaderOutput )等检索操作的延迟非常低。但 AVAssetReader 还是不适用于实时源,并且它的性能也不能保证用于实时操作。 由于使用前需要加载并处理一些样本数据,导致占用的内存可能会比较大,需要注意同一时间使用的 reader 个数不要过多,视频像素越高,占用的内存也会越大。  

AVAssetReader 初始化

使用 AVAsset 对 AVAssetReader 进行初始化,前面也说了初始化之后就会加载样本数据,所以这一步就已经会对内存产生印象,如果内存紧张就不要预先初始化。

 NSError *createReaderError;  _reader = [[AVAssetReader alloc]initWithAsset:_asset error:&createReaderError]; 

 

AVAssetReader 设置 Output

在开始读取之前,需要添加 output 来控制读取初始化使用的 asset 中哪些 track,以及配置如何读取。 AVAssetReaderOutput 还有其他的子类实现,如 AVAssetReaderVideoCompositionOutput,AVAssetReaderAudioMixOutput 和 AVAssetReaderSampleReferenceOutput 。 这里使用 AVAssetReaderTrackOutput 演示。需要一个 track 来初始化,track 从 asset 中获取。

NSArray tracks = [_asset tracksWithMediaType:AVMediaTypeAudio]; if (tracks.count > 0) {     AVAssetTrack audioTrack = [tracks objectAtIndex:0]; } 

或者

 NSArray tracks = [_asset tracksWithMediaType:AVMediaTypeVideo]; if (tracks.count > 0) {     AVAssetTrack videoTrack = [tracks objectAtIndex:0]; } 

还可以对输出的格式进行配置,更多配置可以查阅文档。

NSDictionary * const VideoAssetTrackReaderOutputOptions = @{(id) kCVPixelBufferOpenGLESCompatibilityKey : @(YES),                                                             (id) kCVPixelBufferIOSurfacePropertiesKey : [NSDictionary dictionary],                                                             (NSString*)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}; _readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:_track                                                            outputSettings:VideoAssetTrackReaderOutputOptions]; if ([_reader canAddOutput:_readerOutput]) {     [_reader addOutput:_readerOutput]; } 

 

seek 操作

AVAssetReader 并不适合频繁随机读取的操作,如果需要频繁 seek 可能需要别的方式实现。 在开始读取之前,可以对读取的范围进行设置,当开始读取后不可以修改,只能顺序向后读。 有两种方案来调整读取范围:

  1. output 中可以设置 supportsRandomAccess,当为 true 时,可以重置读取范围,但需要调用方调用 copyNextSampleBuffer,直到该方法返回 NULL 。
  2. 或者重新初始化一个 AVAssetReader 来设置读取时间。 如果尝试第一种方案,需要使用 seek,可以尝试每次设置一个不太长的区间,以保证读取完整个区间不会耗时太多,且时间间隔最好以关键帧划分。

 

读取数据

_reader.timeRange = range; [_reader startReading];  _sampleBuffer = [_readerOutput copyNextSampleBuffer]; 

CMSampleBuffer 中提供了方法获取解码数据,比如获取图像信息可以使用

CVImageBufferRef pixelBuffer =  
CMSampleBufferGetImageBuffer(_sampleBuffer); 

需要注意,当 CMSampleBuffer 使用完毕,需要调用 release 来释放

CFRelease(_sampleBuffer); 

 

代码示例

NSDictionary * const AssetOptions = @{AVURLAssetPreferPreciseDurationAndTimingKey:@YES}; NSDictionary * const VideoAssetTrackReaderOutputOptions = @{(id) kCVPixelBufferOpenGLESCompatibilityKey : @(YES),                                                                 (id) kCVPixelBufferIOSurfacePropertiesKey : [NSDictionary dictionary],                                                                 (NSString*)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA)}; _videoAsset = [[AVURLAsset alloc] initWithURL:[NSURL fileURLWithPath: filePath]                                                                     options:AssetOptions]; _videoTrack = [[mPrivate->mVideoAsset tracksWithMediaType:AVMediaTypeVideo] firstObject]; if (_videoTrack) {     NSError *createReaderError;     _reader = [[AVAssetReader alloc] initWithAsset:_videoAsset error:&createReaderError];     if (!createReaderError) {         _readerOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:mPrivate->_videoTrack                                                                              outputSettings:VideoAssetTrackReaderOutputOptions];         _readerOutput.supportsRandomAccess = YES;         if ([_reader canAddOutput:_readerOutput])         {             [_reader addOutput:_readerOutput];         }         [_reader startReading];          if (_reader.status == AVAssetReaderStatusReading || _reader.status == AVAssetReaderStatusCompleted) {             CMSampleBufferRef samplebuffer = [_readerOutput copyNextSampleBuffer];             if (samplebuffer) {             //绘制 samepleBuffer 中的画面                 CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(samplebuffer);                 CVPixelBufferLockBaseAddress(imageBuffer, 0);                 uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer);                 size_t width = CVPixelBufferGetWidth(imageBuffer);                 size_t height = CVPixelBufferGetHeight(imageBuffer);                 size_t bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0);                 size_t bufferSize = CVPixelBufferGetDataSize(imageBuffer);                  CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();                 CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, baseAddress, bufferSize, NULL);                 CGImageRef cgImage = CGImageCreate(width, height, 8, 32, bytesPerRow, rgbColorSpace, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrderDefault, provider, NULL, true, kCGRenderingIntentDefault);                 CGImageRelease(cgImage);                 CVPixelBufferUnlockBaseAddress(imageBuffer, 0);                 CFRelease(samplebuffer);             }         }     }  } 

大佬有話說 (0)

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具