MediaCodecとMediaExtractorの理解

Powercoder:

私は、ちょうど数学を、それらを再生せずに、オーディオファイルに何らかの処理を行いたいです。私は、右をやっている場合は疑うと、いくつかの質問があります。私はいくつかの例を読みますが、それらのほとんどは、ビデオストリーミング、すべての生データとは、作業がない程度です。

  1. 私はそれがステレオであるが、左右が同じである、すなわち2つの同一のチャンネルを持っているmp3ファイルを用意しました。復号後、私は同様に、交互ためPCM-16はサンプルチャネルの等しい数のペアのバッファを取得することが期待{ L R L R L R...}、右?例えば:

    { 105 105 601 601 -243 -243 -484 -484...}。

    しかし、私は近い数のペアを取得するが、一致しません。

    { -308 -264 -1628 -1667 -2568 -2550 -4396 -4389}

    mp3アルゴリズムが異なったり、なぜ同じ値をエンコードしていますか?

  2. 私は、1024個のサンプルのパックでデータを処理したいです。私は生データの次のバッチまでの残りの部分を保存する別のパックのための十分でないサンプルが存在することになる場合には(参照mExcessコードで)。順序が保持されるという保証はありますか?

  3. 私は、オーディオデータのすべての単一の値として「サンプル」を理解するために使用しました。ここで私が見るMediaExtractor::readSampleDataMediaExtractor::advance方法。最初の戻り〜2000個の値は、第二の説明において「アドバンス次のサンプルを」と述べました。命名のこれだけの重複はありますか?私は、これらの方法は、ループ内でペアに呼ばれている例をいくつか見ました。私の使い方は正しいですか?

ここに私のコードは次のとおりです。

public static void foo(String filepath) throws IOException {
    final int SAMPLES_PER_CHUNK = 1024;

    MediaExtractor mediaExtractor = new MediaExtractor();
    mediaExtractor.setDataSource(filepath);
    MediaFormat mediaFormat = mediaExtractor.getTrackFormat(0);
    mediaExtractor.release();

    MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
    mediaFormat.setString(MediaFormat.KEY_FRAME_RATE, null);
    String codecName = mediaCodecList.findDecoderForFormat(mediaFormat);
    mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 0);  // MediaCodec crashes with JNI
                                                            // error if FRAME_RATE is null
    MediaCodec mediaCodec = MediaCodec.createByCodecName(codecName);
    mediaCodec.setCallback(new MediaCodec.Callback() {
        private MediaExtractor mExtractor;
        private short[] mExcess;

        @Override
        public void onInputBufferAvailable(MediaCodec codec, int index) {
            if (mExtractor == null) {
                mExtractor = new MediaExtractor();
                try {
                    mExtractor.setDataSource(filepath);
                    mExtractor.selectTrack(0);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                mExcess = new short[0];
            }
            ByteBuffer in = codec.getInputBuffer(index);
            in.clear();
            int sampleSize = mExtractor.readSampleData(in, 0);
            if (sampleSize > 0) {
                boolean isOver = !mExtractor.advance();
                codec.queueInputBuffer(
                        index,
                        0,
                        sampleSize,
                        mExtractor.getSampleTime(),
                        isOver ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
            } else {
                int helloAmaBreakpoint = 1;
            }
        }

        @Override
        public void onOutputBufferAvailable(
                MediaCodec codec,
                int index,
                MediaCodec.BufferInfo info) {
            ByteBuffer tmp = codec.getOutputBuffer(index);
            if (tmp.limit() == 0) return;

            ShortBuffer out = tmp.order(ByteOrder.nativeOrder()).asShortBuffer();
            // Prepend the remainder from previous batch to the new data
            short[] buf = new short[mExcess.length + out.limit()];
            System.arraycopy(mExcess, 0, buf, 0, mExcess.length);
            out.get(buf, mExcess.length, out.limit());

            final int channelCount
                    = codec.getOutputFormat().getInteger(MediaFormat.KEY_CHANNEL_COUNT);
            for (
                    int offset  = 0;
                    offset + SAMPLES_PER_CHUNK * channelCount < buf.length;
                    offset += SAMPLES_PER_CHUNK * channelCount) {

                double[] x = new double[SAMPLES_PER_CHUNK];  // left channel
                double[] y = new double[SAMPLES_PER_CHUNK];  // right channel
                switch (channelCount) {
                    case 1:  // if 1 channel then make 2 identical arrays
                        for (int i = 0; i < SAMPLES_PER_CHUNK; ++i) {
                            x[i] = (double) buf[offset + i];
                            y[i] = (double) buf[offset + i];
                        }
                        break;
                    case 2:  // if 2 channels then read values alternately
                        for (int i = 0; i < SAMPLES_PER_CHUNK; ++i) {
                            x[i] = (double) buf[offset + i * 2];
                            y[i] = (double) buf[offset + i * 2 + 1];
                        }
                        break;
                    default:
                        throw new IllegalStateException("No algorithm for " + channelCount + " channels");
                }

                /// ... some processing ... ///
            }

            // Save the rest until next batch of raw data
            int samplesLeft = buf.length % (SAMPLES_PER_CHUNK * channelCount);
            mExcess = new short[samplesLeft];
            System.arraycopy(
                    buf,
                    buf.length - samplesLeft,
                    mExcess,
                    0,
                    samplesLeft);

            codec.releaseOutputBuffer(index, false);
            if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) > 0) {
                codec.stop();
                codec.release();
                mExtractor.release();
            }
        }

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

        }

        @Override
        public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {

        }
    });

    mediaFormat.setInteger(MediaFormat.KEY_PCM_ENCODING, AudioFormat.ENCODING_PCM_16BIT);
    mediaCodec.configure(mediaFormat, null, null, 0);
    mediaCodec.start();
}

クイックコードレビューも大歓迎です。

mstorsjo:
  1. 私は正確に確認してください、それはこのようにそれらをコーディングする理由のだけど、私は小さな変動が予想される許容範囲内にあると思います。mp3は、非可逆コーデックであり、デコーダからの出力値があれば可聴表現が近い十分であるように、入力と同じではないことに留意してください。2つのチャネルが微妙に異なってしまうでしょうしかし、なぜそれが示すものではありません。

  2. はい、デコードされたフレームの個々の順序は同じになります。正確な値は一致しませんが、それの音が類似していなければなりません。

  3. MediaExtractorにおいて、サンプルは、デコーダに供給べきデータの1つの符号化パケットです。mp3の場合、これは一般的に(チャネルあたり)1152個のサンプルになります。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=219258&siteId=1