问题
The code given below works fine on the emulator, but not the device. I found the following lines that looked suspicious to me:
V/MediaExtractor(5030): Autodetected media content as 'audio/mpeg' with confidence 0.20 V/ChromiumHTTPDataSource(5030): mContentSize is undefined or network might be disconnected V/ChromiumHTTPDataSource(5030): mContentSize is undefined or network might be disconnected D/com.example.mediacodectest(5030): MIME TYPE: audio/mpeg
I am looking for hints/suggestions. Thanks in advance...
private class PlayerThread extends Thread {
@Override
public void run() {
MediaExtractor extractor;
MediaCodec codec;
ByteBuffer[] codecInputBuffers;
ByteBuffer[] codecOutputBuffers;
AudioTrack mAudioTrack;
mAudioTrack = new AudioTrack(
AudioManager.STREAM_MUSIC,
44100,
AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT,
8192 * 2,
AudioTrack.MODE_STREAM);
extractor = new MediaExtractor();
try
{
extractor.setDataSource("http://anmp3streamingsource.com/stream");
MediaFormat format = extractor.getTrackFormat(0);
String mime = format.getString(MediaFormat.KEY_MIME);
Log.d(TAG, String.format("MIME TYPE: %s", mime));
codec = MediaCodec.createDecoderByType(mime);
codec.configure(
format,
null /* surface */,
null /* crypto */,
0 /* flags */ );
codec.start();
codecInputBuffers = codec.getInputBuffers();
codecOutputBuffers = codec.getOutputBuffers();
extractor.selectTrack(0); // <= You must select a track. You will read samples from the media from this track!
boolean sawInputEOS = false;
boolean sawOutputEOS = false;
for (;;) {
int inputBufIndex = codec.dequeueInputBuffer(-1);
if (inputBufIndex >= 0) {
ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
int sampleSize = extractor.readSampleData(dstBuf, 0);
long presentationTimeUs = 0;
if (sampleSize < 0) {
sawInputEOS = true;
sampleSize = 0;
} else {
presentationTimeUs = extractor.getSampleTime();
}
codec.queueInputBuffer(inputBufIndex,
0, //offset
sampleSize,
presentationTimeUs,
sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
if (!sawInputEOS) {
extractor.advance();
}
MediaCodec.BufferInfo info = new BufferInfo();
final int res = codec.dequeueOutputBuffer(info, -1);
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
mAudioTrack.play();
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(TAG, "Output format has changed to " + oformat);
mAudioTrack.setPlaybackRate(oformat.getInteger(MediaFormat.KEY_SAMPLE_RATE));
}
}
}
}
catch (IOException e)
{
Log.e(TAG, e.getMessage());
}
}
}
回答1:
I haven't worked with audio, but I think I may see the problem. You're hanging in dequeueOutputBuffer()
because the codec is waiting for more input.
Some of the video codecs want ~4 buffers of input before they'll even finish initialization (for example). I expect some audio codecs may behave the same way. Codec implementations vary from device to device, so it's not surprising that what runs on the emulator behaves much differently.
Change the timeouts from -1 (wait forever) to something modest (say, 1000 microseconds).
来源:https://stackoverflow.com/questions/21864255/android-mediacodec-api-music-plays-on-emulator-not-on-the-device