如何修复ExoPlayer video Freeze 2.9.6

时间:2019-05-06 05:52:18

标签: java android android-videoview exoplayer exoplayer2.x

我使用此代码播放全屏视频,但是在播放视频时出现问题,并且从主要活动移至全屏活动时,视频冻结了2-3秒,仅出现此问题仅适用于2.8.3之后的版本,但适用于2.8.0的版本视频很流畅

完整代码:https://github.com/MATPOCKIH/ExoPlayerFullscreen

PlayerViewManager

public class PlayerViewManager {

private static final String TAG = "ExoPlayerViewManager";

public static final String EXTRA_VIDEO_URI = "video_uri";

private static Map<String, PlayerViewManager> instances = new HashMap<>();
private Uri videoUri;

public boolean isPlayerPlaying;
private boolean isMustPlaying;

private UniversalPlayerView universalPlayer;


public static PlayerViewManager getInstance(String videoUri) {
    PlayerViewManager instance = instances.get(videoUri);
    if (instance == null) {
        instance = new PlayerViewManager(videoUri);
        instances.put(videoUri, instance);
    }
    return instance;
}

private PlayerViewManager(String videoUri) {
    this.videoUri = Uri.parse(videoUri);
}

public void preparePlayer(PlayerHolderView playerHolderView) {
    if (playerHolderView == null) {
        return;
    }

    if (universalPlayer == null) {
        universalPlayer = createPlayer(playerHolderView.getContext());
        isPlayerPlaying = true;
        isMustPlaying = true;
    }

    universalPlayer.initialize(videoUri, playerHolderView);
}

public void releaseVideoPlayer() {
    if (universalPlayer != null) {
        universalPlayer.release();
    }
    universalPlayer = null;
}

public void goToBackground() {
    if (universalPlayer != null /*&& !isMustPlaying*/) {
        //isPlayerPlaying = player.getPlayWhenReady();
        universalPlayer.pause();
    }
}

public void goToForeground() {
    if (universalPlayer != null && isMustPlaying) {
        universalPlayer.play();
    }
}

public void pausePlayer(){
    if (universalPlayer != null) {
        universalPlayer.pause();
        isPlayerPlaying = false;
        isMustPlaying = false;
    }
}

public void playPlayer(){
    if (universalPlayer != null) {
        universalPlayer.play();
        isPlayerPlaying = true;
        isMustPlaying = true;
    }
}

private UniversalPlayerView createPlayer(Context context){
    if (videoUri.getScheme().startsWith("http")){
        return new FaceterExoPlayerView(context);
    }
    return new FaceterExoPlayerView(context);
}
}

FaceterExoPlayerView

public class FaceterExoPlayerView extends UniversalPlayerView {

private Uri videoUri;
private DefaultDataSourceFactory dataSourceFactory;
private SimpleExoPlayer player;
private PlayerView exoPlayerView;
private Context context;

public FaceterExoPlayerView(Context context) {
    this.context = context;
}

@Override
public void initialize(Uri videoUri, PlayerHolderView playerHolderView) {

    if (playerHolderView == null || videoUri == null)
        return;

    exoPlayerView = playerHolderView.findViewById(R.id.exo_player);


    if (player == null) {
        player = ExoPlayerFactory.newSimpleInstance(context, new DefaultTrackSelector());

        dataSourceFactory = new DefaultDataSourceFactory(context,
                Util.getUserAgent(context, "faceter"));

        MediaSource videoSource = buildMediaSource(videoUri, null);
        player.prepare(videoSource);
    }

    player.clearVideoSurface();
    player.setVideoTextureView((TextureView) exoPlayerView.getVideoSurfaceView());
    exoPlayerView.setPlayer(player);
    exoPlayerView.hideController();
    setResizeModeFill(playerHolderView.isResizeModeFill());
}

@Override
public void play() {
    player.setPlayWhenReady(true);
}

@Override
public void pause() {
    player.setPlayWhenReady(false);
}

@SuppressWarnings("unchecked")
private MediaSource buildMediaSource(Uri uri, @Nullable String overrideExtension) {
    int type = Util.inferContentType(uri, overrideExtension);
    switch (type) {
        /*case C.TYPE_DASH:
            return new DashMediaSource.Factory(
                    new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
                    buildDataSourceFactory(false))
                    .setManifestParser(
                            new FilteringManifestParser<>(
                                    new DashManifestParser(), (List<RepresentationKey>) getOfflineStreamKeys(uri)))
                    .createMediaSource(uri);
        case C.TYPE_SS:
            return new SsMediaSource.Factory(
                    new DefaultSsChunkSource.Factory(mediaDataSourceFactory),
                    buildDataSourceFactory(false))
                    .setManifestParser(
                            new FilteringManifestParser<>(
                                    new SsManifestParser(), (List<StreamKey>) getOfflineStreamKeys(uri)))
                    .createMediaSource(uri);*/
        case C.TYPE_HLS:
            return new HlsMediaSource.Factory(dataSourceFactory)
                    /*.setPlaylistParser(
                            new FilteringManifestParser<>(
                                    new HlsPlaylistParser(), (List<RenditionKey>) getOfflineStreamKeys(uri)))*/
                    .createMediaSource(uri);
        case C.TYPE_OTHER:
            return new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
        default: {
            throw new IllegalStateException("Unsupported type: " + type);
        }
    }
}

@Override
public void release() {
    if (player != null) {
        player.release();
    }
    player = null;
}

@Override
public void setResizeModeFill(boolean isResizeModeFill) {
    if (isResizeModeFill) {
        exoPlayerView.setResizeMode(RESIZE_MODE_FILL);
    } else {
        exoPlayerView.setResizeMode(RESIZE_MODE_FIT);
    }
}
}

PlayerHolderView.java

public class PlayerHolderView extends FrameLayout {

private String videoUrl;

private boolean isResizeModeFill = true;

private OnUserInteractionListener onUserInteractionListener;

public PlayerHolderView(@NonNull Context context) {
    super(context);
    init();
}

public PlayerHolderView(@NonNull Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    init();
}

public PlayerHolderView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
}

private void init() {
    LayoutInflater.from(getContext()).inflate(R.layout.layout_player, this, true);

    View controlView = this.findViewById(R.id.exo_controller);

    controlView.findViewById(R.id.exo_play)
            .setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    PlayerViewManager.getInstance(videoUrl).playPlayer();
                }
            });

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

    controlView.findViewById(R.id.exo_fullscreen_button)
            .setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(getContext(), FullscreenVideoActivity.class);
                    intent.putExtra(PlayerViewManager.EXTRA_VIDEO_URI, videoUrl);
                    getContext().startActivity(intent);
                }
            });

MainActivity

public class MainActivity extends AppCompatActivity {

    private List<PlayerHolderView> playerHolders = new ArrayList<>();
    private List<TextView> links = new ArrayList<>();

    private List<String> mVideoUrls = new ArrayList<>(
            Arrays.asList(
                    //"http://10.110.3.30/api/Playlists/6a3ecad7-e744-446f-9341-0e0ba834de63?from=2018-09-20&to=2018-09-21"
                    "https://commondatastorage.googleapis.com/gtv-videos-bucket/CastVideos/hls/TearsOfSteel.m3u8",
                    "http://redirector.c.youtube.com/videoplayback?id=604ed5ce52eda7ee&itag=22&source=youtube&sparams=ip,ipbits,expire,source,id&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=513F28C7FDCBEC60A66C86C9A393556C99DC47FB.04C88036EEE12565A1ED864A875A58F15D8B5300&key=ik0",
                    "https://html5demos.com/assets/dizzy.mp4"
                    //"https://cdn.faceter.io/hls/ab196789-8876-4854-82f3-087e5682d013",
                      //"https://cdn.faceter.io/hls/65d1c673-6a63-44c8-836b-132449c9462a"
            )
    );

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

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        playerHolders.add((PlayerHolderView) findViewById(R.id.holder1));
        playerHolders.add((PlayerHolderView) findViewById(R.id.holder2));
        playerHolders.add((PlayerHolderView) findViewById(R.id.holder3));

        links.add((TextView) findViewById(R.id.title1));
        links.add((TextView) findViewById(R.id.title2));
        links.add((TextView) findViewById(R.id.title3));
    }


    @Override
    public void onResume() {
        super.onResume();
        int i = 0;
        for (final String videoUrl : mVideoUrls) {
            playerHolders.get(i).setupPlayerView(videoUrl);
            playerHolders.get(i).setOnUserInteractionListener(this);

            links.get(i).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    onVideoTitleClicked(videoUrl);
                }
            });

            i++;
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        for (String videoUrl : mVideoUrls) {
            PlayerViewManager.getInstance(videoUrl).goToBackground();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        for (String videoUrl : mVideoUrls) {
            PlayerViewManager.getInstance(videoUrl).releaseVideoPlayer();
        }
    }

    public void onVideoTitleClicked(String videoUrl) {
        Intent intent = new Intent(getBaseContext(), DetailActivity.class);
        intent.putExtra(PlayerViewManager.EXTRA_VIDEO_URI, videoUrl);
        startActivity(intent);
    }
}

FullscreenVideoActivity

public class FullscreenVideoActivity extends AppCompatActivity {

    /**
     * Some older devices needs a small delay between UI widget updates
     * and a change of the status and navigation bar.
     */
    private static final int UI_ANIMATION_DELAY = 300;
    private final Handler mHideHandler = new Handler();
    private View mContentView;
    private final Runnable mHidePart2Runnable = new Runnable() {
        @SuppressLint("InlinedApi")
        @Override
        public void run() {
            // Delayed removal of status and navigation bar

            // Note that some of these constants are new as of
            // API 19 (KitKat). It is safe to use them, as they are inlined
            // at compile-time and do nothing on earlier devices.
            mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
                    | View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
        }
    };
    private final Runnable mHideRunnable = new Runnable() {
        @Override
        public void run() {
            hide();
        }
    };

    private String mVideoUri;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_fullscreen_video);

        mContentView = findViewById(R.id.enclosing_layout);

        PlayerHolderView playerHolderView = findViewById(R.id.player_holder);
        playerHolderView.setResizeModeFill(false);

        mVideoUri = getIntent().getStringExtra(PlayerViewManager.EXTRA_VIDEO_URI);

        PlayerViewManager.getInstance(mVideoUri).preparePlayer(playerHolderView);
/*
        // Set the fullscreen button to "close fullscreen" icon
        View controlView = playerView.findViewById(R.id.exo_controller);
        ImageView fullscreenIcon = controlView.findViewById(R.id.exo_fullscreen_icon);
        fullscreenIcon.setImageResource(R.drawable.exo_controls_fullscreen_exit);
        controlView.findViewById(R.id.exo_fullscreen_button)
                .setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        finish();
                    }
                });
        controlView.findViewById(R.id.exo_play)
                .setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        PlayerViewManager.getInstance(mVideoUri).playPlayer();
                    }
                });
        controlView.findViewById(R.id.exo_pause)
                .setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        PlayerViewManager.getInstance(mVideoUri).pausePlayer();
                    }
                });*/
    }

    @Override
    public void onResume() {
        super.onResume();
        PlayerViewManager.getInstance(mVideoUri).goToForeground();
    }

    @Override
    public void onPause() {
        super.onPause();
        PlayerViewManager.getInstance(mVideoUri).goToBackground();
    }

    @Override
    public void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);

        // Trigger the initial hide() shortly after the activity has been
        // created, to briefly hint to the user that UI controls
        // are available.
        delayedHide();
    }

    private void hide() {
        // Schedule a runnable to remove the status and navigation bar after a delay
        mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY);
    }

    /**
     * Schedules a call to hide() in delay milliseconds, canceling any
     * previously scheduled calls.
     */
    private void delayedHide() {
        mHideHandler.removeCallbacks(mHideRunnable);
        mHideHandler.postDelayed(mHideRunnable, 100);
    }
}

1 个答案:

答案 0 :(得分:2)

只需尝试以下代码即可解决视频冻结问题:

@Override
public void play() {
    player.setPlayWhenReady(true);
    player.getPlaybackState();
}

@Override
public void pause() {
    player.setPlayWhenReady(false);
    player.getPlaybackState();
}

player.getPlaybackState();可以帮助您恢复到原来的状态。