首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Android MediaExtractor退样失败

Android MediaExtractor退样失败
EN

Stack Overflow用户
提问于 2021-01-21 07:29:12
回答 2查看 430关注 0票数 2

我正在尝试使用MediaCodecMediaExtractor将视频解码到安卓的一个表面上。

首先,我在MediaExtractor对象(下面是extractor)上使用setDataSource(context, uri, null)方法来设置数据源uri。uri来自Android视频文件选择器。这个调用似乎没有抛出任何异常。

在解码器的onInputBufferAvailable()调用中,我从提取器读取了一个新的样本,但是extractor.readSampleData(..)调用随机地无法读取正确的数据,并开始返回大小为1的缓冲区。理想情况下,只有在读取完整个文件后,大小才应该为-1。此外,一旦提取器开始返回-1,无论我调用extractor.advance()多少次,它都不会返回正确的样本。

每当发生此问题时,我都会在日志中观察到以下警告消息:

代码语言:javascript
复制
W/NuMediaExtractor: read on track 0 failed with error -2147483646

代码:

代码语言:javascript
复制
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循环从队列中拾取这些缓冲区。

代码语言:javascript
复制
    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
                    )

                }
            }
        }
    }
EN

回答 2

Stack Overflow用户

发布于 2021-01-28 01:56:18

我认为你的根本问题是uri。我的建议是将其重新解析为更常见的东西,并被许多应用程序广泛接受。例如,如果您的uri类似于(以content://com.android.providers.downloads.documents/document/3356://开头)内容,请尝试将其更改为file:///storage/emulated/0/document/3356com.android.providers.downloads.documents是包名,document/3356是文件路径。您可以通过Environment.getExternalStorageDirectory()方法获取/storage/emulated/0。然后使用Uri.parse("string")获取uri实例。

代码语言:javascript
复制
Uri uri = Uri.parse("file:///storage/emulated/0/document/3356");
票数 0
EN

Stack Overflow用户

发布于 2021-02-02 00:53:18

首先在谷歌上搜索"NuMediaExtractor: read on track 0失败,错误为-2147483646“。我看到两个结果:AB

他们写的是Android 10中修复的bug,比如比特率太高,需要重新编码视频。

尽管如此,我仍然建议寻找可能的解决方法。而不是使用setDataSource(Context, Uri, Map),试着调用setDataSource(MediaDataSource),实现你自己的MediaDataSource,只有两个方法:getSize,你返回文件的大小,和readAt,你从文件中读取完全请求的大小(在部分读取后不返回,InputStream有时会返回;部分读取只允许在文件末尾)。您可以通过使用RandomAccessFile加载固定文件来调试它,如果您看到错误已经解决,您可以实现自己的MediaDataSource读取content:// scheme (由系统文件选择器返回)。

您可以在您的MediaDataSource中记录读取,并将日志与在另一台没有发生bug的设备上成功运行进行比较(在同一文件上测试)。也许你会看到Android在Android 9上请求不同的范围,或者它请求相同的读取但仍然失败。那就是Android的bug,你可能无法修复它。

希望这能帮助你更好地找到问题的原因,甚至解决它。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65819174

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档