165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn/* 265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Copyright (C) 2011 The Android Open Source Project 365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * 465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Licensed under the Apache License, Version 2.0 (the "License"); 565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * you may not use this file except in compliance with the License. 665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * You may obtain a copy of the License at 765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * 865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * http://www.apache.org/licenses/LICENSE-2.0 965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * 1065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * Unless required by applicable law or agreed to in writing, software 1165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * distributed under the License is distributed on an "AS IS" BASIS, 1265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * See the License for the specific language governing permissions and 1465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * limitations under the License. 1565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 1665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennpackage android.filterpacks.videosrc; 1965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 2065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.content.Context; 2165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.content.res.AssetFileDescriptor; 2265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.Filter; 2365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.FilterContext; 2465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.Frame; 2565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.FrameFormat; 2665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.FrameManager; 2765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.GenerateFieldPort; 2865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.GenerateFinalPort; 2965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.GLFrame; 3065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.KeyValueMap; 3165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.MutableFrameFormat; 3265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.NativeFrame; 3365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.Program; 3465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.core.ShaderProgram; 3565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.filterfw.format.ImageFormat; 3665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.graphics.SurfaceTexture; 3765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.media.MediaPlayer; 3865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.os.ConditionVariable; 3965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.opengl.Matrix; 4065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.view.Surface; 4165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 4265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.io.IOException; 4365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.io.FileDescriptor; 4465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.lang.IllegalArgumentException; 4565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.List; 4665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport java.util.Set; 4765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 4865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennimport android.util.Log; 4965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 5065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn/** 5165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * @hide 5265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 5365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Rennpublic class MediaSource extends Filter { 5465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 5565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** User-visible parameters */ 5665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 5765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** The source URL for the media source. Can be an http: link to a remote 5865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * resource, or a file: link to a local media file 5965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 6065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFieldPort(name = "sourceUrl", hasDefault = true) 6165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private String mSourceUrl = ""; 6265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 6365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** An open asset file descriptor to a local media source. Default is null */ 6465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFieldPort(name = "sourceAsset", hasDefault = true) 6565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private AssetFileDescriptor mSourceAsset = null; 6665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 6765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Whether the media source is a URL or an asset file descriptor. Defaults 6865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * to false. 6965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 7065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFieldPort(name = "sourceIsUrl", hasDefault = true) 7165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mSelectedIsUrl = false; 7265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 7365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Whether the filter will always wait for a new video frame, or whether it 7465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * will output an old frame again if a new frame isn't available. Defaults 7565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * to true. 7665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 7765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFinalPort(name = "waitForNewFrame", hasDefault = true) 7865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mWaitForNewFrame = true; 7965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 8065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Whether the media source should loop automatically or not. Defaults to 8165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * true. 8265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 8365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFieldPort(name = "loop", hasDefault = true) 8465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mLooping = true; 8565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 8665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Volume control. Currently sound is piped directly to the speakers, so 8765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * this defaults to mute. 8865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 8965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFieldPort(name = "volume", hasDefault = true) 9065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private float mVolume = 0.f; 9165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 9265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Orientation. This controls the output orientation of the video. Valid 9365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn * values are 0, 90, 180, 270 9465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn */ 9565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @GenerateFieldPort(name = "orientation", hasDefault = true) 9665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private int mOrientation = 0; 9765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 9865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private MediaPlayer mMediaPlayer; 9965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private GLFrame mMediaFrame; 10065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private SurfaceTexture mSurfaceTexture; 10165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private ShaderProgram mFrameExtractor; 10265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private MutableFrameFormat mOutputFormat; 10365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private int mWidth, mHeight; 10465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 10565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Total timeouts will be PREP_TIMEOUT*PREP_TIMEOUT_REPEAT 10665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final int PREP_TIMEOUT = 100; // ms 10765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final int PREP_TIMEOUT_REPEAT = 100; 10865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final int NEWFRAME_TIMEOUT = 100; //ms 10965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final int NEWFRAME_TIMEOUT_REPEAT = 10; 11065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 11165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // This is an identity shader; not using the default identity 11265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // shader because reading from a SurfaceTexture requires the 11365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // GL_OES_EGL_image_external extension. 11465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private final String mFrameShader = 11565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "#extension GL_OES_EGL_image_external : require\n" + 11665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "precision mediump float;\n" + 11765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "uniform samplerExternalOES tex_sampler_0;\n" + 11865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "varying vec2 v_texcoord;\n" + 11965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "void main() {\n" + 12065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn " gl_FragColor = texture2D(tex_sampler_0, v_texcoord);\n" + 12165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn "}\n"; 12265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 12365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // The following transforms enable rotation of the decoded source. 12465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // These are multiplied with the transform obtained from the 12565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // SurfaceTexture to get the final transform to be set on the media source. 12665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Currently, given a device orientation, the MediaSource rotates in such a way 12765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // that the source is displayed upright. A particular use case 12865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // is "Background Replacement" feature in the Camera app 12965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // where the MediaSource rotates the source to align with the camera feed and pass it 13065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // on to the backdropper filter. The backdropper only does the blending 13165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // and does not have to do any rotation 13265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // (except for mirroring in case of front camera). 13365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // TODO: Currently the rotations are spread over a bunch of stages in the 13465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // pipeline. A cleaner design 13565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // could be to cast away all the rotation in a separate filter or attach a transform 13665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // to the frame so that MediaSource itself need not know about any rotation. 13765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final float[] mSourceCoords_0 = { 1, 1, 0, 1, 13865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 0, 1, 0, 1, 13965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1, 0, 0, 1, 14065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 0, 0, 0, 1 }; 14165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final float[] mSourceCoords_270 = { 0, 1, 0, 1, 14265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 0, 0, 0, 1, 14365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1, 1, 0, 1, 14465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1, 0, 0, 1 }; 14565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final float[] mSourceCoords_180 = { 0, 0, 0, 1, 14665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1, 0, 0, 1, 14765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 0, 1, 0, 1, 14865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1, 1, 0, 1 }; 14965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final float[] mSourceCoords_90 = { 1, 0, 0, 1, 15065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 1, 1, 0, 1, 15165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 0, 0, 0, 1, 15265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 0, 1, 0, 1 }; 15365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 15465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mGotSize; 15565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mPrepared; 15665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mPlaying; 15765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mNewFrameAvailable; 15865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mOrientationUpdated; 15965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mPaused; 16065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private boolean mCompleted; 16165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 16265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private final boolean mLogVerbose; 16365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private static final String TAG = "MediaSource"; 16465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 16565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public MediaSource(String name) { 16665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn super(name); 16765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mNewFrameAvailable = false; 16865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 16965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE); 17065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 17165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 17265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 17365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void setupPorts() { 17465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Add input port 17565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn addOutputPort("video", ImageFormat.create(ImageFormat.COLORSPACE_RGBA, 17665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn FrameFormat.TARGET_GPU)); 17765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 17865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 17965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private void createFormats() { 18065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOutputFormat = ImageFormat.create(ImageFormat.COLORSPACE_RGBA, 18165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn FrameFormat.TARGET_GPU); 18265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 18365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 18465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 18565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn protected void prepare(FilterContext context) { 18665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Preparing MediaSource"); 18765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 18865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mFrameExtractor = new ShaderProgram(context, mFrameShader); 18965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // SurfaceTexture defines (0,0) to be bottom-left. The filter framework 19065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // defines (0,0) as top-left, so do the flip here. 19165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mFrameExtractor.setSourceRect(0, 1, 1, -1); 19265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 19365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn createFormats(); 19465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 19565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 19665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 19765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void open(FilterContext context) { 19865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) { 19965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Log.v(TAG, "Opening MediaSource"); 20065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mSelectedIsUrl) { 20165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Log.v(TAG, "Current URL is " + mSourceUrl); 20265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 20365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Log.v(TAG, "Current source is Asset!"); 20465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 20565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 20665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 20765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaFrame = (GLFrame)context.getFrameManager().newBoundFrame( 20865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOutputFormat, 20965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn GLFrame.EXTERNAL_TEXTURE, 21065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 0); 21165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 21265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture = new SurfaceTexture(mMediaFrame.getTextureId()); 21365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 21465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (!setupMediaPlayer(mSelectedIsUrl)) { 21565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("Error setting up MediaPlayer!"); 21665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 21765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 21865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 21965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 22065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void process(FilterContext context) { 22165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Note: process is synchronized by its caller in the Filter base class 22265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Processing new frame"); 22365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 22465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mMediaPlayer == null) { 22565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Something went wrong in initialization or parameter updates 22665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new NullPointerException("Unexpected null media player!"); 22765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 22865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 22965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mCompleted) { 23065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Video playback is done, so close us down 23165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn closeOutputPort("video"); 23265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return; 23365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 23465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 23565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (!mPlaying) { 23665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn int waitCount = 0; 23765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Waiting for preparation to complete"); 23865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn while (!mGotSize || !mPrepared) { 23965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn try { 24065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn this.wait(PREP_TIMEOUT); 24165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } catch (InterruptedException e) { 24265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // ignoring 24365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 24465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mCompleted) { 24565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Video playback is done, so close us down 24665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn closeOutputPort("video"); 24765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return; 24865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 24965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn waitCount++; 25065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (waitCount == PREP_TIMEOUT_REPEAT) { 25165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.release(); 25265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("MediaPlayer timed out while preparing!"); 25365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 25465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 25565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Starting playback"); 25665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.start(); 25765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 25865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 25965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Use last frame if paused, unless just starting playback, in which case 26065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // we want at least one valid frame before pausing 26165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (!mPaused || !mPlaying) { 26265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mWaitForNewFrame) { 26365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Waiting for new frame"); 26465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 26565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn int waitCount = 0; 26665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn while (!mNewFrameAvailable) { 26765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (waitCount == NEWFRAME_TIMEOUT_REPEAT) { 26865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mCompleted) { 26965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Video playback is done, so close us down 27065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn closeOutputPort("video"); 27165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return; 27265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 27365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("Timeout waiting for new frame!"); 27465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 27565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 27665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn try { 27765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn this.wait(NEWFRAME_TIMEOUT); 27865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } catch (InterruptedException e) { 27965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "interrupted"); 28065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // ignoring 28165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 28265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn waitCount++; 28365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 28465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mNewFrameAvailable = false; 28565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Got new frame"); 28665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 28765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 28865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture.updateTexImage(); 28965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOrientationUpdated = true; 29065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 29165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mOrientationUpdated) { 29265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn float[] surfaceTransform = new float[16]; 29365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture.getTransformMatrix(surfaceTransform); 29465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 29565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn float[] sourceCoords = new float[16]; 29665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn switch (mOrientation) { 29765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn default: 29865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case 0: 29965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Matrix.multiplyMM(sourceCoords, 0, 30065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surfaceTransform, 0, 30165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSourceCoords_0, 0); 30265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn break; 30365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case 90: 30465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Matrix.multiplyMM(sourceCoords, 0, 30565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surfaceTransform, 0, 30665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSourceCoords_90, 0); 30765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn break; 30865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case 180: 30965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Matrix.multiplyMM(sourceCoords, 0, 31065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surfaceTransform, 0, 31165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSourceCoords_180, 0); 31265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn break; 31365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn case 270: 31465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Matrix.multiplyMM(sourceCoords, 0, 31565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surfaceTransform, 0, 31665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSourceCoords_270, 0); 31765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn break; 31865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 31965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) { 32065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Log.v(TAG, "OrientationHint = " + mOrientation); 32165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn String temp = String.format("SetSourceRegion: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f", 32265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn sourceCoords[4], sourceCoords[5],sourceCoords[0], sourceCoords[1], 32365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn sourceCoords[12], sourceCoords[13],sourceCoords[8], sourceCoords[9]); 32465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Log.v(TAG, temp); 32565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 32665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mFrameExtractor.setSourceRegion(sourceCoords[4], sourceCoords[5], 32765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn sourceCoords[0], sourceCoords[1], 32865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn sourceCoords[12], sourceCoords[13], 32965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn sourceCoords[8], sourceCoords[9]); 33065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOrientationUpdated = false; 33165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 33265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 33365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Frame output = context.getFrameManager().newFrame(mOutputFormat); 33465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mFrameExtractor.process(mMediaFrame, output); 33565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 33665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn long timestamp = mSurfaceTexture.getTimestamp(); 33765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Timestamp: " + (timestamp / 1000000000.0) + " s"); 33865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn output.setTimestamp(timestamp); 33965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 34065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn pushOutput("video", output); 34165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn output.release(); 34265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 34365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPlaying = true; 34465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 34565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 34665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 34765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void close(FilterContext context) { 34865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mMediaPlayer.isPlaying()) { 34965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.stop(); 35065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 35165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPrepared = false; 35265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mGotSize = false; 35365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPlaying = false; 35465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPaused = false; 35565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCompleted = false; 35665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mNewFrameAvailable = false; 35765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 35865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.release(); 35965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer = null; 36065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture.release(); 36165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture = null; 36265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "MediaSource closed"); 36365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 36465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 36565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 36665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void tearDown(FilterContext context) { 36765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mMediaFrame != null) { 36865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaFrame.release(); 36965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 37065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 37165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 37265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // When updating the port values of the filter, users can update sourceIsUrl to switch 37365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // between using URL objects or Assets. 37465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // If updating only sourceUrl/sourceAsset, MediaPlayer gets reset if the current player 37565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // uses Url objects/Asset. 37665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Otherwise the new sourceUrl/sourceAsset is stored and will be used when users switch 37765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // sourceIsUrl next time. 37865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn @Override 37965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void fieldPortValueUpdated(String name, FilterContext context) { 38065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Parameter update"); 38165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (name.equals("sourceUrl")) { 38265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (isOpen()) { 38365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Opening new source URL"); 38465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mSelectedIsUrl) { 38565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn setupMediaPlayer(mSelectedIsUrl); 38665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 38765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 38865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else if (name.equals("sourceAsset") ) { 38965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (isOpen()) { 39065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Opening new source FD"); 39165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (!mSelectedIsUrl) { 39265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn setupMediaPlayer(mSelectedIsUrl); 39365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 39465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 39565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else if (name.equals("loop")) { 39665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (isOpen()) { 39765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setLooping(mLooping); 39865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 39965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else if (name.equals("sourceIsUrl")) { 40065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (isOpen()){ 40165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mSelectedIsUrl){ 40265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Opening new source URL"); 40365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 40465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Opening new source Asset"); 40565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 40665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn setupMediaPlayer(mSelectedIsUrl); 40765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 40865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else if (name.equals("volume")) { 40965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (isOpen()) { 41065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setVolume(mVolume, mVolume); 41165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 41265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else if (name.equals("orientation") && mGotSize) { 41365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mOrientation == 0 || mOrientation == 180) { 41465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOutputFormat.setDimensions(mWidth, mHeight); 41565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 41665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOutputFormat.setDimensions(mHeight, mWidth); 41765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 41865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOrientationUpdated = true; 41965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 42065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 42165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 42265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn synchronized public void pauseVideo(boolean pauseState) { 42365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (isOpen()) { 42465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (pauseState && !mPaused) { 42565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.pause(); 42665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else if (!pauseState && mPaused) { 42765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.start(); 42865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 42965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 43065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPaused = pauseState; 43165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 43265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 43365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn /** Creates a media player, sets it up, and calls prepare */ 43465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn synchronized private boolean setupMediaPlayer(boolean useUrl) { 43565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPrepared = false; 43665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mGotSize = false; 43765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPlaying = false; 43865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPaused = false; 43965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCompleted = false; 44065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mNewFrameAvailable = false; 44165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 44265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Setting up playback."); 44365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 44465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mMediaPlayer != null) { 44565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Clean up existing media players 44665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Resetting existing MediaPlayer."); 44765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.reset(); 44865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 44965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Create new media player 45065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Creating new MediaPlayer."); 45165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer = new MediaPlayer(); 45265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 45365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 45465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mMediaPlayer == null) { 45565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException("Unable to create a MediaPlayer!"); 45665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 45765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 45865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Set up data sources, etc 45965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn try { 46065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (useUrl) { 46165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Setting MediaPlayer source to URI " + mSourceUrl); 46265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setDataSource(mSourceUrl); 46365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 46465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Setting MediaPlayer source to asset " + mSourceAsset); 46565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setDataSource(mSourceAsset.getFileDescriptor(), mSourceAsset.getStartOffset(), mSourceAsset.getLength()); 46665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 46765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } catch(IOException e) { 46865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.release(); 46965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer = null; 47065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (useUrl) { 47165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException(String.format("Unable to set MediaPlayer to URL %s!", mSourceUrl), e); 47265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 47365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException(String.format("Unable to set MediaPlayer to asset %s!", mSourceAsset), e); 47465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 47565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } catch(IllegalArgumentException e) { 47665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.release(); 47765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer = null; 47865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (useUrl) { 47965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException(String.format("Unable to set MediaPlayer to URL %s!", mSourceUrl), e); 48065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 48165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn throw new RuntimeException(String.format("Unable to set MediaPlayer to asset %s!", mSourceAsset), e); 48265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 48365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 48465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 48565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setLooping(mLooping); 48665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setVolume(mVolume, mVolume); 48765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 48865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Bind it to our media frame 48965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Surface surface = new Surface(mSurfaceTexture); 49065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setSurface(surface); 49165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn surface.release(); 49265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 49365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Connect Media Player to callbacks 49465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 49565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setOnVideoSizeChangedListener(onVideoSizeChangedListener); 49665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setOnPreparedListener(onPreparedListener); 49765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.setOnCompletionListener(onCompletionListener); 49865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 49965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn // Connect SurfaceTexture to callback 50065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mSurfaceTexture.setOnFrameAvailableListener(onMediaFrameAvailableListener); 50165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 50265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "Preparing MediaPlayer."); 50365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mMediaPlayer.prepareAsync(); 50465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 50565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn return true; 50665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 50765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 50865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private MediaPlayer.OnVideoSizeChangedListener onVideoSizeChangedListener = 50965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn new MediaPlayer.OnVideoSizeChangedListener() { 51065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { 51165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "MediaPlayer sent dimensions: " + width + " x " + height); 51265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (!mGotSize) { 51365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mOrientation == 0 || mOrientation == 180) { 51465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOutputFormat.setDimensions(width, height); 51565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 51665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOutputFormat.setDimensions(height, width); 51765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 51865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mWidth = width; 51965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mHeight = height; 52065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } else { 52165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mOutputFormat.getWidth() != width || 52265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mOutputFormat.getHeight() != height) { 52365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn Log.e(TAG, "Multiple video size change events received!"); 52465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 52565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 52665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn synchronized(MediaSource.this) { 52765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mGotSize = true; 52865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn MediaSource.this.notify(); 52965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 53065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 53165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn }; 53265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 53365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private MediaPlayer.OnPreparedListener onPreparedListener = 53465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn new MediaPlayer.OnPreparedListener() { 53565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void onPrepared(MediaPlayer mp) { 53665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "MediaPlayer is prepared"); 53765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn synchronized(MediaSource.this) { 53865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mPrepared = true; 53965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn MediaSource.this.notify(); 54065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 54165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 54265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn }; 54365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 54465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private MediaPlayer.OnCompletionListener onCompletionListener = 54565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn new MediaPlayer.OnCompletionListener() { 54665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void onCompletion(MediaPlayer mp) { 54765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "MediaPlayer has completed playback"); 54865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn synchronized(MediaSource.this) { 54965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mCompleted = true; 55065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 55165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 55265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn }; 55365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 55465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn private SurfaceTexture.OnFrameAvailableListener onMediaFrameAvailableListener = 55565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn new SurfaceTexture.OnFrameAvailableListener() { 55665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn public void onFrameAvailable(SurfaceTexture surfaceTexture) { 55765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "New frame from media player"); 55865953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn synchronized(MediaSource.this) { 55965953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "New frame: notify"); 56065953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn mNewFrameAvailable = true; 56165953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn MediaSource.this.notify(); 56265953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn if (mLogVerbose) Log.v(TAG, "New frame: notify done"); 56365953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 56465953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn } 56565953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn }; 56665953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn 56765953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9Marius Renn} 568