twe*_*jen 5 android mediacodec
我的StreamPlayer有一个奇怪的问题,我需要任何帮助.
我需要实现的主要目标是StreamPlayer,它能够以尽可能小的延迟回放MPEG-2传输流.为此,我遵循这种方法:
该流由基于Java的TS Parser解析.我已经实现了一个类似于MediaExtractor的TSExtractor,它工作正常.我可以像使用MediaExtractor一样接收选定轨道的所有媒体样本
extractor.readSampleData(...);
extractor.advance();
Run Code Online (Sandbox Code Playgroud)
要解码我想要创建和配置MediaCodec实例的AAC数据.使用MediaExtractor类通常由此完成
MediaFormat mediaFormat = extractor.getTrackFormat(i);
decoder = MediaCodec.createDecoderByType(mediaFormat.getString(MediaFormat.KEY_MIME));
decoder.configure(mediaFormat, null, null, 0);
Run Code Online (Sandbox Code Playgroud)
因为我必须在TSExtractor.getTrackFormat(int track)方法中初始化MediaFormat,所以我使用
MediaFormat mf = MediaFormat.createAudioFormat ("audio/mp4a-latm", getSampleRate(), getChannelCount());
Run Code Online (Sandbox Code Playgroud)
因为我的所有AAC样本都包括我做的ADTS
mediaFormat.setInteger(MediaFormat.KEY_IS_ADTS, 1);
Run Code Online (Sandbox Code Playgroud)
阅读这篇文章后,我终于使用"csd-0"键添加了ESDS帧
mediaFormat.setByteBuffer("csd-0", ByteBuffer.allocate(2).put(new byte[]{(byte) 0x11, (byte)0x90}));
Run Code Online (Sandbox Code Playgroud)
其中值0x11和0x90是从ADTS中提取的.
当我现在想要解码AAC样本时,解码器发布
AAC decoder returned error 4097, substituting silence
Run Code Online (Sandbox Code Playgroud)
到日志.
为了验证我的TSExtractor正确提取样本我使用VLC记录了相同的流,将其重新转换为mp4文件而不进行转码,因此原始流不变.现在我可以用记录的mp4文件初始化MediaExtractor,并比较我的TSExtractor和MediaExtractor创建的样本.使用跟踪和错误我发现了一个非常奇怪的行为:
当我使用MediaExtractor创建的mediaFormat配置MediaCodec时,MediaCodec会解码我的TSExtractor返回的AAC样本而没有任何问题.比较MediaFormat,它基本上包装了由我的TSExtractor创建的HashMap和由MediaExtractor创建的那个,给出了这些差异:
由MediaExtractor创建:
mediaFormat:{max-input-size = 1212,durationUs = 77428875,is-adts = 1,channel-count = 2,mime = audio/mp4a-latm,csd-0 = java.nio.ByteArrayBuffer [position = 0,limit = 2,容量= 2],采样率= 48000}
由TSExtractor创建:
mediaFormat:{is-adts = 1,channel-count = 2,mime = audio/mp4a-latm,csd-0 = java.nio.ByteArrayBuffer [position = 2,limit = 2,capacity = 2],sample-rate = 48000}
即使我采用TSExtractor创建的MediaFormat与MediaExtractor创建的MediaFormat类似,解码器也会使用self创建并使用另一个解码时出现相同的错误.
任何帮助都会非常有帮助.
我真的不知道为什么,但事实证明以这种方式初始化"csd-0"ByteBuffer
mediaFormat.setByteBuffer("csd-0", ByteBuffer.allocate(2).put(new byte[]{(byte) 0x11, (byte)0x90}));
Run Code Online (Sandbox Code Playgroud)
不起作用,但以这种方式初始化
byte[] bytes = new byte[]{(byte) 0x11, (byte)0x90};
ByteBuffer bb = ByteBuffer.wrap(bytes);
mediaFormat.setByteBuffer("csd-0", bb);
Run Code Online (Sandbox Code Playgroud)
确实.
顺便说一句,比较这两个byteBuffers使用
bb1.equals(bb2);
Run Code Online (Sandbox Code Playgroud)
返回true.
很奇怪!
csd-0 中的值取决于 ADTS 标头。
ADTS 标头长度最多为 9 个字节。要生成 csd-0,您需要标头的第二个和第三个字节。
int profile = (header[2] & 0xC0) >> 6;
int srate = (header[2] & 0x3C) >> 2;
int channel = ((header[2] & 0x01) << 2) | ((header.[3] & 0xC0) >> 6)
ByteBuffer csd = ByteBuffer.allocate(2);
csd.put(0, (byte)( ((profile + 1) << 3) | srate >> 1 ) );
csd.put(1, (byte)( ((srate << 7) & 0x80) | channel << 3 ) );
Run Code Online (Sandbox Code Playgroud)
现在您获得了此 aac 音频流的有效 csd-0。
| 归档时间: |
|
| 查看次数: |
7750 次 |
| 最近记录: |