1/* 2 * Copyright 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package androidx.media.filterfw.decoder; 17 18import android.annotation.TargetApi; 19import android.media.MediaFormat; 20import android.util.Log; 21 22import androidx.media.filterfw.FrameImage2D; 23 24/** 25 * Base class for all {@link TrackDecoder} classes that decode video. 26 */ 27@TargetApi(16) 28public abstract class VideoTrackDecoder extends TrackDecoder { 29 30 private static final String LOG_TAG = "VideoTrackDecoder"; 31 32 protected final Object mFrameMonitor = new Object(); 33 protected volatile boolean mFrameAvailable; // Access guarded by mFrameMonitor. 34 35 protected VideoTrackDecoder(int trackIndex, MediaFormat format, Listener listener) { 36 super(trackIndex, format, listener); 37 if (!DecoderUtil.isVideoFormat(format)) { 38 throw new IllegalArgumentException( 39 "VideoTrackDecoder can only be used with video formats"); 40 } 41 } 42 43 public void grabFrame(FrameImage2D outputVideoFrame, int rotation) { 44 synchronized (mFrameMonitor) { 45 if (!mFrameAvailable) { 46 Log.w(LOG_TAG, "frame is not ready - the caller has to wait for a corresponding " + 47 "onDecodedFrameAvailable() call"); 48 return; 49 } 50 51 copyFrameDataTo(outputVideoFrame, rotation); 52 53 mFrameAvailable = false; 54 mFrameMonitor.notifyAll(); 55 } 56 } 57 58 59 /** 60 * Waits for the frame to be picked up by the MFF thread, i.e. blocks until the 61 * {@link #grabFrame(FrameImage2D, int)}) method is called. 62 */ 63 public boolean waitForFrameGrab() { 64 synchronized (mFrameMonitor) { 65 try { 66 while (mFrameAvailable) { 67 mFrameMonitor.wait(); 68 } 69 return true; 70 } catch (InterruptedException e) { 71 return false; 72 } 73 } 74 } 75 76 protected final void markFrameAvailable() { 77 synchronized (mFrameMonitor) { 78 mFrameAvailable = true; 79 mFrameMonitor.notifyAll(); 80 } 81 } 82 83 /** 84 * @return if the frame dimension needs to be swapped, 85 * i.e. (width,height) becomes (height, width) 86 */ 87 protected static boolean needSwapDimension(int rotation) { 88 switch(rotation) { 89 case MediaDecoder.ROTATE_90_RIGHT: 90 case MediaDecoder.ROTATE_90_LEFT: 91 return true; 92 case MediaDecoder.ROTATE_NONE: 93 case MediaDecoder.ROTATE_180: 94 return false; 95 default: 96 throw new IllegalArgumentException("Unsupported rotation angle."); 97 } 98 } 99 100 /** 101 * Subclasses must implement this to copy the video frame data to an MFF frame. 102 * 103 * @param outputVideoFrame The destination frame 104 * @param rotation The desired rotation of the frame 105 */ 106 protected abstract void copyFrameDataTo(FrameImage2D outputVideoFrame, int rotation); 107 108} 109