轉(zhuǎn)載:https://blog.csdn.net/leonpengweicn/article/details/38021785
項目要求根據(jù)服務(wù)器返回的視頻和秒數(shù),生成該視頻的預(yù)覽圖偷卧。
網(wǎng)上一搜關(guān)鍵詞 “iOS 視頻 幀” 結(jié)果都是:iOS如何獲取視頻的第一幀冈绊。
但是如果我不想要第一幀,要第s秒的第x幀怎么辦异剥?
先貼如何獲取第一幀的代碼:
123456789101112131415-?(UIImage*)?getVideoPreViewImage?{?AVURLAsset?*asset?=?[[AVURLAsset?alloc]?initWithURL:videoPath?options:nil];?AVAssetImageGenerator?*gen?=?[[AVAssetImageGenerator?alloc]?initWithAsset:asset];?[asset?release];?gen.appliesPreferredTrackTransform?=?YES;?CMTime?time?=?CMTimeMakeWithSeconds(0.0,?600);?NSError?*error?=?nil;?CMTime?actualTime;?CGImageRef?image?=?[gen?copyCGImageAtTime:time?actualTime:&actualTime?error:&error];?UIImage?*img?=?[[[UIImage?alloc]?initWithCGImage:image]?autorelease];?CGImageRelease(image);?[gen?release];?return?img;?}
這是很不求甚解的做法,有好多問題都沒有考慮到絮重。
一般來說冤寿,如果我們打算求第x秒 看如上代碼,想都不用想的就去把
1CMTime?time?=?CMTimeMakeWithSeconds(0.0,?600);
改成想要的時間了青伤,但是督怜,跑一下就會發(fā)現(xiàn)差強人意。
為什么呢狠角?
我們先要說CMTime 是什么東西号杠。
CMTime 是一個用來描述視頻時間的結(jié)構(gòu)體。
他有兩個構(gòu)造函數(shù): * CMTimeMake * CMTimeMakeWithSeconds
這兩個的區(qū)別是 * CMTimeMake(a,b) a當(dāng)前第幾幀, b每秒鐘多少幀.當(dāng)前播放時間a/b * CMTimeMakeWithSeconds(a,b) a當(dāng)前時間,b每秒鐘多少幀.
我們引用例子來說明它:
CMTimeMakeWithSeconds
1234Float64?seconds?=?5;?int32_t?preferredTimeScale?=?600;?CMTime?inTime?=?CMTimeMakeWithSeconds(seconds,?preferredTimeScale);?CMTimeShow(inTime);
OUTPUT: {3000/600 = 5.000}
代表當(dāng)前時間為5s丰歌,視頻一共有3000幀姨蟋,一秒鐘600幀
CMTimeMake
1234int64_t?value?=?10000;?int32_t?preferredTimeScale?=?600;?CMTime?inTime?=?CMTimeMake(value,?preferredTimeScale);?CMTimeShow(inTime);
OUTPUT: {10000/600 = 16.667}
代表時間為16.667s, 視頻一共1000幀,每秒600幀
其實立帖,在我們這里眼溶,我們關(guān)心的只有最后那個總時間。 換句話說晓勇,我們把那個(0, 600)換成(x, 600) 是沒問題的… = =!
那么為什么堂飞,效果差了這么多呢? 我們可以把
123CGImageRef?image?=?[gen?copyCGImageAtTime:time?actualTime:&actualTime?error:&error];
返回的 actualTime 輸出一下
1CMTimeShow(actualTime)
就會發(fā)現(xiàn)時間差的很遠(yuǎn)宵蕉。 這是為什么呢酝静。
首先他的 actualTime 使用的 fps * 1000 當(dāng)每秒的幀率。 順路普及下fps的獲取方法
1float?fps?=?[[[asset?tracksWithMediaType:AVMediaTypeVideo]?objectAtIndex:0]?nominalFrameRate];
然后我們來思考為什么要有 requestTime 和 actualTime 呢羡玛? 開始我對這個api 很困惑:為什么我request的時間 不等于 actual
后來查了一下文檔别智。
當(dāng)你想要一個時間點的某一幀的時候,他會在一個范圍內(nèi)找稼稿,如果有緩存薄榛,或者有在索引內(nèi)的關(guān)鍵幀讳窟,就直接返回,從而優(yōu)化性能敞恋。
這個定義范圍的API就是 requestedTimeToleranceAfter 和 requestedTimeToleranceBefore
如果我們要精確時間丽啡,那么只需要
12gen.requestedTimeToleranceAfter?=?kCMTimeZero;?gen.requestedTimeToleranceBefore?=?kCMTimeZero;