Android Open Source - AndroidVideoSamples Media Codec Decode Controller






From Project

Back to project page AndroidVideoSamples.

License

The source code is released under:

Apache License

If you think the Android project AndroidVideoSamples listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/**
   Copyright (c) 2014 Rory Hool/*w  w w  .  j  a v  a  2  s .  c  o m*/
   
   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 com.roryhool.videoplayback;

import java.io.IOException;
import java.nio.ByteBuffer;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import android.view.Surface;
import android.view.ViewGroup;

import com.roryhool.commonvideolibrary.MediaHelper;

@TargetApi( Build.VERSION_CODES.JELLY_BEAN )
public class MediaCodecDecodeController extends ControllerBase {

   private static final String TAG = "MediaCodecDecodeController";

   VideoPlayerView mVideoPlayerView;

   ScaledTextureView mTextureView;

   int mVideoWidth = 0;
   int mVideoHeight = 0;

   int mRotation = 0;

   int mDuration = 0;

   int mCurrentPosition = 0;

   DecoderThread mDecoderThread;

   PlaybackTimer mTimer;

   public MediaCodecDecodeController( Context context, VideoPlayerView view, ScaledTextureView textureView ) {
      super( context );
      mTimer = new PlaybackTimer();
      mVideoPlayerView = view;
      mTextureView = textureView;
   }

   private void calculateMediaStats( Uri uri ) {

      MediaMetadataRetriever r = new MediaMetadataRetriever();

      if ( r != null ) {
         try {
            r.setDataSource( uri.toString() );
         } catch ( RuntimeException exception ) {
            r.release();
            return;
         }

         String widthString = r.extractMetadata( MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH );
         String heightString = r.extractMetadata( MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT );

         String durationString = r.extractMetadata( MediaMetadataRetriever.METADATA_KEY_DURATION );

         r.release();

         mVideoWidth = Integer.parseInt( widthString );
         mVideoHeight = Integer.parseInt( heightString );

         mDuration = Integer.parseInt( durationString );

         mRotation = MediaHelper.GetRotation( uri );

         if ( mRotation == 90 || mRotation == 270 ) {

         }

         ViewGroup.LayoutParams params = mTextureView.getLayoutParams();
         params.width = ViewGroup.LayoutParams.MATCH_PARENT;
         params.height = ViewGroup.LayoutParams.MATCH_PARENT;
         mTextureView.setRotation( mRotation );
         mTextureView.setLayoutParams( params );
         mTextureView.requestLayout();
         mVideoPlayerView.requestLayout();
      }
   }

   @Override
   public void setVideoUri( Uri uri ) {
      super.setVideoUri( uri );
      calculateMediaStats( uri );
   }

   @Override
   public void play() {
      mTimer.start();
      mDecoderThread.play();
   }

   @Override
   public void pause() {
      mTimer.stop();
      mDecoderThread.pause();
   }

   int mSeekToMs = -1;

   @Override
   public void seekTo( int ms ) {
      mSeekToMs = ms;
   }

   @Override
   public boolean isPlaying() {
      return mTimer.isRunning();
   }

   @Override
   public void onSurfaceTextureAvailable( SurfaceTexture surfaceTexture, int width, int height ) {

      Surface surface = new Surface( surfaceTexture );

      mDecoderThread = new DecoderThread( surface, mVideoUri );
      mDecoderThread.start();
   }

   @Override
   public void onSurfaceTextureSizeChanged( SurfaceTexture surface, int width, int height ) {
   }

   @Override
   public boolean onSurfaceTextureDestroyed( SurfaceTexture surface ) {
      return false;
   }

   @Override
   public void onSurfaceTextureUpdated( SurfaceTexture surface ) {
   }

   @Override
   public int getDuration() {
      return mDuration;
   }

   @Override
   public int getCurrentPosition() {
      return (int) mTimer.getTime();
   }

   @Override
   public int getVideoWidth() {
      return mVideoWidth;
   }

   @Override
   public int getVideoHeight() {
      return mVideoHeight;
   }

   public void shutDown() {
      mDecoderThread.shutDown();
   }

   private class DecoderThread extends Thread {

      Surface mSurface;

      Uri mUri;

      MediaExtractor mExtractor;

      ByteBuffer[] mInputBuffers;
      ByteBuffer[] mOutputBuffers;

      boolean mThreadStoped;

      MediaCodec mDecoder;

      BufferInfo mInfo;

      boolean mPlaying;

      public DecoderThread( Surface surface, Uri videoUri ) {
         mSurface = surface;
         mUri = videoUri;

         setupExtractor();
      }

      private void setupExtractor() {
         mExtractor = new MediaExtractor();
         try {
            mExtractor.setDataSource( mUri.toString() );
         } catch ( IOException e ) {
            e.printStackTrace();
         }

         int videoIndex = 0;

         for ( int trackIndex = 0; trackIndex < mExtractor.getTrackCount(); trackIndex++ ) {
            MediaFormat format = mExtractor.getTrackFormat( trackIndex );

            String mime = format.getString( MediaFormat.KEY_MIME );
            if ( mime != null ) {
               if ( mime.equals( "video/avc" ) ) {
                  mExtractor.selectTrack( trackIndex );
                  videoIndex = trackIndex;
                  break;
               }
            }
         }

         mDecoder = MediaCodec.createDecoderByType( "video/avc" );
         mDecoder.configure( mExtractor.getTrackFormat( videoIndex ), mSurface, null, 0 );
         mDecoder.start();

         mInfo = new BufferInfo();

         mInputBuffers = mDecoder.getInputBuffers();
         mOutputBuffers = mDecoder.getOutputBuffers();
      }

      @Override
      public void run() {

         boolean isEOS = false;

         // Log.d( TAG, String.format( "Got ibuffers %d and o buffers %d", mInputBuffers.length, mOutputBuffers.length ) );

         while ( !mThreadStoped ) {

            if ( mPlaying ) {

               if ( isEOS ) {
                  seekTo( 0, MediaExtractor.SEEK_TO_CLOSEST_SYNC );
                  isEOS = false;
               }

               if ( mSeekToMs != -1 ) {
                  seekTo( mSeekToMs, MediaExtractor.SEEK_TO_PREVIOUS_SYNC );
                  mSeekToMs = -1;
               }

               long timertime = mTimer.getTime();

               if ( timertime < mCurrentPosition ) {
                  continue;
               }

               int inIndex = mDecoder.dequeueInputBuffer( 10000 );

               // Log.d( TAG, String.format( "Got index %d", inIndex ) );

               if ( inIndex >= 0 ) {
                  ByteBuffer buffer = mInputBuffers[inIndex];
                  int sampleSize = mExtractor.readSampleData( buffer, 0 );
                  if ( sampleSize < 0 ) {
                     // Log.d( TAG, "InputBuffer BUFFER_FLAG_END_OF_STREAM" );
                     mDecoder.queueInputBuffer( inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM );
                     isEOS = true;
                  } else {
                     // Log.d( TAG, "InputBuffer ADVANCING" );
                     mDecoder.queueInputBuffer( inIndex, 0, sampleSize, mExtractor.getSampleTime(), 0 );
                     if ( ( mExtractor.getSampleFlags() & MediaExtractor.SAMPLE_FLAG_SYNC ) > 0 ) {
                        // Log.d( TAG, String.format( Locale.US, "Sync frame at %d", mExtractor.getSampleTime() ) );
                     }
                     mExtractor.advance();
                  }
               }

               int outIndex = mDecoder.dequeueOutputBuffer( mInfo, 10000 );
               mCurrentPosition = (int) mInfo.presentationTimeUs / 1000;

               // Log.d( TAG, String.format( Locale.US, "current position is %d", mCurrentPosition ) );

               switch ( outIndex ) {
               case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
                  Log.d( TAG, "INFO_OUTPUT_BUFFERS_CHANGED" );
                  mInputBuffers = mDecoder.getInputBuffers();
                  mOutputBuffers = mDecoder.getOutputBuffers();
                  break;
               case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
                  Log.d( TAG, "New format " + mDecoder.getOutputFormat() );
                  break;
               case MediaCodec.INFO_TRY_AGAIN_LATER:
                  Log.d( TAG, "dequeueOutputBuffer timed out!" );
                  break;
               default:
                  ByteBuffer buffer = mOutputBuffers[outIndex];
                  // Log.v( TAG, "We can't use this buffer but render it due to the API limit, " + buffer );

                  mDecoder.releaseOutputBuffer( outIndex, true );
                  break;
               }

               if ( ( mInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM ) != 0 ) {
                  // Log.d( TAG, "OutputBuffer BUFFER_FLAG_END_OF_STREAM" );
                  isEOS = true;
               }

               if ( isEOS ) {
                  pause();
                  onCompletion();
               }
            }
         }

         mDecoder.stop();
         mDecoder.release();
         mExtractor.release();
      }

      private void seekTo( long ms, int seekMode ) {

         // Log.d( TAG, String.format( Locale.US, "seeking to %d", ms ) );

         mExtractor.seekTo( ms * 1000, seekMode );
         mCurrentPosition = (int) mExtractor.getSampleTime() / 1000;
         mTimer.setTime( mCurrentPosition );
         // Log.d( TAG, String.format( Locale.US, "seeking extractor to %d, sample time is now %d", ms, mExtractor.getSampleTime() ) );
         mDecoder.flush();
         mInputBuffers = mDecoder.getInputBuffers();
         mOutputBuffers = mDecoder.getOutputBuffers();

         mInfo = new BufferInfo();
      }

      public void pause() {
         mPlaying = false;
         mTimer.stop();
      }

      public void play() {
         mPlaying = true;
         mTimer.start();
      }

      public void shutDown() {
         mThreadStoped = true;
      }
   }

}




Java Source Code List

com.roryhool.commonvideolibrary.CursorHelper.java
com.roryhool.commonvideolibrary.InputSurface.java
com.roryhool.commonvideolibrary.Intents.java
com.roryhool.commonvideolibrary.MediaHelper.java
com.roryhool.commonvideolibrary.OutputSurface.java
com.roryhool.commonvideolibrary.Resolution.java
com.roryhool.commonvideolibrary.SamplerClip.java
com.roryhool.commonvideolibrary.TextureRenderer.java
com.roryhool.commonvideolibrary.UriHelper.java
com.roryhool.commonvideolibrary.VideoResampler.java
com.roryhool.videocreation.JoinActivity.java
com.roryhool.videocreation.MainActivity.java
com.roryhool.videocreation.RenderFromSurfaceActivity.java
com.roryhool.videocreation.SurfaceEncoder.java
com.roryhool.videomanipulation.MainActivity.java
com.roryhool.videomanipulation.ResampleActivity.java
com.roryhool.videomanipulation.RotationActivity.java
com.roryhool.videomanipulation.TrimActivity.java
com.roryhool.videoplayback.ControllerBase.java
com.roryhool.videoplayback.DecodeWithMediaCodecActivity.java
com.roryhool.videoplayback.MainActivity.java
com.roryhool.videoplayback.MediaCodecDecodeController.java
com.roryhool.videoplayback.MediaPlayerController.java
com.roryhool.videoplayback.PlayWithMediaPlayerActivity.java
com.roryhool.videoplayback.PlaybackTimer.java
com.roryhool.videoplayback.ResizeAnimation.java
com.roryhool.videoplayback.ScaledTextureView.java
com.roryhool.videoplayback.VideoPlayerView.java