android-ndk - 将 AMediaExtractor 与位于媒体存储中的音频文件一起使用时,设置提取器数据源时出错,错误 -10002
问题描述
我正在尝试MediaStore
在 Android 10 上从中获取音频文件,从中提取音频数据,对其进行解码并播放它。
调用实例时出现以下错误setDataSource
:MediaExtractor
Error setting extractor data source, err -10002
重现:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val path = getSong().get(0).path
stringToJNI("file://"+ path)
val URI = Uri.parse(android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.toString() + "/" + getSong().get(0).id)
stringToJNI(URI!!.toString())
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
external fun stringToJNI(URI: String)
companion object {
// Used to load the 'native-lib' library on application startup.
init {
System.loadLibrary("native-lib")
}
}
fun getSong() : MutableList<Songs> {
val SONGS_PROJECTION = arrayOf(
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.DATA
)
val cursor = contentResolver.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
SONGS_PROJECTION,
null,
null,
MediaStore.Audio.Media._ID +
" ASC LIMIT 100"
)
val items: MutableList<Songs> = mutableListOf()
cursor?.let {
if (cursor.count > 0) {
cursor.moveToFirst()
while (!cursor.isAfterLast) {
val s0 = cursor.getString(cursor.getColumnIndex(SONGS_PROJECTION[0]))
val s1 = cursor.getString(cursor.getColumnIndex(SONGS_PROJECTION[1]))
val s2 = cursor.getString(cursor.getColumnIndex(SONGS_PROJECTION[2]))
items.add(Songs(s0, s1, s2))
cursor.moveToNext()
}
}
cursor.close()
}
return items
}
}
在MainActivity
中,我将路径传递给本机端,第二次传递 URI,每次都没有运气。
#include <jni.h>
#include <string>
#include <media/NdkMediaExtractor.h>
#include <android/log.h>
#include <bitset>
#define APP_NAME "MediaStoreToNativeAudio"
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, APP_NAME, __VA_ARGS__))
extern "C" JNIEXPORT void JNICALL
Java_com_example_mediastoretonativeaudio_MainActivity_stringToJNI(
JNIEnv *env,
jobject jobj,
jstring URI) {
const char *uri = env->GetStringUTFChars(URI, NULL);
std::string s(uri);
AMediaExtractor *extractor = AMediaExtractor_new();
media_status_t amresult = AMediaExtractor_setDataSource(extractor, uri);
if (amresult != AMEDIA_OK) {
LOGE("AMediaExtractor_setDataSource called with: [%s]", s.c_str());
LOGE("Error setting extractor data source, err %d", amresult);
}
return;
}
从日志:
2019-11-20 01:09:03.519 8270-8270/com.example.mediastoretonativeaudio E/NdkMediaExtractor: can't create http service
2019-11-20 01:09:03.519 8270-8270/com.example.mediastoretonativeaudio E/MediaStoreToNativeAudio: AMediaExtractor_setDataSource called with: [file:///storage/emulated/0/Music/Thank you for the drum machine/01 - Everything Moves.mp3]
2019-11-20 01:09:03.519 8270-8270/com.example.mediastoretonativeaudio E/MediaStoreToNativeAudio: Error setting extractor data source, err -10002
2019-11-20 01:09:03.543 8270-8270/com.example.mediastoretonativeaudio E/NdkMediaExtractor: can't create http service
2019-11-20 01:09:03.543 8270-8270/com.example.mediastoretonativeaudio E/MediaStoreToNativeAudio: AMediaExtractor_setDataSource called with: [content://media/external/audio/media/472]
2019-11-20 01:09:03.543 8270-8270/com.example.mediastoretonativeaudio E/MediaStoreToNativeAudio: Error setting extractor data source, err -10002
我的清单:
安装应用程序后,我还通过设置授予权限。
编辑:
带有测试代码的公共存储库:https ://github.com/AndrewBloom/MediaStoreToNativeAudioSample
相同的行为结果使用:
android:requestLegacyExternalStorage="true"
解决方案
这对我来说似乎是 Android 10 上的一个错误。似乎 android:requestLegacyExternalStorage="true" 并没有改变这种情况。您可能必须在清单上请求并在运行时请求相同的权限。必须在附加到 Java 的线程上调用 AMediaExtractor_setDataSource 函数。正确执行所有这些操作将使您能够使其在其他版本的 Android 上运行,但不能在 Android 10 上运行。我已经在 Android Bug Tracker 上报告了这个问题:https ://issuetracker.google.com/144837266根据谷歌的回答,似乎所有使用需要通过路径访问文件的本机库的应用程序都会受到影响,并且他们知道问题https://www.youtube.com/watch?v=UnJ3amzJM94。
在我的情况下,一种解决方法是使用 AMediaExtractor_setDataSourceFd,通过 contentResolver 及其方法 openFileDescriptor 获取 Java 级别的文件描述符。
推荐阅读
- uiscrollview - 如何为我的 ios 本机应用程序在 appium 中滚动
- jquery - 在 Ajax 成功中使用 clicked 变量
- python - 使用 Python 将文本输入到 HTML 文档中
- android - BroadcastReceiver 上不存在 AlarmManager 意图数据
- android - 收到阻止的短信时广播接收器未触发
- c# - c# 在 System.OutOfMemoryException 中导出到 excel
- python - 应用函数在熊猫中返回一个数据框
- typescript - typescript - instanceof 数组
- r - 是否可以将串扰与 kableextra 表一起使用?
- docker - 从我的桌面访问与 Oracle 数据库容器位于同一网络的容器上的 Web 应用程序时出现网络适配器错误