首页 > 解决方案 > 其他线程上的android mediaCodec.callback

问题描述

我正在尝试将音频文件转换为 byte[] 并且效果很好。我的问题是它适用于 UI 线程,但我想在其他线程上执行;这是我的代码:

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) {
            }
        }
    }

该文档说,如果您在主线程以外的其他线程上启动媒体编解码器,它应该在该线程中工作,但这不会发生(我测试它)。另一个解决方案是使用 hanlder,但我不知道如何!

标签: androidmultithreadingandroid-mediacodecandroid-handlermediaextractor

解决方案


请参阅MediaCodec.setCallback方法。您需要创建并启动 HandlerThread 来处理其他线程中的数据。

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

然后,Handler在后台创建HandlerThread.looper并将其作为第二个参数传递给MediaCodec.setCallback方法:

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

推荐阅读