我正在尝试使用MediaCodec和MediaExtractor将视频解码到安卓的一个表面上。
首先,我在MediaExtractor对象(下面是extractor)上使用setDataSource(context, uri, null)方法来设置数据源uri。uri来自Android视频文件选择器。这个调用似乎没有抛出任何异常。
在解码器的onInputBufferAvailable()调用中,我从提取器读取了一个新的样本,但是extractor.readSampleData(..)调用随机地无法读取正确的数据,并开始返回大小为1的缓冲区。理想情况下,只有在读取完整个文件后,大小才应该为-1。此外,一旦提取器开始返回-1,无论我调用extractor.advance()多少次,它都不会返回正确的样本。
每当发生此问题时,我都会在日志中观察到以下警告消息:
W/NuMediaExtractor: read on track 0 failed with error -2147483646代码:
object : MediaCodec.Callback() {
override fun onInputBufferAvailable(codec: MediaCodec, index: Int) {
val buffer = codec.getInputBuffer(index)!!
try {
val size = extractor.readSampleData(buffer, 0)
if (size > 0) {
decoder.queueInputBuffer(
index,
0,
size,
extractor.sampleTime,
sampleFlags
)
extractor.advance()
} else if (size == 0) {
Timber.d("Size 0 sample received from extractor")
} else if (size == -1) {
// Size is -1 when no more samples are available
} catch (exception: Exception) {
Timber.e(exception)
}
}这种情况并不总是发生,但已经足够频繁了。到目前为止,我只在Android9操作系统上观察到了这一点。
编辑1:为了防止竞争条件,我将空闲的输入缓冲区保存到阻塞队列中。然后,while循环从队列中拾取这些缓冲区。
private val inputBuffersQueue: BlockingQueue<InputBufferData> = LinkedBlockingQueue()
private fun feedSamplesToDecoder(extractor: MediaExtractor, trimStartUs: Long, trimEndUs: Long) {
inputHandler.post {
while (!wasEOSInputBufferFed) {
val inputBuffer = inputBuffersQueue.take()
val decoder = inputBuffer.codec
val index = inputBuffer.index
val sampleSize = extractor.readSampleData(inputBuffer.codec.getInputBuffer(inputBuffer.index)!!, 0)
if (sampleSize > 0) {
val sampleTime = extractor.sampleTime
lastSampleTimestampUs = sampleTime
val sampleFlags = extractor.sampleFlags
decoder.queueInputBuffer(
index,
0,
sampleSize,
sampleTime - trimStartUs,
sampleFlags
)
extractor.advance()
} else if (sampleSize == 0) {
Timber.d("Size 0 sample received from extractor")
} else {
decoder.queueInputBuffer(
index,
0,
0,
0,
BUFFER_FLAG_END_OF_STREAM
)
}
}
}
}发布于 2021-01-28 01:56:18
我认为你的根本问题是uri。我的建议是将其重新解析为更常见的东西,并被许多应用程序广泛接受。例如,如果您的uri类似于(以content://com.android.providers.downloads.documents/document/3356://开头)内容,请尝试将其更改为file:///storage/emulated/0/document/3356。com.android.providers.downloads.documents是包名,document/3356是文件路径。您可以通过Environment.getExternalStorageDirectory()方法获取/storage/emulated/0。然后使用Uri.parse("string")获取uri实例。
Uri uri = Uri.parse("file:///storage/emulated/0/document/3356");发布于 2021-02-02 00:53:18
首先在谷歌上搜索"NuMediaExtractor: read on track 0失败,错误为-2147483646“。我看到两个结果:A,B
他们写的是Android 10中修复的bug,比如比特率太高,需要重新编码视频。
尽管如此,我仍然建议寻找可能的解决方法。而不是使用setDataSource(Context, Uri, Map),试着调用setDataSource(MediaDataSource),实现你自己的MediaDataSource,只有两个方法:getSize,你返回文件的大小,和readAt,你从文件中读取完全请求的大小(在部分读取后不返回,InputStream有时会返回;部分读取只允许在文件末尾)。您可以通过使用RandomAccessFile加载固定文件来调试它,如果您看到错误已经解决,您可以实现自己的MediaDataSource读取content:// scheme (由系统文件选择器返回)。
您可以在您的MediaDataSource中记录读取,并将日志与在另一台没有发生bug的设备上成功运行进行比较(在同一文件上测试)。也许你会看到Android在Android 9上请求不同的范围,或者它请求相同的读取但仍然失败。那就是Android的bug,你可能无法修复它。
希望这能帮助你更好地找到问题的原因,甚至解决它。
https://stackoverflow.com/questions/65819174
复制相似问题