private final void handleStop() {
   if (DEBUG) Log.v(TAG, "handleStop:");
   synchronized (mVideoTask) {
     internal_stop_video();
     mVideoTrackIndex = -1;
   }
   if (mVideoMediaCodec != null) {
     mVideoMediaCodec.stop();
     mVideoMediaCodec.release();
     mVideoMediaCodec = null;
   }
   if (mVideoMediaExtractor != null) {
     mVideoMediaExtractor.release();
     mVideoMediaExtractor = null;
   }
   mVideoBufferInfo = null;
   mVideoInputBuffers = mVideoOutputBuffers = null;
   if (mMetadata != null) {
     mMetadata.release();
     mMetadata = null;
   }
   synchronized (mSync) {
     mVideoOutputDone = mVideoInputDone = true;
     mState = STATE_STOP;
   }
   mCallback.onFinished();
 }
 /**
  * @param sourceFile
  * @throws IOException
  */
 private final void handlePrepare(final String source_file) throws IOException {
   if (DEBUG) Log.v(TAG, "handlePrepare:");
   synchronized (mSync) {
     if (mState != STATE_STOP) {
       throw new RuntimeException("invalid state:" + mState);
     }
   }
   final File src = new File(source_file);
   if (TextUtils.isEmpty(source_file) || !src.canRead()) {
     throw new FileNotFoundException("Unable to read " + source_file);
   }
   mVideoTrackIndex = -1;
   mMetadata = new MediaMetadataRetriever();
   mMetadata.setDataSource(source_file);
   updateMovieInfo();
   // preparation for video playback
   mVideoTrackIndex = internal_prepare_video(source_file);
   if (mVideoTrackIndex < 0) {
     throw new RuntimeException("No video track found in " + source_file);
   }
   synchronized (mSync) {
     mState = STATE_PREPARED;
   }
   mCallback.onPrepared();
 }
 /** @param frameCallback */
 private final void handleOutputVideo(final IFrameCallback frameCallback) {
   //    	if (DEBUG) Log.v(TAG, "handleDrainVideo:");
   while (mIsRunning && !mVideoOutputDone) {
     final int decoderStatus =
         mVideoMediaCodec.dequeueOutputBuffer(mVideoBufferInfo, TIMEOUT_USEC);
     if (decoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
       return;
     } else if (decoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
       mVideoOutputBuffers = mVideoMediaCodec.getOutputBuffers();
       if (DEBUG) Log.d(TAG, "INFO_OUTPUT_BUFFERS_CHANGED:");
     } else if (decoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
       final MediaFormat newFormat = mVideoMediaCodec.getOutputFormat();
       if (DEBUG) Log.d(TAG, "video decoder output format changed: " + newFormat);
     } else if (decoderStatus < 0) {
       throw new RuntimeException(
           "unexpected result from video decoder.dequeueOutputBuffer: " + decoderStatus);
     } else { // decoderStatus >= 0
       boolean doRender = false;
       if (mVideoBufferInfo.size > 0) {
         doRender =
             (mVideoBufferInfo.size != 0)
                 && !internal_write_video(
                     mVideoOutputBuffers[decoderStatus],
                     0,
                     mVideoBufferInfo.size,
                     mVideoBufferInfo.presentationTimeUs);
         if (doRender) {
           if (!frameCallback.onFrameAvailable(mVideoBufferInfo.presentationTimeUs))
             mVideoStartTime =
                 adjustPresentationTime(
                     mVideoSync, mVideoStartTime, mVideoBufferInfo.presentationTimeUs);
         }
       }
       mVideoMediaCodec.releaseOutputBuffer(decoderStatus, doRender);
       if ((mVideoBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
         if (DEBUG) Log.d(TAG, "video:output EOS");
         synchronized (mSync) {
           mVideoOutputDone = true;
           mSync.notifyAll();
         }
       }
     }
   }
 }