Android Open Source - MediaCodecDemo Decode Activity






From Project

Back to project page MediaCodecDemo.

License

The source code is released under:

Copyright (c) 2012, Cedric Fung <cedric@vec.io> All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following condit...

If you think the Android project MediaCodecDemo 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

package io.vec.demo.mediacodec;
/*from   ww w .  java  2s. com*/
import java.nio.ByteBuffer;

import android.app.Activity;
import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class DecodeActivity extends Activity implements SurfaceHolder.Callback {
  private static final String SAMPLE = Environment.getExternalStorageDirectory() + "/video.mp4";
  private PlayerThread mPlayer = null;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    SurfaceView sv = new SurfaceView(this);
    sv.getHolder().addCallback(this);
    setContentView(sv);
  }

  protected void onDestroy() {
    super.onDestroy();
  }

  @Override
  public void surfaceCreated(SurfaceHolder holder) {
  }

  @Override
  public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    if (mPlayer == null) {
      mPlayer = new PlayerThread(holder.getSurface());
      mPlayer.start();
    }
  }

  @Override
  public void surfaceDestroyed(SurfaceHolder holder) {
    if (mPlayer != null) {
      mPlayer.interrupt();
    }
  }

  private class PlayerThread extends Thread {
    private MediaExtractor extractor;
    private MediaCodec decoder;
    private Surface surface;

    public PlayerThread(Surface surface) {
      this.surface = surface;
    }

    @Override
    public void run() {
      extractor = new MediaExtractor();
      extractor.setDataSource(SAMPLE);

      for (int i = 0; i < extractor.getTrackCount(); i++) {
        MediaFormat format = extractor.getTrackFormat(i);
        String mime = format.getString(MediaFormat.KEY_MIME);
        if (mime.startsWith("video/")) {
          extractor.selectTrack(i);
          decoder = MediaCodec.createDecoderByType(mime);
          decoder.configure(format, surface, null, 0);
          break;
        }
      }

      if (decoder == null) {
        Log.e("DecodeActivity", "Can't find video info!");
        return;
      }

      decoder.start();

      ByteBuffer[] inputBuffers = decoder.getInputBuffers();
      ByteBuffer[] outputBuffers = decoder.getOutputBuffers();
      BufferInfo info = new BufferInfo();
      boolean isEOS = false;
      long startMs = System.currentTimeMillis();

      while (!Thread.interrupted()) {
        if (!isEOS) {
          int inIndex = decoder.dequeueInputBuffer(10000);
          if (inIndex >= 0) {
            ByteBuffer buffer = inputBuffers[inIndex];
            int sampleSize = extractor.readSampleData(buffer, 0);
            if (sampleSize < 0) {
              // We shouldn't stop the playback at this point, just pass the EOS
              // flag to decoder, we will get it again from the
              // dequeueOutputBuffer
              Log.d("DecodeActivity", "InputBuffer BUFFER_FLAG_END_OF_STREAM");
              decoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
              isEOS = true;
            } else {
              decoder.queueInputBuffer(inIndex, 0, sampleSize, extractor.getSampleTime(), 0);
              extractor.advance();
            }
          }
        }

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

          // We use a very simple clock to keep the video FPS, or the video
          // playback will be too fast
          while (info.presentationTimeUs / 1000 > System.currentTimeMillis() - startMs) {
            try {
              sleep(10);
            } catch (InterruptedException e) {
              e.printStackTrace();
              break;
            }
          }
          decoder.releaseOutputBuffer(outIndex, true);
          break;
        }

        // All decoded frames have been rendered, we can stop playing now
        if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
          Log.d("DecodeActivity", "OutputBuffer BUFFER_FLAG_END_OF_STREAM");
          break;
        }
      }

      decoder.stop();
      decoder.release();
      extractor.release();
    }
  }
}




Java Source Code List

io.vec.demo.mediacodec.DecodeActivity.java