1aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata/*
2aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata * Copyright (C) 2016 The Android Open Source Project
3aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata *
4aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata * in compliance with the License. You may obtain a copy of the License at
6aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata *
7aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata * http://www.apache.org/licenses/LICENSE-2.0
8aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata *
9aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata * Unless required by applicable law or agreed to in writing, software distributed under the License
10aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata * or implied. See the License for the specific language governing permissions and limitations under
12aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata * the License.
13aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata */
14aa49439ba6276137f94fcdc1bf4f69b78833dad6susnatapackage com.example.android.leanback;
15aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata
16aa49439ba6276137f94fcdc1bf4f69b78833dad6susnataimport android.net.Uri;
17aa49439ba6276137f94fcdc1bf4f69b78833dad6susnataimport android.os.Bundle;
18aa49439ba6276137f94fcdc1bf4f69b78833dad6susnataimport android.support.v17.leanback.app.VideoFragmentGlueHost;
193bcad88cbf4488e747d84893c35f2351b8f84afeDake Guimport android.support.v17.leanback.media.MediaPlayerAdapter;
2095ac470f2bbea06114a64906d95c0da7d9412db0Dake Guimport android.support.v17.leanback.media.PlaybackGlue;
213bcad88cbf4488e747d84893c35f2351b8f84afeDake Guimport android.support.v17.leanback.media.PlaybackTransportControlGlue;
223bcad88cbf4488e747d84893c35f2351b8f84afeDake Guimport android.support.v17.leanback.widget.PlaybackControlsRow;
2316248e64d407edcead2b8ae54d526e409e02a992jingjiangliimport android.support.v4.media.session.MediaSessionCompat;
24aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata
25aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata/**
26aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata * Fragment demonstrating the use of {@link android.support.v17.leanback.app.VideoFragment} to
27ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu * render video with playback controls. And demonstrates video seeking with thumbnails.
28ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu *
29ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu * Generate 1 frame per second thumbnail bitmaps and put on sdcard:
30ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu * <pre>
31ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu * sudo apt-get install libav-tools
32ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu * avconv -i input.mp4 -s 240x135 -vsync 1 -r 1 -an -y -qscale 8 frame_%04d.jpg
33ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu * adb shell mkdir /sdcard/seek
34ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu * adb push frame_*.jpg /sdcard/seek/
35ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu * </pre>
36ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu * Change to 1 frame per minute: use "-r 1/60".
37ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu * For more options, see https://wiki.libav.org/Snippets/avconv
38ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu *
393bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu * <p>
403bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu * Showcase:
413bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu * </p>
423bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu * <li>Auto play when ready</li>
433bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu * <li>Set seek provider</li>
443bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu * <li>switch MediaSource</li>
453bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu * <li>switch PlaybackGlue</li>
46aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata */
47aa49439ba6276137f94fcdc1bf4f69b78833dad6susnatapublic class SampleVideoFragment extends android.support.v17.leanback.app.VideoFragment {
4816248e64d407edcead2b8ae54d526e409e02a992jingjiangli
4916248e64d407edcead2b8ae54d526e409e02a992jingjiangli    // Media Session Token
5016248e64d407edcead2b8ae54d526e409e02a992jingjiangli    private static final String MEDIA_SESSION_COMPAT_TOKEN = "media session support video";
5116248e64d407edcead2b8ae54d526e409e02a992jingjiangli
523bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    private PlaybackTransportControlGlueSample<MediaPlayerAdapter> mMediaPlayerGlue;
53aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata
5416248e64d407edcead2b8ae54d526e409e02a992jingjiangli    private MediaSessionCompat mMediaSessionCompat;
5516248e64d407edcead2b8ae54d526e409e02a992jingjiangli
563bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    final VideoFragmentGlueHost mHost = new VideoFragmentGlueHost(SampleVideoFragment.this);
57aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata
583bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    static void playWhenReady(PlaybackGlue glue) {
593bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        if (glue.isPrepared()) {
603bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            glue.play();
613bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        } else {
623bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            glue.addPlayerCallback(new PlaybackGlue.PlayerCallback() {
633bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                @Override
643bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                public void onPreparedStateChanged(PlaybackGlue glue) {
653bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    if (glue.isPrepared()) {
663bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                        glue.removePlayerCallback(this);
673bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                        glue.play();
683bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    }
693bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                }
703bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            });
713bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        }
72aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata    }
73aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata
743bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    static void loadSeekData(final PlaybackTransportControlGlue glue) {
753bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        if (glue.isPrepared()) {
76ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu            glue.setSeekProvider(new PlaybackSeekDiskDataProvider(
773bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    glue.getDuration(),
78ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu                    1000,
79ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu                    "/sdcard/seek/frame_%04d.jpg"));
803bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        } else {
813bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            glue.addPlayerCallback(new PlaybackGlue.PlayerCallback() {
823bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                @Override
833bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                public void onPreparedStateChanged(PlaybackGlue glue) {
843bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    if (glue.isPrepared()) {
853bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                        glue.removePlayerCallback(this);
863bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                        PlaybackTransportControlGlue transportControlGlue =
873bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                                (PlaybackTransportControlGlue) glue;
88ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu                        transportControlGlue.setSeekProvider(new PlaybackSeekDiskDataProvider(
893bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                                transportControlGlue.getDuration(),
90ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu                                1000,
91ffddec570a27891c0e13d24b1558c6f61ed99fb9Dake Gu                                "/sdcard/seek/frame_%04d.jpg"));
923bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    }
933bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                }
943bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            });
953bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        }
963bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
97aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata
98aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata    @Override
993bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    public void onCreate(Bundle savedInstanceState) {
1003bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        super.onCreate(savedInstanceState);
1013bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        mMediaPlayerGlue = new PlaybackTransportControlGlueSample(getActivity(),
1023bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                new MediaPlayerAdapter(getActivity()));
10316248e64d407edcead2b8ae54d526e409e02a992jingjiangli
10416248e64d407edcead2b8ae54d526e409e02a992jingjiangli        // create a media session inside of a fragment, and app developer can determine if connect
10516248e64d407edcead2b8ae54d526e409e02a992jingjiangli        // this media session to glue or not
10616248e64d407edcead2b8ae54d526e409e02a992jingjiangli        // as requested in b/64935838
10716248e64d407edcead2b8ae54d526e409e02a992jingjiangli        mMediaSessionCompat = new MediaSessionCompat(getActivity(), MEDIA_SESSION_COMPAT_TOKEN);
10816248e64d407edcead2b8ae54d526e409e02a992jingjiangli        mMediaPlayerGlue.connectToMediaSession(mMediaSessionCompat);
10916248e64d407edcead2b8ae54d526e409e02a992jingjiangli
1103bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        mMediaPlayerGlue.setHost(mHost);
111946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu        mMediaPlayerGlue.setMode(PlaybackControlsRow.RepeatAction.INDEX_NONE);
1123bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        mMediaPlayerGlue.addPlayerCallback(new PlaybackGlue.PlayerCallback() {
1133bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            boolean mSecondCompleted = false;
114aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata            @Override
1153bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            public void onPlayCompleted(PlaybackGlue glue) {
1163bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                if (!mSecondCompleted) {
1173bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    mSecondCompleted = true;
1183bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    mMediaPlayerGlue.setSubtitle("Leanback artist Changed!");
1193bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    mMediaPlayerGlue.setTitle("Leanback team at work");
1203bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    String uriPath = "https://storage.googleapis.com/android-tv/Sample videos/"
1213bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                            + "April Fool's 2013/Explore Treasure Mode with Google Maps.mp4";
1223bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    mMediaPlayerGlue.getPlayerAdapter().setDataSource(Uri.parse(uriPath));
1233bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    loadSeekData(mMediaPlayerGlue);
1243bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    playWhenReady(mMediaPlayerGlue);
1253bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                } else {
1263bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    mMediaPlayerGlue.removePlayerCallback(this);
1273bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                    switchAnotherGlue();
1283bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                }
129aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata            }
1303bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        });
1313bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        mMediaPlayerGlue.setSubtitle("Leanback artist");
1323bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        mMediaPlayerGlue.setTitle("Leanback team at work");
1333bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        String uriPath = "https://storage.googleapis.com/android-tv/Sample videos/"
1343bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                + "April Fool's 2013/Explore Treasure Mode with Google Maps.mp4";
1353bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        mMediaPlayerGlue.getPlayerAdapter().setDataSource(Uri.parse(uriPath));
1363bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        loadSeekData(mMediaPlayerGlue);
1373bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        playWhenReady(mMediaPlayerGlue);
1383bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
139aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata
1403bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    @Override
1413bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    public void onPause() {
1423bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        if (mMediaPlayerGlue != null) {
1433bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu            mMediaPlayerGlue.pause();
1443bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        }
1453bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        super.onPause();
1463bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    }
147aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata
14816248e64d407edcead2b8ae54d526e409e02a992jingjiangli    @Override
14916248e64d407edcead2b8ae54d526e409e02a992jingjiangli    public void onDestroy() {
15016248e64d407edcead2b8ae54d526e409e02a992jingjiangli        super.onDestroy();
15116248e64d407edcead2b8ae54d526e409e02a992jingjiangli        mMediaPlayerGlue.disconnectToMediaSession();
15216248e64d407edcead2b8ae54d526e409e02a992jingjiangli    }
15316248e64d407edcead2b8ae54d526e409e02a992jingjiangli
1543bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu    void switchAnotherGlue() {
1553bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        mMediaPlayerGlue = new PlaybackTransportControlGlueSample(getActivity(),
1563bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                new MediaPlayerAdapter(getActivity()));
15716248e64d407edcead2b8ae54d526e409e02a992jingjiangli
15816248e64d407edcead2b8ae54d526e409e02a992jingjiangli        // If the glue is switched, re-register the media session
15916248e64d407edcead2b8ae54d526e409e02a992jingjiangli        mMediaPlayerGlue.connectToMediaSession(mMediaSessionCompat);
16016248e64d407edcead2b8ae54d526e409e02a992jingjiangli
161946a01cfedb6838e98d7a37e30f64c39b603893dDake Gu        mMediaPlayerGlue.setMode(PlaybackControlsRow.RepeatAction.INDEX_ONE);
1623bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        mMediaPlayerGlue.setSubtitle("A Googler");
1633bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        mMediaPlayerGlue.setTitle("Swimming with the fishes");
1643bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        mMediaPlayerGlue.getPlayerAdapter().setDataSource(
1653bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu                Uri.parse("http://techslides.com/demos/sample-videos/small.mp4"));
1663bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        mMediaPlayerGlue.setHost(mHost);
1673bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        loadSeekData(mMediaPlayerGlue);
1683bcad88cbf4488e747d84893c35f2351b8f84afeDake Gu        playWhenReady(mMediaPlayerGlue);
169aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata    }
170aa49439ba6276137f94fcdc1bf4f69b78833dad6susnata}
171