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