Skip to content

Instantly share code, notes, and snippets.

@jedhoffmann
Created December 11, 2015 17:41
Show Gist options
  • Save jedhoffmann/b99b384be76e353dc08f to your computer and use it in GitHub Desktop.
Save jedhoffmann/b99b384be76e353dc08f to your computer and use it in GitHub Desktop.
VariableSpeedMediaCodecAudioTrackRenderer
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);
}
}
@kang2nana
Copy link

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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment