(二十二)深入了解AVFoundation-編輯:視頻變速功能-實戰在Demo中實現視頻變速

一. 引言

視頻變速(Speed Ramp)是視頻編輯中最常見的特效之一:

  • 慢動作(Slow Motion):強調細節,讓觀眾捕捉到肉眼難以察覺的瞬間;
  • 快動作(Fast Motion):壓縮時長,強化節奏,常用于 vlog、綜藝片段。

在 AVFoundation 中,視頻變速的本質是?對音視頻軌道的時間線進行重新映射。通過調整時間范圍(CMTimeRange)與目標時長(toDuration),即可讓視頻和音頻實現同步的快進或慢放效果。

本文將通過一個完整的?Demo 實戰,展示如何在 iOS 中使用 AVFoundation 實現視頻的變速處理,涵蓋從模型設計到合成器構建的完整流程。

二. 核心思路回顧

要實現變速,必須同時處理?視頻軌道?與?音頻軌道,以保證二者的同步:

1. 視頻軌道

  • 借助?AVMutableVideoCompositionInstruction?和?AVMutableVideoCompositionLayerInstruction,保證變速后的視頻能夠正常渲染。
  • 關鍵在于:

  1. videoTrack.scaleTimeRange():調整視頻的時間范圍到新的時長;
  2. instruction.timeRange:指定變速后的可見區間;
  3. videoComposition:控制整體渲染(幀率、尺寸等)。

2. 音頻軌道

  • 音頻不涉及渲染和圖層,處理方式更簡單。
  • 只需調用?audioTrack.scaleTimeRange(),將某一時間段的音頻拉伸或壓縮到新的時長,從而實現變速效果。

三. Demo 架構設計

在本次 Demo 中,我們延續前文的?時間線(TimeLine)驅動合成?的設計思路。通過定義模型與 Builder,將變速邏輯解耦,使其可以靈活擴展。

1. PHSpeedItem —— 變速模型

class PHSpeedItem: PHMediaItem {/// 變速的倍速var scaleSpeed: Float = 2.0
}

PHSpeedItem?繼承自?PHMediaItem,用于描述一段變速操作。它包含了:

  • startTime:變速的起始時間點;
  • timeRange:變速的持續時長;
  • scaleSpeed:變速的倍速(例如?2.0?表示慢兩倍,0.5?表示快兩倍)。

這樣,我們就能精確地定義:從視頻的某個時間點開始,持續多少秒,需要以什么速度播放

2. PHTimeLine —— 時間線模型

class PHTimeLine: NSObject {var videoItmes = [PHVideoItem]()var audioItems = [PHAudioItem]()var musicItems = [PHMusicItem]()var maskItem = PHMaskItem(text: "PHVideoExample",image: UIImage(named: "mask1"),bounds: CGRect(x: 0, y: 0, width: 1280, height: 720))var seepItems = [PHSpeedItem]()
}

PHTimeLine?是整個編輯流程的核心。它聚合了:

  • 視頻軌道(videoItems)
  • 音頻軌道(audioItems)
  • 背景音樂(musicItems)
  • 水印(maskItem)
  • 變速效果(seepItems)

通過在?buildTimeLine?時一次性構建這些屬性,后續的 CompositionBuilder 只需要解析?timeLine?即可。

3. PHSpeedCompositionBuilder —— 合成器

class PHSpeedCompositionBuilder: PHComositionBuilder {private let composition = AVMutableComposition()private let timeLine: PHTimeLineprivate var videoComposition: AVMutableVideoCompositionprivate var audioMix: AVAudioMix?init(timeLine: PHTimeLine) {self.timeLine = timeLineself.videoComposition = AVMutableVideoComposition()videoComposition.frameDuration = CMTime(value: 1, timescale: 30)videoComposition.renderSize = CGSize(width: 1280, height: 720)}func buildComposition() -> (any PHComposition)? {// 添加視頻 & 音頻軌道guard let videoTrack = self.addTrack(with: .video, mediaItems: self.timeLine.videoItmes),let audioTrack = self.addTrack(with: .audio, mediaItems: self.timeLine.audioItems) else {return nil}// 遍歷變速片段for seepItem in timeLine.seepItems {self.applySpeed(to: videoTrack,audioTrack: audioTrack,startTime: seepItem.startTime,duration: seepItem.timeRange.duration,scaleSpeed: seepItem.scaleSpeed)}return PHSpeedComposition(composition: composition,videoComposition: videoComposition,audioMix: audioMix)}
}

在?PHSpeedCompositionBuilder?中,我們做了三件核心的事:

  • 初始化渲染配置:幀率(30fps)、渲染尺寸(1280x720)。
  • 加載軌道:將視頻、音頻素材插入到?AVMutableComposition。
  • 應用變速:遍歷?seepItems,對每個變速區間調用?applySpeed,從而實現快動作/慢動作。

四. 變速核心實現

視頻變速的核心邏輯集中在?applySpeed?方法中。它的作用是:

  • 調整?視頻軌道?的播放時長,實現快動作或慢動作;
  • 調整?音頻軌道?的播放時長,保持與視頻同步;
  • 更新?視頻合成指令,確保渲染時長正確。

來看代碼:

/// 應用變速效果
/// - Parameters:
///   - videoTrack: 視頻軌道
///   - audioTrack: 音頻軌道
///   - startTime: 變速開始時間
///   - duration: 變速持續時間
///   - scaleSpeed: 變速比例,例如 2.0 表示慢動作,0.5 表示快動作
private func applySpeed(to videoTrack: AVMutableCompositionTrack,audioTrack: AVMutableCompositionTrack,startTime: CMTime,duration: CMTime,scaleSpeed: Float) {let instruction = AVMutableVideoCompositionInstruction()// 計算變速后的時長let scaledDuration = CMTimeMultiplyByFloat64(duration, multiplier: Float64(scaleSpeed))let totalDuration = CMTimeSubtract(videoTrack.timeRange.duration, duration) + scaledDuration// 設置渲染時長instruction.timeRange = CMTimeRange(start: .zero, duration: totalDuration)let layerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videoTrack)instruction.layerInstructions = [layerInstruction]videoComposition.instructions.append(instruction)// 視頻變速:修改時間區間videoTrack.scaleTimeRange(CMTimeRange(start: startTime, duration: duration),toDuration: scaledDuration)// 音頻變速:保持同步let audioDuration = CMTimeMultiplyByFloat64(duration, multiplier: Float64(scaleSpeed))audioTrack.scaleTimeRange(CMTimeRange(start: startTime, duration: duration),toDuration: audioDuration)print("視頻軌道總時長: \(CMTimeGetSeconds(videoTrack.timeRange.duration)) 秒")
}

1. 核心計算公式

let scaledDuration = duration * scaleSpeed
let totalDuration = (原始總時長 - duration) + scaledDuration
  • scaledDuration:表示?變速區間在新速度下的時長
  • totalDuration:表示?整條視頻在變速后新的總時長

👉 這一步非常關鍵。如果直接把?instruction.timeRange?設置為?scaledDuration,就會出現畫面丟失的問題。必須用?totalDuration?來覆蓋渲染范圍,確保整個視頻能正常播放。

2. 視頻軌道處理

videoTrack.scaleTimeRange(CMTimeRange(start: startTime, duration: duration),toDuration: scaledDuration)

這一步會將?startTime ~ duration?的視頻片段?拉伸/壓縮?到新的時長,實現快/慢動作。

  • scaleSpeed = 2.0?→ 時長 *2 → 慢動作;
  • scaleSpeed = 0.5?→ 時長 *0.5 → 快動作。

3. 音頻軌道處理

audioTrack.scaleTimeRange(CMTimeRange(start: startTime, duration: duration),toDuration: audioDuration)

音頻的邏輯與視頻相同,只是?不需要渲染指令。通過調整?timeRange,即可保證音視頻同步。

4. 視頻 vs 音頻 的區別

  • 視頻軌道:必須結合?AVMutableVideoCompositionInstruction?來更新渲染時長,否則會丟畫面。
  • 音頻軌道:只需調整?scaleTimeRange?即可,不需要合成指令。

五. 實戰效果驗證

在前面,我們已經完成了?PHSpeedCompositionBuilder?的核心實現。現在,只需要在 Demo 中構建一個?PHTimeLine,并添加?PHSpeedItem,就能快速驗證效果。

1. 構建 TimeLine

// 構建帶變速的時間線
let timeLine = PHTimeLine.buildTimeLine(with: items)// 假設我們在第 2 秒開始,持續 3 秒,并讓視頻變慢 2 倍
let speedItem = PHSpeedItem()
speedItem.startTime = CMTime(seconds: 2, preferredTimescale: 600)
speedItem.timeRange = CMTimeRange(start: speedItem.startTime,duration: CMTime(seconds: 3, preferredTimescale: 600))
speedItem.scaleSpeed = 2.0timeLine.seepItems = [speedItem]

2. 構建 Composition

let builder = PHSpeedCompositionBuilder(timeLine: timeLine)
guard let composition = builder.buildComposition() else {print("? 構建 Composition 失敗")return
}

3. 播放或導出

如果原始視頻是?15 秒

  • 在第?2 ~ 5 秒的區間變慢 2 倍 → 該區間時長變為 6 秒;
  • 總時長 =?15 - 3 + 6 = 18 秒;
  • 播放時可以清晰看到?2s → 5s 片段被拉長

六. 結語

在本文中,我們完整實現了?視頻變速處理,并通過 Demo 驗證了其效果。核心思想是:

  • 視頻軌道:通過?scaleTimeRange?拉伸或壓縮片段時長,并結合?AVMutableVideoCompositionInstruction?和?AVMutableVideoCompositionLayerInstruction?確保畫面渲染正確。
  • 音頻軌道:相比視頻更為簡單,僅需調整?timeRange?即可保證與視頻保持同步。

在實戰中,我們實現了?局部變速?的支持,例如在第 2 秒 ~ 5 秒區間執行 2 倍慢動作,總時長相應調整為 18 秒。通過這種方式,我們不僅能夠處理?整體變速,也能靈活地在指定區間內應用變速效果。

不過,本篇案例依然有一個簡化假設:從一個起點到一個終點單段變速。而在實際開發中,用戶往往希望在多個不同的區間應用不同的變速效果(例如“先快 → 再慢 → 再恢復正常”)。這會帶來更復雜的軌道管理、區間拼接和指令疊加問題。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/96875.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/96875.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/96875.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MCP零基礎學習(7)|實戰指南:構建論文分析智能體

在之前的教程中,我們已經介紹了 MCP(Model Context Protocol)的基本概念及其核心組件。在本篇教程中,我們將通過一個實際案例,演示如何運用 MCP 構建一個能夠分析學術論文的智能體。這個智能體將具備讀取 PDF 文件、提…

Unity URP半透明物體自身交疊解決方案

前言 在 Unity 的通用渲染管線(URP)中,處理半透明物體的自身交疊是一個常見挑戰。當半透明物體(如玻璃、水或透明材質)的某些部分相互重疊時,可能會出現渲染順序問題,導致視覺瑕疵。 對惹&…

哈希算法入門:深入淺出講明白HASH哈希算法

一、先搞懂:哈希算法到底是 “啥玩意兒”?咱們先別碰復雜概念,從你每天都會遇到的事說起 —— 你會發現,“哈希思維” 其實早就藏在生活里了。(一)生活中的 “哈希例子”:給東西 “貼標簽、找位…

Vuex 和 Pinia 各自的優點

核心總結(一句話概括) Vuex:Vue 官方曾經的狀態管理標準解決方案,成熟穩定,概念清晰,但語法稍顯冗長。Pinia:Vue 官方推薦的新一代狀態管理庫,API 設計極其簡潔,完美支持…

幾種方式實現文件自動上傳到服務器共享文件夾

文章目錄一、方案核心邏輯二、詳細實現步驟(以Windows系統為例)1. 確認服務器共享文件夾的“訪問權限”(前提)2. 選擇“傳輸觸發方式”(按需求選實時/周期)(1)周期傳輸(如…

Milvus介紹及多模態檢索實踐

1、核心組件 1.1 Collection (集合) 可以用一個圖書館的比喻來理解 Collection: Collection (集合): 相當于一個圖書館,是所有數據的頂層容器。一個 Collection 可以包含多個 Partition,每個 Partition 可以包含多個 Entity。 Partition (分區…

第二十三天-LCD液晶顯示實驗

一、LCD結構體定義LCD為LCD_TypeDef類型的指針,指向0x6C000000的地址空間(bank1分區4的地址范圍)。為什么需要并上0x000007FE呢?因為雖然驅動SRAM的時序和16位8080接口時序(驅動LCD時序)很像,但…

SQL性能調優

MySQL出現性能差的原因有哪些? 可能是 SOL查詢使用了全表掃描,也可能是查詢語句過于復雜,如多表 IOIN 或嵌套子查詢。 也有可能是單表數據量過大。 通常情況下,添加索引就能解決大部分性能問題。對于一些熱點數據,還可以通過增加…

dapo:開源大規模llm強化學習系統的突破與實現

本文由「大千AI助手」原創發布,專注用真話講AI,回歸技術本質。拒絕神話或妖魔化。搜索「大千AI助手」關注我,一起撕掉過度包裝,學習真實的AI技術! ? 1. dapo概述:開源llm強化學習系統的重要突破 dapo&…

【車載開發系列】ParaSoft集成測試環境配置(五)

【車載開發系列】ParaSoft集成測試環境配置(五) 【車載開發系列】ParaSoft集成測試環境配置(五) 【車載開發系列】ParaSoft集成測試環境配置(五) 一. 剝離硬件環境的設置 二. 靈活使用編譯開關 三. 導入修改后的bdf文件 四. 自動生成底層樁函數 五. 開始跑集成測試用例 六…

大模型(一)什么是 MCP?如何使用 Charry Studio 集成 MCP?

目錄一、什么是 MCP?1.1 🤔 開始之前的思考1.2 MCP 的定義1.3 MCP 結構二、MCP 的使用2.1 uv 的安裝2.2 MCP 廣場2.3 MCP 的配置2.4 MCP 的依賴安裝2.5 Charry Studio2.6 測試結果背景: MCP 這個概念大概是 2025 年上半年火起來的&#xff0c…

源碼導航頁

一、Python捕捉動作發送到Unity驅動模型跟著動(獲取源碼) 二、AI輸入法源碼(獲取源碼) 三、Java企業級后臺管理系統-登錄授權角色菜單(獲取源碼) 四、Jetson實現純視覺導航(獲取源碼&#xff09…

HTTP/2 性能提升的核心原因

一、協議架構優化??二進制分幀(Binary Framing)?HTTP/2 將傳統文本格式的報文(如請求頭、數據體)拆分為獨立的二進制幀(Frame),每個幀包含流標識符(Stream ID)&#x…

vulnhub-billu_b0x靶機滲透

一、靶場詳情 Billu_b0x 是 Vulnhub 上的經典中等難度靶機,主要考察從信息收集到提權的完整滲透流程:先通過端口和目錄掃描發現網站入口,利用 SQL 注入或文件包含進入后臺并上傳 WebShell,再通過反彈 Shell 獲取低權限用戶&#…

C# 相機內存復用(減少圖像采集耗時)以及行數復用

背景我們在做圖像處理時,都會對一些相機的SDK進行開發完成圖像采集的操作,為后續圖像處理做準備。本文主要的目的是降低圖像采集的耗時,應用在一些高速檢測的場景下。利用循環隊列內存復用的方式,去掉或者減少新建內存的時間。線掃…

MTK Linux DRM分析(十三)- Mediatek KMS實現mtk_drm_drv.c(Part.1)

一、簡介 MediaTek (MTK) 的DRM驅動(基于mtk_drm_drv.c)是為MediaTek SoC(如MT6985、MT6895等)設計的顯示子系統(Display Subsystem)驅動程序。它實現了Linux DRM/KMS框架,支持多CRTC、多平面(plane)、連接器(connector)和編碼器(encoder)的顯示管道。驅動處理硬…

Wireshark筆記-DHCP流程與數據包解析

背景DHCP從大學上網絡課時就開始知道了,當時只知道,能讓計算機上網,要不就靜態配IP,要不就DHCP獲取,就能上網。2021年時,畢業好幾年了,想學習下網絡知識,就準備考一個軟考網工。按要…

Coze用戶賬號設置修改用戶頭像-前端源碼

概述 Coze Studio的用戶頭像修改功能是用戶賬號設置中的重要組成部分,允許用戶上傳和更新個人頭像。本文將深入分析該功能的前端實現,包括組件架構、文件上傳處理、API設計和用戶體驗優化等方面。 技術架構 整體架構設計 Coze Studio采用現代化的前端架構…

新手Github提交PR(Pull requests)詳細教程

一、什么是Pull requests? Pull Requests(PR)是代碼協作平臺(如 GitHub、GitLab 等)中的一種功能,用于提議將某分支的代碼變更合并到另一個分支(通常是主分支)。它允許開發者在合并…

本地通過跳板機連接無公網IP的內網服務器

本地環境:SSH client 堡壘機:有公網IP,有連接內網服務器的秘鑰 SSH配置: Host jmsHostName [堡壘機的公網IP]Port 22User rootIdentityFile ~/.ssh/id_rsaHost appHostName 10.0.0.14Port 22User rootIdentityFile ~/.ssh/svc-p…