Search in sources :

Example 21 with DrmSession

use of com.google.android.exoplayer2.drm.DrmSession in project ExoPlayer by google.

the class MediaCodecRenderer method maybeInitCodec.

@SuppressWarnings("deprecation")
protected final void maybeInitCodec() throws ExoPlaybackException {
    if (!shouldInitCodec()) {
        return;
    }
    drmSession = pendingDrmSession;
    String mimeType = format.sampleMimeType;
    MediaCrypto mediaCrypto = null;
    boolean drmSessionRequiresSecureDecoder = false;
    if (drmSession != null) {
        @DrmSession.State int drmSessionState = drmSession.getState();
        if (drmSessionState == DrmSession.STATE_ERROR) {
            throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex());
        } else if (drmSessionState == DrmSession.STATE_OPENED || drmSessionState == DrmSession.STATE_OPENED_WITH_KEYS) {
            mediaCrypto = drmSession.getMediaCrypto().getWrappedMediaCrypto();
            drmSessionRequiresSecureDecoder = drmSession.requiresSecureDecoderComponent(mimeType);
        } else {
            // The drm session isn't open yet.
            return;
        }
    }
    MediaCodecInfo decoderInfo = null;
    try {
        decoderInfo = getDecoderInfo(mediaCodecSelector, format, drmSessionRequiresSecureDecoder);
        if (decoderInfo == null && drmSessionRequiresSecureDecoder) {
            // The drm session indicates that a secure decoder is required, but the device does not have
            // one. Assuming that supportsFormat indicated support for the media being played, we know
            // that it does not require a secure output path. Most CDM implementations allow playback to
            // proceed with a non-secure decoder in this case, so we try our luck.
            decoderInfo = getDecoderInfo(mediaCodecSelector, format, false);
            if (decoderInfo != null) {
                Log.w(TAG, "Drm session requires secure decoder for " + mimeType + ", but " + "no secure decoder available. Trying to proceed with " + decoderInfo.name + ".");
            }
        }
    } catch (DecoderQueryException e) {
        throwDecoderInitError(new DecoderInitializationException(format, e, drmSessionRequiresSecureDecoder, DecoderInitializationException.DECODER_QUERY_ERROR));
    }
    if (decoderInfo == null) {
        throwDecoderInitError(new DecoderInitializationException(format, null, drmSessionRequiresSecureDecoder, DecoderInitializationException.NO_SUITABLE_DECODER_ERROR));
    }
    String codecName = decoderInfo.name;
    codecIsAdaptive = decoderInfo.adaptive;
    codecNeedsDiscardToSpsWorkaround = codecNeedsDiscardToSpsWorkaround(codecName, format);
    codecNeedsFlushWorkaround = codecNeedsFlushWorkaround(codecName);
    codecNeedsAdaptationWorkaround = codecNeedsAdaptationWorkaround(codecName);
    codecNeedsEosPropagationWorkaround = codecNeedsEosPropagationWorkaround(codecName);
    codecNeedsEosFlushWorkaround = codecNeedsEosFlushWorkaround(codecName);
    codecNeedsEosOutputExceptionWorkaround = codecNeedsEosOutputExceptionWorkaround(codecName);
    codecNeedsMonoChannelCountWorkaround = codecNeedsMonoChannelCountWorkaround(codecName, format);
    try {
        long codecInitializingTimestamp = SystemClock.elapsedRealtime();
        TraceUtil.beginSection("createCodec:" + codecName);
        codec = MediaCodec.createByCodecName(codecName);
        TraceUtil.endSection();
        TraceUtil.beginSection("configureCodec");
        configureCodec(decoderInfo, codec, format, mediaCrypto);
        TraceUtil.endSection();
        TraceUtil.beginSection("startCodec");
        codec.start();
        TraceUtil.endSection();
        long codecInitializedTimestamp = SystemClock.elapsedRealtime();
        onCodecInitialized(codecName, codecInitializedTimestamp, codecInitializedTimestamp - codecInitializingTimestamp);
        inputBuffers = codec.getInputBuffers();
        outputBuffers = codec.getOutputBuffers();
    } catch (Exception e) {
        throwDecoderInitError(new DecoderInitializationException(format, e, drmSessionRequiresSecureDecoder, codecName));
    }
    codecHotswapDeadlineMs = getState() == STATE_STARTED ? (SystemClock.elapsedRealtime() + MAX_CODEC_HOTSWAP_TIME_MS) : C.TIME_UNSET;
    inputIndex = C.INDEX_UNSET;
    outputIndex = C.INDEX_UNSET;
    waitingForFirstSyncFrame = true;
    decoderCounters.decoderInitCount++;
}
Also used : DecoderQueryException(com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException) ExoPlaybackException(com.google.android.exoplayer2.ExoPlaybackException) CodecException(android.media.MediaCodec.CodecException) CryptoException(android.media.MediaCodec.CryptoException) DecoderQueryException(com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryException) FrameworkMediaCrypto(com.google.android.exoplayer2.drm.FrameworkMediaCrypto) MediaCrypto(android.media.MediaCrypto)

Example 22 with DrmSession

use of com.google.android.exoplayer2.drm.DrmSession in project ExoPlayer by google.

the class MediaCodecRenderer method onInputFormatChanged.

/**
   * Called when a new format is read from the upstream {@link MediaPeriod}.
   *
   * @param newFormat The new format.
   * @throws ExoPlaybackException If an error occurs reinitializing the {@link MediaCodec}.
   */
protected void onInputFormatChanged(Format newFormat) throws ExoPlaybackException {
    Format oldFormat = format;
    format = newFormat;
    boolean drmInitDataChanged = !Util.areEqual(format.drmInitData, oldFormat == null ? null : oldFormat.drmInitData);
    if (drmInitDataChanged) {
        if (format.drmInitData != null) {
            if (drmSessionManager == null) {
                throw ExoPlaybackException.createForRenderer(new IllegalStateException("Media requires a DrmSessionManager"), getIndex());
            }
            pendingDrmSession = drmSessionManager.acquireSession(Looper.myLooper(), format.drmInitData);
            if (pendingDrmSession == drmSession) {
                drmSessionManager.releaseSession(pendingDrmSession);
            }
        } else {
            pendingDrmSession = null;
        }
    }
    if (pendingDrmSession == drmSession && codec != null && canReconfigureCodec(codec, codecIsAdaptive, oldFormat, format)) {
        codecReconfigured = true;
        codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING;
        codecNeedsAdaptationWorkaroundBuffer = codecNeedsAdaptationWorkaround && format.width == oldFormat.width && format.height == oldFormat.height;
    } else {
        if (codecReceivedBuffers) {
            // Signal end of stream and wait for any final output buffers before re-initialization.
            codecReinitializationState = REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM;
        } else {
            // There aren't any final output buffers, so perform re-initialization immediately.
            releaseCodec();
            maybeInitCodec();
        }
    }
}
Also used : MediaFormat(android.media.MediaFormat) Format(com.google.android.exoplayer2.Format)

Example 23 with DrmSession

use of com.google.android.exoplayer2.drm.DrmSession in project ExoPlayer by google.

the class DefaultDrmSessionManagerTest method sessionReacquired_keepaliveTimeOutCancelled.

@Test(timeout = 10_000)
public void sessionReacquired_keepaliveTimeOutCancelled() throws Exception {
    FakeExoMediaDrm.LicenseServer licenseServer = FakeExoMediaDrm.LicenseServer.allowingSchemeDatas(DRM_SCHEME_DATAS);
    DrmSessionManager drmSessionManager = new DefaultDrmSessionManager.Builder().setUuidAndExoMediaDrmProvider(DRM_SCHEME_UUID, uuid -> new FakeExoMediaDrm()).setSessionKeepaliveMs(10_000).build(/* mediaDrmCallback= */
    licenseServer);
    drmSessionManager.prepare();
    drmSessionManager.setPlayer(/* playbackLooper= */
    Looper.myLooper(), PlayerId.UNSET);
    DrmSession firstDrmSession = checkNotNull(drmSessionManager.acquireSession(/* eventDispatcher= */
    null, FORMAT_WITH_DRM_INIT_DATA));
    waitForOpenedWithKeys(firstDrmSession);
    firstDrmSession.release(/* eventDispatcher= */
    null);
    ShadowLooper.idleMainLooper(5, SECONDS);
    // Acquire a session for the same init data 5s in to the 10s timeout (so expect the same
    // instance).
    DrmSession secondDrmSession = checkNotNull(drmSessionManager.acquireSession(/* eventDispatcher= */
    null, FORMAT_WITH_DRM_INIT_DATA));
    assertThat(secondDrmSession).isSameInstanceAs(firstDrmSession);
    // Let the timeout definitely expire, and check the session didn't get released.
    ShadowLooper.idleMainLooper(10, SECONDS);
    assertThat(secondDrmSession.getState()).isEqualTo(DrmSession.STATE_OPENED_WITH_KEYS);
}
Also used : FakeExoMediaDrm(com.google.android.exoplayer2.testutil.FakeExoMediaDrm) Test(org.junit.Test)

Example 24 with DrmSession

use of com.google.android.exoplayer2.drm.DrmSession in project ExoPlayer by google.

the class DefaultDrmSessionManagerTest method preacquireSession_releaseBeforeUnderlyingAcquisitionCompletesReleasesSessionOnceAcquired.

@Test(timeout = 10_000)
public void preacquireSession_releaseBeforeUnderlyingAcquisitionCompletesReleasesSessionOnceAcquired() throws Exception {
    FakeExoMediaDrm.LicenseServer licenseServer = FakeExoMediaDrm.LicenseServer.allowingSchemeDatas(DRM_SCHEME_DATAS);
    DrmSessionManager drmSessionManager = new DefaultDrmSessionManager.Builder().setUuidAndExoMediaDrmProvider(DRM_SCHEME_UUID, uuid -> new FakeExoMediaDrm()).setSessionKeepaliveMs(C.TIME_UNSET).build(/* mediaDrmCallback= */
    licenseServer);
    drmSessionManager.prepare();
    drmSessionManager.setPlayer(/* playbackLooper= */
    Looper.myLooper(), PlayerId.UNSET);
    DrmSessionReference sessionReference = drmSessionManager.preacquireSession(/* eventDispatcher= */
    null, FORMAT_WITH_DRM_INIT_DATA);
    // Release the pre-acquired reference before the underlying session has had a chance to be
    // constructed.
    sessionReference.release();
    // Acquiring the same session triggers a second key load (because the pre-acquired session was
    // fully released).
    DrmSession drmSession = checkNotNull(drmSessionManager.acquireSession(/* eventDispatcher= */
    null, FORMAT_WITH_DRM_INIT_DATA));
    assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED);
    waitForOpenedWithKeys(drmSession);
    drmSession.release(/* eventDispatcher= */
    null);
    assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_RELEASED);
}
Also used : DrmSessionReference(com.google.android.exoplayer2.drm.DrmSessionManager.DrmSessionReference) FakeExoMediaDrm(com.google.android.exoplayer2.testutil.FakeExoMediaDrm) Test(org.junit.Test)

Example 25 with DrmSession

use of com.google.android.exoplayer2.drm.DrmSession in project ExoPlayer by google.

the class DefaultDrmSessionManagerTest method keyRefreshEvent_whileManagerIsReleasing_triggersKeyRefresh.

@Test(timeout = 10_000)
public void keyRefreshEvent_whileManagerIsReleasing_triggersKeyRefresh() throws Exception {
    FakeExoMediaDrm exoMediaDrm = new FakeExoMediaDrm();
    FakeExoMediaDrm.LicenseServer licenseServer = FakeExoMediaDrm.LicenseServer.allowingSchemeDatas(DRM_SCHEME_DATAS);
    DrmSessionManager drmSessionManager = new DefaultDrmSessionManager.Builder().setUuidAndExoMediaDrmProvider(DRM_SCHEME_UUID, new AppManagedProvider(exoMediaDrm)).build(/* mediaDrmCallback= */
    licenseServer);
    drmSessionManager.prepare();
    drmSessionManager.setPlayer(/* playbackLooper= */
    Looper.myLooper(), PlayerId.UNSET);
    DefaultDrmSession drmSession = (DefaultDrmSession) checkNotNull(drmSessionManager.acquireSession(/* eventDispatcher= */
    null, FORMAT_WITH_DRM_INIT_DATA));
    waitForOpenedWithKeys(drmSession);
    assertThat(licenseServer.getReceivedSchemeDatas()).hasSize(1);
    drmSessionManager.release();
    exoMediaDrm.triggerEvent(drmSession::hasSessionId, ExoMediaDrm.EVENT_KEY_REQUIRED, /* extra= */
    0, /* data= */
    Util.EMPTY_BYTE_ARRAY);
    while (licenseServer.getReceivedSchemeDatas().size() == 1) {
        // Allow the key refresh event to be handled.
        ShadowLooper.idleMainLooper();
    }
    assertThat(licenseServer.getReceivedSchemeDatas()).hasSize(2);
    assertThat(ImmutableSet.copyOf(licenseServer.getReceivedSchemeDatas())).hasSize(1);
    drmSession.release(/* eventDispatcher= */
    null);
    exoMediaDrm.release();
}
Also used : AppManagedProvider(com.google.android.exoplayer2.drm.ExoMediaDrm.AppManagedProvider) FakeExoMediaDrm(com.google.android.exoplayer2.testutil.FakeExoMediaDrm) Test(org.junit.Test)

Aggregations

Test (org.junit.Test)18 FakeExoMediaDrm (com.google.android.exoplayer2.testutil.FakeExoMediaDrm)16 AppManagedProvider (com.google.android.exoplayer2.drm.ExoMediaDrm.AppManagedProvider)7 Nullable (androidx.annotation.Nullable)5 Format (com.google.android.exoplayer2.Format)5 DrmSessionReference (com.google.android.exoplayer2.drm.DrmSessionManager.DrmSessionReference)5 DrmSessionException (com.google.android.exoplayer2.drm.DrmSession.DrmSessionException)4 MediaSource (com.google.android.exoplayer2.source.MediaSource)4 DrmSession (com.google.android.exoplayer2.drm.DrmSession)3 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)3 Looper (android.os.Looper)2 AndroidJUnit4 (androidx.test.ext.junit.runners.AndroidJUnit4)2 C (com.google.android.exoplayer2.C)2 ExoPlaybackException (com.google.android.exoplayer2.ExoPlaybackException)2 PlayerId (com.google.android.exoplayer2.analytics.PlayerId)2 SchemeData (com.google.android.exoplayer2.drm.DrmInitData.SchemeData)2 ExoMediaCrypto (com.google.android.exoplayer2.drm.ExoMediaCrypto)2 TestUtil (com.google.android.exoplayer2.testutil.TestUtil)2 Assertions.checkNotNull (com.google.android.exoplayer2.util.Assertions.checkNotNull)2 MimeTypes (com.google.android.exoplayer2.util.MimeTypes)2