| /* |
| * 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); |
| |
| } |