title: Playing HLS with ExoPlayer
body: <p>I'm trying to create a very simple view by extending SurfaceView and rendering the ExoPlayer video to the its surface.  I want to support HLS and ONLY HLS.  I seem to get audio consistently but I never see video rendered to the screen.  I'm curious as to what I could be doing wrong.</p>
  
  <p>The only error that I am seeing in my Logcat is the following:</p>
  
  <pre><code>E/OMXMaster﹕ A component of name 'OMX.qcom.audio.decoder.aac' already exists, ignoring this one.
  </code></pre>
  
  <p>Below is my code.</p>
  
  <pre><code>private static final int BUFFER_SEGMENT_SIZE = 256 * 1024;
  private static final int BUFFER_SEGMENTS = 64;
  
  private ExoPlayer mExoPlayer;
  private Handler mHandler;
  private AudioCapabilitiesReceiver mAudioCapabilitiesReceiver;
  private AudioCapabilities mAudioCapabilities;
  private ManifestFetcher&lt;HlsPlaylist&gt; playlistFetcher;
  private String mUserAgent;
  String url = "http://solutions.brightcove.com/bcls/assets/videos/Great-Blue-Heron.m3u8";
  
  public ExoPlayerView(Context context) {
      super(context);
  }
  
  public ExoPlayerView(Context context, AttributeSet attrs) {
      super(context, attrs);
  }
  
  public ExoPlayerView(Context context, AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
  }
  
  @Override
  public void init() {
      mHandler = new Handler();
      mUserAgent = Util.getUserAgent(getContext(), "CX Video Player");
      HlsPlaylistParser parser = new HlsPlaylistParser();
      playlistFetcher = new ManifestFetcher&lt;&gt;(url, new DefaultUriDataSource(getContext(), mUserAgent),
              parser);
      mAudioCapabilitiesReceiver = new AudioCapabilitiesReceiver(getContext(), this);
      mAudioCapabilitiesReceiver.register();
  }
  
  @Override
  public void play() {
      mExoPlayer.setPlayWhenReady(true);
  }
  
  @Override
  public void stop() {
      mExoPlayer.stop();
      release();
  }
  
  @Override
  public void pause() {
      mExoPlayer.setPlayWhenReady(false);
  }
  
  @Override
  public void seekTo(long timeMillis) {
      mExoPlayer.seekTo(timeMillis);
  }
  
  @Override
  public long getCurrentPosition() {
      return mExoPlayer.getCurrentPosition();
  }
  
  @Override
  public boolean isPlaying() {
      return false;
  }
  
  @Override
  public void playNext() {
  
  }
  
  @Override
  public boolean isPlayingLastVideo() {
      return false;
  }
  
  @Override
  public int getDuration() {
      return (int)mExoPlayer.getDuration();
  }
  
  @Override
  public void addVideo(Uri uri) {
  
  }
  
  @Override
  public void addVideos(List&lt;Uri&gt; uris) {
  
  }
  
  @Override
  public void release() {
      mAudioCapabilitiesReceiver.unregister();
      mExoPlayer.release();
  }
  
  @Override
  public void onSingleManifest(HlsPlaylist hlsPlaylist) {
      final int numRenderers = 2;
  
      LoadControl loadControl = new DefaultLoadControl(new DefaultAllocator(BUFFER_SEGMENT_SIZE));
      DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
  
      int[] variantIndices = null;
      if (hlsPlaylist instanceof HlsMasterPlaylist) {
          HlsMasterPlaylist masterPlaylist = (HlsMasterPlaylist) hlsPlaylist;
          try {
              variantIndices = VideoFormatSelectorUtil.selectVideoFormatsForDefaultDisplay(
                      getContext(), masterPlaylist.variants, null, false);
          } catch (MediaCodecUtil.DecoderQueryException e) {
              e.printStackTrace();
              return;
          }
          if (variantIndices.length == 0) {
              return;
          }
      }
  
      DataSource dataSource = new DefaultUriDataSource(getContext(), bandwidthMeter, mUserAgent);
      HlsChunkSource hlsChunkSource = new HlsChunkSource(dataSource, url, hlsPlaylist, bandwidthMeter,
              variantIndices, HlsChunkSource.ADAPTIVE_MODE_SPLICE, mAudioCapabilities);
      HlsSampleSource hlsSampleSource = new HlsSampleSource(hlsChunkSource, loadControl, BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE);
  
      // Build the track renderers
      TrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(hlsSampleSource, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
      TrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(hlsSampleSource);
  
      // Build the ExoPlayer and start playback
      mExoPlayer = ExoPlayer.Factory.newInstance(numRenderers);
      mExoPlayer.prepare(videoRenderer, audioRenderer);
  
      // Pass the surface to the video renderer.
      mExoPlayer.sendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, getHolder().getSurface());
  
      mExoPlayer.setPlayWhenReady(true);
  }
  
  @Override
  public void onSingleManifestError(IOException e) {
  
  }
  
  @Override
  public void onAudioCapabilitiesChanged(AudioCapabilities audioCapabilities) {
      mAudioCapabilities = audioCapabilities;
      playlistFetcher.singleLoad(mHandler.getLooper(), this);
  }
  }
  </code></pre>