/* * Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Codename One designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Codename One through http://www.codenameone.com/ if you * need additional information or have any questions. */ package com.codename1.components; import com.codename1.io.Log; import com.codename1.media.Media; import com.codename1.media.MediaManager; import com.codename1.ui.Button; import com.codename1.ui.Component; import com.codename1.ui.Container; import com.codename1.ui.Display; import com.codename1.ui.FontImage; import com.codename1.ui.Image; import com.codename1.ui.events.ActionEvent; import com.codename1.ui.events.ActionListener; import com.codename1.ui.geom.Dimension; import com.codename1.ui.layouts.BorderLayout; import com.codename1.ui.layouts.FlowLayout; import com.codename1.ui.plaf.UIManager; import java.io.IOException; import java.io.InputStream; /** * <p>Video playback component with control buttons for back, play/pause and * forward buttons. In the simulator those controls are implemented locally but on the * device the native playback controls are used. * </p> * * <script src="https://gist.github.com/codenameone/fb73f5d47443052f8956.js"></script> * <img src="https://www.codenameone.com/img/developer-guide/components-mediaplayer.png" alt="Media player sample" /> * */ public class MediaPlayer extends Container { private Image playIcon; private Image pauseIcon; private Image backIcon; private Image fwdIcon; private boolean userSetIcons = false; private Media video; private String dataSource; private String pendingDataURI; private boolean autoplay; private boolean loop; private Runnable onCompletion; /** * Empty constructor */ public MediaPlayer() { playIcon = FontImage.createMaterial(FontImage.MATERIAL_PLAY_ARROW, "Button", 3); pauseIcon = FontImage.createMaterial(FontImage.MATERIAL_PAUSE, "Button", 3); fwdIcon = FontImage.createMaterial(FontImage.MATERIAL_FAST_FORWARD, "Button", 3); backIcon = FontImage.createMaterial(FontImage.MATERIAL_FAST_REWIND, "Button", 3); } /** * Empty constructor */ public MediaPlayer(Media video) { this(); this.video = video; initUI(); } /** * Returns the Media Object of this MediaPlayer * @return */ public Media getMedia(){ return video; } /** * {@inheritDoc} */ protected void initComponent() { if(userSetIcons){ Image play = UIManager.getInstance().getThemeImageConstant("mediaPlayImage"); if(play != null){ playIcon = play; } Image pause = UIManager.getInstance().getThemeImageConstant("mediaPauseImage"); if(pause != null){ pauseIcon = pause; } Image back = UIManager.getInstance().getThemeImageConstant("mediaBackImage"); if(back != null){ backIcon = back; } Image fwd = UIManager.getInstance().getThemeImageConstant("mediaFwdImage"); if(fwd != null){ fwdIcon = fwd; } } if(pendingDataURI != null) { setDataSource(pendingDataURI); pendingDataURI = null; } initUI(); } /** * {@inheritDoc} */ @Override protected void deinitialize() { super.deinitialize(); if(autoplay) { if(video != null && video.isPlaying()){ video.pause(); } } } /** * {@inheritDoc} */ protected Dimension calcPreferredSize() { if(video == null && dataSource == null) { return new Dimension(240, 320); } return super.calcPreferredSize(); } /** * Sets the back Button Icon * @param backIcon */ public void setBackIcon(Image backIcon) { this.backIcon = backIcon; userSetIcons = true; } /** * Sets the forward Button Icon * @param fwdIcon */ public void setFwdIcon(Image fwdIcon) { this.fwdIcon = fwdIcon; userSetIcons = true; } /** * Sets the pause Button Icon * @param pauseIcon */ public void setPauseIcon(Image pauseIcon) { this.pauseIcon = pauseIcon; userSetIcons = true; } /** * Sets the play Button Icon * @param playIcon */ public void setPlayIcon(Image playIcon) { this.playIcon = playIcon; userSetIcons = true; } /** * Sets the data source of this video player * @param uri the uri of the media can start with file://, http:// (can also * use rtsp:// although may not be supported on all target platforms) * @throws IOException if creation of media from the given URI has failed */ public void setDataSource(String uri, Runnable onCompletion) throws IOException{ dataSource = uri; if(onCompletion instanceof CompletionWrapper) { video = MediaManager.createMedia(uri, true, onCompletion); } else { this.onCompletion = onCompletion; video = MediaManager.createMedia(uri, true, new CompletionWrapper()); } initUI(); } /** * Convenience JavaBean method, see other version of this method * @param uri the URL for the media */ public void setDataSource(final String uri) { if(!isInitialized()) { pendingDataURI = uri; return; } if(dataSource == null || !dataSource.equals(uri)) { Display.getInstance().startThread(new Runnable() { public void run() { try { setDataSource(uri, null); } catch(Throwable t) { Log.e(t); } } }, "Media Thread").start(); } } /** * Convenience JavaBean method, see other version of this method * * @return the data source uri */ public String getDataSource() { if(!isInitialized() && dataSource == null) { return pendingDataURI; } return dataSource; } /** * Sets the data source of this video player * @param is the stream containing the media data * @param mimeType the type of the data in the stream * @throws java.io.IOException if the creation of the Media has failed */ public void setDataSource(InputStream is, String mimeType, Runnable onCompletion) throws IOException{ if(onCompletion instanceof CompletionWrapper) { video = MediaManager.createMedia(is, mimeType, onCompletion); } else { this.onCompletion = onCompletion; video = MediaManager.createMedia(is, mimeType, new CompletionWrapper()); } initUI(); } private void initUI() { removeAll(); setLayout(new BorderLayout()); if(video != null){ addComponent(BorderLayout.CENTER, video.getVideoComponent()); } Container buttonsBar = new Container(new FlowLayout(Container.CENTER)); if(!Display.getInstance().isNativeVideoPlayerControlsIncluded()) { addComponent(BorderLayout.SOUTH, buttonsBar); } if(video == null || !video.isNativePlayerMode()){ Button back = new Button(); back.setUIID("MediaPlayerBack"); if(backIcon != null){ back.setIcon(backIcon); }else{ back.setText("Back"); } buttonsBar.addComponent(back); back.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { if(video == null){ return; } int t = video.getTime(); video.setTime(t - 2); } }); } final Button play = new Button(); play.setUIID("MediaPlayerPlay"); if(playIcon != null){ play.setIcon(playIcon); }else{ play.setText("play"); } if(autoplay) { if(video != null && !video.isPlaying()){ if (getPauseIcon() != null) { play.setIcon(getPauseIcon()); } else { play.setText("pause"); } video.play(); } } play.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { if(video == null){ return; } if(!video.isPlaying()){ video.play(); play.setUIID("MediaPlayerPause"); if (getPauseIcon() != null) { play.setIcon(getPauseIcon()); } else { play.setText("pause"); } play.repaint(); }else{ video.pause(); play.setUIID("MediaPlayerPlay"); if (getPlayIcon() != null) { play.setIcon(getPlayIcon()); } else { play.setText("play"); } play.repaint(); } } }); buttonsBar.addComponent(play); if(video == null || !video.isNativePlayerMode()){ Button fwd = new Button(); fwd.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { if(video == null){ return; } int t = video.getTime(); video.setTime(t + 1); } }); fwd.setUIID("MediaPlayerFwd"); if(fwdIcon != null){ fwd.setIcon(fwdIcon); }else{ fwd.setText("fwd"); } buttonsBar.addComponent(fwd); } if(isInitialized()) { revalidate(); } } public void run() { } /** * {@inheritDoc} */ public String[] getPropertyNames() { return new String[] {"backIcon", "forwardIcon", "pauseIcon", "playIcon", "dataSource"}; } /** * {@inheritDoc} */ public Class[] getPropertyTypes() { return new Class[] {Image.class, Image.class, Image.class, Image.class, String.class}; } /** * {@inheritDoc} */ public Object getPropertyValue(String name) { if(name.equals("backIcon")) { return getBackIcon(); } if(name.equals("forwardIcon")) { return getFwdIcon(); } if(name.equals("playIcon")) { return getPlayIcon(); } if(name.equals("pauseIcon")) { return getPauseIcon(); } if(name.equals("dataSource")) { return getDataSource(); } return super.getPropertyValue(name); } /** * {@inheritDoc} */ public String setPropertyValue(String name, Object value) { if(name.equals("backIcon")) { this.backIcon = (Image)value; return null; } if(name.equals("forwardIcon")) { this.fwdIcon = (Image)value; return null; } if(name.equals("playIcon")) { this.playIcon = (Image)value; return null; } if(name.equals("pauseIcon")) { this.pauseIcon = (Image)value; return null; } if(name.equals("dataSource")) { setDataSource((String)value); return null; } return super.setPropertyValue(name, value); } /** * @return the playIcon */ public Image getPlayIcon() { return playIcon; } /** * @return the pauseIcon */ public Image getPauseIcon() { return pauseIcon; } /** * @return the backIcon */ public Image getBackIcon() { return backIcon; } /** * @return the fwdIcon */ public Image getFwdIcon() { return fwdIcon; } /** * Sets playback to start automatically * @return the autoplay */ public boolean isAutoplay() { return autoplay; } /** * Sets playback to start automatically * @param autoplay the autoplay to set */ public void setAutoplay(boolean autoplay) { this.autoplay = autoplay; } /** * Sets playback to loop * @return the loop */ public boolean isLoop() { return loop; } /** * Sets playback to loop * @param loop the loop to set */ public void setLoop(boolean loop) { this.loop = loop; } class CompletionWrapper implements Runnable { public void run() { if(onCompletion != null) { onCompletion.run(); } if(isLoop()) { try { setDataSource(dataSource, this); } catch(IOException err) { Log.e(err); } } } } }