Android Open Source - screenshare-playground Decoder Async Task






From Project

Back to project page screenshare-playground.

License

The source code is released under:

GNU General Public License

If you think the Android project screenshare-playground 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) 2015 Renard Wellnitz.//www .j  av a 2s .  c  o  m
 *
 *  This file is part of ScreenShare.
 *
 *     Foobar is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     Foobar is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.screenshare.renard314.screensharelib;

import android.media.MediaCodec;
import android.media.MediaFormat;
import android.media.MediaPlayer;
import android.os.AsyncTask;
import android.provider.MediaStore;
import android.util.Log;
import android.util.Pair;
import android.view.Surface;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * Created by renard on 18/12/14.
 */
public class DecoderAsyncTask extends AsyncTask<Void, Pair<Integer,Integer>, Void> {

  private static final String LOG_TAG = DecoderAsyncTask.class.getSimpleName();
  private final OnVideoSizeChangedListener mListener;
  MediaCodec mDecoder;
    LinkedBlockingQueue<VideoChunk> mVideoChunks = new LinkedBlockingQueue<VideoChunk>();
    List<Pair<Long,Integer>> mReceivedChunks = new ArrayList<Pair<Long,Integer>>();

  public DecoderAsyncTask(MediaCodecFactory factory, Surface surface, OnVideoSizeChangedListener listener) throws IOException {
    mListener = listener;
    mDecoder = factory.createVideoDecoder(surface);
  }

  public void addChunk(VideoChunk chunk) {
        //mReceivedChunks.add(Pair.create(System.currentTimeMillis(), mVideoChunks.size()+1));
        mVideoChunks.add(chunk);
    }

  @Override
  protected Void doInBackground(Void... params) {
        Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
        mDecoder.start();
    final int TIMEOUT_USEC = 10000;
    MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
    boolean isCancelled = isCancelled();
    int inputBufIndex = -1;
    while (!isCancelled) {
      inputBufIndex = mDecoder.dequeueInputBuffer(TIMEOUT_USEC);
      if (inputBufIndex >= 0) {
        isCancelled = isCancelled();
        if(isCancelled()){
          Log.i(LOG_TAG, "got cancel signal");
          break;
        }
        VideoChunk chunk = null;
        try {
          //Log.d(LOG_TAG,"waiting for data to decode from "+ mVideoChunks.size()+" chunks");
                    Log.i(LOG_TAG,"decoder queue = "+ (mVideoChunks.size()+1));
                    chunk = pickFrame();
          //Log.d(LOG_TAG,"got data");
        } catch (InterruptedException e) {
          e.printStackTrace();
          continue;
        }
        // Copy a chunk of input to the decoder.  The first chunk should have
        // the BUFFER_FLAG_CODEC_CONFIG flag set.
        ByteBuffer inputBuf = mDecoder.getInputBuffer(inputBufIndex);
        inputBuf.clear();
        inputBuf.put(chunk.getData());
        int flags = chunk.getFlags();
        long time = chunk.getTimeUs();
        mDecoder.queueInputBuffer(inputBufIndex, 0, inputBuf.position(), time, flags);
        //Log.d(LOG_TAG, "submitted frame to dec, size=" + inputBuf.position() + " flags=" + flags);
      }
      boolean decoderDone =  false;
      while(!decoderDone){
        int decoderStatus = mDecoder.dequeueOutputBuffer(info, TIMEOUT_USEC);
        if (decoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
          // no output available yet
          decoderDone = true;
        }else if (decoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
          //decoderOutputBuffers = decoder.getOutputBuffers();
          Log.d(LOG_TAG, "decoder output buffers changed (we don't care)");
        } else if (decoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
          // expected before first buffer of data
          MediaFormat newFormat = mDecoder.getOutputFormat();
          int width = newFormat.getInteger(MediaFormat.KEY_WIDTH);
          int height = newFormat.getInteger(MediaFormat.KEY_HEIGHT);
          publishProgress(Pair.create(width,height));
          Log.d(LOG_TAG, "decoder output format changed: " + newFormat);
        } else if (decoderStatus < 0) {
          throw new IllegalStateException("unexpected result from decoder.dequeueOutputBuffer: "+decoderStatus);
        } else { // decoderStatus >= 0
          //Log.d(LOG_TAG, "surface decoder given buffer " + decoderStatus + " (size=" + info.size + ")");
          // The ByteBuffers are null references, but we still get a nonzero
          // size for the decoded data.
          boolean doRender = (info.size != 0);
          mDecoder.releaseOutputBuffer(decoderStatus, doRender);
        }

      }
    }
    if(inputBufIndex!=-1) {
      // End of stream -- send empty frame with EOS flag set.
      mDecoder.queueInputBuffer(inputBufIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
      Log.d(LOG_TAG, "sent input EOS (with zero-length frame)");
    }


    mDecoder.stop();

    return null;
  }

    private VideoChunk pickFrame() throws InterruptedException {
        VideoChunk chunk = mVideoChunks.take();
        return chunk;
        //find newest keyframe. discard all frames before that that are no config frames
        //if no keyframe is present just take oldest frame
//        synchronized (mVideoChunks){
//            while(mVideoChunks.size()>0){
//                VideoChunk chunk = mVideoChunks.takeLast();
//                if(chunk.i)
//
//            }
//            for(int i=mVideoChunks.size()-1;i>=0;i--){
//                VideoChunk chunk = mVideoChunks.element()
//            }
//            for(VideoChunk chunk: mVideoChunks){
//                if(chunk.isKeyFrame())
//            }
//        }
//        try {
//            return mVideoChunks.takeFirst();
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//            return null;
//        }
    }

    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);
        if(mListener!=null){
            mListener.onVideoEnded(mReceivedChunks);
        }
    }

    @Override
  protected void onProgressUpdate(Pair<Integer, Integer>... values) {
    super.onProgressUpdate(values);
    if(mListener!=null){
      mListener.onVideoSizeChanged(values[0].first, values[0].second);
    }
  }
}




Java Source Code List

com.screenshare.renard314.decoder.ApplicationTest.java
com.screenshare.renard314.decoder.MainActivity.java
com.screenshare.renard314.decoder.MyApplication.java
com.screenshare.renard314.decoder.ReceiverAsyncTask.java
com.screenshare.renard314.screenshare.ApplicationTest.java
com.screenshare.renard314.screenshare.EncoderAsyncTask.java
com.screenshare.renard314.screenshare.MainActivity.java
com.screenshare.renard314.screenshare.SenderAsyncTask.java
com.screenshare.renard314.screensharelib.ApplicationTest.java
com.screenshare.renard314.screensharelib.DecoderAsyncTask.java
com.screenshare.renard314.screensharelib.MediaCodecFactory.java
com.screenshare.renard314.screensharelib.OnVideoSizeChangedListener.java
com.screenshare.renard314.screensharelib.VideoChunk.java