Search in sources :

Example 1 with MediaCodecAdapter

use of com.google.android.exoplayer2.mediacodec.MediaCodecAdapter in project ExoPlayer by google.

the class MediaCodecVideoRenderer method setOutput.

private void setOutput(@Nullable Object output) throws ExoPlaybackException {
    // Handle unsupported (i.e., non-Surface) outputs by clearing the surface.
    @Nullable Surface surface = output instanceof Surface ? (Surface) output : null;
    if (surface == null) {
        // Use a dummy surface if possible.
        if (dummySurface != null) {
            surface = dummySurface;
        } else {
            MediaCodecInfo codecInfo = getCodecInfo();
            if (codecInfo != null && shouldUseDummySurface(codecInfo)) {
                dummySurface = DummySurface.newInstanceV17(context, codecInfo.secure);
                surface = dummySurface;
            }
        }
    }
    // We only need to update the codec if the surface has changed.
    if (this.surface != surface) {
        this.surface = surface;
        frameReleaseHelper.onSurfaceChanged(surface);
        haveReportedFirstFrameRenderedForCurrentSurface = false;
        @State int state = getState();
        @Nullable MediaCodecAdapter codec = getCodec();
        if (codec != null) {
            if (Util.SDK_INT >= 23 && surface != null && !codecNeedsSetOutputSurfaceWorkaround) {
                setOutputSurfaceV23(codec, surface);
            } else {
                releaseCodec();
                maybeInitCodecOrBypass();
            }
        }
        if (surface != null && surface != dummySurface) {
            // If we know the video size, report it again immediately.
            maybeRenotifyVideoSizeChanged();
            // We haven't rendered to the new surface yet.
            clearRenderedFirstFrame();
            if (state == STATE_STARTED) {
                setJoiningDeadlineMs();
            }
        } else {
            // The surface has been removed.
            clearReportedVideoSize();
            clearRenderedFirstFrame();
        }
    } else if (surface != null && surface != dummySurface) {
        // The surface is set and unchanged. If we know the video size and/or have already rendered to
        // the surface, report these again immediately.
        maybeRenotifyVideoSizeChanged();
        maybeRenotifyRenderedFirstFrame();
    }
}
Also used : MediaCodecAdapter(com.google.android.exoplayer2.mediacodec.MediaCodecAdapter) MediaCodecInfo(com.google.android.exoplayer2.mediacodec.MediaCodecInfo) Nullable(androidx.annotation.Nullable) SuppressLint(android.annotation.SuppressLint) Point(android.graphics.Point) Surface(android.view.Surface)

Example 2 with MediaCodecAdapter

use of com.google.android.exoplayer2.mediacodec.MediaCodecAdapter in project ExoPlayer by google.

the class MediaCodecVideoRenderer method onOutputFormatChanged.

@Override
protected void onOutputFormatChanged(Format format, @Nullable MediaFormat mediaFormat) {
    @Nullable MediaCodecAdapter codec = getCodec();
    if (codec != null) {
        // Must be applied each time the output format changes.
        codec.setVideoScalingMode(scalingMode);
    }
    if (tunneling) {
        currentWidth = format.width;
        currentHeight = format.height;
    } else {
        Assertions.checkNotNull(mediaFormat);
        boolean hasCrop = mediaFormat.containsKey(KEY_CROP_RIGHT) && mediaFormat.containsKey(KEY_CROP_LEFT) && mediaFormat.containsKey(KEY_CROP_BOTTOM) && mediaFormat.containsKey(KEY_CROP_TOP);
        currentWidth = hasCrop ? mediaFormat.getInteger(KEY_CROP_RIGHT) - mediaFormat.getInteger(KEY_CROP_LEFT) + 1 : mediaFormat.getInteger(MediaFormat.KEY_WIDTH);
        currentHeight = hasCrop ? mediaFormat.getInteger(KEY_CROP_BOTTOM) - mediaFormat.getInteger(KEY_CROP_TOP) + 1 : mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);
    }
    currentPixelWidthHeightRatio = format.pixelWidthHeightRatio;
    if (Util.SDK_INT >= 21) {
        // to flip the width, height and pixel aspect ratio to reflect the rotation that was applied.
        if (format.rotationDegrees == 90 || format.rotationDegrees == 270) {
            int rotatedHeight = currentWidth;
            currentWidth = currentHeight;
            currentHeight = rotatedHeight;
            currentPixelWidthHeightRatio = 1 / currentPixelWidthHeightRatio;
        }
    } else {
        // On API level 20 and below the decoder does not apply the rotation.
        currentUnappliedRotationDegrees = format.rotationDegrees;
    }
    frameReleaseHelper.onFormatChanged(format.frameRate);
}
Also used : MediaCodecAdapter(com.google.android.exoplayer2.mediacodec.MediaCodecAdapter) Nullable(androidx.annotation.Nullable) SuppressLint(android.annotation.SuppressLint) Point(android.graphics.Point)

Example 3 with MediaCodecAdapter

use of com.google.android.exoplayer2.mediacodec.MediaCodecAdapter in project ExoPlayer by google.

the class MediaCodecVideoRenderer method handleMessage.

@Override
public void handleMessage(@MessageType int messageType, @Nullable Object message) throws ExoPlaybackException {
    switch(messageType) {
        case MSG_SET_VIDEO_OUTPUT:
            setOutput(message);
            break;
        case MSG_SET_SCALING_MODE:
            scalingMode = (Integer) message;
            @Nullable MediaCodecAdapter codec = getCodec();
            if (codec != null) {
                codec.setVideoScalingMode(scalingMode);
            }
            break;
        case MSG_SET_CHANGE_FRAME_RATE_STRATEGY:
            frameReleaseHelper.setChangeFrameRateStrategy((int) message);
            break;
        case MSG_SET_VIDEO_FRAME_METADATA_LISTENER:
            frameMetadataListener = (VideoFrameMetadataListener) message;
            break;
        case MSG_SET_AUDIO_SESSION_ID:
            int tunnelingAudioSessionId = (int) message;
            if (this.tunnelingAudioSessionId != tunnelingAudioSessionId) {
                this.tunnelingAudioSessionId = tunnelingAudioSessionId;
                if (tunneling) {
                    releaseCodec();
                }
            }
            break;
        case MSG_SET_AUDIO_ATTRIBUTES:
        case MSG_SET_AUX_EFFECT_INFO:
        case MSG_SET_CAMERA_MOTION_LISTENER:
        case MSG_SET_SKIP_SILENCE_ENABLED:
        case MSG_SET_VOLUME:
        case MSG_SET_WAKEUP_LISTENER:
        default:
            super.handleMessage(messageType, message);
    }
}
Also used : MediaCodecAdapter(com.google.android.exoplayer2.mediacodec.MediaCodecAdapter) Nullable(androidx.annotation.Nullable) SuppressLint(android.annotation.SuppressLint) Point(android.graphics.Point)

Example 4 with MediaCodecAdapter

use of com.google.android.exoplayer2.mediacodec.MediaCodecAdapter in project ExoPlayer by google.

the class MediaCodecRenderer method onInputFormatChanged.

/**
 * Called when a new {@link Format} is read from the upstream {@link MediaPeriod}.
 *
 * @param formatHolder A {@link FormatHolder} that holds the new {@link Format}.
 * @throws ExoPlaybackException If an error occurs re-initializing the {@link MediaCodec}.
 * @return The result of the evaluation to determine whether the existing decoder instance can be
 *     reused for the new format, or {@code null} if the renderer did not have a decoder.
 */
@CallSuper
@Nullable
protected DecoderReuseEvaluation onInputFormatChanged(FormatHolder formatHolder) throws ExoPlaybackException {
    waitingForFirstSampleInFormat = true;
    Format newFormat = checkNotNull(formatHolder.format);
    if (newFormat.sampleMimeType == null) {
        throw createRendererException(new IllegalArgumentException(), newFormat, PlaybackException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED);
    }
    setSourceDrmSession(formatHolder.drmSession);
    inputFormat = newFormat;
    if (bypassEnabled) {
        bypassDrainAndReinitialize = true;
        // Need to drain batch buffer first.
        return null;
    }
    if (codec == null) {
        availableCodecInfos = null;
        maybeInitCodecOrBypass();
        return null;
    }
    // We have an existing codec that we may need to reconfigure, re-initialize, or release to
    // switch to bypass. If the existing codec instance is kept then its operating rate and DRM
    // session may need to be updated.
    // Copy the current codec and codecInfo to local variables so they remain accessible if the
    // member variables are updated during the logic below.
    MediaCodecAdapter codec = this.codec;
    MediaCodecInfo codecInfo = this.codecInfo;
    Format oldFormat = codecInputFormat;
    if (drmNeedsCodecReinitialization(codecInfo, newFormat, codecDrmSession, sourceDrmSession)) {
        drainAndReinitializeCodec();
        return new DecoderReuseEvaluation(codecInfo.name, oldFormat, newFormat, REUSE_RESULT_NO, DISCARD_REASON_DRM_SESSION_CHANGED);
    }
    boolean drainAndUpdateCodecDrmSession = sourceDrmSession != codecDrmSession;
    Assertions.checkState(!drainAndUpdateCodecDrmSession || Util.SDK_INT >= 23);
    DecoderReuseEvaluation evaluation = canReuseCodec(codecInfo, oldFormat, newFormat);
    @DecoderDiscardReasons int overridingDiscardReasons = 0;
    switch(evaluation.result) {
        case REUSE_RESULT_NO:
            drainAndReinitializeCodec();
            break;
        case REUSE_RESULT_YES_WITH_FLUSH:
            if (!updateCodecOperatingRate(newFormat)) {
                overridingDiscardReasons |= DISCARD_REASON_OPERATING_RATE_CHANGED;
            } else {
                codecInputFormat = newFormat;
                if (drainAndUpdateCodecDrmSession) {
                    if (!drainAndUpdateCodecDrmSessionV23()) {
                        overridingDiscardReasons |= DISCARD_REASON_WORKAROUND;
                    }
                } else if (!drainAndFlushCodec()) {
                    overridingDiscardReasons |= DISCARD_REASON_WORKAROUND;
                }
            }
            break;
        case REUSE_RESULT_YES_WITH_RECONFIGURATION:
            if (!updateCodecOperatingRate(newFormat)) {
                overridingDiscardReasons |= DISCARD_REASON_OPERATING_RATE_CHANGED;
            } else {
                codecReconfigured = true;
                codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING;
                codecNeedsAdaptationWorkaroundBuffer = codecAdaptationWorkaroundMode == ADAPTATION_WORKAROUND_MODE_ALWAYS || (codecAdaptationWorkaroundMode == ADAPTATION_WORKAROUND_MODE_SAME_RESOLUTION && newFormat.width == oldFormat.width && newFormat.height == oldFormat.height);
                codecInputFormat = newFormat;
                if (drainAndUpdateCodecDrmSession && !drainAndUpdateCodecDrmSessionV23()) {
                    overridingDiscardReasons |= DISCARD_REASON_WORKAROUND;
                }
            }
            break;
        case REUSE_RESULT_YES_WITHOUT_RECONFIGURATION:
            if (!updateCodecOperatingRate(newFormat)) {
                overridingDiscardReasons |= DISCARD_REASON_OPERATING_RATE_CHANGED;
            } else {
                codecInputFormat = newFormat;
                if (drainAndUpdateCodecDrmSession && !drainAndUpdateCodecDrmSessionV23()) {
                    overridingDiscardReasons |= DISCARD_REASON_WORKAROUND;
                }
            }
            break;
        default:
            // Never happens.
            throw new IllegalStateException();
    }
    if (evaluation.result != REUSE_RESULT_NO && (this.codec != codec || codecDrainAction == DRAIN_ACTION_REINITIALIZE)) {
        // The reasons are indicated by overridingDiscardReasons.
        return new DecoderReuseEvaluation(codecInfo.name, oldFormat, newFormat, REUSE_RESULT_NO, overridingDiscardReasons);
    }
    return evaluation;
}
Also used : Format(com.google.android.exoplayer2.Format) MediaFormat(android.media.MediaFormat) DecoderReuseEvaluation(com.google.android.exoplayer2.decoder.DecoderReuseEvaluation) DecoderDiscardReasons(com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.DecoderDiscardReasons) CallSuper(androidx.annotation.CallSuper) Nullable(androidx.annotation.Nullable)

Aggregations

Nullable (androidx.annotation.Nullable)4 SuppressLint (android.annotation.SuppressLint)3 Point (android.graphics.Point)3 MediaCodecAdapter (com.google.android.exoplayer2.mediacodec.MediaCodecAdapter)3 MediaFormat (android.media.MediaFormat)1 Surface (android.view.Surface)1 CallSuper (androidx.annotation.CallSuper)1 Format (com.google.android.exoplayer2.Format)1 DecoderReuseEvaluation (com.google.android.exoplayer2.decoder.DecoderReuseEvaluation)1 DecoderDiscardReasons (com.google.android.exoplayer2.decoder.DecoderReuseEvaluation.DecoderDiscardReasons)1 MediaCodecInfo (com.google.android.exoplayer2.mediacodec.MediaCodecInfo)1