【Android FFMPEG 开发】FFMPEG 视频播放进度控制 ( 显示播放进度 | 拖动进度条播放 )
文章目錄
- I . FFMPEG 播放進度控制
- II . FFMPEG 播放視頻 ( 效果展示 )
- III . FFMPEG 獲取視頻時長
- IV . FFMPEG 視頻播放進度獲取
- V . FFMPEG 設置播放進度
I . FFMPEG 播放進度控制
FFMPEG 播放進度控制 : 為 FFMPEG 播放視頻添加拖動進度條功能 , 主要包含以下兩個功能 ;
第一 , 進度更新 , 視頻播放過程中 , 播放的同時更新當前的播放進度 , 界面中的進度條實時顯示當前的播放進度 ;
第二 , 進度控制 , 拖動進度條 , 控制視頻播放進度跳轉 ;
進度控制前提 : 上述功能主要用于 視頻播放 , 只有完整的視頻才能添加進度控制功能 , 直播視頻流是無法添加進度功能的 ;
II . FFMPEG 播放視頻 ( 效果展示 )
GitHub 項目地址 : han1202012 / 011_FFMPEG
直播功能 : 之前使用 FFMPEG 開發直播流播放功能 , 播放的是網絡上的 RTPM 直播流 , 當時使用的是 avformat_open_input 方法 , 將下面的視頻流地址傳遞到該方法中 , 即可播放網絡視頻流 ;
播放湖南衛視直播流 : rtmp://58.200.131.2:1935/livetv/hunantv
本次在直播功能的基礎上 , 添加了本地文件播放功能 , 進度控制主要在本地視頻文件播放功能上進行 ;
視頻文件播放功能 : 將本地 SD 卡中的視頻地址傳入到上述 avformat_open_input 方法中 , 即可播放手機本地的視頻文件 ;
播放手機本地文件 : /sdcard/game.mp4 , 本文件放在了 GitHub 源碼的 Assets 目錄中 , 將其拷貝到 SD 卡根目錄即可在本程序中播放 ;
III . FFMPEG 獲取視頻時長
1 . 視頻時長信息 : FFMPEG 的音頻時長封裝在 AVFormatContext 結構體中 , 只要 AVFormatContext 初始化成功 , 就可以獲取該結構體中的視頻時長 ;
2 . AVFormatContext 結構體 : 該結構體中封裝了 音頻 視頻相關信息 , 包括音頻的采樣率 , 采樣位數等屬性 , 視頻的寬高 , 編解碼信息 , 音視頻時長 等信息 ;
3 . FFMPEG 獲取視頻時長流程 :
① 打開視頻文件 : 使用 avformat_open_input 方法 , 打開視頻文件 , 將視頻文件地址傳入該方法中 ;
// 打開音視頻地址 ( 播放文件前 , 需要先將文件打開 ) // 地址類型 : ① 文件類型 , ② 音視頻流 int open_result = avformat_open_input(&formatContext, dataSource, 0, 0);② 查找媒體流 : 調用 avformat_find_stream_info 方法 , 查找打開文件的媒體流信息 ;
//2 . 查找媒體 地址 對應的音視頻流 ( 給 AVFormatContext* 成員賦值 ) // 方法原型 : int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options); // 調用該方法后 , AVFormatContext 結構體的 nb_streams 元素就有值了 , // 該值代表了音視頻流 AVStream 個數 int find_result = avformat_find_stream_info(formatContext, 0);③ 獲取視頻時長 : 視頻時長就封裝在 AVFormatContext *formatContext 編解碼上下文環境結構體的 duration 結構體成員中 ;
//獲取視頻時長, 單位是微秒 , 除以 1000000 是秒時間 duration = formatContext->duration / 1000000;④ duration 視頻時長原型 : 下面是封裝在 AVFormatContext 結構體中的 duration 原型 ; 這是音視頻流的時長 , 其單位是 微秒 , 一般不需要手動設置該值 , 該值是從音視頻文件中解析出來的 ;
typedef struct AVFormatContext {.../*** Duration of the stream, in AV_TIME_BASE fractional* seconds. Only set this value if you know none of the individual stream* durations and also do not set any of them. This is deduced from the* AVStream values if not set.** Demuxing only, set by libavformat.*/int64_t duration;... }IV . FFMPEG 視頻播放進度獲取
1 . 視頻播放進度 : 之前已經獲取了視頻的時長 , 即 AVFormatContext 中提取的 duration 元素值 , 是視頻的總時長微秒數 , 這里獲取到當前的播放時間 , 就可以得到當前時刻的播放進度百分比 ;
2 . 主要問題 : 那么問題就集中在了 如何獲取當前的播放時間 , 當前的播放時間可以從 AVFrame 音視頻幀中獲取 ;
3 . 獲取當前播放時間流程 :
① 獲取 AVFrame 結構體 : 這是解碼后的音視頻數據幀 , 從音視頻流中讀取出來的是 AVPacket 數據包 , 使用編解碼器將 AVPacket 壓縮數據包 解碼成 AVFrame 實際的數據幀 , 其中的 音頻 / 視頻 是解碼后的 采樣 或 圖像 數據 , 可以用于直接播放 ;
② 從 AVFrame 中獲取當前的相對播放時間 : AVFrame 結構體中封裝的 best_effort_timestamp 元素值 , 就是當前 畫面 或 采樣 的相對播放時間 , 注意其單位是 AVRational ;
③ 時間單位轉換 : best_effort_timestamp 的時間單位是 AVRational , 這里需要將其 轉為 秒 , av_q2d 方法可以將 AVRational 時間單位轉為秒單位 ;
//獲取當前畫面的相對播放時間 , 相對 : 即從播放開始到現在的時間 // 該值大多數情況下 , 與 pts 值是相同的 // 該值比 pts 更加精準 , 參考了更多的信息 // 轉換成秒 : 這里要注意 pts 需要轉成 秒 , 需要乘以 time_base 時間單位 // 其中 av_q2d 是將 AVRational 轉為 double 類型 double vedio_best_effort_timestamp_second = avFrame->best_effort_timestamp * av_q2d(time_base);④ AVFrame 結構體中的 best_effort_timestamp 元素原型 : 這是結合各種因素估算出來的當前幀應該播放的時間 , 其單位是 time base , 即 AVRational 類型 ;
/*** frame timestamp estimated using various heuristics, in stream time base* - encoding: unused* - decoding: set by libavcodec, read by user.*/ int64_t best_effort_timestamp;V . FFMPEG 設置播放進度
1 . FFMPEG 設置播放進度 : 傳入一個播放進度后 , 首先將播放的進度轉成微秒值 , 然后調用 av_seek_frame 方法 , 傳入一系列參數 , 即可完成 FFMPEG 播放本地視頻文件的進度跳轉 ;
//將秒單位 轉為 微秒單位 int64_t seek = progress * 1000 * 1000;// 跳轉核心方法 , 跳轉到距離時間戳最近的關鍵幀位置 av_seek_frame(formatContext, -1, seek, AVSEEK_FLAG_BACKWARD);2 . av_seek_frame ( ) 函數原型 : 查找第 stream_index 個媒體流的 timestamp 微秒附近的關鍵幀 , 并跳轉到該幀開始播放 ;
① AVFormatContext **ps 參數 : 封裝了文件格式相關信息的結構體 , 如視頻寬高 , 音頻采樣率等信息 ; 該參數是 二級指針 , 意味著在方法中會修改該指針的指向 , 該參數的實際作用是當做返回值用的 ;
② int stream_index 參數 : 音視頻流索引 , 如果設置 -1 , 說明是所有的媒體流同時跳轉 ;
③ int64_t timestamp 參數 : 要跳轉的目的時間戳 , 之后要在該時間附近查找關鍵幀 ;
④ int flags 參數 : 設置跳轉模式 ;
⑤ int 返回值 : 返回值大于等于 0 , 代表打開成功 , 否則失敗 ;
/*** Seek to the keyframe at timestamp.* 'timestamp' in 'stream_index'.** @param s media file handle* @param stream_index If stream_index is (-1), a default* stream is selected, and timestamp is automatically converted* from AV_TIME_BASE units to the stream specific time_base.* @param timestamp Timestamp in AVStream.time_base units* or, if no stream is specified, in AV_TIME_BASE units.* @param flags flags which select direction and seeking mode* @return >= 0 on success*/ int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp,int flags); 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的【Android FFMPEG 开发】FFMPEG 视频播放进度控制 ( 显示播放进度 | 拖动进度条播放 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Kotlin】函数类型 ( 函数类型
- 下一篇: 【计算理论】自动机设计 ( 设计自动机