我正在尝试从解码的mp4缓冲区中获取PCM样本以进行进一步处理。我首先从使用手机的相机应用程序录制的视频文件中提取音轨,并且我已经确保在获得“音频/mp4”mime键时选择了音轨:
MediaExtractor extractor = new MediaExtractor();
try {
extractor.setDataSource(fileUri.getPath());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int numTracks = extractor.getTrackCount();
for(int i =0; i<numTracks; ++i) {
MediaFormat format = extractor.getTrackFormat(i);
String mime = format.getString(MediaFormat.KEY_MIME);
//Log.d("mime =",mime);
if(mime.startsWith("audio/")) {
extractor.selectTrack(i);
decoder = MediaCodec.createDecoderByType(mime);
decoder.configure(format, null, null, 0);
//getSampleCryptoInfo(MediaCodec.CryptoInfo info)
break;
}
}
if (decoder == null) {
Log.e("DecodeActivity", "Can't find audio info!");
return;
}
decoder.start();
之后,我遍历轨道,向编解码器提供编码访问单元流,并将解码的访问单元拉入ByteBuffer(这是我从此处发布的视频渲染示例中回收的代码https://github.com/vecio/MediaCodecDemo):
ByteBuffer[] inputBuffers = decoder.getInputBuffers();
ByteBuffer[] outputBuffers = decoder.getOutputBuffers();
BufferInfo info = new BufferInfo();
boolean isEOS = false;
while (true) {
if (!isEOS) {
int inIndex = decoder.dequeueInputBuffer(10000);
if (inIndex >= 0) {
ByteBuffer buffer = inputBuffers[inIndex];
int sampleSize = extractor.readSampleData(buffer, 0);
if (sampleSize < 0) {
// We shouldn't stop the playback at this point, just pass the EOS
// flag to decoder, we will get it again from the
// dequeueOutputBuffer
Log.d("DecodeActivity", "InputBuffer BUFFER_FLAG_END_OF_STREAM");
decoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
isEOS = true;
} else {
decoder.queueInputBuffer(inIndex, 0, sampleSize, extractor.getSampleTime(), 0);
extractor.advance();
}
}
}
int outIndex = decoder.dequeueOutputBuffer(info, 10000);
switch (outIndex) {
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
Log.d("DecodeActivity", "INFO_OUTPUT_BUFFERS_CHANGED");
outputBuffers = decoder.getOutputBuffers();
break;
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
Log.d("DecodeActivity", "New format " + decoder.getOutputFormat());
break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
Log.d("DecodeActivity", "dequeueOutputBuffer timed out!");
break;
default:
ByteBuffer buffer = outputBuffers[outIndex];
// How to obtain PCM samples from this buffer variable??
decoder.releaseOutputBuffer(outIndex, true);
break;
}
// All decoded frames have been rendered, we can stop playing now
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
Log.d("DecodeActivity", "OutputBuffer BUFFER_FLAG_END_OF_STREAM");
break;
}
}
到目前为止,该代码似乎没有错误,但我目前一直在尝试弄清楚如何从获取输出缓冲区值的ByteBuffer中获取PCM样本。我想我可以假设,由于我正在使用16位立体声音频文件,因此交错方案中应该至少有两个字节......但是我不太确定这一点,所以要明确地从这个字节流中检索PCM样本。有人知道如何从MediaCodec API中获取这些吗?
我读过一些使用ffmpeg或openSL的替代方案,但由于我对Android编程还不熟悉,我希望避免使用基于c的API带来的复杂性,并仅使用Android框架提供的工具构建我的第一个应用程序(我使用的是KitKat)。任何帮助都将不胜感激。
更新:我能够提取PCM样本,按照我假设的方式以及way@marcone指出的方式。为此,我在缓冲区分配下方添加了以下行:
byte[] b = new byte[info.size-info.offset];
int a = buffer.position();
buffer.get(b);
buffer.position(a);
最后通过以下方式将字节数组写入文件:
f.write(b,0,info.size-info.offset);
我现在面临的问题是:
解码后的音频样本与iZotope对mp4音频曲目的解码不完全匹配。波形文件大小存在48个样本不匹配,解码信号存在2112个样本延迟。我现在的问题是:所有mp4解码器会产生相同的输出PCM流,还是取决于解码器的实现?
我知道问题在这里解决了。但MediaCodec在当前代码中是同步使用的,到目前为止,该代码已被弃用。我从这个问题中学到了一些东西,并在异步使用MediaCodec时做了同样的事情。只需发布github链接,以便日后对他人有所帮助。
Github异步实现:链接
仅供参考:目前使用的音频播放器只是从其他线程复制粘贴。它是去润滑的。我会在有时间的时候更新。代码也在Kotlin中。(仍然很容易理解)
请查看官方MediaCodec文档的异步链接
我发现延迟是由AAC编码启动和剩余时间引起的,如下所述:
https://developer.apple.com/library/mac/documentation/quicktime/qtff/QTFFAppenG/QTFFAppenG.html
在我的例子中,启动时间总是2112个样本,剩余时间自然会根据音频大小而变化。
Android MediaCodec可以用来解码输出的yuv420格式。我猜应该是NV12格式,但是当我在Nexus6 7.1.1设备上试用的时候。结果很奇怪: > 对于720p视频,它工作良好,输出的yuv可以通过ffplay播放,使用以下命令: ffplay-V信息-F rawvideo-PIXEL_FORMAT yuv420p-VIDEO_SIZE 1280x720 OUT.YUV 当试图解
我有一个Android MediaCodec解码器,配置了一个来自SurfaceTexture对象的Surface。MP4文件解码工作良好,帧可以在设备上看到。但是如果尝试用MediaMuxer重新编码为新的MP4文件,则输出文件大小为零,因为SurfaceTexture.getTimestamp()返回的总是0。在这种情况下,获得帧呈现时间的适当方法是什么?
数据:“{\”数据\“:[\”124“,\”611“]}”,Lasteventid:“”} 是否可以只抓取,因为否则客户端在反序列化方面会出现问题。
大小范围在2.5MB-20MB之间。这个问题在较长的剪辑上变得更糟,例如7分钟的范围是9MB-120MB。 正常吗? 我试图捕捉同样的场景,但还是得到了不同的结果。
问题内容: 要获取有关媒体文件的大量信息,可以做 它会输出很多行,特别是一行 我只想输出,所以我尝试 但是它可以打印所有内容,而不仅仅是长度。 甚至输出所有内容。 如何获得持续时间长度? 问题答案: ffmpeg正在将该信息写入,而不是。尝试这个: 注意重定向到: 编辑: 您的陈述也不起作用。尝试这个:
问题内容: 我写了一个小小的go脚本,并使用strace跟踪了该脚本,我试图使用netlink协议从内核中获取审核消息,就像auditd一样。 以下是我的旅途中strace的输出脚本- http://paste.ubuntu.com/8272760/ 我试图找到auditd提供给sendto函数的参数。当我在auditd上运行strace时,我得到以下输出 当我追踪我的go文件时,我得到以下输出。