Search code examples
androidmp3android-mediacodecmediaextractor

MediaExtractor.advance() - End of stream signalled earlier than expected


I have problem with end of stream signalled earlier than expected (way before file ends) by the advance() method of MediaExtractor class. According to Google reference the advance() method could work wrong when using a local file (and this is my case - filePath ponits to a local file):

When extracting a local file, the behaviors of advance() and readSampleData(ByteBuffer, int) are undefined in presence of concurrent writes to the same local file:

Unfortunately there is no single word about using MediaExtractor without advance() method. How to move to the next sample? If there is no way to do it then I'd like to know how to feed inputBuffer without using MediaExtractor.

A fragment of my code below:

 if(Build.VERSION.SDK_INT >= 21 ) {

        try {
            codec = MediaCodec.createByCodecName("OMX.google.mp3.decoder");

        } catch (IOException e) {
            e.printStackTrace();
        }

        final MediaExtractor extractor = new MediaExtractor();
        try {
            extractor.setDataSource(filePath);     //local file
            Log.i("filePath", String.valueOf(filePath));
            extractor.selectTrack(0);
        } catch (IOException e) {
            e.printStackTrace();
        }


        codec.setCallback(new MediaCodec.Callback() {

            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
            @Override
            public void onInputBufferAvailable(MediaCodec mc, int inputBufferId) {

                ByteBuffer inputBuffer = codec.getInputBuffer(inputBufferId);
                // fill inputBuffer with valid data
                int sampleSize = extractor.readSampleData(inputBuffer,0);

                if(extractor.advance) {

                    codec.queueInputBuffer(inputBufferId, 0, sampleSize, 0, 0);


                } else {
                        // EOS
                    codec.queueInputBuffer(inputBufferId, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                    codec.stop();
                    codec.release();
                }


            }
// more callbacks

};


}

Solution

  • In my samples MediaExtractor worked correctly when I used another construction of statements. I did not check EOS with extractor.advance() like you. Try how other samples offer:

       int chunkSize = extractor.readSampleData(inputBuffer, 0);
       if (chunkSize < 0) {
            // End of stream -- send empty frame with EOS flag set.
            codec.queueInputBuffer(inputBufferId, 0, 0, 0L,
                    MediaCodec.BUFFER_FLAG_END_OF_STREAM);
        } else {
            // No EOS -- continue
            long presentationTimeUs = extractor.getSampleTime();
            codec.queueInputBuffer(inputBufferId, 0, chunkSize,
                    presentationTimeUs, 0 /*flags*/);
            extractor.advance();
        }
    

    BTW, the guide of MediaExtractor tells about such usage. Fadden has MoviePlayer in Grafika with MediaExtractor. But it feeds decoder without MediaCodec.Callback.