Jua*_*lez 7 audio mp3 android mediacodec mediaextractor
我正在尝试使用MediaExtractor/MediaCodec播放mp3流.由于延迟和长缓冲区大小,MediaPlayer是不可能的.
我找到的唯一示例代码是:http://dpsm.wordpress.com/category/android/
代码示例只是parcial(?)并使用File而不是stream.
我一直在尝试调整这个例子来播放音频流,但我无法理解它应该如何工作.像往常一样Android文档没有帮助.
据我所知,首先我们获取有关流的信息,可能是使用此信息设置AudioTrack(代码示例包括AudioTrack初始化?)然后打开输入缓冲区和输出缓冲区.
我已经为此重新创建了代码,我可以猜到这将是缺少的部分,但没有音频出来.
有人能指出我正确的方向,以了解这应该如何工作?
public final String LOG_TAG = "mediadecoderexample";
private static int TIMEOUT_US = -1;
MediaCodec codec;
MediaExtractor extractor;
MediaFormat format;
ByteBuffer[] codecInputBuffers;
ByteBuffer[] codecOutputBuffers;
Boolean sawInputEOS = false;
Boolean sawOutputEOS = false;
AudioTrack mAudioTrack;
BufferInfo info;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String url = "http://82.201.100.9:8000/RADIO538_WEB_MP3";
extractor = new MediaExtractor();
try {
extractor.setDataSource(url);
} catch (IOException e) {
}
format = extractor.getTrackFormat(0);
String mime = format.getString(MediaFormat.KEY_MIME);
int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
Log.i(LOG_TAG, "===========================");
Log.i(LOG_TAG, "url "+url);
Log.i(LOG_TAG, "mime type : "+mime);
Log.i(LOG_TAG, "sample rate : "+sampleRate);
Log.i(LOG_TAG, "===========================");
codec = MediaCodec.createDecoderByType(mime);
codec.configure(format, null , null , 0);
codec.start();
codecInputBuffers = codec.getInputBuffers();
codecOutputBuffers = codec.getOutputBuffers();
extractor.selectTrack(0);
mAudioTrack = new AudioTrack(
AudioManager.STREAM_MUSIC,
sampleRate,
AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT,
AudioTrack.getMinBufferSize (
sampleRate,
AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT
),
AudioTrack.MODE_STREAM
);
info = new BufferInfo();
input();
output();
}
private void output()
{
final int res = codec.dequeueOutputBuffer(info, TIMEOUT_US);
if (res >= 0) {
int outputBufIndex = res;
ByteBuffer buf = codecOutputBuffers[outputBufIndex];
final byte[] chunk = new byte[info.size];
buf.get(chunk); // Read the buffer all at once
buf.clear(); // ** MUST DO!!! OTHERWISE THE NEXT TIME YOU GET THIS SAME BUFFER BAD THINGS WILL HAPPEN
if (chunk.length > 0) {
mAudioTrack.write(chunk, 0, chunk.length);
}
codec.releaseOutputBuffer(outputBufIndex, false /* render */);
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
sawOutputEOS = true;
}
} else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
codecOutputBuffers = codec.getOutputBuffers();
} else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
final MediaFormat oformat = codec.getOutputFormat();
Log.d(LOG_TAG, "Output format has changed to " + oformat);
mAudioTrack.setPlaybackRate(oformat.getInteger(MediaFormat.KEY_SAMPLE_RATE));
}
}
private void input()
{
Log.i(LOG_TAG, "inputLoop()");
int inputBufIndex = codec.dequeueInputBuffer(TIMEOUT_US);
Log.i(LOG_TAG, "inputBufIndex : "+inputBufIndex);
if (inputBufIndex >= 0) {
ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
int sampleSize = extractor.readSampleData(dstBuf, 0);
Log.i(LOG_TAG, "sampleSize : "+sampleSize);
long presentationTimeUs = 0;
if (sampleSize < 0) {
Log.i(LOG_TAG, "Saw input end of stream!");
sawInputEOS = true;
sampleSize = 0;
} else {
presentationTimeUs = extractor.getSampleTime();
Log.i(LOG_TAG, "presentationTimeUs "+presentationTimeUs);
}
codec.queueInputBuffer(inputBufIndex,
0, //offset
sampleSize,
presentationTimeUs,
sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
if (!sawInputEOS) {
Log.i(LOG_TAG, "extractor.advance()");
extractor.advance();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:添加logcat输出以获得额外的想法.
03-10 16:47:54.115: I/mediadecoderexample(24643): ===========================
03-10 16:47:54.115: I/mediadecoderexample(24643): url ....
03-10 16:47:54.115: I/mediadecoderexample(24643): mime type : audio/mpeg
03-10 16:47:54.115: I/mediadecoderexample(24643): sample rate : 32000
03-10 16:47:54.115: I/mediadecoderexample(24643): ===========================
03-10 16:47:54.120: I/OMXClient(24643): Using client-side OMX mux.
03-10 16:47:54.150: I/Reverb(24643): getpid() 24643, IPCThreadState::self()->getCallingPid() 24643
03-10 16:47:54.150: I/mediadecoderexample(24643): inputLoop()
03-10 16:47:54.155: I/mediadecoderexample(24643): inputBufIndex : 0
03-10 16:47:54.155: I/mediadecoderexample(24643): sampleSize : 432
03-10 16:47:54.155: I/mediadecoderexample(24643): presentationTimeUs 0
03-10 16:47:54.155: I/mediadecoderexample(24643): extractor.advance()
03-10 16:47:59.085: D/HTTPBase(24643): [2] Network BandWidth = 187 Kbps
03-10 16:47:59.085: D/NuCachedSource2(24643): Remaining (64K), HighWaterThreshold (20480K)
03-10 16:48:04.635: D/HTTPBase(24643): [3] Network BandWidth = 141 Kbps
03-10 16:48:04.635: D/NuCachedSource2(24643): Remaining (128K), HighWaterThreshold (20480K)
03-10 16:48:09.930: D/HTTPBase(24643): [4] Network BandWidth = 127 Kbps
03-10 16:48:09.930: D/NuCachedSource2(24643): Remaining (192K), HighWaterThreshold (20480K)
03-10 16:48:15.255: D/HTTPBase(24643): [5] Network BandWidth = 120 Kbps
03-10 16:48:15.255: D/NuCachedSource2(24643): Remaining (256K), HighWaterThreshold (20480K)
03-10 16:48:20.775: D/HTTPBase(24643): [6] Network BandWidth = 115 Kbps
03-10 16:48:20.775: D/NuCachedSource2(24643): Remaining (320K), HighWaterThreshold (20480K)
03-10 16:48:26.510: D/HTTPBase(24643): [7] Network BandWidth = 111 Kbps
03-10 16:48:26.510: D/NuCachedSource2(24643): Remaining (384K), HighWaterThreshold (20480K)
03-10 16:48:31.740: D/HTTPBase(24643): [8] Network BandWidth = 109 Kbps
03-10 16:48:31.740: D/NuCachedSource2(24643): Remaining (448K), HighWaterThreshold (20480K)
03-10 16:48:37.260: D/HTTPBase(24643): [9] Network BandWidth = 107 Kbps
03-10 16:48:37.260: D/NuCachedSource2(24643): Remaining (512K), HighWaterThreshold (20480K)
03-10 16:48:42.620: D/HTTPBase(24643): [10] Network BandWidth = 106 Kbps
03-10 16:48:42.620: D/NuCachedSource2(24643): Remaining (576K), HighWaterThreshold (20480K)
03-10 16:48:48.295: D/HTTPBase(24643): [11] Network BandWidth = 105 Kbps
03-10 16:48:48.295: D/NuCachedSource2(24643): Remaining (640K), HighWaterThreshold (20480K)
03-10 16:48:53.735: D/HTTPBase(24643): [12] Network BandWidth = 104 Kbps
03-10 16:48:53.735: D/NuCachedSource2(24643): Remaining (704K), HighWaterThreshold (20480K)
03-10 16:48:59.115: D/HTTPBase(24643): [13] Network BandWidth = 103 Kbps
03-10 16:48:59.115: D/NuCachedSource2(24643): Remaining (768K), HighWaterThreshold (20480K)
03-10 16:49:04.480: D/HTTPBase(24643): [14] Network BandWidth = 103 Kbps
03-10 16:49:04.480: D/NuCachedSource2(24643): Remaining (832K), HighWaterThreshold (20480K)
03-10 16:49:09.955: D/HTTPBase(24643): [15] Network BandWidth = 102 Kbps
Run Code Online (Sandbox Code Playgroud)
中的代码onCreate()表明您对工作原理有误解MediaCodec。您的代码当前是:
onCreate() {
...setup...
input();
output();
}
Run Code Online (Sandbox Code Playgroud)
MediaCodec在访问单元上运行。对于视频,每次调用输入/输出都会获得一帧视频。我没有使用过音频,但我的理解是它的行为类似。您不会将整个文件加载到输入缓冲区中,并且它不会为您播放流;您取出文件的一小部分,将其交给解码器,然后解码器传回解码后的数据(例如 YUV 视频缓冲区或 PCM 音频数据)。然后,您可以执行任何必要的操作来播放该数据。
因此,您的示例最多只能解码一小部分音频。您需要在循环中执行提交-输入-获取-输出,并正确处理流结束。您可以在各种bigflake示例中看到针对视频完成的操作。看起来您的代码具有必要的部分。
您使用的超时值为 -1(无限),因此您将提供一个输入缓冲区并永远等待一个输出缓冲区。在视频中,这是行不通的——我测试过的解码器似乎需要大约四个输入缓冲区才能产生任何输出——但我还没有处理过音频,所以我不确定这是否有效预计会起作用。由于您的代码已挂起,我猜它不是。将超时更改为(例如)10000 并查看挂起是否消失可能会很有用。
我假设这是一个实验,并且您不会真正在onCreate(). :-)
| 归档时间: |
|
| 查看次数: |
12299 次 |
| 最近记录: |