Skip to content

Commit

Permalink
Support tunneling in video renderer
Browse files Browse the repository at this point in the history
At this point the renderers all have TODOs in enable(),
and turning on tunneling is reduced to the problem of
propagating a tunneling ID to these points.

Issue: #1688

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=144619393
  • Loading branch information
ojw28 committed Jan 16, 2017
1 parent 5742c87 commit 60a3eda
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 12 deletions.
11 changes: 11 additions & 0 deletions library/src/main/java/com/google/android/exoplayer2/C.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2;

import android.annotation.TargetApi;
import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.MediaCodec;
Expand Down Expand Up @@ -550,4 +552,13 @@ public static long msToUs(long timeMs) {
return timeMs == TIME_UNSET ? TIME_UNSET : (timeMs * 1000);
}

/**
* Returns a newly generated {@link android.media.AudioTrack} session identifier.
*/
@TargetApi(21)
public static int generateAudioSessionIdV21(Context context) {
return ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE))
.generateAudioSessionId();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import android.annotation.TargetApi;
import android.content.Context;
import android.media.MediaCodec;
import android.media.MediaCodecInfo.CodecCapabilities;
import android.media.MediaCrypto;
import android.media.MediaFormat;
import android.os.Handler;
Expand All @@ -28,6 +29,7 @@
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
import com.google.android.exoplayer2.drm.DrmInitData;
import com.google.android.exoplayer2.drm.DrmSessionManager;
import com.google.android.exoplayer2.drm.FrameworkMediaCrypto;
Expand Down Expand Up @@ -83,6 +85,10 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
private int lastReportedUnappliedRotationDegrees;
private float lastReportedPixelWidthHeightRatio;

private boolean tunneling;
private int tunnelingAudioSessionId;
/* package */ OnFrameRenderedListenerV23 tunnelingOnFrameRenderedListener;

/**
* @param context A context.
* @param mediaCodecSelector A decoder selector.
Expand Down Expand Up @@ -204,6 +210,9 @@ protected int supportsFormat(MediaCodecSelector mediaCodecSelector, Format forma
@Override
protected void onEnabled(boolean joining) throws ExoPlaybackException {
super.onEnabled(joining);
// TODO: Allow this to be set.
tunnelingAudioSessionId = C.AUDIO_SESSION_ID_UNSET;
tunneling = tunnelingAudioSessionId != C.AUDIO_SESSION_ID_UNSET;
eventDispatcher.enabled(decoderCounters);
frameReleaseTimeHelper.enable();
}
Expand All @@ -217,7 +226,7 @@ protected void onStreamChanged(Format[] formats) throws ExoPlaybackException {
@Override
protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
super.onPositionReset(positionUs, joining);
renderedFirstFrame = false;
clearRenderedFirstFrame();
consecutiveDroppedFrameCount = 0;
joiningDeadlineMs = joining && allowedJoiningTimeMs > 0
? (SystemClock.elapsedRealtime() + allowedJoiningTimeMs) : C.TIME_UNSET;
Expand Down Expand Up @@ -264,6 +273,7 @@ protected void onDisabled() {
pendingPixelWidthHeightRatio = Format.NO_VALUE;
clearLastReportedVideoSize();
frameReleaseTimeHelper.disable();
tunnelingOnFrameRenderedListener = null;
try {
super.onDisabled();
} finally {
Expand All @@ -288,11 +298,7 @@ public void handleMessage(int messageType, Object message) throws ExoPlaybackExc
}

private void setSurface(Surface surface) throws ExoPlaybackException {
// Clear state so that we always call the event listener with the video size and when a frame
// is rendered, even if the surface hasn't changed.
renderedFirstFrame = false;
clearLastReportedVideoSize();
// We only need to actually release and reinitialize the codec if the surface has changed.
// We only need to release and reinitialize the codec if the surface has changed.
if (this.surface != surface) {
this.surface = surface;
int state = getState();
Expand All @@ -301,6 +307,10 @@ private void setSurface(Surface surface) throws ExoPlaybackException {
maybeInitCodec();
}
}
// Clear state so that we always call the event listener with the video size and when a frame
// is rendered, even if the surface hasn't changed.
clearRenderedFirstFrame();
clearLastReportedVideoSize();
}

@Override
Expand All @@ -311,8 +321,12 @@ protected boolean shouldInitCodec() {
@Override
protected void configureCodec(MediaCodec codec, Format format, MediaCrypto crypto) {
codecMaxValues = getCodecMaxValues(format, streamFormats);
MediaFormat mediaFormat = getMediaFormat(format, codecMaxValues, deviceNeedsAutoFrcWorkaround);
MediaFormat mediaFormat = getMediaFormat(format, codecMaxValues, deviceNeedsAutoFrcWorkaround,
tunnelingAudioSessionId);
codec.configure(mediaFormat, surface, crypto, 0);
if (Util.SDK_INT >= 23 && tunneling) {
tunnelingOnFrameRenderedListener = new OnFrameRenderedListenerV23(codec);
}
}

@Override
Expand All @@ -329,6 +343,13 @@ protected void onInputFormatChanged(Format newFormat) throws ExoPlaybackExceptio
pendingRotationDegrees = getRotationDegrees(newFormat);
}

@Override
protected void onQueueInputBuffer(DecoderInputBuffer buffer) {
if (Util.SDK_INT < 23 && tunneling) {
maybeNotifyRenderedFirstFrame();
}
}

@Override
protected void onOutputFormatChanged(MediaCodec codec, android.media.MediaFormat outputFormat) {
boolean hasCrop = outputFormat.containsKey(KEY_CROP_RIGHT)
Expand Down Expand Up @@ -479,10 +500,7 @@ private void renderOutputBuffer(MediaCodec codec, int bufferIndex) {
TraceUtil.endSection();
decoderCounters.renderedOutputBufferCount++;
consecutiveDroppedFrameCount = 0;
if (!renderedFirstFrame) {
renderedFirstFrame = true;
eventDispatcher.renderedFirstFrame(surface);
}
maybeNotifyRenderedFirstFrame();
}

@TargetApi(21)
Expand All @@ -493,6 +511,25 @@ private void renderOutputBufferV21(MediaCodec codec, int bufferIndex, long relea
TraceUtil.endSection();
decoderCounters.renderedOutputBufferCount++;
consecutiveDroppedFrameCount = 0;
maybeNotifyRenderedFirstFrame();
}

private void clearRenderedFirstFrame() {
renderedFirstFrame = false;
// The first frame notification is triggered by renderOutputBuffer or renderOutputBufferV21 for
// non-tunneled playback, onQueueInputBuffer for tunneled playback prior to API level 23, and
// OnFrameRenderedListenerV23.onFrameRenderedListener for tunneled playback on API level 23 and
// above.
if (Util.SDK_INT >= 23 && tunneling) {
MediaCodec codec = getCodec();
// If codec is null then the listener will be instantiated in configureCodec.
if (codec != null) {
tunnelingOnFrameRenderedListener = new OnFrameRenderedListenerV23(codec);
}
}
}

/* package */ void maybeNotifyRenderedFirstFrame() {
if (!renderedFirstFrame) {
renderedFirstFrame = true;
eventDispatcher.renderedFirstFrame(surface);
Expand Down Expand Up @@ -531,7 +568,7 @@ private void maybeNotifyDroppedFrames() {

@SuppressLint("InlinedApi")
private static MediaFormat getMediaFormat(Format format, CodecMaxValues codecMaxValues,
boolean deviceNeedsAutoFrcWorkaround) {
boolean deviceNeedsAutoFrcWorkaround, int tunnelingAudioSessionId) {
MediaFormat frameworkMediaFormat = format.getFrameworkMediaFormatV16();
// Set the maximum adaptive video dimensions.
frameworkMediaFormat.setInteger(MediaFormat.KEY_MAX_WIDTH, codecMaxValues.width);
Expand All @@ -544,6 +581,11 @@ private static MediaFormat getMediaFormat(Format format, CodecMaxValues codecMax
if (deviceNeedsAutoFrcWorkaround) {
frameworkMediaFormat.setInteger("auto-frc", 0);
}
// Configure tunneling if enabled.
if (tunnelingAudioSessionId != C.AUDIO_SESSION_ID_UNSET) {
frameworkMediaFormat.setFeatureEnabled(CodecCapabilities.FEATURE_TunneledPlayback, true);
frameworkMediaFormat.setInteger(MediaFormat.KEY_AUDIO_SESSION_ID, tunnelingAudioSessionId);
}
return frameworkMediaFormat;
}

Expand Down Expand Up @@ -682,4 +724,22 @@ public CodecMaxValues(int width, int height, int inputSize) {

}

@TargetApi(23)
private final class OnFrameRenderedListenerV23 implements MediaCodec.OnFrameRenderedListener {

private OnFrameRenderedListenerV23(MediaCodec codec) {
codec.setOnFrameRenderedListener(this, new Handler());
}

@Override
public void onFrameRendered(MediaCodec codec, long presentationTimeUs, long nanoTime) {
if (this != tunnelingOnFrameRenderedListener) {
// Stale event.
return;
}
maybeNotifyRenderedFirstFrame();
}

}

}

0 comments on commit 60a3eda

Please sign in to comment.