在MediaExtractor seekTo和AudioTrack刷新行为意外不好后,Android MediaCodec刷新

时间:2014-07-02 12:51:06

标签: android mediacodec audiotrack mediaextractor

我正在使用AudioTrack,MediaCodec和MediaExtractor的组合来解码和播放音乐。

根据the document

  

为了开始解码与先前提交的数据不相邻的数据(即,在搜索之后),必须刷新()解码器。客户端可以在刷新点处拥有的任何输入或输出缓冲区立即被撤销,即在调用flush()之后,客户端不再拥有任何缓冲区。

我在搜索后调用flush,所以我也应该调用mAudioTrack.flush();

虽然调用了flush,但是audioTrack会播放以前写入数据的某些部分,并从新写入的数据继续播放。

不调用decoder.flush,可能会在音频播放中听到明显的故障。那么如何实现瞬时刷新并继续播放新写入的数据

代码段:

更新了代码

do {
                int codedbufferIndex = decoder.dequeueInputBuffer(1000);
                if (codedbufferIndex >= 0) {
                    ByteBuffer codecInput = inputBuffers[codedbufferIndex];
                    synchronized (playerState) {
                        if (seek) {
                            extractor.seekTo(seekTo,
                                    MediaExtractor.SEEK_TO_CLOSEST_SYNC);
                        //  audioTrack.pause();
                        //  audioTrack.stop();
                        //  audioTrack.flush();
                            decoder.flush();
                            seek = false;
                        //  audioTrack.play();
                            continue;
                        }
                    }
                    read = extractor.readSampleData(codecInput, offset);
                    if (read < 0) {
                        if (extractor.hasCacheReachedEndOfStream())
                            Log.e(TAG, "extractor.hasCacheReachedEndOfStream()");
                        break;
                    }
                    presentationTimeUs = extractor.getSampleTime();
                    decoder.queueInputBuffer(codedbufferIndex, offset, read,
                            presentationTimeUs, (read > 0) ? 0
                                    : MediaCodec.BUFFER_FLAG_END_OF_STREAM);
                    int decodedDataBufIndex = decoder.dequeueOutputBuffer(info,
                            2000);
                    if (decodedDataBufIndex >= 0) {
                        ByteBuffer codecOutput = outputBuffers[decodedDataBufIndex];
                        byte[] atInput = new byte[info.size];
                        codecOutput.get(atInput);
                        codecOutput.clear();
                        decoder.releaseOutputBuffer(decodedDataBufIndex, false);
                        if(info.offset != 0){
                            Log.e(TAG,"info.offset = "+String.valueOf(info.offset));
                        }
                        audioTrack.write(atInput, /*0*/info.offset, info.size);
                        extractor.advance();
                    } else if (decodedDataBufIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
                        MediaFormat newFormat = decoder.getOutputFormat();
                        Log.e(TAG,
                                "newFormat: "
                                        + newFormat
                                                .getString(MediaFormat.KEY_MIME));
                        Log.e(TAG,
                                "newFormat: "
                                        + String.valueOf(newFormat
                                                .getInteger(MediaFormat.KEY_SAMPLE_RATE)));

                        Log.e(TAG, "Inside INFO_OUTPUT_FORMAT_CHANGED");
                        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                                sampleRate, AudioFormat.CHANNEL_OUT_STEREO,
                                AudioFormat.ENCODING_PCM_16BIT, 32768,
                                AudioTrack.MODE_STREAM);
                        audioTrack.play();
                    }
                } else {
                    Log.e(TAG,"codedbufferIndex is  "+String.valueOf(codedbufferIndex));
                }
            } while (read >= 0);

1 个答案:

答案 0 :(得分:0)

AudioTrack.flush()如果没有暂停或停止,则为无操作。

  

如果没有停止或暂停,或者轨道的创建模式不是,则为无操作   MODE_STREAM。

一种解决方案是降低AudioTrack的缓冲区,因此先前提交的字节的播放是不可察觉的。在我的应用程序中,我使用了相当大的32K大小,这并不麻烦。