问题描述
我的 StreamPlayer 有一个奇怪的问题,我需要任何帮助.
I have a strange issue with my StreamPlayer and I need any help I can get.
我需要实现的主要目标是 StreamPlayer,它能够以尽可能小的延迟播放 MPEG-2 传输流.为此,我遵循这种方法:
The main goal I need to achieve is StreamPlayer which is able to play back MPEG-2 Transport Streams with smallest possible latency. For this I am following this approach:
流由基于 Java 的 TS 解析器解析.我已经实现了一个类似于 MediaExtractor 并且工作正常的 TSExtractor.我可以以与使用 MediaExtractor 和
The stream is parsed by a Java based TS Parser. I have implemented a TSExtractor which is similar to the MediaExtractor and which works fine. I can receive all the media samples for a selected track the same way it is possible using the MediaExtractor with
extractor.readSampleData(...);
extractor.advance();
要解码 AAC 数据,我想创建和配置 MediaCodec 的实例.使用 MediaExtractor 类通常由
To decode the AAC data I want to create and configure an instance of MediaCodec. Using the MediaExtractor class this is usually done by
MediaFormat mediaFormat = extractor.getTrackFormat(i);
decoder = MediaCodec.createDecoderByType(mediaFormat.getString(MediaFormat.KEY_MIME));
decoder.configure(mediaFormat, null, null, 0);
因为我必须在我使用的 TSExtractor.getTrackFormat(int track) 方法中初始化 MediaFormat
As I have to initialize the MediaFormat in the TSExtractor.getTrackFormat(int track) method I use
MediaFormat mf = MediaFormat.createAudioFormat ("audio/mp4a-latm", getSampleRate(), getChannelCount());
并且因为我所有的 AAC 样本都包含一个 ADTS,所以我会这样做
and because all my AAC samples include an ADTS I do
mediaFormat.setInteger(MediaFormat.KEY_IS_ADTS, 1);
阅读这篇后,我终于添加了一个 ESDS 框架使用csd-0"键
After reading this post I finally add an ESDS frame using the "csd-0" key
mediaFormat.setByteBuffer("csd-0", ByteBuffer.allocate(2).put(new byte[]{(byte) 0x11, (byte)0x90}));
从 ADTS 中提取值 0x11 和 0x90.
where the values 0x11 and 0x90 are extracted from the ADTS.
当我现在想解码 AAC 样本时,解码器发布
When I now want to decode the AAC samples the decoder posts
AAC decoder returned error 4097, substituting silence
到日志.
为了验证我的 TSExtractor 是否正确提取了样本,我使用 VLC 将相同的流录制为 mp4 文件而不进行转码,因此原始流保持不变.现在我可以用录制的 mp4 文件初始化 MediaExtractor,并比较由我的 TSExtractor 和 MediaExtractor 创建的样本.使用跟踪和错误,我发现了一个非常奇怪的行为:
To verify that my TSExtractor extracts the samples correctly I recorded the same stream using VLC remuxing it to an mp4 file without transcoding so the raw stream is unchanged. Now I can initialize the MediaExtractor with the recorded mp4 file and compare the samples created by my TSExtractor and the MediaExtractor. Using trail and error I found a very strange behavior:
当我使用 MediaExtractor 创建的 mediaFormat 配置 MediaCodec 时,MediaCodec 可以毫无问题地解码我的 TSExtractor 返回的 AAC 样本.比较 MediaFormat,它基本上包装了一个 HashMap,由我的 TSExtractor 创建和由 MediaExtractor 创建的,给出了以下差异:
When I configure the MediaCodec using the mediaFormat created by the MediaExtractor the MediaCodec decodes the AAC samples returned by my TSExtractor without any problems. Comparing the MediaFormat, which basically wraps a HashMap, created by my TSExtractor and the one created by the MediaExtractor gives this differences:
由 MediaExtractor 创建:
Created by MediaExtractor:
mediaFormat: {max-input-size=1212, durationUs=77428875, is-adts=1,通道数=2,mime=audio/mp4a-latm,csd-0=java.nio.ByteArrayBuffer[位置=0,限制=2,容量=2],采样率=48000}
由 TSExtractor 创建:
Created by TSExtractor:
mediaFormat: {is-adts=1, channel-count=2, mime=audio/mp4a-latm,csd-0=java.nio.ByteArrayBuffer[位置=2,限制=2,容量=2],采样率=48000}
即使我采用 TSExtractor 创建的 MediaFormat 与 MediaExtractor 创建的 MediaFormat 相似,解码器使用自己创建的解码器也会出现相同的错误,并且使用另一个解码器没有任何问题.
Even when I adopt the MediaFormat created by the TSExtractor to be similar to the one created by the MediaExtractor the decoder gives the same error using the self created and decodes without any problems using the other one.
任何帮助都会非常有帮助.
Any help would be really helpful.
推荐答案
我真的不知道为什么,但事实证明以这种方式初始化csd-0"ByteBuffer
I really don't know why, but it turns out that initializing the "csd-0" ByteBuffer this way
mediaFormat.setByteBuffer("csd-0", ByteBuffer.allocate(2).put(new byte[]{(byte) 0x11, (byte)0x90}));
不起作用,但以这种方式初始化
doesn't work, but initializing it this way
byte[] bytes = new byte[]{(byte) 0x11, (byte)0x90};
ByteBuffer bb = ByteBuffer.wrap(bytes);
mediaFormat.setByteBuffer("csd-0", bb);
确实如此.
顺便说一句,使用
bb1.equals(bb2);
返回真.
很奇怪!
这篇关于如何初始化 MediaFormat 以配置 MediaCodec 以解码原始 AAC 数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!