AVPlayer常用

這次主要是總結(jié)和記錄下視頻播放遇到的坑舰讹,視頻播放采用的是AVPlayer這個控件阳藻,語法大致如下:

NSURL*url=[NSURLfileURLWithPath:@"視頻地址"];AVPlayerItem*playerItem=[AVPlayerItemplayerItemWithURL:url];self.player=[AVPlayerplayerWithPlayerItem:playerItem];[self.playeraddObserver:selfforKeyPath:@"status"options:NSKeyValueObservingOptionNewcontext:nil];self.player.actionAtItemEnd=AVPlayerActionAtItemEndNone;self.playerLayer=[AVPlayerLayerplayerLayerWithPlayer:self.player];self.playerLayer.videoGravity=AVLayerVideoGravityResizeAspect;self.playerLayer.frame=self.view.bounds;[self.view.layeraddSublayer:self.playerLayer];

這里要監(jiān)聽一下AVPlayer的status屬性,當status的狀態(tài)變?yōu)锳VPlayerStatusReadyToPlay時,說明視頻就可以播放了,此時我們調(diào)用[self.player play];就好了。

如果是AVPlayerStatusFailed說明視頻加載失敗豺裆,這時可以通過self.player.error.description屬性來找出具體的原因。

當status變?yōu)锳VPlayerStatusReadyToPlay后号显,我們調(diào)用play方法真的就能保證視頻正常播放嗎臭猜?

眾所周知,AVPlayer支持的視頻押蚤、音頻格式非常廣泛蔑歌,拋開那些無法正常編解碼的情況,在某些情況下其可能就是無法正常播放揽碘。

AVPlayer在進行播放時次屠,會預先解碼一些內(nèi)容,而此時如果我們的App使用CPU過多雳刺,I/O讀寫過多時劫灶,有可能導致視頻播放聲/畫不同步,這點尤其在iPhone4上面表現(xiàn)更為明顯掖桦。

而如果是發(fā)生在AVPlayer初始化解碼視頻的時候本昏,有可能導致視頻直接無法播放,這時枪汪,我們再調(diào)用play或者seekToTime:方法都無法正常播放涌穆。

建議不要在CPU或者I/O很頻繁的情況下使用AVPlayer,例如剛登錄App加載各種數(shù)據(jù)的情況下,可以等App預熱以后再使用料饥。

當rate屬性的值大于0后,真的就在播放視頻了嗎朱监?

答案是否定的岸啡,當發(fā)生上面所講的情況時,我打印了當前的rate情況赫编,是大于0的巡蘸,但是頁面上顯示的情況卻還是什么也沒有奋隶。

有時候我們?nèi)绻胍谝曨l一播放的時候去做一些事情,例如設(shè)置一下播放器的背景色悦荒,如果我們僅僅是監(jiān)聽這個rate可能無法100%保證有效唯欣,而如果我們真的要監(jiān)聽這種情況的話,有一個取巧的方法

id_timerObserver=[self.playeraddBoundaryTimeObserverForTimes:@[[NSValuevalueWithCMTime:CMTimeMake(1,30)]]queue:dispatch_get_main_queue()usingBlock:^{//do something}];

另外如果不需要監(jiān)聽播放進度的時候可以調(diào)

[self.playerremoveTimeObserver:_timerObserver];

AVPlayer前后臺播放的那些問題

當我們切換到后臺后搬味,這時AVPlayer通常會自動暫停境氢,當然如果設(shè)置了后臺播放音頻的話,是可以在后臺繼續(xù)播放聲音的碰纬,正如蘋果自己的WWDC這個App一樣萍聊。

如果我們想要在程序切回來前臺繼續(xù)播放的話,我們需要監(jiān)聽兩個通知

[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(appBecomeActive:)name:UIApplicationDidBecomeActiveNotificationobject:nil];[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(appWillResignActive:)name:UIApplicationWillResignActiveNotificationobject:nil];

先在appWillResignActive:方法中記錄當前播放的時間CMTime

-(void)appWillResignActive:(NSNotification*)notification{if(self.player){[self.playerpause];self.time=self.player.currentTime;}}

等到切回前臺的時候再繼續(xù)播放

@try{[self.playerseekToTime:self.timetoleranceBefore:kCMTimeZerotoleranceAfter:kCMTimeZerocompletionHandler:^(BOOLfinished){if(finished){[self.playerplay];}}];}@catch(NSException*exception){[self.playerplay];}

這里如果我們只是調(diào)用[self.player play];悦析,則在繼續(xù)播放的時候可能會后退一定的時間寿桨,而如果我們想要精準地繼續(xù)播放則需要下面這個方法,toleranceBefore:與toleranceAfter:均設(shè)置成kCMTimeZero.

[self.playerseekToTime:self.timetoleranceBefore:kCMTimeZerotoleranceAfter:kCMTimeZerocompletionHandler:

當然這個方法也會有一些問題强戴,例如在剛啟動播放的時候亭螟,以及在播放到最后一幀的時候,首先是其有可能會出現(xiàn)異常并crash.

所以我們用了@try@catch來捕獲這個異常骑歹,當出現(xiàn)異常的時候直接調(diào)用play讓播放器自己決定播放的進度预烙。

另外一個問題是其在最后一幀的時候有可能會白屏,因為最后一幀的內(nèi)容有可能是空的陵刹,或者其它一些特殊的中間情況默伍,所以在視頻快要播放結(jié)束的時候建議,直接使用play方法衰琐。

音頻通道的搶占引起的無法播放視頻問題

iOS系統(tǒng)有如下幾種聲音播放模式

enum{kAudioSessionCategory_AmbientSound='ambi',kAudioSessionCategory_SoloAmbientSound='solo',kAudioSessionCategory_MediaPlayback='medi',kAudioSessionCategory_RecordAudio='reca',kAudioSessionCategory_PlayAndRecord='plar',kAudioSessionCategory_AudioProcessing='proc'};

App運行的時候通常只能使用一種聲音播放模式也糊,而如果我們在錄制視頻或者錄制聲音的時候,把模式設(shè)置成了kAudioSessionCategory_RecordAudio,這個時候如果我們使用AVPlayer播放視頻羡宙,可能就無法播放視頻狸剃。

這個時候我們需要把模式切換成kAudioSessionCategory_MediaPlayback或者其它合適的模式,切換模式的代碼如下:

UInt32category=kAudioSessionCategory_MediaPlayback;UInt32size=sizeof(category);AudioSessionGetProperty(kAudioSessionProperty_AudioCategory,&size,&category);if(category!=kAudioSessionCategory_MediaPlayback){category=kAudioSessionCategory_MediaPlayback;AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,size,&category);QLog_Event(MODULE_IMPB_RICHMEDIA,"change route category to media play back.");}

關(guān)于上面這幾個模式的作用這兒有比較詳細的解釋,如果我們需要在用戶靜音時狗热,不播放聲音钞馁,可以選擇kAudioSessionCategory_SoloAmbientSound.

其它App播放聲音打斷問題

如果用戶當時在后臺聽音樂,如QQ音樂匿刮,或者喜馬拉雅這些App僧凰,這個時候播放視頻后,其會被我們打斷熟丸,當我們不再播放視頻的時候训措,自然需要繼續(xù)這些后臺聲音的播放。

首先,我們需要先向設(shè)備注冊激活聲音打斷AudioSessionSetActive(YES);,當然我們也可以通過

[AVAudioSession sharedInstance].otherAudioPlaying;這個方法來判斷還有沒有其它業(yè)務的聲音在播放绩鸣。

當我們播放完視頻后怀大,需要恢復其它業(yè)務或App的聲音,這時我們可以調(diào)用如下方法:

OSStatusret=AudioSessionSetActiveWithFlags(NO,kAudioSessionSetActiveFlag_NotifyOthersOnDeactivation);

其它的坑

1呀闻、在用戶插入和拔出耳機時化借,有可能也會導致視頻暫停。

其實插捡多、拔耳機是屬性改變聲音輸出設(shè)備的一種方式蓖康,其次還有修改為聽筒、揚聲器局服,或者其它藍牙設(shè)備輸出钓瞭。相關(guān)代碼如下:

AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange,audioRouteChangeListenerCallback,(__bridgevoid*)self);voidaudioRouteChangeListenerCallback(void*inUserData,AudioSessionPropertyIDinPropertyID,UInt32inPropertyValueS,constvoid*inPropertyValue){UInt32propertySize=sizeof(CFStringRef);AudioSessionInitialize(NULL,NULL,NULL,NULL);CFStringRefstate=nil;//獲取音頻路線AudioSessionGetProperty(kAudioSessionProperty_AudioRoute,&propertySize,&state);//kAudioSessionProperty_AudioRoute:音頻路線NSLog(@"%@",(NSString*)state);//Headphone 耳機? Speaker 喇叭.}

如果是輸出設(shè)備發(fā)生變化,我們?nèi)绻^續(xù)播放視頻的話淫奔,我們只需監(jiān)聽到設(shè)備變化時調(diào)用play就好了.

2山涡、性能問題

其實在UITableView中使用AVPlayer播放多個視頻時,是很容易出現(xiàn)性能問題的唆迁,當然這個時候我們也通常是靜音的鸭丛,不然多個視頻一起播聲音,沒有人會承受得了唐责。

當然你可以選擇muted以及把volume設(shè)置為0來達到目的鳞溉。在TableViewCell重用時,我們也可以使用pause方法來暫停之前的視頻鼠哥,并使用- (void)replaceCurrentItemWithPlayerItem:(AVPlayerItem *)item方法來加載一個新的視頻熟菲。

使用這樣的一個套路,可能仍然無法解決切換視頻時帶來的卡頓朴恳,尤其在視頻內(nèi)容比較多的時候抄罕。關(guān)于這個問題,微信內(nèi)部自己寫了一個簡易版的AVAssetReader+AVAssetReaderTrackOutput組件于颖,在靜音模式下播放列表里面的視頻呆贿,同時也不用考慮播放模式了,微信博客鏈接為iOS小視頻優(yōu)化心得森渐。

3做入、內(nèi)存泄漏問題

當我們釋放一個正在播放的視頻時,需要先調(diào)用pause方法同衣,如果由于某些原因竟块,例如切前后臺時,導致又調(diào)用了play方法耐齐,那么有可能會hold住內(nèi)存空間而導致內(nèi)存泄漏浪秘。

4前弯、獲取視頻縮略圖

獲取首幀視頻截圖的方法如下:

AVAssetImageGenerator*imageGen=[[AVAssetImageGeneratoralloc]initWithAsset:self.source];if(imageGen){imageGen.appliesPreferredTrackTransform=YES;CMTimeactualTime;CGImageRefcgImage=[imageGencopyCGImageAtTime:CMTimeMakeWithSeconds(0,30)actualTime:&actualTimeerror:NULL];if(cgImage){UIImage*image=[UIImageimageWithCGImage:cgImage];CGImageRelease(cgImage);returnimage;}}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市秫逝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌询枚,老刑警劉巖违帆,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異金蜀,居然都是意外死亡刷后,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門渊抄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尝胆,“玉大人,你說我怎么就攤上這事护桦『危” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵二庵,是天一觀的道長贪染。 經(jīng)常有香客問我,道長催享,這世上最難降的妖魔是什么杭隙? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮因妙,結(jié)果婚禮上痰憎,老公的妹妹穿的比我還像新娘。我一直安慰自己攀涵,他們只是感情好铣耘,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著汁果,像睡著了一般涡拘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上据德,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天鳄乏,我揣著相機與錄音,去河邊找鬼棘利。 笑死橱野,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的善玫。 我是一名探鬼主播水援,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼密强,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蜗元?” 一聲冷哼從身側(cè)響起或渤,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎奕扣,沒想到半個月后薪鹦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡惯豆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年池磁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片楷兽。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡地熄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出芯杀,到底是詐尸還是另有隱情端考,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布揭厚,位于F島的核電站跛梗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏棋弥。R本人自食惡果不足惜核偿,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望顽染。 院中可真熱鬧漾岳,春花似錦、人聲如沸粉寞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唧垦。三九已至捅儒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間振亮,已是汗流浹背巧还。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留坊秸,地道東北人麸祷。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像褒搔,于是被迫代替她去往敵國和親阶牍。 傳聞我的和親對象是個殘疾皇子喷面,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容