• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 package com.example.android.leanback;
15 
16 import android.net.Uri;
17 import android.os.Bundle;
18 import android.support.v4.media.session.MediaSessionCompat;
19 
20 import androidx.leanback.app.VideoFragmentGlueHost;
21 import androidx.leanback.media.MediaPlayerAdapter;
22 import androidx.leanback.media.PlaybackGlue;
23 import androidx.leanback.media.PlaybackTransportControlGlue;
24 import androidx.leanback.widget.PlaybackControlsRow;
25 
26 /**
27  * Fragment demonstrating the use of {@link androidx.leanback.app.VideoFragment} to
28  * render video with playback controls. And demonstrates video seeking with thumbnails.
29  *
30  * Generate 1 frame per second thumbnail bitmaps and put on sdcard:
31  * <pre>
32  * sudo apt-get install libav-tools
33  * avconv -i input.mp4 -s 240x135 -vsync 1 -r 1 -an -y -qscale 8 frame_%04d.jpg
34  * adb shell mkdir /sdcard/seek
35  * adb push frame_*.jpg /sdcard/seek/
36  * </pre>
37  * Change to 1 frame per minute: use "-r 1/60".
38  * For more options, see https://wiki.libav.org/Snippets/avconv
39  *
40  * <p>
41  * Showcase:
42  * </p>
43  * <li>Auto play when ready</li>
44  * <li>Set seek provider</li>
45  * <li>switch MediaSource</li>
46  * <li>switch PlaybackGlue</li>
47  */
48 public class SampleVideoFragment extends androidx.leanback.app.VideoFragment {
49 
50     // Media Session Token
51     private static final String MEDIA_SESSION_COMPAT_TOKEN = "media session support video";
52 
53     private PlaybackTransportControlGlueSample<MediaPlayerAdapter> mMediaPlayerGlue;
54 
55     private MediaSessionCompat mMediaSessionCompat;
56 
57     final VideoFragmentGlueHost mHost = new VideoFragmentGlueHost(SampleVideoFragment.this);
58 
playWhenReady(PlaybackGlue glue)59     static void playWhenReady(PlaybackGlue glue) {
60         if (glue.isPrepared()) {
61             glue.play();
62         } else {
63             glue.addPlayerCallback(new PlaybackGlue.PlayerCallback() {
64                 @Override
65                 public void onPreparedStateChanged(PlaybackGlue glue) {
66                     if (glue.isPrepared()) {
67                         glue.removePlayerCallback(this);
68                         glue.play();
69                     }
70                 }
71             });
72         }
73     }
74 
loadSeekData(final PlaybackTransportControlGlue glue)75     static void loadSeekData(final PlaybackTransportControlGlue glue) {
76         if (glue.isPrepared()) {
77             glue.setSeekProvider(new PlaybackSeekDiskDataProvider(
78                     glue.getDuration(),
79                     1000,
80                     "/sdcard/seek/frame_%04d.jpg"));
81         } else {
82             glue.addPlayerCallback(new PlaybackGlue.PlayerCallback() {
83                 @Override
84                 public void onPreparedStateChanged(PlaybackGlue glue) {
85                     if (glue.isPrepared()) {
86                         glue.removePlayerCallback(this);
87                         PlaybackTransportControlGlue transportControlGlue =
88                                 (PlaybackTransportControlGlue) glue;
89                         transportControlGlue.setSeekProvider(new PlaybackSeekDiskDataProvider(
90                                 transportControlGlue.getDuration(),
91                                 1000,
92                                 "/sdcard/seek/frame_%04d.jpg"));
93                     }
94                 }
95             });
96         }
97     }
98 
99     @Override
onCreate(Bundle savedInstanceState)100     public void onCreate(Bundle savedInstanceState) {
101         super.onCreate(savedInstanceState);
102         mMediaPlayerGlue = new PlaybackTransportControlGlueSample(getActivity(),
103                 new MediaPlayerAdapter(getActivity()));
104 
105         // create a media session inside of a fragment, and app developer can determine if connect
106         // this media session to glue or not
107         // as requested in b/64935838
108         mMediaSessionCompat = new MediaSessionCompat(getActivity(), MEDIA_SESSION_COMPAT_TOKEN);
109         mMediaPlayerGlue.connectToMediaSession(mMediaSessionCompat);
110 
111         mMediaPlayerGlue.setHost(mHost);
112         mMediaPlayerGlue.setMode(PlaybackControlsRow.RepeatAction.INDEX_NONE);
113         mMediaPlayerGlue.addPlayerCallback(new PlaybackGlue.PlayerCallback() {
114             boolean mSecondCompleted = false;
115             @Override
116             public void onPlayCompleted(PlaybackGlue glue) {
117                 if (!mSecondCompleted) {
118                     mSecondCompleted = true;
119                     mMediaPlayerGlue.setSubtitle("Leanback artist Changed!");
120                     mMediaPlayerGlue.setTitle("Leanback team at work");
121                     String uriPath = "https://storage.googleapis.com/android-tv/Sample videos/"
122                             + "April Fool's 2013/Explore Treasure Mode with Google Maps.mp4";
123                     mMediaPlayerGlue.getPlayerAdapter().setDataSource(Uri.parse(uriPath));
124                     loadSeekData(mMediaPlayerGlue);
125                     playWhenReady(mMediaPlayerGlue);
126                 } else {
127                     mMediaPlayerGlue.removePlayerCallback(this);
128                     switchAnotherGlue();
129                 }
130             }
131         });
132         mMediaPlayerGlue.setSubtitle("Leanback artist");
133         mMediaPlayerGlue.setTitle("Leanback team at work");
134         String uriPath = "https://storage.googleapis.com/android-tv/Sample videos/"
135                 + "April Fool's 2013/Explore Treasure Mode with Google Maps.mp4";
136         mMediaPlayerGlue.getPlayerAdapter().setDataSource(Uri.parse(uriPath));
137         loadSeekData(mMediaPlayerGlue);
138         playWhenReady(mMediaPlayerGlue);
139     }
140 
141     @Override
onPause()142     public void onPause() {
143         if (mMediaPlayerGlue != null) {
144             mMediaPlayerGlue.pause();
145         }
146         super.onPause();
147     }
148 
149     @Override
onDestroy()150     public void onDestroy() {
151         super.onDestroy();
152         mMediaPlayerGlue.disconnectToMediaSession();
153     }
154 
switchAnotherGlue()155     void switchAnotherGlue() {
156         mMediaPlayerGlue = new PlaybackTransportControlGlueSample(getActivity(),
157                 new MediaPlayerAdapter(getActivity()));
158 
159         // If the glue is switched, re-register the media session
160         mMediaPlayerGlue.connectToMediaSession(mMediaSessionCompat);
161 
162         mMediaPlayerGlue.setMode(PlaybackControlsRow.RepeatAction.INDEX_ONE);
163         mMediaPlayerGlue.setSubtitle("A Googler");
164         mMediaPlayerGlue.setTitle("Swimming with the fishes");
165         mMediaPlayerGlue.getPlayerAdapter().setDataSource(
166                 Uri.parse("http://techslides.com/demos/sample-videos/small.mp4"));
167         mMediaPlayerGlue.setHost(mHost);
168         loadSeekData(mMediaPlayerGlue);
169         playWhenReady(mMediaPlayerGlue);
170     }
171 }
172