/* * Copyright 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package androidx.media.filterfw.decoder; import android.annotation.TargetApi; import android.media.MediaFormat; import android.util.Log; import androidx.media.filterfw.FrameImage2D; /** * Base class for all {@link TrackDecoder} classes that decode video. */ @TargetApi(16) public abstract class VideoTrackDecoder extends TrackDecoder { private static final String LOG_TAG = "VideoTrackDecoder"; protected final Object mFrameMonitor = new Object(); protected volatile boolean mFrameAvailable; // Access guarded by mFrameMonitor. protected VideoTrackDecoder(int trackIndex, MediaFormat format, Listener listener) { super(trackIndex, format, listener); if (!DecoderUtil.isVideoFormat(format)) { throw new IllegalArgumentException( "VideoTrackDecoder can only be used with video formats"); } } public void grabFrame(FrameImage2D outputVideoFrame, int rotation) { synchronized (mFrameMonitor) { if (!mFrameAvailable) { Log.w(LOG_TAG, "frame is not ready - the caller has to wait for a corresponding " + "onDecodedFrameAvailable() call"); return; } copyFrameDataTo(outputVideoFrame, rotation); mFrameAvailable = false; mFrameMonitor.notifyAll(); } } /** * Waits for the frame to be picked up by the MFF thread, i.e. blocks until the * {@link #grabFrame(FrameImage2D, int)}) method is called. */ public boolean waitForFrameGrab() { synchronized (mFrameMonitor) { try { while (mFrameAvailable) { mFrameMonitor.wait(); } return true; } catch (InterruptedException e) { return false; } } } protected final void markFrameAvailable() { synchronized (mFrameMonitor) { mFrameAvailable = true; mFrameMonitor.notifyAll(); } } /** * @return if the frame dimension needs to be swapped, * i.e. (width,height) becomes (height, width) */ protected static boolean needSwapDimension(int rotation) { switch(rotation) { case MediaDecoder.ROTATE_90_RIGHT: case MediaDecoder.ROTATE_90_LEFT: return true; case MediaDecoder.ROTATE_NONE: case MediaDecoder.ROTATE_180: return false; default: throw new IllegalArgumentException("Unsupported rotation angle."); } } /** * Subclasses must implement this to copy the video frame data to an MFF frame. * * @param outputVideoFrame The destination frame * @param rotation The desired rotation of the frame */ protected abstract void copyFrameDataTo(FrameImage2D outputVideoFrame, int rotation); }