user13954958
user13954958

Reputation:

android mediaCodec.callback on other Thread

i am trying to convert audio file to byte[] and it works well. my problem is that it works on UI thread but i want to do it on other Thread; this is my code:

private class DecodeMusic extends Thread {
        @RequiresApi(api = Build.VERSION_CODES.M)
        public void run() {
            playing = true;
            sample = musics.get(current_music).getSample();
            channel = musics.get(current_music).getChannel();
            duration = musics.get(current_music).getDuration();

            try {
                if (mediaCodec != null) {
                    mediaCodec.stop();
                    mediaCodec.release();
                    mediaCodec = null;
                }

                if (mediaExtractor != null)
                    mediaExtractor.release();

                musicQueue = new ArrayList<>();
                StereoFile stereoFile = musics.get(current_music);

                mediaExtractor = new MediaExtractor();
                mediaExtractor.setDataSource(stereoFile.getPath());

                MediaFormat format = mediaExtractor.getTrackFormat(0);
                mediaExtractor.selectTrack(0);

                MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
                mediaCodec = MediaCodec.createByCodecName(mediaCodecList.findDecoderForFormat(format));

                musicQueue = new ArrayList<>(duration * sample);

                try {
                    Looper.prepare();
                    Handler handler = new Handler();

                    mediaCodec.setCallback(new MediaCodec.Callback() {
                        @Override
                        public void onInputBufferAvailable(@NonNull MediaCodec codec, int index) {
                            ByteBuffer decoderInputBuffer = codec.getInputBuffer(index);
                            int size = mediaExtractor.readSampleData(decoderInputBuffer, 0);
                            if (size < 0) {
                                codec.queueInputBuffer(index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                            } else {
                                codec.queueInputBuffer(index, 0, size, mediaExtractor.getSampleTime(), 0);
                                mediaExtractor.advance();
                            }
                        }

                        @Override
                        public void onOutputBufferAvailable(@NonNull MediaCodec codec, int index, @NonNull MediaCodec.BufferInfo info) {
                            byte[] data = new byte[info.size - info.offset];
                            mediaCodec.getOutputBuffer(index).get(data);
                            musicQueue.add(data);
                            mediaCodec.releaseOutputBuffer(index, true);
                        }

                        @Override
                        public void onError(@NonNull MediaCodec codec, @NonNull MediaCodec.CodecException e) {

                        }

                        @Override
                        public void onOutputFormatChanged(@NonNull MediaCodec codec, @NonNull MediaFormat format) {
                        }
                    }, handler);

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

                mediaCodec.configure(format, null, null, 0);
                mediaCodec.start();
            } catch (IOException ignored) {
            }
        }
    }

The doc says that if you start mediacodec on other thread than main, it should works in that thread but this doesn't happen(i test it). another solution is using hanlder but i don't know how!

Upvotes: 0

Views: 1394

Answers (1)

balezz
balezz

Reputation: 838

Please, see MediaCodec.setCallback method. You need to create and start HandlerThread to process data in other thread.

private var codecHandlerThread: HandlerThread = HandlerThread(TAG)
codecHandlerThread.start()

Then, create Handler on background HandlerThread.looper and pass it as a second argument to MediaCodec.setCallback method:

val backgroundHandler = Handler(decoderHandlerThread.looper)
mediaCodec.setCallback(yourCallback, backgroundHandler)

Upvotes: 1

Related Questions