中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

個(gè)人做旅游網(wǎng)站的意義百度首頁(yè)排名優(yōu)化服務(wù)

個(gè)人做旅游網(wǎng)站的意義,百度首頁(yè)排名優(yōu)化服務(wù),西安駕校網(wǎng)站建設(shè),WordPress主題安全嗎引言 當(dāng)涉及到音視頻編輯時(shí),媒體資源的提取和組合是至關(guān)重要的環(huán)節(jié)。在iOS平臺(tái)上,AVFoundation框架提供了豐富而強(qiáng)大的功能,使得媒體資源的操作變得輕松而高效。從原始的媒體中提取片段,然后將它們巧妙地組合成一個(gè)完整的作品&am…

引言

當(dāng)涉及到音視頻編輯時(shí),媒體資源的提取和組合是至關(guān)重要的環(huán)節(jié)。在iOS平臺(tái)上,AVFoundation框架提供了豐富而強(qiáng)大的功能,使得媒體資源的操作變得輕松而高效。從原始的媒體中提取片段,然后將它們巧妙地組合成一個(gè)完整的作品,這是音視頻編輯過(guò)程中的常見(jiàn)任務(wù)之一。在這篇博客中,我們將深入探討iOS AVFoundation框架中的媒體組合功能,探索其如何為開(kāi)發(fā)者提供豐富的工具和技術(shù),幫助他們實(shí)現(xiàn)創(chuàng)意無(wú)限的音視頻編輯項(xiàng)目。

概述

媒體組合類(lèi)關(guān)系

上圖是關(guān)于媒體功能中的核心類(lèi),以及類(lèi)直接的關(guān)系圖。有關(guān)資源組合的功能就源于AVAsset的子類(lèi)AVComposition。一個(gè)組合就是將多種媒體資源組合成一個(gè)自定義的臨時(shí)排列,再將這個(gè)臨時(shí)排列視為一個(gè)可呈現(xiàn)的獨(dú)立媒體項(xiàng)目。就比如AVAsset對(duì)象,組合相當(dāng)于包含了一個(gè)或多個(gè)給定類(lèi)型的媒體軌道的容器。AVComposition中的軌道都是AVAssetTrack的子類(lèi)AVCompositionTrack。一個(gè)組合軌道本身由一個(gè)或多個(gè)媒體片段組成,由AVCompositionTrackSegment類(lèi)定義,代表這個(gè)組合中的實(shí)際媒體區(qū)域。

組合后的對(duì)象關(guān)系如下:

組合排列

AVComposition和AVCompositionTrack都是不可變對(duì)象,提供對(duì)資源的只讀操作。這些對(duì)象提供了一個(gè)合適的接口讓?xiě)?yīng)用程序的一部分可以進(jìn)行播放或處理。不過(guò),當(dāng)創(chuàng)建自己的組合時(shí),就需要使用AVMutableComposition和AVMutableCompositionTrack所提供的可變子類(lèi)。這些對(duì)象提供的類(lèi)接口需要操作軌道和軌道分段,這樣我們就可以創(chuàng)建所需的臨時(shí)排列了。

基礎(chǔ)方法

這個(gè)基礎(chǔ)的實(shí)例會(huì)將兩個(gè)視頻片段中的前5秒內(nèi)容提取出來(lái),并按照組合視頻軌道的順序進(jìn)行排序。還會(huì)從MP3文件中獎(jiǎng)音頻軌道整合到視頻中,期間會(huì)用到Core Media框架中定義的CMTime數(shù)據(jù)類(lèi)型作為時(shí)間格式,相關(guān)內(nèi)容可以查看其它博客。

        let composition = AVMutableComposition()var videoTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)!var audioTrack = composition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid)

上面的示例創(chuàng)建了一個(gè)AVMutableComposition并用它的addMutableTrackWithMediaType:preferredTrackID:方法添加了兩個(gè)軌道對(duì)象。當(dāng)創(chuàng)建組合軌道時(shí),開(kāi)發(fā)者必須指明它所能支持的媒體類(lèi)型,并給出一個(gè)軌道標(biāo)識(shí)符。設(shè)置preferredTrackID:參數(shù)為CMPersistentTrackID,這是一個(gè)32位的整數(shù)值。雖然我們可以傳遞任意標(biāo)識(shí)符作為參數(shù),這個(gè)標(biāo)識(shí)符在我們之后需要返回軌道時(shí)會(huì)用到,不過(guò)一般來(lái)說(shuō)都是賦給它一個(gè)kCMPersistentTrackID_Invalid常量。這個(gè)有著奇怪名字的常量的意思是我們需要?jiǎng)?chuàng)建一個(gè)合適軌道ID的任務(wù)委托給框架,標(biāo)識(shí)符會(huì)以1..n排列。

現(xiàn)在我們已經(jīng)實(shí)現(xiàn)了一個(gè)組合資源:

組合狀態(tài)

下一步就是將獨(dú)立的媒體片段插入到組合的軌道中。

        //1.創(chuàng)建資源let goldenGateAsset = AVURLAsset(url: URL(string: "1")!, options: nil)let teaGardenAsset = AVURLAsset(url: URL(string: "2")!, options: nil)let soundTrackAsset = AVURLAsset(url: URL(string: "3")!, options: nil)//2.定義插入點(diǎn)var cursorTime = CMTime.zero//3.定義片段時(shí)長(zhǎng)let videoDuration = CMTime(value: 5, timescale: 1)let videoTimeRange = CMTimeRange(start: cursorTime, duration: videoDuration)//4.提取資源中的視頻軌道并插入到組合中的視頻軌道let goldenGateAssetTrack = goldenGateAsset.tracks(withMediaType: .video).first!do {try videoTrack.insertTimeRange(videoTimeRange, of: goldenGateAssetTrack, at: cursorTime)} catch {print("Error inserting time range: \(error)")}//5.調(diào)整插入時(shí)間cursorTime = CMTimeAdd(cursorTime, videoDuration)    //6.提取資源中的視頻軌道并插入到組合中的視頻軌道let teaGardenAssetTrack = teaGardenAsset.tracks(withMediaType: .video).first!do {try videoTrack.insertTimeRange(videoTimeRange, of: teaGardenAssetTrack, at: cursorTime)} catch {print("Error inserting time range: \(error)")}//7.調(diào)整插入時(shí)間和時(shí)長(zhǎng)cursorTime = CMTime.zerolet audioDuration = composition.durationlet audioTimeRange = CMTimeRangeMake(start: cursorTime, duration: audioDuration)//8.提取音頻軌道并插入到組合中的音頻軌道let soundTrackAssetTrack = soundTrackAsset.tracks(withMediaType: .audio).first!do {try audioTrack?.insertTimeRange(audioTimeRange, of: soundTrackAssetTrack, at: cursorTime)} catch {print("Error inserting time range: \(error)")}
  1. 首先我們創(chuàng)建了3個(gè)AVAsset資源,當(dāng)然這里面是模擬創(chuàng)建的,其中前2個(gè)表示視頻,第3個(gè)表示音頻。
  2. 定義了資源的插入時(shí)間點(diǎn)。
  3. 定義每個(gè)視頻片段資源的插入時(shí)長(zhǎng)。
  4. 提取第1個(gè)視頻資源的視頻軌道,默認(rèn)視頻資源只有一個(gè)視頻軌道,插入到組合的視頻軌道。
  5. 調(diào)整下一個(gè)視頻資源的插入時(shí)間為上一個(gè)視頻資源的結(jié)束時(shí)間點(diǎn)。
  6. 同樣獲取第2個(gè)視頻資源的視頻軌道,插入到組合的視頻軌道。
  7. 調(diào)整插入時(shí)間為0,并設(shè)置音頻的時(shí)長(zhǎng)。
  8. 提取音頻資源的音頻軌道并插入到組合的音頻軌道中。

這樣我們的組合就構(gòu)建完成了:

完成的組合

使用示例

下面我們將著色創(chuàng)建一個(gè)視頻編輯的應(yīng)用程序,接下來(lái)的博客也將圍繞這個(gè)程序不斷的添加和完善視頻編輯的功能。

項(xiàng)目介紹

應(yīng)用程序?qū)瑑蓚€(gè)不同的部分,一個(gè)是視頻播放器,我們只需在之前博客的視頻播放器中稍作改動(dòng),一個(gè)是可以選擇媒體和允許媒體排列組合的視頻編輯部分,重點(diǎn)會(huì)放在視頻編輯的部分。

播放器

播放器和視頻播放相關(guān)博客的播放器大致相同,只是原來(lái)傳入播放器的是視頻地址,而現(xiàn)在傳入的需要是一個(gè)完整的AVPlayerItem。因此需要重寫(xiě)了init方法,并且添加另一個(gè)用于替換當(dāng)前播放AVPlayerItem的方法。

init方法:

    override init() {super.init()self.player = AVPlayer(playerItem: playerItem)if let player = player {playerView = PHPlayerView(player: player)}addObserverForPlayerItem()}/// 自定義初始化方法////// - Parameters:///   - playerItem: AVPlayerIteminit(playerItem: AVPlayerItem? = nil) {super.init()self.playerItem = playerItemself.player = AVPlayer(playerItem: playerItem)if let player = player {playerView = PHPlayerView(player: player)}addObserverForPlayerItem()}

替換當(dāng)前AVPlayerItem方法:

    /// AVPlayer的同名方法,替換當(dāng)前播的資源////// - Parameters:///   - playerItem: AVPlayerItemfunc replaceCurrentItem(playerItem:AVPlayerItem?) {guard let player = self.player else { return }self.playerItem = playerItemplayer.replaceCurrentItem(with: playerItem)addObserverForPlayerItem()}/// 為AVPlayerItem添加監(jiān)聽(tīng)func addObserverForPlayerItem() {guard let playerItem = playerItem else { return }playerItem.addObserver(self, forKeyPath: status_keypath, context: &playerItemContext)}

另外我們將播放進(jìn)度的監(jiān)聽(tīng)由原來(lái)的0.5改為了1/60秒,因?yàn)槲覀冃枰褂盟鼇?lái)同步動(dòng)畫(huà),而不僅僅是顯示當(dāng)前時(shí)間。

    /// 監(jiān)聽(tīng)播放進(jìn)度f(wàn)unc addPlayerItemTimeObserver() {guard let player = player else { return }let interval = CMTimeMakeWithSeconds(1/60.0, preferredTimescale: Int32(NSEC_PER_SEC))let queue = DispatchQueue.maintimeObserver = player.addPeriodicTimeObserver(forInterval: interval, queue: queue, using: {[weak self] time inguard let self = self else { return }guard let playerItem = self.playerItem else { return }guard let delegate = self.delegate else { return }let currentTime = CMTimeGetSeconds(time)let duration = CMTimeGetSeconds(playerItem.duration)delegate.setCuttentTime(time: currentTime, duration: duration)})}
編輯器

編輯器由兩部分構(gòu)成,媒體資源選擇器,和媒體資源編輯區(qū)域。

博客的示例項(xiàng)目中,我們只獲取了視頻媒體資源,音頻媒體資源的做法與視頻完全相同,只是傳入的mediaType為audio。

媒體資源選擇器為一個(gè)簡(jiǎn)單的列表,點(diǎn)擊加號(hào)后會(huì)根據(jù)所選擇的媒體資源創(chuàng)建一個(gè)PHMediaItem,PHMediaItem是一個(gè)基類(lèi),它的子類(lèi)又分為PHVideoItem和PHAudioItem,后續(xù)的功能我們也許會(huì)用到PHAudioItem,但目前我們只需要使用PHVideoItem即可。

媒體資源選擇器

媒體資源編輯器就是頁(yè)面除播放器以外的下半部分,有顯示媒體選擇器的按鈕,和控制播放器播放和暫停的按鈕,以及一個(gè)顯示媒體剪輯狀態(tài)的時(shí)間軸區(qū)域。

媒體編輯器

創(chuàng)建組合

我們的核心任務(wù)就是通過(guò)頁(yè)面上的一些操作來(lái)創(chuàng)建一個(gè)媒體組合,首先聲明一個(gè)PHComposition協(xié)議,協(xié)議中定義了兩個(gè)方法分別用來(lái)生成組合的可播放版本和可導(dǎo)出版本。

import UIKit
import AVFoundationprotocol PHComposition {/// 協(xié)議方法-生成AVPlayerItem////// - Returns: 返回一個(gè)可播放的AVPlayerItemfunc makePlayerItem() -> AVPlayerItem?/// 協(xié)議方法-生成AVAssetExportSession////// - Returns: 返回一個(gè)可導(dǎo)出的AVAssetExportSessionfunc makeAssetExportSession() -> AVAssetExportSession?}

創(chuàng)建一個(gè)遵循PHComposition協(xié)議的類(lèi),并提供協(xié)議方法的實(shí)現(xiàn)。

//  負(fù)責(zé)創(chuàng)建 視頻的可播放資源和可導(dǎo)出資源import UIKit
import AVFoundationclass PHBaseComposition: NSObject,PHComposition {//只讀compositionprivate var compostion:AVComposition?//自定義初始化init(compostion: AVComposition? = nil) {self.compostion = compostion}//MARK: PHComposition - 生成 AVPlayerItemfunc makePlayerItem() -> AVPlayerItem? {if let compostion = compostion {let playerItem =  AVPlayerItem(asset: compostion)return playerItem}return nil}//MARK: PHComposition - 生成 AVAssetExportSessionfunc makeAssetExportSession() -> AVAssetExportSession? {return nil}
}

創(chuàng)建一個(gè)組合的構(gòu)建器,同樣我們創(chuàng)建一個(gè)協(xié)議,負(fù)責(zé)來(lái)創(chuàng)建遵循PHComposition協(xié)議的對(duì)象。

import UIKitprotocol PHCompositionBuilder {/// 協(xié)議方法-生成一個(gè)遵循PHComposition協(xié)議的對(duì)象////// - Returns: 返回一個(gè)最新PHComposition協(xié)議的對(duì)象func buildComposition() -> PHComposition?
}

這個(gè)協(xié)議的具體方法由PHBaseCompositionBuilder來(lái)實(shí)現(xiàn),代碼如下。

import UIKit
import AVFoundationclass PHBaseCompositionBuilder: NSObject,PHCompositionBuilder {/// 時(shí)間線(xiàn)var timeLine:PHTimeLine!/// compositionprivate var composition = AVMutableComposition()init(timeLine: PHTimeLine!) {self.timeLine = timeLine}//MARK: PHCompositionBuilder - 生成 PHCompositionfunc buildComposition() -> PHComposition? {addCompositionTrack(mediaType: .video, mediaItems: timeLine.videoItmes)return PHBaseComposition(compostion: self.composition)}/// 私有方法-添加媒體資源軌道/// - Parameters:///   - mediaType: 媒體類(lèi)型///   - mediaItems: 媒體媒體資源數(shù)組/// - Returns: 返回一個(gè)可播放的AVPlayerItemprivate func addCompositionTrack(mediaType:AVMediaType,mediaItems:[PHMediaItem]?) {if PHIsEmpty(array: mediaItems) {return}let trackID = kCMPersistentTrackID_Invalidguard let compositionTrack = composition.addMutableTrack(withMediaType: mediaType, preferredTrackID: trackID) else { return }//設(shè)置起始時(shí)間var cursorTime = CMTime.zeroguard let mediaItems = mediaItems else { return }for item in mediaItems {//這里默認(rèn)時(shí)間都是從0開(kāi)始guard let asset = item.asset else { continue }guard let assetTrack = asset.tracks(withMediaType: mediaType).first  else { continue }do {try compositionTrack.insertTimeRange(item.timeRange, of: assetTrack, at: cursorTime)} catch {print("addCompositionTrack error")}cursorTime = CMTimeAdd(cursorTime, item.timeRange.duration)}}
}
  1. PHBaseCompositionBuilder在初始化的時(shí)候會(huì)默認(rèn)創(chuàng)建一個(gè)AVMutableComposition對(duì)象用于媒體編輯操作。
  2. 獲取timeLine對(duì)象中的所有視頻資源,調(diào)用addCompositionTrack方法進(jìn)行拼接。
  3. addCompositionTrack方法中首先判斷了傳入的資源數(shù)組是否為空。
  4. 當(dāng)媒體資源數(shù)組不為空的時(shí)候,從composition中獲取對(duì)應(yīng)的媒體軌道。
  5. 設(shè)置起始時(shí)間,遍歷媒體資源數(shù)組,從每個(gè)資源中獲取對(duì)應(yīng)的媒體軌道并添加到組合媒體軌道中。
  6. 修改下一個(gè)媒體資源的插入起始時(shí)間。

實(shí)現(xiàn)播放組合媒體

選擇媒體資源

點(diǎn)擊頁(yè)面上的加號(hào)按鈕,顯示媒體選擇列表,點(diǎn)擊列表后會(huì)將選擇的媒體資源創(chuàng)建為PHMediaItem并添加到當(dāng)前的timeLine對(duì)應(yīng)的資源數(shù)組下。

    //MARK: 顯示選擇視頻視圖@objc func showItemPickerView() {let resourcePickerView = PHResourcePickerView(frame: CGRect(x: 0, y: UIScreen.main.bounds.height * 0.5, width: 150.0, height: 200.0))resourcePickerView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 1.0)resourcePickerView.layer.masksToBounds = trueresourcePickerView.layer.cornerRadius = 5.0resourcePickerView.layer.borderColor = UIColor.white.cgColorresourcePickerView.layer.borderWidth = 1.0resourcePickerView.showDialog()resourcePickerView.addMediaItemBlock = { [weak self] mediaItem inguard let self = self else { return }if var videoItmes = timeLine.videoItmes {videoItmes.append(mediaItem as! PHVideoItem)timeLine.videoItmes = videoItmes} else {var videoItmes = [PHVideoItem]()videoItmes.append(mediaItem as! PHVideoItem)timeLine.videoItmes = videoItmes}self.collectionView?.reloadData()self.needReplay = true}}
點(diǎn)擊播放按鈕

點(diǎn)擊播放按鈕后判斷是否有可播放資源,再進(jìn)行播放。播放分為兩種情況,從頭開(kāi)始播放和暫停后的繼續(xù)播放。

    //MARK: 播放按鈕點(diǎn)擊@objc func playerButtonOnlick(button:UIButton) {if PHIsEmpty(array: timeLine.videoItmes) {playerButton.isSelected = falsereturn}button.isSelected = !button.isSelected//回調(diào)guard let delegate = self.delegate else { return }if button.isSelected {if needReplay {player()needReplay = false} else {delegate.play()}} else {delegate.pause()}}func player() {guard let delegate = self.delegate else { return }let compositionBuilder = PHBaseCompositionBuilder(timeLine: timeLine)let composition = compositionBuilder.buildComposition()let playerItem = composition?.makePlayerItem()delegate.replaceCurrentItem(playerItem: playerItem)}
同步播放進(jìn)度

PHEditorView視頻編輯器遵循了PHControlDelegate協(xié)議,這里我們只關(guān)注setCuttentTime和playbackComplete方法。

setCuttentTime方法用來(lái)同步編輯器時(shí)間軸的進(jìn)度。

playbackComplete用來(lái)同步播放按鈕的狀態(tài)。

extension PHEditorView:PHControlDelegate{func playpause(currentTime: TimeInterval) {}func playstart(duration: TimeInterval) {}func setCuttentTime(time: TimeInterval, duration: TimeInterval) {let origin_offsetX = -UIScreen.main.bounds.width * 0.5self.collectionView?.contentOffset = CGPointMake(origin_offsetX + time * item_size.width, 0.0)}func playbackComplete() {self.playerButton.isSelected = false}}

結(jié)語(yǔ)

在示例項(xiàng)目中,我們僅僅涉及了視頻媒體資源,并默認(rèn)這些資源都是單軌道的。然而,在實(shí)際的應(yīng)用開(kāi)發(fā)中,我們可能會(huì)面對(duì)更加復(fù)雜的情況,涉及到多種類(lèi)型的媒體資源,以及多軌道的組合。iOS AVFoundation框架為我們提供了強(qiáng)大的工具和靈活的接口,讓我們能夠處理各種各樣的媒體資源,并將它們巧妙地組合成為精彩紛呈的作品。通過(guò)深入理解和靈活運(yùn)用AVFoundation框架,我們可以實(shí)現(xiàn)更加復(fù)雜和令人驚嘆的音視頻編輯應(yīng)用,為用戶(hù)帶來(lái)全新的體驗(yàn)和享受。在今后的開(kāi)發(fā)過(guò)程中,讓我們繼續(xù)探索和挖掘AVFoundation框架的潛力,創(chuàng)造出更加優(yōu)秀和創(chuàng)新的音視頻編輯應(yīng)用!

項(xiàng)目地址:PHEditorPlayer: AV Foundation 音視頻編輯

http://m.risenshineclean.com/news/64605.html

相關(guān)文章:

  • 做網(wǎng)站用什么語(yǔ)言好廣告聯(lián)盟app下載
  • 南昌新建網(wǎng)站建設(shè)如何讓百度快速收錄網(wǎng)站文章
  • 做網(wǎng)絡(luò)推廣的網(wǎng)站有哪些如何做電商 個(gè)人
  • 包頭正規(guī)旅游網(wǎng)站開(kāi)發(fā)哪家好aso關(guān)鍵詞排名優(yōu)化是什么
  • 做網(wǎng)站界面尺寸是多少網(wǎng)上營(yíng)銷(xiāo)的平臺(tái)有哪些
  • wordpress sparklingseo視頻教程百度云
  • 南京房產(chǎn)網(wǎng)站建設(shè)手機(jī)如何做網(wǎng)站
  • 保定市做網(wǎng)站的公司網(wǎng)絡(luò)策劃營(yíng)銷(xiāo)
  • wordpress怎么切換成中文的seo服務(wù)顧問(wèn)
  • 網(wǎng)站公司不給ftp怎么免費(fèi)制作網(wǎng)頁(yè)
  • 做網(wǎng)站是什么優(yōu)化設(shè)計(jì)官方電子版
  • 網(wǎng)站與域名的關(guān)系廣告免費(fèi)發(fā)布信息平臺(tái)
  • 綿陽(yáng)政府網(wǎng)站建設(shè)國(guó)內(nèi)建站平臺(tái)有哪些
  • 動(dòng)漫谷網(wǎng)站建設(shè)策劃書(shū)網(wǎng)站推廣的平臺(tái)
  • 太平洋在線(xiàn)企業(yè)建站系統(tǒng)華聯(lián)股份股票
  • 做類(lèi)似3d溜溜的網(wǎng)站網(wǎng)上怎么注冊(cè)公司免費(fèi)的
  • 投注網(wǎng)站建設(shè)需要優(yōu)書(shū)網(wǎng)
  • 在網(wǎng)站怎么做收款二維碼短信營(yíng)銷(xiāo)
  • 泰州做直銷(xiāo)會(huì)員結(jié)算管理網(wǎng)站公司網(wǎng)站如何推廣
  • wordpress 主題庫(kù)安徽seo人員
  • ??诰W(wǎng)站建設(shè)公司哪家好抖音seo優(yōu)化
  • 圖書(shū)館網(wǎng)站建設(shè)情況說(shuō)明網(wǎng)站排名優(yōu)化多少錢(qián)
  • 做網(wǎng)站避免上當(dāng)文案短句干凈治愈
  • 手機(jī)網(wǎng)站注冊(cè)頁(yè)面百度一下你就知道移動(dòng)首頁(yè)
  • 阿里云輕云服務(wù)器可以放多個(gè)網(wǎng)站啊怎么做做網(wǎng)站需要準(zhǔn)備什么
  • dreamweaver最新版本引擎優(yōu)化是什么意思
  • 響應(yīng)式建站工具58同城發(fā)布免費(fèi)廣告
  • 公司名logo設(shè)計(jì)圖片seow是什么意思
  • 設(shè)計(jì)公司給公司做網(wǎng)站用了方正字體app開(kāi)發(fā)教程
  • 網(wǎng)站做app的軟件叫什么seo快速優(yōu)化排名