【Android FFMPEG 开发】FFMPEG 视频播放进度控制 ( 显示播放进度 | 拖动进度条播放 )

简介: 【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);


目录
相关文章
|
Linux 开发工具 Android开发
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
ijkplayer是由Bilibili基于FFmpeg3.4研发并开源的播放器,适用于Android和iOS,支持本地视频及网络流媒体播放。本文详细介绍如何在新版Android Studio中导入并使用ijkplayer库,包括Gradle版本及配置更新、导入编译好的so文件以及添加直播链接播放代码等步骤,帮助开发者顺利进行App调试与开发。更多FFmpeg开发知识可参考《FFmpeg开发实战:从零基础到短视频上线》。
1585 2
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
|
编解码 语音技术 内存技术
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
《FFmpeg开发实战:从零基础到短视频上线》一书中的“5.1.2 把音频流保存为PCM文件”章节介绍了将媒体文件中的音频流转换为原始PCM音频的方法。示例代码直接保存解码后的PCM数据,保留了原始音频的采样频率、声道数量和采样位数。但在实际应用中,有时需要特定规格的PCM音频。例如,某些语音识别引擎仅接受16位PCM数据,而标准MP3音频通常采用32位采样,因此需将32位MP3音频转换为16位PCM音频。
476 0
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
|
9月前
|
XML 搜索推荐 Android开发
Android改变进度条控件progressbar的样式(根据源码修改)
本文介绍了如何基于Android源码自定义ProgressBar样式。首先分析了系统源码中ProgressBar样式的定义,发现其依赖一张旋转图片实现动画效果。接着分两步指导开发者实现自定义:1) 模仿源码创建一个旋转动画XML文件(放置在drawable文件夹),修改图片为自定义样式;2) 在UI控件中通过`indeterminateDrawable`属性应用该动画。最终实现简单且个性化的ProgressBar效果,附带效果图展示。
600 2
|
XML 开发工具 Android开发
FFmpeg开发笔记(五十六)使用Media3的Exoplayer播放网络视频
ExoPlayer最初是为了解决Android早期MediaPlayer控件对网络视频兼容性差的问题而推出的。现在,Android官方已将其升级并纳入Jetpack的Media3库,使其成为音视频操作的统一引擎。新版ExoPlayer支持多种协议,解决了设备和系统碎片化问题,可在整个Android生态中一致运行。通过修改`build.gradle`文件、布局文件及Activity代码,并添加必要的权限,即可集成并使用ExoPlayer进行网络视频播放。具体步骤包括引入依赖库、配置播放界面、编写播放逻辑以及添加互联网访问权限。
1353 1
FFmpeg开发笔记(五十六)使用Media3的Exoplayer播放网络视频
|
Web App开发 安全 程序员
FFmpeg开发笔记(五十五)寒冬里的安卓程序员可进阶修炼的几种姿势
多年的互联网寒冬在今年尤为凛冽,坚守安卓开发愈发不易。面对是否转行或学习新技术的迷茫,安卓程序员可从三个方向进阶:1)钻研谷歌新技术,如Kotlin、Flutter、Jetpack等;2)拓展新功能应用,掌握Socket、OpenGL、WebRTC等专业领域技能;3)结合其他行业,如汽车、游戏、安全等,拓宽职业道路。这三个方向各有学习难度和保饭碗指数,助你在安卓开发领域持续成长。
319 1
FFmpeg开发笔记(五十五)寒冬里的安卓程序员可进阶修炼的几种姿势
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
625 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
Android开发 开发者
FFmpeg开发笔记(五十七)使用Media3的Transformer加工视频文件
谷歌推出的Transformer,作为Jetpack Media3架构的一部分,助力开发者实现音视频格式转换与编辑。Media3简化了媒体处理流程,提升了定制性和可靠性。Transformer可用于剪辑、添加滤镜等操作,其示例代码可在指定GitHub仓库中找到。要使用Transformer,需在`build.gradle`中添加相关依赖,并按文档编写处理逻辑,最终完成音视频转换任务。具体步骤包括配置剪辑参数、设置空间效果以及监听转换事件等。
342 0
FFmpeg开发笔记(五十七)使用Media3的Transformer加工视频文件
|
Linux 视频直播
FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播
本文介绍了如何使用EasyPusher-Android实现RTSP直播流程。首先对比了RTSP、RTMP、SRT和RIST四种流媒体协议,并以RTSP为例,详细说明了使用EasyPusher-Android向流媒体服务器进行RTSP直播推流的方法。文中还提供了OBS Studio配置RTSP插件及ZLMediaKit云服务器部署的相关信息,通过修改EasyPusher-Android源码使其支持通用RTSP地址,最终验证了直播功能的成功实现。
681 0
FFmpeg开发笔记(五十四)使用EasyPusher实现移动端的RTSP直播
|
XML Java Android开发
FFmpeg开发笔记(五十二)移动端的国产视频播放器GSYVideoPlayer
GSYVideoPlayer是一款国产移动端视频播放器,支持弹幕、滤镜、广告等功能,采用IJKPlayer、Media3(EXOPlayer)、MediaPlayer及AliPlayer多种内核。截至2024年8月,其GitHub星标数达2万。集成时需使用新版Android Studio,并按特定步骤配置依赖与权限。提供了NormalGSYVideoPlayer、GSYADVideoPlayer及ListGSYVideoPlayer三种控件,支持HLS、RTMP等多种直播链接。
600 18
FFmpeg开发笔记(五十二)移动端的国产视频播放器GSYVideoPlayer