Exploring AVFoundation - Notes

WWDC 2011 - Session 405 - Exploring AV Foundation
https://developer.apple.com/videos/play/wwdc2011/405/

1. 扯淡

可以学习英文教程,但要循序渐进,之后总结实践很重要。转化为自己的理解才行。之前看了一段时间 Doctmentation,感觉很大很复杂的框架。之后动手写了一些代码,回头再看相关 Session 就豁然开朗,一切不过是熟悉 Cocoa 框架结构,无非就是本事视频相关的不熟悉,直接开发就比较抽象。开发实践中持续学习,也就进入佳境。

视频学习时,双屏必备利器。加上最近 iPad 在 Session Keynote 上笔记,效率很高。

Session 不停的示例代码非常易于理解。

2. 总结

Keynote 要点如下:

  1. 五大功能:检测/播放/编辑片段/导出/录制。
  2. 两种媒体 model:static/dynamic, 类似NSArray/NSMutableArray,对应读取时是否会 mutate。
  3. 异步加载
  4. Key-Value Observe 支持大多数属性
  5. “There’s a protocol for that” TM
  6. AVPlayerItem: AVAsynchronousKeyValueLoading: loadValuesAsynchronouslyForKeys(_:completionHandler:),可以异步获取状态/属性变化,以更新 UI 等。
  7. AVPlayer 时间属性变化很快,异步 KVO 不再合适,改为同步 KVO,需要添加/移除观察:addPeriodicTimeObserverForInterval(_:queue:usingBlock:)
  8. AVPlayerItem 可获取媒体相关的属性,对 status 添加KVO。
  9. AVPlayerItemTrack:enabled 属性可以选择性播放 track。
  10. AVQueuePlayer:播放一组 AVAsset,适用于编辑完播放。
  11. AVPlayerLayer 用于显示媒体在屏幕上。有 readyForDisplay/videoGravity 等属性。
  12. AVMediaSelectionGroup 用于字幕/音频等可选 track。
  13. iPod Library: MPMediaQuery
  14. Camera Roll: AssetsLibrary (iOS 9: Photos)
  15. static/dynamic model 对应不同的观察机制,如下:

Matters of protocol And platform etiquette

  • AVAsynchronousKeyValueLoading
1
2
loadValuesAsynchronouslyForKeys:completionHandler: 
statusOfValueForKey:error:
  • NSObject(NSKeyValueObserving)
1
2
3
addObserver:forKeyPath:options:context: 
removeObserver:forKeyPath:
observeValueForKeyPath:ofObject:change:context:

3. 部分示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
NSArray *keys = [NSArray arrayWithObject:@”playable”];
[asset
loadValuesAsynchronouslyForKeys:keys
completionHandler:^{
NSError *error = nil;
AVKeyValueStatus playableStatus =
[asset statusOfValueForKey:@"playable" error:&error];
switch (playableStatus) {
case AVKeyValueStatusLoaded:
[self updateUIForAsset];
break;
case AVKeyValueStatusFailed:
[self reportError:error forAsset:asset];
break;
...
}
}];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (void)setUpTransportUI {
CMTime interval = CMTimeMakeWithSeconds(0.5);
id myObserver =
[[myPlayer addPeriodicTimeObserverForInterval:interval
queue:dispatch_get_main_queue()
usingBlock:^{
[self movePlayheadUI];
}] retain];
}

- (void)cleanUp {
[myPlayer removeTimeObserver:myObserver];
[myObserver release];
}