赞
踩
- AVFoundation框架简介AVFoundation框架是iOS中专门处理音视频的框架,其中集成了音频播放以及处理和视频播放处理以及采集等功能(实现录制,编辑和播放音视频功能);以及配置音频会话更新设备音视频环境等功能。AVKit框架基于此框架实现的。
-
- 在 AVFoundation 框架中使用的基本数据结构,如时间相关的或描述媒体数据的数据结构都声明在 CoreMedia 框架中。
-
-
-
- AVFoundation 框架包含视频相关的接口以及音频相关的接口,与音频相关的类有 AVAudioPlayer、AVAudioRecorder、AVAudioSession。
-
- AVFoundation 框架中最基本的类是 AVAsset ,它是一个或者多个媒体数据的集合,描述的是整个集合的属性,如标题、时长、大小等,并且没有特定的数据格式。集合的每一个媒体数据都是统一的数据类型,称之为 track。简单的情况是一种数据是音频数据,一种是视频数据,而较复杂的情况是一种数据交织着音频和视频数据,并且 AVAsset 是可能有元数据的。
-
- 另外,需要明白的是在 AVFoundation 中,初始化了 asset 及 track 后,并不意味着资源已经可用,因为若资源本身并不携带自身信息时,那么系统需要自己计算相关信息,这个过程会阻塞线程,所以应该使用异步方式进行获取资源信息后的操作。
-
- AVFoundation 提供了丰富的方法来管理视听资源的播放,为了支持这些方法,它将描述 asset 的状态与 asset 本身分离,这就使得在同一个时刻,以不同的方式播放同一个 asset 中的不同的媒体数据变得可能。对于 asset 的状态是由 player 管理的,而 asset 中的 track 的状态是由 player tracker 管理的。使用这两个状态管理对象,可以实现诸如设置 asset 中视频部分的大小、设置音频的混合参数及与视频的合成或者将 asset 中的某些媒体数据置为不可用。
-
- 另外,还可以通过 player 将输出定位到 Core Animation 层中,或通过播放队列设置 player 集合的播放顺序。
-
- AVFoundation 提供了多种方法来创建 asset ,可以简单的重编码已经存在的 asset ,这个过程可以使用 export session 或者使用 asset reader 和 asset writer 。
-
- 若要生成视频的缩略图,可以使用 asset 初始化一个 AVAssetImageGenerator 实例对象,它会使用默认可用的视频 tracks 来生成图片。
-
- AVFoundation 中可以使用 compositions 将多个媒体数据(video/audio tracks)合成为一个 asset ,这个过程中,可以添加或移除 tracks ,调整它们的顺序,或者设置音频的音量和变化坡度,视频容量等属性。这些媒体数据的集合保存在内存中,直到使用 export session 将它导出到本地文件中。另外,还可以使用 asset writer 创建 asset 。
-
- 使用 capture session 协调从设备(如相机、麦克风)输入的数据和输出目标(如视频文件)。可以为 session 设置多个输入和输出,即使它正在工作,还可以通过它停止数据的流动。另外,还可以使用 preview layer 将相机记录的影像实时展示给用户。
-
- 在 AVFoundation 中的回调处理并不保证回调任务在某个特定的线程或队列中执行,其遵循两个原则,UI 相关的操作在主线程中执行,其他回调需要为其指定调用的队列。
-
- swift 中通过AVFoundation来定制拍摄窗口
-
- swift AVFoundation PlayBack——swift学习(十)
****** AVPlayerItem 一个媒体资源管理对象,管理者视频的一些基本信息和状态,如 播放进度、缓存进度等 。 一个AVPlayerItem对应着一个视频资源。
******AVPlayer 视频操作对象,但是无法显示视频,需要把自己添加到一个AVPlayerLayer 上
******AVPlayerLayer 用来显示视频的。
=========AVPlayer实现无控制界面======
//定义一个视频文件路径
let filePath = Bundle.main.path(forResource: "test", ofType: "mov")
let videoURL = URL(fileURLWithPath: filePath!)
//定义一个视频播放器,通过本地文件路径初始化
let player = AVPlayer(url: videoURL)
//设置大小和位置(全屏)
let playerLayer = AVPlayerLayer(player: player)//显示视频的图层
playerLayer.frame = self.view.bounds
//添加到界面上
self.view.layer.addSublayer(playerLayer)
//开始播放
player.play()
==============AVPlayer实现无控制界面===带通知功能===
// 我们可以定义一个 AVPlayerItem,当视频播放完毕后它会发送一个 AVPlayerItemDidPlayToEndTime 通知。我们可以监听这个通知,在响应事件中
//定义一个视频文件路径
let filePath = Bundle.main.path(forResource: "test", ofType: "mov")
let videoURL = URL(fileURLWithPath: filePath!)//也可以播放网络资源URL
(string:
"http://baidu.com/demo.mp4"
)!
//定义一个playerItem,并监听相关的通知
let playerItem = AVPlayerItem(url: videoURL)
NotificationCenter.default.addObserver(self,
selector: #selector(playerDidFinishPlaying),
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
object: playerItem)
//定义一个视频播放器,通过playerItem径初始化
let player = AVPlayer(playerItem: playerItem)
//设置大小和位置(全屏)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.view.bounds
//添加到界面上
self.view.layer.addSublayer(playerLayer)
//开始播放
player.play()
}
//视频播放完毕的通知响应
@objc func playerDidFinishPlaying() {
print("播放完毕!")
}
==============AVKIt实现自定义视屏界面===========
参考oc:https://www.cnblogs.com/mzds/p/3711867.html
import UIKit
import AVFoundation
import AVKit
class LYBPhoneczVC: LYBBaseVC {
var link:CADisplayLink?
var playerItem:AVPlayerItem?
var player:AVPlayer?
var slide:UISlider?
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title="话费充值"
let autodioBtn:UIButton=UIButton.init(frame: CGRect.init(x: 0, y: 10, width: WIDTH, height: 50))
autodioBtn.setTitle("音频", for: UIControlState.normal)
autodioBtn.setTitleColor(UIColor.red, for: UIControlState.normal)
autodioBtn.addTarget(self, action:#selector(audioSet), for: UIControlEvents.touchUpInside)
view.addSubview(autodioBtn)
}
@objc func audioSet(){
//自定义视屏播放界面
//定义一个视频文件路径
let filePath = Bundle.main.path(forResource: "test", ofType: "mov")
let videoURL = URL(fileURLWithPath: filePath!)//也可以播放网络资源URL(string: "http://baidu.com/demo.mp4")!
//定义一个playerItem,并监听相关的通知
self.playerItem = AVPlayerItem(url: videoURL)
// kvo监听缓冲进度改变
self.playerItem?.addObserver(self, forKeyPath: "loadedTimeRanges", options: NSKeyValueObservingOptions.new, context: nil)
// kvo监听状态改变
self.playerItem?.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.new, context: nil)
//定义一个视频播放器,通过playerItem径初始化
player = AVPlayer(playerItem: self.playerItem)
//设置大小和位置(全屏)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.view.bounds
// 设置显示模式
playerLayer.videoGravity = AVLayerVideoGravity.resizeAspect
playerLayer.contentsScale = UIScreen.main.scale
//添加到界面上
self.view.layer.addSublayer(playerLayer)
//播放按钮
let playBtn:UIButton=UIButton.init(frame: CGRect.init(x: 0, y: 300, width: 50, height: 50))
playBtn.setTitle("播放", for: UIControlState.normal)
playBtn.setTitleColor(UIColor.red, for: UIControlState.normal)
playBtn.addTarget(self, action: #selector(palyBtn), for: UIControlEvents.touchUpInside)
view.addSubview(playBtn)
//进度条
slide=UISlider.init(frame: CGRect.init(x: 80, y: 300, width: WIDTH-100, height: 50))
slide?.backgroundColor=UIColor.red//进度条总的背景
slide?.tintColor=UIColor.black//进度的颜色
slide?.thumbTintColor=UIColor.yellow//点击后滑块的颜色
slide?.minimumValue=1//最小值
slide?.maximumValue=10//最大值
slide?.setThumbImage(UIImage.init(named: "guanyu"), for: UIControlState.normal)//进度条上的滑块图片,如果是UIImage.init(),刚开始不显示,点击滑动时才显示,滑块的大小有提供的图片大小来控制
slide?.setValue(5, animated: true)//设置进度的值(滑块的位置)
// 按下的时候
slide?.addTarget(self, action: #selector(sliderTouchDown(slide:)), for: UIControlEvents.touchDown)
// 弹起的时候
slide?.addTarget(self, action: #selector(sliderTouchUpOut(slide:)), for: UIControlEvents.touchUpOutside)
slide?.addTarget(self, action: #selector(sliderTouchUpOut(slide:)), for: UIControlEvents.touchUpInside)
slide?.addTarget(self, action: #selector(sliderTouchUpOut(slide:)), for: UIControlEvents.touchCancel)
view.addSubview(slide!)
// CADisplayLink 的执行次数相当于屏幕的帧数,iPhone 不卡顿的时候是每秒60次。把它加入主loop中,默认Mode 。差不多每秒执行60次。
self.link = CADisplayLink(target: self, selector: #selector(update))
self.link?.add(to: RunLoop.main, forMode: RunLoopMode.defaultRunLoopMode)
}
// //观察这响应-
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard let playerItem = object as? AVPlayerItem else { return }
if keyPath == "loadedTimeRanges"{
// 缓冲进度
// 通过监听AVPlayerItem的"loadedTimeRanges",可以实时知道当前视频的进度缓冲
}else if keyPath == "status"{
// 监听状态改变(一共三种状态unknown、readyToPlay、failed)
if playerItem.status == AVPlayerItemStatus.readyToPlay{
// 只有在readyToPlay这个状态下才能播放
print("播放")
}else{
print("加载异常")
}
}
}
//吧时间分转换成秒
func formatPlayTime(secounds:TimeInterval)->String{
if secounds.isNaN{
return "00:00"
}
let Min = Int(secounds / 60)
let Sec = Int(secounds .truncatingRemainder(dividingBy: 60))
return String(format: "%02d:%02d", Min, Sec)
}
@objc func update(){
let currentTime = CMTimeGetSeconds((player?.currentTime())!)//当前的时间进度
let totalTime = TimeInterval((playerItem?.duration.value)!) / TimeInterval((playerItem?.duration.timescale)!)//(playerItem?.duration.value)!) / TimeInterval((playerItem?.duration.timescale)!是吧获取的时间转换成秒
let timeStr = "\(formatPlayTime(secounds: currentTime))/\(formatPlayTime(secounds: totalTime))"
print(timeStr)
print(player?.currentTime())
}
@objc func palyBtn(){
//开始播放
player?.play()
}
@objc func sliderTouchDown(slide:UISlider){
//当视频状态为AVPlayerStatusReadyToPlay时才处理
if player?.status == AVPlayerStatus.readyToPlay{
let duration = slide.value * Float(CMTimeGetSeconds((self.player?.currentItem!.duration)!))//player?.currentItem!.duration是播放总时间长度.
let seekTime = CMTimeMake(Int64(duration), 1)//第一个参数是时间,第二个参数是倍率scale
//下面是让播放器找到seelktime这个时间对应的资源
player?.seek(to: seekTime, completionHandler: { (b) in
//这里可以开始播放、暂停等操作,根据需要
})
}
}
//开始播放或者暂停都可以
@objc func sliderTouchUpOut(slide:UISlider){
if player?.status == AVPlayerStatus.readyToPlay{
player?.play()
}
}
//获取缓冲区的进度
func avalableDurationWithplayerItem()->TimeInterval{
let loadedTimeRanges = player?.currentItem?.loadedTimeRanges//这是一个数组
let first = loadedTimeRanges?.first
let timeRange = first?.timeRangeValue//这是获取缓冲区
let startSeconds = CMTimeGetSeconds((timeRange?.start)!)
let durationSecound = CMTimeGetSeconds((timeRange?.duration)!)
let result = startSeconds + durationSecound
return result
}
}
=============AVPlayerViewController实现视频播放系统自带控制按钮======
//定义一个视频文件路径
let filePath = Bundle.main.path(forResource: "test", ofType: "mov")
let videoURL = URL(fileURLWithPath: filePath!)//也可以播放网络资源URL(string: "http://baidu.com/demo.mp4")!
//定义一个视频播放器,通过本地文件路径初始化
let player = AVPlayer(url: videoURL)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true) {
playerViewController.player!.play()
}
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+1) {
player.pause()//暂停---player.play()//播放
}
********音频录制和播放*******
- /**
- 音频---录音和播放
- */
-
- import UIKit
- import AVFoundation
- @available(iOS 10.0, *)
- class LYBAudioVC: UIViewController {
-
- var recorder: AVAudioRecorder?
- var player: AVAudioPlayer?
- let file_path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first?.appending("/recordAudio.wav")
-
-
- //开始录音
- func beginRecord() {
- // 获得音频会话对像,该对像属于单例模式,也就是说不用开发者而自行实例化,这个类在各种音频环境中起着非常重要的作用
- let session = AVAudioSession.sharedInstance()
- //设置session类型 设置音频操作类别,标示该应用仅支持音频的播放
- do {
- try session.setCategory(AVAudioSession.Category.playAndRecord, mode: AVAudioSession.Mode.default, options: AVAudioSession.CategoryOptions.defaultToSpeaker)
-
- } catch let err{
- print("设置类型失败:\(err.localizedDescription)")
- }
- //设置session动作, 启动音频会话的管理,此时会阻断后台音乐的播放
- do {
- try session.setActive(true)
- } catch let err {
- print("初始化动作失败:\(err.localizedDescription)")
- }
- //录音设置,注意,后面需要转换成NSNumber,如果不转换,你会发现,无法录制音频文件,我猜测是因为底层还是用OC写的原因
- let recordSetting: [String: Any] = [AVSampleRateKey: NSNumber(value: 16000),//采样率
- AVFormatIDKey: NSNumber(value: kAudioFormatLinearPCM),//音频格式
- AVLinearPCMBitDepthKey: NSNumber(value: 16),//采样位数
- AVNumberOfChannelsKey: NSNumber(value: 1),//通道数
- AVEncoderAudioQualityKey: NSNumber(value: AVAudioQuality.min.rawValue)//录音质量
- ];
- //开始录音
- do {
- let url = URL(fileURLWithPath: file_path!)
- recorder = try AVAudioRecorder(url: url, settings: recordSetting)
- recorder!.prepareToRecord()
- recorder!.record()
- print("开始录音")
- } catch let err {
- print("录音失败:\(err.localizedDescription)")
- }
- }
-
-
- //结束录音
- func stopRecord() {
- if let recorder = self.recorder {
- if recorder.isRecording {
- print("正在录音...:\(file_path!)")
- }else {
- print("没有录音")
- }
- recorder.stop()
- self.recorder = nil
- }else {
- print("未初始化")
- }
- }
-
-
- //播放
- func play() {
- do {
- // 设置应用程序支持接受远程控制事件
- UIApplication.shared.beginReceivingRemoteControlEvents()
- player = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: file_path!))
- print("歌曲长度:\(player!.duration)")
- player!.prepareToPlay()
- // 设置音频播放对象的音量大小/
- player!.volume = 1.0
- // 设置音频的播放次数,-1为无限循环
- player!.numberOfLoops = -1
- player!.play()
- } catch let err {
- print("播放失败:\(err.localizedDescription)")
- }
- }
-
-
-
-
- }
-
-
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。