0

私は非常に単純な音楽アプリを作成しています。これを行う方法を見つけようとしています:

  • オーディオ ファイルをダウンロードし、ファイルをローカルに録音する
  • いつでも、ファイルからオーディオ フレームを抽出します (ダウンロード中またはダウンロード後)。

1)ダウンロード部分については、この例に従って Retrofit を使用します。簡単に言うと、ファイルをダウンロードし、ダウンロード中にローカルに記録することができます (そのため、ファイルのデータにアクセスするためにダウンロードの終了を待つ必要はありません)。

2)フレーム抽出部分については、次のように使用MediaExtractorします。MediaCodec

MediaCodec codec;
MediaExtractor extractor;

MediaFormat format;
ByteBuffer[] codecInputBuffers;
ByteBuffer[] codecOutputBuffers;
Boolean sawInputEOS = false;
Boolean sawOutputEOS = false;
AudioTrack mAudioTrack;
MediaCodec.BufferInfo info;

File outputFile = null;
FileDescriptor fileDescriptor = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
   ...
   // the file being downloaded:
   outputFile = new File(directory, "test.mp3");
   try {
      FileInputStream fileInputStream = new FileInputStream(outputFile);
      fileDescriptor = fileInputStream.getFD();
   }
   catch (Exception e) {}
}

// Called once when enough data to extract.
private void onAudioFileReady() {
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            // thread :
            Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO);

            // audio :
            extractor = new MediaExtractor();

            // the extractor only extracts the already downloaded part of the file:
            try {
                //  extractor.setDataSource(url);
                //  extractor.setDataSource(outputFile.getAbsolutePath());
                //  extractor.setDataSource(MainActivity.this, Uri.parse(outputFile.getAbsolutePath()), null);
                extractor.setDataSource(fileDescriptor);
            }
            catch (IOException e) {}

            format = extractor.getTrackFormat(0);
            String mime = format.getString(MediaFormat.KEY_MIME);
            int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);

            try {
                codec = MediaCodec.createDecoderByType(mime);
            }
            catch (IOException e) {}
            codec.configure(format, null, null, 0);
            codec.start();

            codecInputBuffers = codec.getInputBuffers();
            codecOutputBuffers = codec.getOutputBuffers();

            extractor.selectTrack(0);

            int minBufferSize = AudioTrack.getMinBufferSize(
                    sampleRate,
                    AudioFormat.CHANNEL_OUT_STEREO,
                    AudioFormat.ENCODING_PCM_16BIT);

            mAudioTrack = new AudioTrack(
                    AudioManager.STREAM_MUSIC,
                    sampleRate,
                    AudioFormat.CHANNEL_OUT_STEREO,
                    AudioFormat.ENCODING_PCM_16BIT,
                    minBufferSize,
                    AudioTrack.MODE_STREAM
            );
            info = new MediaCodec.BufferInfo();
            mAudioTrack.play();

            do {
                input();
                output();
            }
            while (!sawInputEOS);
        }
    });
    thread.start();
}

private void input() {
    int inputBufferIndex = codec.dequeueInputBuffer(-1);
    if (inputBufferIndex >= 0) {
        ByteBuffer byteBuffer = codecInputBuffers[inputBufferIndex];
        int sampleSize = extractor.readSampleData(byteBuffer, 0);
        long presentationTimeUs = 0;

        if (sampleSize < 0) {
            Log.w(LOG_TAG, "Saw input end of stream!");
            sampleSize = 0;
        }
        else {
            presentationTimeUs = extractor.getSampleTime();
        }

        codec.queueInputBuffer(inputBufferIndex,
                0,
                sampleSize,
                presentationTimeUs,
                sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);

        // doesn't seem to work:
        extractor.advance();
    }
}

private void output() {
    final int res = codec.dequeueOutputBuffer(info, -1);
    if (res >= 0) {
        ByteBuffer buf = codecOutputBuffers[res];

        final byte[] chunk = new byte[info.size];
        buf.get(chunk);
        buf.clear();

        if (chunk.length > 0) {
            mAudioTrack.write(chunk, 0, chunk.length);
        }
        codec.releaseOutputBuffer(res, false);

        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();
        mAudioTrack.setPlaybackRate(oformat.getInteger(MediaFormat.KEY_SAMPLE_RATE));
    }
}

機能:

onAudioFileReady()呼び出されると、このコードはファイルのオーディオ サンプルを抽出して再生しますが、既にダウンロードされたもののみを再生します。すでにダウンロードされた部分の最後に到達すると、利用可能なデータがさらにある場合でもMediaExtractor停止します(extractor.advance()抽出を続行したくないようです...)。

私が達成したいこと:

もちろん、十分なデータがある限り、ファイルのオーディオ サンプルの抽出を続行できるようにしたいと考えています。

重要:

その時点で、なぜ私が単に を使用しないのかと尋ねるかもしれませんextractor.setDataSource(url)。理由は次のとおりです。

  • 後で再生できるように、オーディオ ファイルをローカルに保存したい
  • ダウンロード開始後もずっと再生できるようにしたい

誰もそれを達成する方法を知っていますか? よろしくお願いします。

4

0 に答える 0