Home | History | Annotate | Download | only in exoplayer
      1 package com.android.tv.tuner.exoplayer;
      2 
      3 import android.content.Context;
      4 import android.media.MediaCodec;
      5 import android.os.Handler;
      6 import android.util.Log;
      7 
      8 import com.google.android.exoplayer.DecoderInfo;
      9 import com.google.android.exoplayer.ExoPlaybackException;
     10 import com.google.android.exoplayer.MediaCodecSelector;
     11 import com.google.android.exoplayer.MediaCodecUtil;
     12 import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
     13 import com.google.android.exoplayer.MediaFormatHolder;
     14 import com.google.android.exoplayer.MediaSoftwareCodecUtil;
     15 import com.google.android.exoplayer.SampleSource;
     16 import com.android.tv.common.feature.CommonFeatures;
     17 
     18 import java.lang.reflect.Field;
     19 
     20 /**
     21  * MPEG-2 TS video track renderer
     22  */
     23 public class MpegTsVideoTrackRenderer extends MediaCodecVideoTrackRenderer {
     24     private static final String TAG = "MpegTsVideoTrackRender";
     25 
     26     private static final int VIDEO_PLAYBACK_DEADLINE_IN_MS = 5000;
     27     // If DROPPED_FRAMES_NOTIFICATION_THRESHOLD frames are consecutively dropped, it'll be notified.
     28     private static final int DROPPED_FRAMES_NOTIFICATION_THRESHOLD = 10;
     29     private static final int MIN_HD_HEIGHT = 720;
     30     private static final String MIMETYPE_MPEG2 = "video/mpeg2";
     31     private static Field sRenderedFirstFrameField;
     32 
     33     private final boolean mIsSwCodecEnabled;
     34     private boolean mCodecIsSwPreferred;
     35     private boolean mSetRenderedFirstFrame;
     36 
     37     static {
     38         // Remove the reflection below once b/31223646 is resolved.
     39         try {
     40             sRenderedFirstFrameField = MediaCodecVideoTrackRenderer.class.getDeclaredField(
     41                     "renderedFirstFrame");
     42             sRenderedFirstFrameField.setAccessible(true);
     43         } catch (NoSuchFieldException e) {
     44             // Null-checking for {@code sRenderedFirstFrameField} will do the error handling.
     45         }
     46     }
     47 
     48     public MpegTsVideoTrackRenderer(Context context, SampleSource source, Handler handler,
     49             MediaCodecVideoTrackRenderer.EventListener listener) {
     50         super(context, source, MediaCodecSelector.DEFAULT,
     51                 MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT, VIDEO_PLAYBACK_DEADLINE_IN_MS, handler,
     52                 listener, DROPPED_FRAMES_NOTIFICATION_THRESHOLD);
     53         mIsSwCodecEnabled = CommonFeatures.USE_SW_CODEC_FOR_SD.isEnabled(context);
     54     }
     55 
     56     @Override
     57     protected DecoderInfo getDecoderInfo(MediaCodecSelector codecSelector, String mimeType,
     58             boolean requiresSecureDecoder) throws MediaCodecUtil.DecoderQueryException {
     59         try {
     60             if (mIsSwCodecEnabled && mCodecIsSwPreferred) {
     61                 DecoderInfo swCodec = MediaSoftwareCodecUtil.getSoftwareDecoderInfo(
     62                         mimeType, requiresSecureDecoder);
     63                 if (swCodec != null) {
     64                     return swCodec;
     65                 }
     66             }
     67         } catch (MediaSoftwareCodecUtil.DecoderQueryException e) {
     68         }
     69         return super.getDecoderInfo(codecSelector, mimeType,requiresSecureDecoder);
     70     }
     71 
     72     @Override
     73     protected void onInputFormatChanged(MediaFormatHolder holder) throws ExoPlaybackException {
     74         mCodecIsSwPreferred = MIMETYPE_MPEG2.equalsIgnoreCase(holder.format.mimeType)
     75                 && holder.format.height < MIN_HD_HEIGHT;
     76         super.onInputFormatChanged(holder);
     77     }
     78 
     79     @Override
     80     protected void onDiscontinuity(long positionUs) throws ExoPlaybackException {
     81         super.onDiscontinuity(positionUs);
     82         // Disabling pre-rendering of the first frame in order to avoid a frozen picture when
     83         // starting the playback. We do this only once, when the renderer is enabled at first, since
     84         // we need to pre-render the frame in advance when we do trickplay backed by seeking.
     85         if (!mSetRenderedFirstFrame) {
     86             setRenderedFirstFrame(true);
     87             mSetRenderedFirstFrame = true;
     88         }
     89     }
     90 
     91     private void setRenderedFirstFrame(boolean renderedFirstFrame) {
     92         if (sRenderedFirstFrameField != null) {
     93             try {
     94                 sRenderedFirstFrameField.setBoolean(this, renderedFirstFrame);
     95             } catch (IllegalAccessException e) {
     96                 Log.w(TAG, "renderedFirstFrame is not accessible. Playback may start with a frozen"
     97                         +" picture.");
     98             }
     99         }
    100     }
    101 }
    102