android - BrightcoveExoMediaPlayer custom controls -
i trying add custom controls bright cove exo media player hls streaming. able play hls videos default controls not want use.
any suggestions.
first of have hide default media controller of brightcove , can achieved below method
brightcovevideoview.setmediacontroller((mediacontroller) null);
then need design custom controller per needs. sample attaching below
public class videocontrollerview extends framelayout { private static final string tag = "videocontrollerview"; private mediaplayercontrol mplayer; private context mcontext; private viewgroup manchor; private view mroot; private progressbar mprogress; private textview mendtime, mcurrenttime,mtextviewlive; private boolean mshowing; private boolean mdragging; private static final int sdefaulttimeout = 3000; private static final int fade_out = 1; private static final int show_progress = 2; private boolean musefastforward; private boolean mfromxml; private boolean mlistenersset; private onsingleclicklistener mnextlistener, mprevlistener; stringbuilder mformatbuilder; formatter mformatter; private button mpausebutton; private imagebutton mffwdbutton; private imagebutton mrewbutton; private button mnextbutton; private button mprevbutton; private handler mhandler = new messagehandler(this); public videocontrollerview(context context, attributeset attrs) { super(context, attrs); mroot = null; mcontext = context; musefastforward = true; mfromxml = true; log.i(tag, tag); } public videocontrollerview(context context, boolean usefastforward) { super(context); mcontext = context; musefastforward = usefastforward; log.i(tag, tag); } public videocontrollerview(context context) { this(context, true); log.i(tag, tag); } @override public void onfinishinflate() { if (mroot != null) initcontrollerview(mroot); } public void setmediaplayer(mediaplayercontrol player) { mplayer = player; updatepauseplay(); } /** * set view acts anchor control view. * can example videoview, or activity's main view. * @param view view anchor controller when visible. */ public void setanchorview(viewgroup view) { manchor = view; framelayout.layoutparams frameparams = new framelayout.layoutparams( viewgroup.layoutparams.match_parent, viewgroup.layoutparams.match_parent ); removeallviews(); view v = makecontrollerview(); addview(v, frameparams); } /** * create view holds widgets control playback. * derived classes can override create own. * @return controller view. * @hide doesn't work advertised */ protected view makecontrollerview() { layoutinflater inflate = (layoutinflater) mcontext.getsystemservice(context.layout_inflater_service); mroot = inflate.inflate(r.layout.media_controller, null); initcontrollerview(mroot); return mroot; } private void initcontrollerview(view v) { mpausebutton = (button) v.findviewbyid(r.id.pause); if (mpausebutton != null) { mpausebutton.requestfocus(); mpausebutton.setonclicklistener(mpauselistener); } /* mfullscreenbutton = (imagebutton) v.findviewbyid(r.id.fullscreen); if (mfullscreenbutton != null) { mfullscreenbutton.requestfocus(); mfullscreenbutton.setonclicklistener(mfullscreenlistener); } mffwdbutton = (imagebutton) v.findviewbyid(r.id.ffwd); if (mffwdbutton != null) { mffwdbutton.setonclicklistener(mffwdlistener); if (!mfromxml) { mffwdbutton.setvisibility(musefastforward ? view.visible : view.gone); } } mrewbutton = (imagebutton) v.findviewbyid(r.id.rew); if (mrewbutton != null) { mrewbutton.setonclicklistener(mrewlistener); if (!mfromxml) { mrewbutton.setvisibility(musefastforward ? view.visible : view.gone); } }*/ setprevnextlisteners() called mnextbutton = (button) v.findviewbyid(r.id.next); if (mnextbutton != null && !mfromxml && !mlistenersset) { mnextbutton.setvisibility(view.gone); } mprevbutton = (button) v.findviewbyid(r.id.previous); if (mprevbutton != null && !mfromxml && !mlistenersset) { mprevbutton.setvisibility(view.gone); } mprogress = (seekbar) v.findviewbyid(r.id.mediacontroller_progress); if (mprogress != null) { if (mprogress instanceof seekbar) { seekbar seeker = (seekbar) mprogress; seeker.setonseekbarchangelistener(mseeklistener); } mprogress.setmax(1000); } mendtime = (textview) v.findviewbyid(r.id.time); mcurrenttime = (textview) v.findviewbyid(r.id.time_current); mtextviewlive = (textview) v.findviewbyid(r.id.textviewlive); mformatbuilder = new stringbuilder(); mformatter = new formatter(mformatbuilder, locale.getdefault()); installprevnextlisteners(); } /** * show controller on screen. go away * automatically after 3 seconds of inactivity. */ public void show() { show(sdefaulttimeout); } /** * disable pause or seek buttons if stream cannot paused or seeked. * requires control interface mediaplayercontrolext */ private void disableunsupportedbuttons() { if (mplayer == null) { return; } try { if (mpausebutton != null && !mplayer.canpause()) { mpausebutton.setenabled(false); } /* if (mrewbutton != null && !mplayer.canseekbackward()) { mrewbutton.setenabled(false); } if (mffwdbutton != null && !mplayer.canseekforward()) { mffwdbutton.setenabled(false); }*/ } catch (incompatibleclasschangeerror ex) { // given old version of interface, doesn't have // canpause/canseekxyz methods. ok, means // assume media can paused , seeked, , don't disable // buttons. } } /** * show controller on screen. go away * automatically after 'timeout' milliseconds of inactivity. * @param timeout timeout in milliseconds. use 0 show * controller until hide() called. */ public void show(int timeout) { if (!mshowing && manchor != null) { setprogress(); if (mpausebutton != null) { mpausebutton.requestfocus(); } disableunsupportedbuttons(); framelayout.layoutparams tlp = new framelayout.layoutparams( viewgroup.layoutparams.match_parent, viewgroup.layoutparams.wrap_content, gravity.bottom ); manchor.addview(this, tlp); mshowing = true; } updatepauseplay(); updatefullscreen(); // cause progress bar updated if mshowing // true. happens, example, if we're // paused progress bar showing user hits play. mhandler.sendemptymessage(show_progress); message msg = mhandler.obtainmessage(fade_out); if (timeout != 0) { mhandler.removemessages(fade_out); mhandler.sendmessagedelayed(msg, timeout); } } public boolean isshowing() { return mshowing; } /** * remove controller screen. */ public void hide() { if (manchor == null) { return; } try { manchor.removeview(this); mhandler.removemessages(show_progress); } catch (illegalargumentexception ex) { log.w("mediacontroller", "already removed"); } mshowing = false; } private string stringfortime(int timems) { int totalseconds = timems / 1000; int seconds = totalseconds % 60; int minutes = (totalseconds / 60) % 60; int hours = totalseconds / 3600; mformatbuilder.setlength(0); // if (hours > 0) { return mformatter.format("%d:%02d:%02d", hours, minutes, seconds).tostring(); // } else { // return mformatter.format("%02d:%02d", minutes, seconds).tostring(); // } } private int setprogress() { int position =0; if (mplayer == null || mdragging) { return 0; } try { position = mplayer.getcurrentposition(); int duration = mplayer.getduration(); if (mprogress != null) { if (duration > 0) { // use long avoid overflow long pos = 1000l * position / duration; mprogress.setprogress( (int) pos); } int percent = mplayer.getbufferpercentage(); mprogress.setsecondaryprogress(percent * 10); } if (mendtime != null) mendtime.settext(stringfortime(duration)); if (mcurrenttime != null) mcurrenttime.settext(stringfortime(position)); } catch (illegalstateexception e) { } return position; } @override public boolean ontouchevent(motionevent event) { show(sdefaulttimeout); return true; } @override public boolean ontrackballevent(motionevent ev) { show(sdefaulttimeout); return false; } @override public boolean dispatchkeyevent(keyevent event) { if (mplayer == null) { return true; } int keycode = event.getkeycode(); final boolean uniquedown = event.getrepeatcount() == 0 && event.getaction() == keyevent.action_down; if (keycode == keyevent.keycode_headsethook || keycode == keyevent.keycode_media_play_pause || keycode == keyevent.keycode_space) { if (uniquedown) { dopauseresume(); show(sdefaulttimeout); if (mpausebutton != null) { mpausebutton.requestfocus(); } } return true; } else if (keycode == keyevent.keycode_media_play) { if (uniquedown && !mplayer.isplaying()) { mplayer.start(); updatepauseplay(); show(sdefaulttimeout); } return true; } else if (keycode == keyevent.keycode_media_stop || keycode == keyevent.keycode_media_pause) { if (uniquedown && mplayer.isplaying()) { mplayer.pause(); updatepauseplay(); show(sdefaulttimeout); } return true; } else if (keycode == keyevent.keycode_volume_down || keycode == keyevent.keycode_volume_up || keycode == keyevent.keycode_volume_mute) { // don't show controls volume adjustment return super.dispatchkeyevent(event); } else if (keycode == keyevent.keycode_back || keycode == keyevent.keycode_menu) { if (uniquedown) { hide(); } return true; } show(sdefaulttimeout); return super.dispatchkeyevent(event); } private view.onclicklistener mpauselistener = new view.onclicklistener() { public void onclick(view v) { dopauseresume(); show(sdefaulttimeout); } }; private view.onclicklistener mfullscreenlistener = new view.onclicklistener() { public void onclick(view v) { dotogglefullscreen(); show(sdefaulttimeout); } }; public void updatepauseplay() { if (mroot == null || mpausebutton == null || mplayer == null) { return; } if (mplayer.isplaying()) { mpausebutton.setbackgroundresource(r.drawable.ic_pause); } else { mpausebutton.setbackgroundresource(r.drawable.ic_play_btn); } } public void updatepauseplay(boolean isplay) { if (mroot == null || mpausebutton == null || mplayer == null) { return; } if (isplay) { mpausebutton.setbackgroundresource(r.drawable.ic_pause); } else { mpausebutton.setbackgroundresource(r.drawable.ic_play_btn); } } public void updatefullscreen() { if (mroot == null || mplayer == null) { // mfullscreenbutton == null { return; } } private void dopauseresume() { if (mplayer == null) { return; } /*if (mplayer.isplaying()) { mplayer.pause(); } else { mplayer.start(); }*/ mplayer.togglepauseplay(); // updatepauseplay(); } private void dotogglefullscreen() { if (mplayer == null) { return; } mplayer.togglefullscreen(); } // there 2 scenarios can trigger seekbar listener trigger: // // first user using touchpad adjust posititon of // seekbar's thumb. in case onstarttrackingtouch called followed // number of onprogresschanged notifications, concluded onstoptrackingtouch. // we're setting field "mdragging" true duration of dragging // session avoid jumps in position in case of ongoing playback. // // second scenario involves user operating scroll ball, in // case there won't onstarttrackingtouch/onstoptrackingtouch notifications, // apply updated position without suspending regular updates. private onseekbarchangelistener mseeklistener = new onseekbarchangelistener() { public void onstarttrackingtouch(seekbar bar) { show(3600000); mdragging = true; // removing these pending progress messages make sure // a) won't update progress while user adjusts // seekbar , b) once user done dragging thumb // post 1 of these messages queue again , // ensures there 1 message queued up. mhandler.removemessages(show_progress); } public void onprogresschanged(seekbar bar, int progress, boolean fromuser) { if (mplayer == null) { return; } if (!fromuser) { // we're not interested in programmatically generated changes // progress bar's position. return; } long duration = mplayer.getduration(); long newposition = (duration * progress) / 1000l; mplayer.seekto( (int) newposition); if (mcurrenttime != null) mcurrenttime.settext(stringfortime( (int) newposition)); } public void onstoptrackingtouch(seekbar bar) { mdragging = false; setprogress(); updatepauseplay(); show(sdefaulttimeout); // ensure progress updated in future, // call show() not guarantee because // no-op if showing. mhandler.sendemptymessage(show_progress); } }; @override public void setenabled(boolean enabled) { if (mpausebutton != null) { mpausebutton.setenabled(enabled); } /*if (mffwdbutton != null) { mffwdbutton.setenabled(enabled); } if (mrewbutton != null) { mrewbutton.setenabled(enabled); } */ if (mnextbutton != null) { mnextbutton.setenabled(enabled && mnextlistener != null); } if (mprevbutton != null) { mprevbutton.setenabled(enabled && mprevlistener != null); } if (mprogress != null) { mprogress.setenabled(enabled); } disableunsupportedbuttons(); super.setenabled(enabled); } public void enablenextbutton(boolean enabled) { if (mnextbutton != null) { mnextbutton.setenabled(enabled); if(enabled) { mnextbutton.setvisibility(visible); } else { mnextbutton.setvisibility(gone); } } } public void enablepreviousbutton(boolean enabled) { if (mprevbutton != null) { mprevbutton.setenabled(enabled); if(enabled) { mprevbutton.setvisibility(visible); } else { mprevbutton.setvisibility(gone); } } } public void enableprogressbar(boolean enabled) { if (mprogress != null) { mprogress.setenabled(enabled); if(enabled) { mprogress.setvisibility(visible); } else { mprogress.setvisibility(gone); } } } public void enabletimertext(boolean enabled) { if (mcurrenttime != null && mendtime!=null) { mcurrenttime.setenabled(enabled); mendtime.setenabled(enabled); if(enabled) { mcurrenttime.setvisibility(visible); mendtime.setvisibility(visible); } else { mcurrenttime.setvisibility(gone); if(mplayer!=null) { mtextviewlive.setvisibility(visible); mplayer.setlivetext(mtextviewlive); } mendtime.setvisibility(gone); } } } @override public void oninitializeaccessibilityevent(accessibilityevent event) { super.oninitializeaccessibilityevent(event); event.setclassname(videocontrollerview.class.getname()); } @override public void oninitializeaccessibilitynodeinfo(accessibilitynodeinfo info) { super.oninitializeaccessibilitynodeinfo(info); info.setclassname(videocontrollerview.class.getname()); } private view.onclicklistener mrewlistener = new view.onclicklistener() { public void onclick(view v) { if (mplayer == null) { return; } int pos = mplayer.getcurrentposition(); pos -= 5000; // milliseconds mplayer.seekto(pos); setprogress(); show(sdefaulttimeout); } }; private view.onclicklistener mffwdlistener = new view.onclicklistener() { public void onclick(view v) { if (mplayer == null) { return; } int pos = mplayer.getcurrentposition(); pos += 15000; // milliseconds mplayer.seekto(pos); setprogress(); show(sdefaulttimeout); } }; private void installprevnextlisteners() { if (mnextbutton != null) { mnextbutton.setonclicklistener(mnextlistener); mnextbutton.setenabled(mnextlistener != null); } if (mprevbutton != null) { mprevbutton.setonclicklistener(mprevlistener); mprevbutton.setenabled(mprevlistener != null); } } public void setprevnextlisteners(onsingleclicklistener next, onsingleclicklistener prev) { mnextlistener = next; mprevlistener = prev; mlistenersset = true; if (mroot != null) { installprevnextlisteners(); if (mnextbutton != null && !mfromxml) { mnextbutton.setvisibility(view.visible); } if (mprevbutton != null && !mfromxml) { mprevbutton.setvisibility(view.visible); } } } public interface mediaplayercontrol { void start(); void pause(); int getduration(); int getcurrentposition(); void seekto(int pos); boolean isplaying(); int getbufferpercentage(); boolean canpause(); boolean canseekbackward(); boolean canseekforward(); boolean isfullscreen(); void togglefullscreen(); void togglepauseplay(); void setlivetext(textview view); } private static class messagehandler extends handler { private final weakreference<videocontrollerview> mview; messagehandler(videocontrollerview view) { mview = new weakreference<videocontrollerview>(view); } @override public void handlemessage(message msg) { videocontrollerview view = mview.get(); if (view == null || view.mplayer == null) { return; } int pos; switch (msg.what) { case fade_out: view.hide(); break; case show_progress: pos = view.setprogress(); if (!view.mdragging && view.mshowing && view.mplayer.isplaying()) { msg = obtainmessage(show_progress); sendmessagedelayed(msg, 1000 - (pos % 1000)); } break; } } }
next need set below code display controller on top of player
controller = new videocontrollerview(this); controller.setmediaplayer(this); controller.setanchorview(videocontainer);
note: there various methods in videocontrollerview class exclusively project dependencies. please discard/add per needs
Comments
Post a Comment