Created
December 11, 2015 17:41
-
-
Save jedhoffmann/b99b384be76e353dc08f to your computer and use it in GitHub Desktop.
VariableSpeedMediaCodecAudioTrackRenderer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.media.MediaCodec; | |
import android.media.MediaFormat; | |
import com.google.android.exoplayer.ExoPlaybackException; | |
import com.google.android.exoplayer.ExoPlayer; | |
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer; | |
import com.google.android.exoplayer.SampleSource; | |
import com.google.android.exoplayer.util.Util; | |
import java.nio.ByteBuffer; | |
import sonic.Sonic; | |
public class VariableSpeedMediaCodecAudioTrackRenderer extends MediaCodecAudioTrackRenderer { | |
private static final int SAMPLES_PER_CODEC_FRAME = 1024; | |
private Sonic sonic; | |
private byte[] sonicInputBuffer; | |
private byte[] sonicOutputBuffer; | |
private float narrationSpeed; | |
private int lastSeenBufferIndex = -1; | |
private ByteBuffer lastInternalBuffer; | |
public VariableSpeedEnabledMediaCodecAudioTrackRenderer(final SampleSource source, final float narrationSpeed) { | |
super(source); | |
this.narrationSpeed = narrationSpeed; | |
} | |
@Override | |
protected boolean processOutputBuffer(final long positionUs, final long elapsedRealtimeUs, final MediaCodec codec, final ByteBuffer buffer, | |
final MediaCodec.BufferInfo bufferInfo, final int bufferIndex, final boolean shouldSkip) throws ExoPlaybackException { | |
// If this buffer was previously seen that means part, but not all, was consumed by the AudioTrack. Pass it | |
// again so the remainder can be consumed. | |
if (bufferIndex == lastSeenBufferIndex) { | |
return super.processOutputBuffer(positionUs, elapsedRealtimeUs, codec, lastInternalBuffer, bufferInfo, bufferIndex, shouldSkip); | |
} else { | |
lastSeenBufferIndex = bufferIndex; | |
} | |
final int bytesToRead; | |
if (Util.SDK_INT < 21) { | |
buffer.position(0); | |
bytesToRead = bufferInfo.size; | |
} else { | |
bytesToRead = buffer.remaining(); | |
} | |
buffer.get(sonicInputBuffer, 0, bytesToRead); | |
sonic.writeBytesToStream(sonicInputBuffer, bytesToRead); | |
final int readThisTime = sonic.readBytesFromStream(sonicOutputBuffer, sonicOutputBuffer.length); | |
bufferInfo.offset = 0; | |
lastInternalBuffer.position(0); | |
bufferInfo.size = readThisTime; | |
lastInternalBuffer.limit(readThisTime); | |
return super.processOutputBuffer(positionUs, elapsedRealtimeUs, codec, lastInternalBuffer, bufferInfo, bufferIndex, shouldSkip); | |
} | |
@Override | |
protected void onOutputFormatChanged(final MediaFormat format) { | |
super.onOutputFormatChanged(format); | |
final int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE); | |
final int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT); | |
// Two samples per frame * 2 to support narration speeds down to 0.5 | |
final int bufferSizeBytes = SAMPLES_PER_CODEC_FRAME * 2 * 2 * channelCount; | |
this.sonicInputBuffer = new byte[bufferSizeBytes]; | |
this.sonicOutputBuffer = new byte[bufferSizeBytes]; | |
this.sonic = new Sonic(sampleRate, channelCount); | |
this.lastInternalBuffer = ByteBuffer.wrap(sonicOutputBuffer, 0, 0); | |
setSpeedInternal(narrationSpeed); | |
} | |
private synchronized void setSpeedInternal(final float narrationSpeed) { | |
this.narrationSpeed = narrationSpeed; | |
this.sonic.setSpeed(narrationSpeed); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
hello, can you help me ?
Sometimes I had such a problem:
I/ExoPlayerImpl(23722): Init 1.5.9
ExoPlayerImplInternal(23722): Internal runtime error.
E/ExoPlayerImplInternal(23722): java.lang.IndexOutOfBoundsException: offset=0, count=42812, length=4096
E/ExoPlayerImplInternal(23722): at java.nio.Buffer.checkGetBounds(Buffer.java:167)
E/ExoPlayerImplInternal(23722): at java.nio.DirectByteBuffer.get(DirectByteBuffer.java:114)
E/ExoPlayerImplInternal(23722): at com.*.media.r.a(VariableSpeedMediaCodecAudioTrackRenderer.java:63)
E/ExoPlayerImplInternal(23722): at com.google.android.exoplayer.s.b(MediaCodecTrackRenderer.java:915)
E/ExoPlayerImplInternal(23722): at com.google.android.exoplayer.s.a(MediaCodecTrackRenderer.java:512)
E/ExoPlayerImplInternal(23722): at com.google.android.exoplayer.z.a(SampleSourceTrackRenderer.java:129)
E/ExoPlayerImplInternal(23722): at com.google.android.exoplayer.l.e(ExoPlayerImplInternal.java:434)
E/ExoPlayerImplInternal(23722): at com.google.android.exoplayer.l.handleMessage(ExoPlayerImplInternal.java:213)
E/ExoPlayerImplInternal(23722): at android.os.Handler.dispatchMessage(Handler.java:106)
E/ExoPlayerImplInternal(23722): at android.os.Looper.loop(Looper.java:229)
E/ExoPlayerImplInternal(23722): at android.os.HandlerThread.run(HandlerThread.java:61)
E/ExoPlayerImplInternal(23722): at com.google.android.exoplayer.k.t.run(PriorityHandlerThread.java:40)