音频渲染

音频播放是通过Android的OpenSL ES接口实现的。具体代码是基于ndk-samples中audio-echo的修改。

当播放或录音缓冲区溢出时,ndk-samples 中的音频回声将自动停止播放或录音。演示中进行了一些修改来解决此问题。此外,修改音频回显代码以支持自定义播放的音频内容。

为Android应用程序集成ffmpeg库

android.sh脚本的执行流程大致如下: mobile-ffmpeg/android.sh - mobile-ffmpeg/build/main-android.sh - mobile-ffmpeg/build/android-ffmpeg.sh, mobile-ffmpeg/build/android-更详细的编译配置可以在ffmpeg.sh脚本中看到。编译过程中,编译日志会输出到mobile-ffmpeg/build.log。从这个文件中,你可以看到有关编译过程的更详细的信息。

您可以在mobile-ffmpeg/build/android-ffmpeg.sh 脚本中看到这一点:

LIB_NAME='ffmpeg'。/configure \ --cross-prefix='${BUILD_HOST}-' \ --sysroot='${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/${TOOLCHAIN}/sysroot' \ --prefix='${ BASEDIR}/prebuilt/android-$(get_target_build)/${LIB_NAME}' \.rm -rf ${BASEDIR}/prebuilt/android-$(get_target_build) /${LIB_NAME}make install 1${BASEDIR}/build.log 21将编译好的头文件和动态链接库文件安装到mobile-ffmpeg/prebuilt/android-$(get_target_build)/ffmpeg,如图所示x86_64编译的动态链接库安装在mobile-ffmpeg/prebuilt/android-x86_64/ffmpeg/lib目录下,放置x86_64平台的头文件在mobile-ffmpeg/prebuilt/android-x86_64/ffmpeg/include 目录中。而为arm64编译的动态链接库安装在mobile-ffmpeg/prebuilt/android-arm64/ffmpeg/lib目录下,arm64平台的头文件放在mobile-ffmpeg/prebuilt/android-arm64/ffmpeg /include 目录,对于其他ABI 依此类推。

mobile-ffmpeg的android.sh还会编译并生成ffmpeg库的AAR文件,位于mobile-ffmpeg/prebuilt/android-aar/mobile-ffmpeg/mobile-ffmpeg.aar。

可以参考文章Android studio中NDK开发(二)——使用CMake引入第三方so库和头文件以及用NDK-CMakeLists配置第三方so库。在CMake中添加预编译库。一般方法是:

将ffmpeg库的几个动态链接库文件和头文件复制到合适的位置。

添加CMake 库。当需要添加多个so库依赖时,还需要在CMake中添加多个add_library()项。

设置库二进制文件的搜索路径。当需要添加多个so库依赖时,还需要在CMake中添加多个set_target_properties()项。

设置头文件搜索路径。要为JNI 目标添加头文件搜索路径,请添加target_include_directories(),但它可以包含一个或多个路径。

设置链接依赖关系。添加JNI 目标的库依赖项,每个库都有一个target_link_libraries() 项。

当通过CMake自动打包预构建依赖项时,不再需要在build.gradle中设置预构建项的地址,如下所示:

sourceSets { main { jniLibs.srcDirs=['src/main/libs'] } } 使用Android Gradle 插件4.0,不再需要上述配置,并且会导致构建失败:

-----------* 出了什么问题:任务“:app:mergeReleaseNativeLibs”执行失败。执行com.android.build.gradle.internal.tasks.MergeJavaResWorkAction 2 个文件时发生故障,该文件的路径为“lib/x86/libswscale.so”(来自input: - /Users/henryhan/Projects/Shopee/henry-entrytask/app/) build/intermediates/merged_jni_libs/release/out - /Users/henryhan/Projects/Shopee/henry-entrytask/app/build/intermediates /cmake/release/obj 如果您使用的是jniLibs 和CMake IMPORTED 目标,请参阅https://developer.android.com /r/tools/jniLibs-vs-imported-targets 更多信息可以参考Google的官方文档。

通过System.loadLibrary()加载ffmpeg和JNI的so文件时,需要注意加载so文件的顺序。依赖的so文件需要先加载,依赖的so文件需要最后加载。例如,如果swscale库依赖于avutil库,则需要System.loadLibrary。 ('avutil');放在System.loadLibrary('swscale') 前面;否则会报错说找不到该符号。

ffmpeg 是一个纯C 库,就像在任何C++ 代码中使用FFmpeg 的API 一样。如果JNI代码是用C++编写的,那么ffmpeg头文件的include应该放在extern 'C'中。

免费音视频学习地址:FFmpeg/WebRTC/RTMP/NDK/Android音视频流高级开发

音视频解封装与解码

代码参考了HelloFFmpeg和goffmpeg项目的代码。

视频:解封装以获得H264 编码帧- 解码以获得裸YUV 视频流。

音频:解封装得到AAC编码的音频帧——解码得到裸PCM音频流——样本格式转换后(样本格式由32位浮点类型转换为16位有符号整数类型),重采样(采样率由48转换) kHz到44.1 kHz),以及通道数转换(从立体声双通道到单通道),以获得适合在Android平台上播放的裸PCM音频流。

解码后的音频直接获得Non-interleaved格式的所谓裸PCM音频流,即音频数据以LLLL.RRRR.的形式存储在内存中,首先是所有左声道数据,然后是右通道数据。以这种格式保存的数据很容易进行编码、解码等数据处理。一般情况下,音频数据处理都是针对某一通道的连续数据。但这种格式保存的数据对于播放、传输等场景来说并不是很友好。这就要求播放设备或者数据接收端在开始播放之前获取到所有的数据。因此,播放设备一般要求的裸PCM音频格式就是所谓的interleaved,即以LRLRLRLR.格式保存的数据。

在ffmpeg的术语和概念体系中,使用AVSampleFormat的平面来表示这种音频数据存储格式的差异。对于planar的音频PCM数据保存格式,保存音频数据的方式为LLLL.RRRR.如AV_SAMPLE_FMT_S16P、AV_SAMPLE_FMT_FLTP。对于非平面格式,保存音频数据的方式是LRLRLRLR.

对于音频重采样,需要注意保持输入样本格式与实际数据格式的一致性。例如,解码后的格式为AV_SAMPLE_FMT_FLTP。但为了后续处理的方便,对解码后的音频数据进行交织,并转换音频样本数据格式。对于AV_SAMPLE_FMT_FLT,输入样本格式还应通过av_opt_set_sample_fmt(swr_ctx_, 'in_sample_fmt', format, 0) 设置为AV_SAMPLE_FMT_FLT; ffmpeg 提供了一个API enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar);来进行这种格式转换。

整个解封装和解码过程都是由播放线程驱动的。在播放线程中,当请求播放数据的回调到来时,会检查缓冲区中是否有一定数量的解码后的音视频数据。当数据不足时,通过解复用器和解码器对音视频数据进行解封装和解码,并存储在缓冲区中。

要测试解码和解封装过程,可以将解码后的数据直接保存在文件中,然后通过ffplay等工具进行播放和检查。

使用ffplay查看YUV数据包括视频或图片:

$ ffplay -f rawvideo -video_size 854x480 Trailer.yuv 注意: (1) -f rawvideo:该选项可加也可不加。 (2)YUV文件不包含宽度和高度数据,所以必须使用-video_size指定宽度和高度。格式为:widthxheight (3) test.yuv可以是一帧(图片)或多帧(视频)数据

裸PCM数据播放命令如下:

$ ffplay -f f32le -ac 2 -ar 48000 Trailer_.pcm$ ffplay -f s16le -ac 1 -ar 44100 Trailer_441.pcm 以上命令用于播放样本格式为32位浮点数,采样率为48 kHz ,通道数为2的裸PCM音频流。以下命令用于播放裸PCM音频流,采样格式为16位有符号整数,采样率为44.1 kHz,通道数为1。

ffmpeg -i Trailer.mp4 -ar 44100 -ac 1 output_1.mp4 参考以下文档:

使用av_read_frame将h264和mp4多媒体文件解码为yuv

基于FFmpeg的播放器demo

ffmpeg 查看YUV 图片/视频

FFmpeg 将MP4 文件解码为h264 和YUV 文件

FFmpeg —— 9.示例程序(三):音视频分离(分离为PCM、YUV格式)

FFmpeg重采样示例代码

音视频播放

视频渲染指的是Android基于FFmpeg的视频播放渲染CMake + ANativeWindow,同时也指的是其代码NDKtest。这个demo在目前的开发环境下基本无法运行。这个demo的gradle版本太老了,而且包含了ffmpeg所以只有armeabi ABI,但是代码还是有一定参考价值的。然而代码中存在大量的资源泄漏,包括Android资源泄漏,如本机窗口句柄,以及ffmpeg对象泄漏,如AVFrame和SwsContext。

前面提到,解封装和解码过程是由音频播放线程驱动的,它将解码后的音视频数据放入缓冲区。应用程序中将启动专用的视频播放线程。视频播放线程定期从视频缓冲区请求YUV视频数据。如果视频YUV数据存在,则播放。

播放控制和音视频同步

Android调用系统文件选择器并获取文件路径的方法参考Android Selecting Files and Returning Paths及其代码ForeverLibrary。

对于拖拽的实现,当用户拖动进度条时,会在全局状态下设置进度值,在音频播放线程中请求音频数据的回调中检查进度值,并根据进度值、seek是通过ffmpeg的API实现的。 ffmpeg的seek API的使用可以参考如何在FFmpeg C/C++中seek等。

对于暂停的实现,当用户点击暂停按钮时,也会在全局状态中设置暂停状态,并在音频播放线程中请求音频数据的回调中检查暂停状态,并采取一定的措施。

测试文件下载

1.地址:http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4 1分钟

2、地址:http://vjs.zencdn.net/v/oceans.mp4

3.地址:https://media.w3.org/2010/05/sintel/trailer.mp4 52秒

4.地址:http://mirror.aarnet.edu.au/pub/TED-talks/911Mothers_2010W-480p.mp4 10分钟

各种其他格式,MP4、flv、mkv、3gp视频下载

下载示例视频

MPlayer官方提供的各种视频格式的测试文件,下载地址:/的索引

测试视频下载地址

http://ultravideo.cs.tut.fi/#testsequences

404 未找到

404 未找到

测试视频下载地址

测试视频、音频、图片下载

视频下载用于测试

测试在线视频地址

常用的各种视频测试文件

样本视频

开发过程中的问题分析与调查

解封装后的H264和AAC文件,由于H264对编码帧的字节串进行了分段,而AAC有ADTS头,因此这些转储的文件可以直接用一些播放器(例如VLC播放器)播放。

对于解码后的YUV和PCM数据,可以使用ffplay播放裸YUV和PCM音视频流,但需要正确指定裸流的参数。 Audacity 可用于播放原始PCM 音频流并查看音频信号的波形。

我们在开发调试的时候,还可以通过命令行显示某个包的权限,如下图

adb shell pm grant com.xxx.xxx android.permission.READ_EXTERNAL_STORAGE

用户评论

桃洛憬

哇,FFmpeg的播放器demo看起来好强大啊!我一直在找这样的工具,希望用起来能很方便。

    有11位网友表示赞同!

打个酱油卖个萌

这个基于FFmpeg的播放器demo真的很有潜力,我迫不及待想试试看效果了。

    有18位网友表示赞同!

熟悉看不清

FFmpeg的播放器demo,听说支持多种格式,我是做视频剪辑的,这对我来说简直是福音!

    有16位网友表示赞同!

颓废i

刚刚试了试这个基于FFmpeg的播放器demo,操作简单,画质也很清晰,赞一个!

    有13位网友表示赞同!

冷风谷离殇

这个demo的界面有点不美观,希望开发者能优化一下,毕竟第一印象很重要。

    有15位网友表示赞同!

■□丶一切都无所谓

看了这个基于FFmpeg的播放器demo,发现它居然可以自定义播放列表,太实用了。

    有5位网友表示赞同!

见朕骑妓的时刻

听说这个播放器demo是基于开源的FFmpeg,那更新速度应该很快吧,期待后续版本。

    有13位网友表示赞同!

陌颜幽梦

用了基于FFmpeg的播放器demo之后,感觉之前的播放器都是渣,这太强大了。

    有14位网友表示赞同!

哭着哭着就萌了°

这个播放器demo的音视频同步有点问题,希望更新时能解决。

    有20位网友表示赞同!

漫长の人生

FFmpeg的播放器demo,功能丰富,但是内存占用有点大,希望优化一下。

    有8位网友表示赞同!

瑾澜

我一直在寻找一个轻量级的播放器,这个基于FFmpeg的demo似乎符合我的需求。

    有5位网友表示赞同!

旧事酒浓

这个播放器demo的UI设计很简洁,用起来很舒服,推荐给大家。

    有20位网友表示赞同!

太难

刚刚看到这个基于FFmpeg的播放器demo,不过我更希望它支持4K视频播放。

    有19位网友表示赞同!

冷眼旁观i

FFmpeg的播放器demo,兼容性怎么样?我担心不支持某些格式。

    有15位网友表示赞同!

金橙橙。-

这个播放器demo的代码很清晰,我是个开发者,想学习一下它的实现方式。

    有9位网友表示赞同!

关于道别

用了这个基于FFmpeg的播放器demo,感觉比之前的播放器稳定多了,再也不怕卡顿了。

    有6位网友表示赞同!

┲﹊怅惘。

这个播放器demo的音质很好,但有时候会有杂音,希望后续版本能改进。

    有6位网友表示赞同!

喜欢梅西

FFmpeg的播放器demo,虽然功能强大,但对我来说还是有点复杂,希望能简化操作。

    有11位网友表示赞同!

几妆痕

这个基于FFmpeg的播放器demo,是我在众多播放器中找到的最合适的一个,真心推荐!

    有6位网友表示赞同!

标签: