Question

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());
        }
    }
}
Was it helpful?

Solution

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).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top