0

I am trying to develop a TV player with a bitrates option (Managing Video Quality like in YouTube). My player plays all videos except the live stream (TV Channel from the link).

Solutions I tried:

Answer1: Error playing HLS stream with Google Exoplayer on Android

Answer2: Exoplayer v2, live video stream

I tried some other answers on StackOverflow and read some blog but didn't help.

Below is my code if anyone can help me to solve the issue. Following activity also contains code for managing stream speed

   import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.DialogInterface;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.ui.PlayerControlView;
import com.google.android.exoplayer2.ui.PlayerView;

public class MainActivity extends AppCompatActivity {

    private boolean isShowingTrackSelectionDialog;
    private DefaultTrackSelector trackSelector;
//Below line is for video speed option
    String[] speed = {"0.25x","0.5x","Normal","1.5x","2x"};
 
    //Below ARE WORKING URLS becuase video is present on server and is not live
    //String url1 = "https://5b44cf20b0388.streamlock.net:8443/vod/smil:bbb.smil/playlist.m3u8";
   // String url1 = "https://5b44cf20b0388.streamlock.net:8443/vod/smil:ed.smil/playlist.m3u8";
    //String url1 = "https://5b44cf20b0388.streamlock.net:8443/vod/smil:sintel-hd.smil/playlist.m3u8";
   
//Below are urls don't work because these are for tv channels
     // String url1 = "https://stream.commec.tv/iframe/b/169562/c/5707742";
       String url1 = "http://app.pakistanVision.tv:1935/live/PTVnews/player.m3u8";
      //String url1 = "http://cdn.ebound.tv/tv/expressentertainment/chunks.m3u8";
      //String url1 = "https://s3-us-west-2.amazonaws.com/hls-playground/hls.m3u8";
     // String url1 = "http://192.168.0.102:8001/1:0:19:4E89:14:70:1680000:0:0:0:";
       // String url1 = "http://cspan1-lh.akamaihd.net/i/cspan1_1@304727/index_1000_av-p.m3u8";

    PlayerView playerView;
    SimpleExoPlayer simpleExoPlayer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        trackSelector = new DefaultTrackSelector(this);


  simpleExoPlayer = new SimpleExoPlayer.Builder(this).setTrackSelector(trackSelector).build();

        playerView = findViewById(R.id.exoPlayerView);
        playerView.setPlayer(simpleExoPlayer);
       

 /*When used the below code it doesn't work for anything           
            simpleExoPlayer =
                    new SimpleExoPlayer.Builder(this)
                            .setMediaSourceFactory(
                                    new DefaultMediaSourceFactory(this).setLiveTargetOffsetMs(5000))
                           .build();
    
            MediaItem mediaItem =
                    new MediaItem.Builder()
                            .setUri(url1)
                            .setLiveMaxPlaybackSpeed(1.02f)
                            .build();
            simpleExoPlayer.setMediaItem(mediaItem); up-to here*/




 simpleExoPlayer.addMediaItem(mediaItem);
            simpleExoPlayer.prepare();
            simpleExoPlayer.play();


        ImageView farwordBtn = playerView.findViewById(R.id.fwd);
        ImageView rewBtn = playerView.findViewById(R.id.rew);
        ImageView setting = playerView.findViewById(R.id.exo_track_selection_view);
        ImageView speedBtn = playerView.findViewById(R.id.exo_playback_speed);
        TextView speedTxt = playerView.findViewById(R.id.speed);



        speedBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {


                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                builder.setTitle("Set Speed");
                builder.setItems(speed, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // the user clicked on colors[which]

                        if (which==0){

                            speedTxt.setVisibility(View.VISIBLE);
                            speedTxt.setText("0.25X");
                            PlaybackParameters param = new PlaybackParameters(0.5f);
                            simpleExoPlayer.setPlaybackParameters(param);


                        }  if (which==1){

                            speedTxt.setVisibility(View.VISIBLE);
                            speedTxt.setText("0.5X");
                            PlaybackParameters param = new PlaybackParameters(0.5f);
                            simpleExoPlayer.setPlaybackParameters(param);


                        }
                        if (which==2){

                            speedTxt.setVisibility(View.GONE);
                            PlaybackParameters param = new PlaybackParameters(1f);
                            simpleExoPlayer.setPlaybackParameters(param);


                        }
                        if (which==3){
                            speedTxt.setVisibility(View.VISIBLE);
                            speedTxt.setText("1.5X");
                            PlaybackParameters param = new PlaybackParameters(1.5f);
                            simpleExoPlayer.setPlaybackParameters(param);

                        }
                        if (which==4){


                            speedTxt.setVisibility(View.VISIBLE);
                            speedTxt.setText("2X");

                            PlaybackParameters param = new PlaybackParameters(2f);
                            simpleExoPlayer.setPlaybackParameters(param);



                        }



                    }
                });
                builder.show();





            }
        });


        farwordBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                simpleExoPlayer.seekTo(simpleExoPlayer.getCurrentPosition() + 10000);

            }
        });
        rewBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                long num = simpleExoPlayer.getCurrentPosition() - 10000;
                if (num < 0) {

                    simpleExoPlayer.seekTo(0);


                } else {

                    simpleExoPlayer.seekTo(simpleExoPlayer.getCurrentPosition() - 10000);

                }


            }
        });

        ImageView fullscreenButton = playerView.findViewById(R.id.fullscreen);
        fullscreenButton.setOnClickListener(new View.OnClickListener() {
            @SuppressLint("SourceLockedOrientationActivity")
            @Override
            public void onClick(View view) {


                int orientation = MainActivity.this.getResources().getConfiguration().orientation;
                if (orientation == Configuration.ORIENTATION_PORTRAIT) {
                    // code for portrait mode

                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);


                } else {
                    // code for landscape mode

                    Toast.makeText(MainActivity.this, "Land", Toast.LENGTH_SHORT).show();
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

                }


            }
        });


        findViewById(R.id.exo_play).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                simpleExoPlayer.play();

            }
        });
        findViewById(R.id.exo_pause).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                simpleExoPlayer.pause();

            }
        });


        simpleExoPlayer.addListener(new Player.Listener() {
            @Override
            public void onPlaybackStateChanged(int state) {
                if (state == ExoPlayer.STATE_ENDED) {

                }

            }
        });


        playerView.setControllerVisibilityListener(new PlayerControlView.VisibilityListener() {
            @Override
            public void onVisibilityChange(int visibility) {

            }
        });


        setting.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!isShowingTrackSelectionDialog
                        && TrackSelectionDialog.willHaveContent(trackSelector)) {
                    isShowingTrackSelectionDialog = true;
                    TrackSelectionDialog trackSelectionDialog =
                            TrackSelectionDialog.createForTrackSelector(
                                    trackSelector,
                                    /* onDismissListener= */ dismissedDialog -> isShowingTrackSelectionDialog = false);
                    trackSelectionDialog.show(getSupportFragmentManager(), /* tag= */ null);


                }


            }
        });

    }

}

XML For Above JAVA CODE:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <FrameLayout
        android:id="@+id/fram"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.google.android.exoplayer2.ui.PlayerView
            android:id="@+id/exoPlayerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/black"
            app:controller_layout_id="@layout/ustom_controls"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:resize_mode="fixed_width"
            app:show_buffering="when_playing">

        </com.google.android.exoplayer2.ui.PlayerView>
    </FrameLayout>

My Build.Gradle:

plugins {
    id 'com.android.application'
}

android {
    compileSdkVersion 30

    defaultConfig {
        applicationId "com.stremobuilders321.stremoplayer"
        minSdkVersion 21
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"
        multiDexEnabled true

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.3.1'
    implementation 'com.google.android.material:material:1.4.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
    implementation'com.google.android.exoplayer:exoplayer:2.14.1'
    implementation 'com.android.support:multidex:1.0.3'
}

Beside all the above I am using Custom Control xml Layout (For media player buttons), and a class to control bitrates, if needed I'll provide both of these too.

The Error my Application gives: E/ExoPlayerImplInternal: Playback error com.google.android.exoplayer2.ExoPlaybackException: Source error

Caused by: com.google.android.exoplayer2.upstream.HttpDataSource$HttpDataSourceException: Unable to connect

It works fine for stored videos on servers, but doesn't work for live stream tv channels gives above error.

Kamran Khan
  • 48
  • 1
  • 7

2 Answers2

0

You can try to download this sample at https://drive.google.com/file/d/0Byr1H33Pe7u-MW93UUpmMUhGTTQ/view and modify Uri

video_url = "http://cspan1-lh.akamaihd.net/i/cspan1_1@304727/index_1000_av-p.m3u8";

Note: some m3u8 files wont play because of incorrect format Check for supported formats here https://google.github.io/ExoPlayer/supported-formats.html

Aditya Rizqi
  • 63
  • 1
  • 7
  • This code is too old, and work fine for video store on server but for TV channel links it shows black screen nothing else. I tried your provided link still the same no effect... – Kamran Khan Aug 08 '21 at 09:07
0

try setting mime type

        MediaItem mediaItem = new MediaItem.Builder()
                .setUri(uri)
                .setMimeType(MimeTypes.APPLICATION_M3U8)
                .build();