FileDocCategorySizeDatePackage
MediaSource.javaAPI DocAndroid 5.1 API22238Thu Mar 12 22:22:30 GMT 2015android.filterpacks.videosrc

MediaSource

public class MediaSource extends android.filterfw.core.Filter
hide

Fields Summary
private String
mSourceUrl
The source URL for the media source. Can be an http: link to a remote resource, or a file: link to a local media file
private android.content.res.AssetFileDescriptor
mSourceAsset
An open asset file descriptor to a local media source. Default is null
private android.content.Context
mContext
The context for the MediaPlayer to resolve the sourceUrl. Make sure this is set before the sourceUrl to avoid unexpected result. If the sourceUrl is not a content URI, it is OK to keep this as null.
private boolean
mSelectedIsUrl
Whether the media source is a URL or an asset file descriptor. Defaults to false.
private boolean
mWaitForNewFrame
Whether the filter will always wait for a new video frame, or whether it will output an old frame again if a new frame isn't available. Defaults to true.
private boolean
mLooping
Whether the media source should loop automatically or not. Defaults to true.
private float
mVolume
Volume control. Currently sound is piped directly to the speakers, so this defaults to mute.
private int
mOrientation
Orientation. This controls the output orientation of the video. Valid values are 0, 90, 180, 270
private android.media.MediaPlayer
mMediaPlayer
private android.filterfw.core.GLFrame
mMediaFrame
private android.graphics.SurfaceTexture
mSurfaceTexture
private android.filterfw.core.ShaderProgram
mFrameExtractor
private android.filterfw.core.MutableFrameFormat
mOutputFormat
private int
mWidth
private int
mHeight
private static final int
PREP_TIMEOUT
private static final int
PREP_TIMEOUT_REPEAT
private static final int
NEWFRAME_TIMEOUT
private static final int
NEWFRAME_TIMEOUT_REPEAT
private final String
mFrameShader
private static final float[]
mSourceCoords_0
private static final float[]
mSourceCoords_270
private static final float[]
mSourceCoords_180
private static final float[]
mSourceCoords_90
private boolean
mGotSize
private boolean
mPrepared
private boolean
mPlaying
private boolean
mNewFrameAvailable
private boolean
mOrientationUpdated
private boolean
mPaused
private boolean
mCompleted
private final boolean
mLogVerbose
private static final String
TAG
private MediaPlayer.OnVideoSizeChangedListener
onVideoSizeChangedListener
private MediaPlayer.OnPreparedListener
onPreparedListener
private MediaPlayer.OnCompletionListener
onCompletionListener
private SurfaceTexture.OnFrameAvailableListener
onMediaFrameAvailableListener
Constructors Summary
public MediaSource(String name)


       
        super(name);
        mNewFrameAvailable = false;

        mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
    
Methods Summary
public voidclose(android.filterfw.core.FilterContext context)

        if (mMediaPlayer.isPlaying()) {
            mMediaPlayer.stop();
        }
        mPrepared = false;
        mGotSize = false;
        mPlaying = false;
        mPaused = false;
        mCompleted = false;
        mNewFrameAvailable = false;

        mMediaPlayer.release();
        mMediaPlayer = null;
        mSurfaceTexture.release();
        mSurfaceTexture = null;
        if (mLogVerbose) Log.v(TAG, "MediaSource closed");
    
private voidcreateFormats()

        mOutputFormat = ImageFormat.create(ImageFormat.COLORSPACE_RGBA,
                                           FrameFormat.TARGET_GPU);
    
public voidfieldPortValueUpdated(java.lang.String name, android.filterfw.core.FilterContext context)

        if (mLogVerbose) Log.v(TAG, "Parameter update");
        if (name.equals("sourceUrl")) {
           if (isOpen()) {
                if (mLogVerbose) Log.v(TAG, "Opening new source URL");
                if (mSelectedIsUrl) {
                    setupMediaPlayer(mSelectedIsUrl);
                }
            }
        } else if (name.equals("sourceAsset") ) {
            if (isOpen()) {
                if (mLogVerbose) Log.v(TAG, "Opening new source FD");
                if (!mSelectedIsUrl) {
                    setupMediaPlayer(mSelectedIsUrl);
                }
            }
        } else if (name.equals("loop")) {
            if (isOpen()) {
                mMediaPlayer.setLooping(mLooping);
            }
        } else if (name.equals("sourceIsUrl")) {
            if (isOpen()){
                if (mSelectedIsUrl){
                    if (mLogVerbose) Log.v(TAG, "Opening new source URL");
                } else {
                    if (mLogVerbose) Log.v(TAG, "Opening new source Asset");
                }
                setupMediaPlayer(mSelectedIsUrl);
            }
        } else if (name.equals("volume")) {
            if (isOpen()) {
                mMediaPlayer.setVolume(mVolume, mVolume);
            }
        } else if (name.equals("orientation") && mGotSize) {
            if (mOrientation == 0 || mOrientation == 180) {
                mOutputFormat.setDimensions(mWidth, mHeight);
            } else {
                mOutputFormat.setDimensions(mHeight, mWidth);
            }
            mOrientationUpdated = true;
        }
    
public voidopen(android.filterfw.core.FilterContext context)

        if (mLogVerbose) {
            Log.v(TAG, "Opening MediaSource");
            if (mSelectedIsUrl) {
                Log.v(TAG, "Current URL is " + mSourceUrl);
            } else {
                Log.v(TAG, "Current source is Asset!");
            }
        }

        mMediaFrame = (GLFrame)context.getFrameManager().newBoundFrame(
                mOutputFormat,
                GLFrame.EXTERNAL_TEXTURE,
                0);

        mSurfaceTexture = new SurfaceTexture(mMediaFrame.getTextureId());

        if (!setupMediaPlayer(mSelectedIsUrl)) {
          throw new RuntimeException("Error setting up MediaPlayer!");
        }
    
public synchronized voidpauseVideo(boolean pauseState)

        if (isOpen()) {
            if (pauseState && !mPaused) {
                mMediaPlayer.pause();
            } else if (!pauseState && mPaused) {
                mMediaPlayer.start();
            }
        }
        mPaused = pauseState;
    
protected voidprepare(android.filterfw.core.FilterContext context)

        if (mLogVerbose) Log.v(TAG, "Preparing MediaSource");

        mFrameExtractor = new ShaderProgram(context, mFrameShader);
        // SurfaceTexture defines (0,0) to be bottom-left. The filter framework
        // defines (0,0) as top-left, so do the flip here.
        mFrameExtractor.setSourceRect(0, 1, 1, -1);

        createFormats();
    
public voidprocess(android.filterfw.core.FilterContext context)

        // Note: process is synchronized by its caller in the Filter base class
        if (mLogVerbose) Log.v(TAG, "Processing new frame");

        if (mMediaPlayer == null) {
            // Something went wrong in initialization or parameter updates
            throw new NullPointerException("Unexpected null media player!");
        }

        if (mCompleted) {
            // Video playback is done, so close us down
            closeOutputPort("video");
            return;
        }

        if (!mPlaying) {
            int waitCount = 0;
            if (mLogVerbose) Log.v(TAG, "Waiting for preparation to complete");
            while (!mGotSize || !mPrepared) {
                try {
                    this.wait(PREP_TIMEOUT);
                } catch (InterruptedException e) {
                    // ignoring
                }
                if (mCompleted) {
                    // Video playback is done, so close us down
                    closeOutputPort("video");
                    return;
                }
                waitCount++;
                if (waitCount == PREP_TIMEOUT_REPEAT) {
                    mMediaPlayer.release();
                    throw new RuntimeException("MediaPlayer timed out while preparing!");
                }
            }
            if (mLogVerbose) Log.v(TAG, "Starting playback");
            mMediaPlayer.start();
        }

        // Use last frame if paused, unless just starting playback, in which case
        // we want at least one valid frame before pausing
        if (!mPaused || !mPlaying) {
            if (mWaitForNewFrame) {
                if (mLogVerbose) Log.v(TAG, "Waiting for new frame");

                int waitCount = 0;
                while (!mNewFrameAvailable) {
                    if (waitCount == NEWFRAME_TIMEOUT_REPEAT) {
                        if (mCompleted) {
                            // Video playback is done, so close us down
                            closeOutputPort("video");
                            return;
                        } else {
                            throw new RuntimeException("Timeout waiting for new frame!");
                        }
                    }
                    try {
                        this.wait(NEWFRAME_TIMEOUT);
                    } catch (InterruptedException e) {
                        if (mLogVerbose) Log.v(TAG, "interrupted");
                        // ignoring
                    }
                    waitCount++;
                }
                mNewFrameAvailable = false;
                if (mLogVerbose) Log.v(TAG, "Got new frame");
            }

            mSurfaceTexture.updateTexImage();
            mOrientationUpdated = true;
        }
        if (mOrientationUpdated) {
            float[] surfaceTransform = new float[16];
            mSurfaceTexture.getTransformMatrix(surfaceTransform);

            float[] sourceCoords = new float[16];
            switch (mOrientation) {
                default:
                case 0:
                    Matrix.multiplyMM(sourceCoords, 0,
                                      surfaceTransform, 0,
                                      mSourceCoords_0, 0);
                    break;
                case 90:
                    Matrix.multiplyMM(sourceCoords, 0,
                                      surfaceTransform, 0,
                                      mSourceCoords_90, 0);
                    break;
                case 180:
                    Matrix.multiplyMM(sourceCoords, 0,
                                      surfaceTransform, 0,
                                      mSourceCoords_180, 0);
                    break;
                case 270:
                    Matrix.multiplyMM(sourceCoords, 0,
                                      surfaceTransform, 0,
                                      mSourceCoords_270, 0);
                    break;
            }
            if (mLogVerbose) {
                Log.v(TAG, "OrientationHint = " + mOrientation);
                String temp = String.format("SetSourceRegion: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %.2f",
                        sourceCoords[4], sourceCoords[5],sourceCoords[0], sourceCoords[1],
                        sourceCoords[12], sourceCoords[13],sourceCoords[8], sourceCoords[9]);
                Log.v(TAG, temp);
            }
            mFrameExtractor.setSourceRegion(sourceCoords[4], sourceCoords[5],
                    sourceCoords[0], sourceCoords[1],
                    sourceCoords[12], sourceCoords[13],
                    sourceCoords[8], sourceCoords[9]);
            mOrientationUpdated = false;
        }

        Frame output = context.getFrameManager().newFrame(mOutputFormat);
        mFrameExtractor.process(mMediaFrame, output);

        long timestamp = mSurfaceTexture.getTimestamp();
        if (mLogVerbose) Log.v(TAG, "Timestamp: " + (timestamp / 1000000000.0) + " s");
        output.setTimestamp(timestamp);

        pushOutput("video", output);
        output.release();

        mPlaying = true;
    
private synchronized booleansetupMediaPlayer(boolean useUrl)
Creates a media player, sets it up, and calls prepare

        mPrepared = false;
        mGotSize = false;
        mPlaying = false;
        mPaused = false;
        mCompleted = false;
        mNewFrameAvailable = false;

        if (mLogVerbose) Log.v(TAG, "Setting up playback.");

        if (mMediaPlayer != null) {
            // Clean up existing media players
            if (mLogVerbose) Log.v(TAG, "Resetting existing MediaPlayer.");
            mMediaPlayer.reset();
        } else {
            // Create new media player
            if (mLogVerbose) Log.v(TAG, "Creating new MediaPlayer.");
            mMediaPlayer = new MediaPlayer();
        }

        if (mMediaPlayer == null) {
            throw new RuntimeException("Unable to create a MediaPlayer!");
        }

        // Set up data sources, etc
        try {
            if (useUrl) {
                if (mLogVerbose) Log.v(TAG, "Setting MediaPlayer source to URI " + mSourceUrl);
                if (mContext == null) {
                    mMediaPlayer.setDataSource(mSourceUrl);
                } else {
                    mMediaPlayer.setDataSource(mContext, Uri.parse(mSourceUrl.toString()));
                }
            } else {
                if (mLogVerbose) Log.v(TAG, "Setting MediaPlayer source to asset " + mSourceAsset);
                mMediaPlayer.setDataSource(mSourceAsset.getFileDescriptor(), mSourceAsset.getStartOffset(), mSourceAsset.getLength());
            }
        } catch(IOException e) {
            mMediaPlayer.release();
            mMediaPlayer = null;
            if (useUrl) {
                throw new RuntimeException(String.format("Unable to set MediaPlayer to URL %s!", mSourceUrl), e);
            } else {
                throw new RuntimeException(String.format("Unable to set MediaPlayer to asset %s!", mSourceAsset), e);
            }
        } catch(IllegalArgumentException e) {
            mMediaPlayer.release();
            mMediaPlayer = null;
            if (useUrl) {
                throw new RuntimeException(String.format("Unable to set MediaPlayer to URL %s!", mSourceUrl), e);
            } else {
                throw new RuntimeException(String.format("Unable to set MediaPlayer to asset %s!", mSourceAsset), e);
            }
        }

        mMediaPlayer.setLooping(mLooping);
        mMediaPlayer.setVolume(mVolume, mVolume);

        // Bind it to our media frame
        Surface surface = new Surface(mSurfaceTexture);
        mMediaPlayer.setSurface(surface);
        surface.release();

        // Connect Media Player to callbacks

        mMediaPlayer.setOnVideoSizeChangedListener(onVideoSizeChangedListener);
        mMediaPlayer.setOnPreparedListener(onPreparedListener);
        mMediaPlayer.setOnCompletionListener(onCompletionListener);

        // Connect SurfaceTexture to callback
        mSurfaceTexture.setOnFrameAvailableListener(onMediaFrameAvailableListener);

        if (mLogVerbose) Log.v(TAG, "Preparing MediaPlayer.");
        mMediaPlayer.prepareAsync();

        return true;
    
public voidsetupPorts()

        // Add input port
        addOutputPort("video", ImageFormat.create(ImageFormat.COLORSPACE_RGBA,
                                                  FrameFormat.TARGET_GPU));
    
public voidtearDown(android.filterfw.core.FilterContext context)

        if (mMediaFrame != null) {
            mMediaFrame.release();
        }