音视频播放器—快进快退及逐帧播放
------------------------------------全系列文章目錄------------------------------------
快進(jìn)快退
大致流程
獲取跳轉(zhuǎn)的文件位置
-
通過捕獲SDL_KEYDOWN按鍵按下事件,并通過標(biāo)志位判斷當(dāng)前的鍵位SDL_Event::SDL_KeyboardEvent::SDL_Keysym::SDL_Keycode為SDLK_LEFT或SDLK_RIGHT,以此來確定是向前跳轉(zhuǎn)還是向后跳轉(zhuǎn)。
switch (_event.type) {case SDL_KEYDOWN:switch (_event.key.keysym.sym) {case SDLK_LEFT:avc->set_seek_pos(-SEEK_POS_CHANGE);break;case SDLK_RIGHT:avc->set_seek_pos(SEEK_POS_CHANGE);break;default:break;} } -
使用一個(gè)標(biāo)志位seek_pos來表示跳轉(zhuǎn)到文件中的位置;每次發(fā)生跳轉(zhuǎn)時(shí),先更新當(dāng)前文件位置,將seek_pos加上上次跳轉(zhuǎn)時(shí)時(shí)間和當(dāng)前時(shí)間的時(shí)間差作為最新的seek_pos;然后加上當(dāng)前的跳轉(zhuǎn)變化量,作為跳轉(zhuǎn)到文件中的位置。
void AVCtrl::set_seek_pos(int64_t _pos) {int64_t _pos_time = av_gettime() / MICROSECOND_TO_SECOND; seek_flag = 1;//加上 距離上次跳轉(zhuǎn)到現(xiàn)在的時(shí)間差 作為最新的seek_pos, 并加上當(dāng)前的變化量seek_pos += (_pos + _pos_time - pos_time);seek_pos = seek_pos < 0 ? 0 : seek_pos;seek_pos = seek_pos > file_duration ? file_duration : seek_pos;pos_time = _pos_time; //更新發(fā)生跳轉(zhuǎn)時(shí)的時(shí)間 }
重定向文件
-
重定向文件使用av_seek_frame函數(shù)來實(shí)現(xiàn),其函數(shù)定義如下:
int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags);-
s:多媒體文件的句柄,即打開文件時(shí)所使用的AVFormatContext結(jié)構(gòu)體;
-
stream_index:選擇跳轉(zhuǎn)后選取的數(shù)據(jù)流,如果為 -1,則選擇默認(rèn)流,并且時(shí)間戳?xí)詣?dòng)從 AV_TIME_BASE 單位轉(zhuǎn)換為特定于流的 time_base;
-
timestamp:以 AVStream.time_base 為單位的時(shí)間戳,如果未指定流,則以 AV_TIME_BASE 為單位。
-
flags:用于選擇方向和搜索模式的標(biāo)志位(主要是對(duì)關(guān)鍵幀的選取),可選標(biāo)志如下
/*跳轉(zhuǎn)到非關(guān)鍵幀時(shí), 往回找到關(guān)鍵幀, 作為跳轉(zhuǎn)點(diǎn)*/ #define AVSEEK_FLAG_BACKWARD 1 ///< seek backward #define AVSEEK_FLAG_BYTE 2 ///< seeking based on position in bytes /*可以跳轉(zhuǎn)到任何幀*/ #define AVSEEK_FLAG_ANY 4 ///< seek to any frame, even non-keyframes /*跳轉(zhuǎn)到非關(guān)鍵幀時(shí), 往后找到關(guān)鍵幀, 作為跳轉(zhuǎn)點(diǎn)*/ #define AVSEEK_FLAG_FRAME 8 ///< seeking based on frame number -
返回≥0表示成功
-
-
因此在線程中檢測(cè)重定事件是否發(fā)生,若發(fā)生了,則通過av_seek_frame函數(shù)進(jìn)行文件重定向處理
if (avc->get_seek_flag()) {avc->set_seek_flag(0);av_seek_frame(avc->pFormatCtx, -1, avc->get_seek_pos() * AV_TIME_BASE, AVSEEK_FLAG_BACKWARD); //重定位文件, 定位至關(guān)鍵幀........ } -
當(dāng)發(fā)生文件跳轉(zhuǎn)時(shí),原本demux時(shí)存取在隊(duì)列中的數(shù)據(jù)包,以及解碼后的數(shù)據(jù)包都不能使用,因此要進(jìn)行清空隊(duì)列操作。
逐幀播放
事件捕獲
- 通過捕獲SDL_KEYDOWN按鍵按下事件,并通過標(biāo)志位判斷當(dāng)前的鍵位SDL_Event::SDL_KeyboardEvent::SDL_Keysym::SDL_Keycode是否為一特定按鍵如SDLK_p來啟動(dòng)逐幀播放操作。需要注意的是SDLK_p按鍵應(yīng)該在暫停時(shí)才會(huì)觸發(fā),并且需要保證播放完一幀后才會(huì)繼續(xù)觸發(fā)。
大致流程如下
- 當(dāng)播放暫停時(shí),若按下SDLK_p鍵,標(biāo)記該事件,同時(shí)暫停接收SDLK_p按鍵事件;
- 視頻線程解碼一幀,并將其顯示出來;并判斷當(dāng)前視頻幀pts是否大于音頻幀pts,若大于則解鎖音頻播放標(biāo)志;最后取消SDLK_p按鍵事件,并解鎖再次接收SDLK_p按鍵事件;
- 音頻線程若檢測(cè)到可以播放,則解碼音頻幀并播放,直到音頻幀pts大于等于視頻幀pts,則取消音頻播放事件;
總結(jié)
以上是生活随笔為你收集整理的音视频播放器—快进快退及逐帧播放的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Open Sans字体
- 下一篇: 【产品】保险业务收付管理系统概要