package com.exovlc; import java.util.ArrayList; import java.util.Arrays; import org.videolan.libvlc.LibVLC; import org.videolan.libvlc.LibVlcException; import org.videolan.libvlc.LibVlcUtil; import org.videolan.libvlc.Media; import org.videolan.libvlc.Media.AudioTrack; import org.videolan.libvlc.Media.SubtitleTrack; import org.videolan.libvlc.Media.VideoTrack; import org.videolan.libvlc.MediaList; import android.annotation.TargetApi; import android.content.Context; import android.content.SharedPreferences; import android.graphics.Rect; import android.media.MediaFormat; import android.os.Build; import android.preference.PreferenceManager; import android.util.Log; import android.view.SurfaceHolder; import com.google.android.exoplayer.ExoPlaybackException; import com.google.android.exoplayer.TrackInfo; public class ExoVlcUtil { static final int MS_2_MICRO = 1000; static final String DUMM_VDO_MIME = "video/uncknown"; private static final int[] MEDIA_TYPES = { Media.Track.Type.Audio, Media.Track.Type.Video, Media.Track.Type.Text };// should // be // sorted // !! static { Arrays.sort(MEDIA_TYPES); } private ExoVlcUtil() { } static void releaseVLC(LibVLC lib) { synchronized (ExoVlcUtil.class) { if (lib != null) { lib.destroy(); lib = null; } libCtx = null; } } static boolean validSurface(SurfaceHolder holder) { if (holder.getSurface() != null) { Rect r = holder.getSurfaceFrame(); System.out.println("ExoVlcUtil.validSurface() r = " + r); return (r.width() * r.height()) > 0; } return false; } static synchronized void updateLibVlcSettings(SharedPreferences pref, LibVLC sLibVLC) { sLibVLC.setSubtitlesEncoding(pref.getString("subtitle_text_encoding", "")); sLibVLC.setTimeStretching(pref.getBoolean("enable_time_stretching_audio", false)); sLibVLC.setFrameSkip(pref.getBoolean("enable_frame_skip", false)); sLibVLC.setChroma(pref.getString("chroma_format", "")); // sLibVLC.setVerboseMode(pref.getBoolean("enable_verbose_mode", true)); sLibVLC.setHardwareAcceleration(LibVLC.HW_ACCELERATION_FULL);// HW_ACCELERATION_AUTOMATIC);// // HW_ACCELERATION_FULL);//HW_ACCELERATION_DISABLED); System.out.println("######VideoActivity..updateLibVlcSettings() setChroma=" + pref.getString("chroma_format", "")); System.out.println("######VideoActivity..updateLibVlcSettings() enable_frame_skip=" + pref.getBoolean("enable_frame_skip", false)); System.out.println("######VideoActivity..updateLibVlcSettings() enable_time_stretching_audio = " + pref.getBoolean("enable_time_stretching_audio", false)); System.out.println("######VideoActivity..updateLibVlcSettings() subtitle_text_encoding = " + pref.getString("subtitle_text_encoding", "")); System.out.println("######VideoActivity..updateLibVlcSettings() equalizer_enabled = " + pref.getBoolean("equalizer_enabled", false)); // if (pref.getBoolean("equalizer_enabled", false)) // sLibVLC.setEqualizer(Preferences.getFloatArray(pref, // "equalizer_values")); int aout; try { aout = Integer.parseInt(pref.getString("aout", "-1")); } catch (NumberFormatException nfe) { aout = -1; } int vout; try { vout = Integer.parseInt(pref.getString("vout", "-1")); } catch (NumberFormatException nfe) { vout = -1; } int deblocking; try { deblocking = Integer.parseInt(pref.getString("deblocking", "-1")); } catch (NumberFormatException nfe) { deblocking = -1; } int hardwareAcceleration; try { hardwareAcceleration = Integer.parseInt(pref.getString("hardware_acceleration", "-1")); } catch (NumberFormatException nfe) { hardwareAcceleration = -1; } int devHardwareDecoder; try { devHardwareDecoder = Integer.parseInt(pref.getString("dev_hardware_decoder", "-1")); } catch (NumberFormatException nfe) { devHardwareDecoder = -1; } int networkCaching = pref.getInt("network_caching_value", 0); if (networkCaching > 60000) networkCaching = 60000; else if (networkCaching < 0) networkCaching = 0; System.out.println("###### VLCInstance.updateLibVlcSettings()aout=" + aout); sLibVLC.setAout(aout); System.out.println("######VideoActivity..updateLibVlcSettings()vout=" + vout); /************/ /************/ /************/ /************/ /*vout = org.videolan.libvlc.LibVLC.VOUT_OPEGLES2;*/ /************/ /************/ /************/ /************/ if (vout != -1) sLibVLC.setVout(vout); else sLibVLC.setVout(LibVlcUtil.isGingerbreadOrLater() ? LibVLC.VOUT_ANDROID_WINDOW : LibVLC.VOUT_ANDROID_SURFACE); System.out.println("######VideoActivity..updateLibVlcSettings()deblocking=" + deblocking); sLibVLC.setDeblocking(deblocking); System.out.println("######VideoActivity..updateLibVlcSettings()networkCaching=" + networkCaching); sLibVLC.setNetworkCaching(networkCaching); // System.out.println("######VideoActivity..updateLibVlcSettings()hardwareAcceleration=" // + hardwareAcceleration); // sLibVLC.setHardwareAcceleration(hardwareAcceleration); System.out.println("######VideoActivity..updateLibVlcSettings()devHardwareDecoder=" + devHardwareDecoder); sLibVLC.setDevHardwareDecoder(devHardwareDecoder); } private static LibVLC lib; private static Context libCtx; public static LibVLC getVLC(Context context) throws com.google.android.exoplayer.ExoPlaybackException { synchronized (ExoVlcUtil.class) { if (lib != null) { if (context.equals(libCtx)) return lib; try { lib.detachSurface(); } catch (Exception e) { } lib.destroy(); } lib = new LibVLC(); updateLibVlcSettings(PreferenceManager.getDefaultSharedPreferences(context), lib); try { lib.init(libCtx = context); } catch (LibVlcException e) { e.printStackTrace(); throw new com.google.android.exoplayer.ExoPlaybackException(e.getCause()); } return lib; } } public static void log(Object o, String msg) { String tag = o != null ? o.getClass().getSimpleName() : ""; log(tag, msg); } static void log(String tag, String msg) { Log.d(tag, msg); } public static org.videolan.libvlc.Media getMedia(LibVLC vlc, String uri) throws ExoPlaybackException { System.out.println(">> ExoVlcUtil.getMedia() uri = " + uri); org.videolan.libvlc.Media media = new org.videolan.libvlc.Media(vlc, uri); boolean parsed = media.parse(org.videolan.libvlc.Media.Parse.FetchNetwork); media.release(); System.out.println("ExoVlcUtil.getMedia() is parsed media=" + media.isParsed()); System.out.println("ExoVlcUtil.getMedia() media duration ="); MediaList mlist = media.subItems(); System.out.println("ExoVlcUtil.getMedia() sub item =" + mlist); if (mlist != null) { System.out.println(">>> ExoVlcUtil.getMedia() parsed media subItems count : " + mlist.getCount()); for (int i = 0; i < mlist.getCount(); i++) { System.out.println(">>> ExoVlcUtil.getMedia() parsed media subItems item (" + i + ") : " + mlist.getMediaAt(i).getType() + " track count " + mlist.getMediaAt(i).getTrackCount()); } } System.out.println(">>> ExoVlcUtil.getMedia() parsed media dump tracks : " + media.getTrackCount()); for (int i = 0; i < media.getTrackCount(); i++) { System.out.println(">>> ExoVlcUtil.getMedia() parsed media track[" + i + "]:" + media.getTrack(i).type); } // try { // boolean hv =vlc.hasVideoTrack(uri); // System.out.println(">>> ExoVlcUtil.getMedia() HAS VDO="+hv); // } catch (IOException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // if (!parsed) throw new ExoPlaybackException("Unable to parse media " + uri); return media; } /** * * @param media * @return */ static org.videolan.libvlc.Media.Track[] getAvailableTracks(org.videolan.libvlc.Media media) { ArrayList<Media.Track> l = new ArrayList<Media.Track>(); int c = media.getTrackCount(); while (--c >= 0) { Media.Track t = media.getTrack(c); System.out.println("ExoVlcUtil.getAvailableTracks() ?? type : " + t.type + " search " + Arrays.binarySearch(MEDIA_TYPES, t.type)); if (Arrays.binarySearch(MEDIA_TYPES, t.type) >= 0) l.add(t); } return l.toArray(new org.videolan.libvlc.Media.Track[l.size()]); } static TrackInfo[] getDummyVdoTrack(org.videolan.libvlc.Media media, String mime) { System.out.println(">>> ExoVlcUtil.getDummyVdoTrack() ---> duration = " + media.getDuration()); return new TrackInfo[] { new TrackInfo(mime, media.getDuration()) }; } /** * * @param media * @param vlcTracks * @param lib * @return */ static com.google.android.exoplayer.TrackInfo[] vlc2exoTracks(long duration, org.videolan.libvlc.Media.Track[] vlcTracks, LibVLC lib) { com.google.android.exoplayer.TrackInfo[] res = new com.google.android.exoplayer.TrackInfo[vlcTracks.length]; System.out.println("ExoVlcUtil.vlc2exoTracks() vlcTracks = " + vlcTracks.length); // Media.Track for (int i = 0; i < res.length; i++) { MediaFormat mf = track2mediaFormat(vlcTracks[i]); res[i] = new TrackInfo(mf.getString(MediaFormat.KEY_MIME), duration); System.out.println("\t track " + i + " mime type =" + mf.getString(MediaFormat.KEY_MIME) + " duration =" + duration); } /* * System.out.println(">>>> ExoVlcUtil.vlc2exoTracks() vlcTracks.length = " * +vlcTracks.length); long l; for (int i = 0; i < vlcTracks.length; * i++) { org.videolan.libvlc.TrackInfo vt = vlcTracks[i]; * System.out.println("\t\t >>>>>Codec("+i+") "+vlcTracks[i].Codec); * res[i] = new TrackInfo( vt.Codec, (l=lib.getLength()) == -1 ? * com.google.android.exoplayer.C.UNKNOWN_TIME_US : l * MS_2_MICRO); } */ return res; } /** * * @param code */ static void nativeVlcMsg(int code) { if (code == -1) log(" Lib VLC", "Err msg:" + LibVlcUtil.getErrorMsg()); } static float pos2percentage(long microsec, LibVLC lib) { float fp = .0f; long lms = lib.getLength(); if (lms != -1) { lms *= MS_2_MICRO; fp = (((float) microsec) / lms); } return fp; } @TargetApi(Build.VERSION_CODES.KITKAT) static android.media.MediaFormat track2mediaFormat(Media.Track track) { android.media.MediaFormat mf; // TODO fix track switch (track.type) { case Media.Track.Type.Video: { VideoTrack vt = (VideoTrack) track; mf = android.media.MediaFormat.createVideoFormat(track.codec, vt.width, vt.height); mf.setInteger(android.media.MediaFormat.KEY_WIDTH, vt.width); mf.setInteger(android.media.MediaFormat.KEY_HEIGHT, vt.height); mf.setFloat(android.media.MediaFormat.KEY_FRAME_RATE, vt.frameRateNum); } break; case Media.Track.Type.Audio: { AudioTrack at = (AudioTrack) track; mf = android.media.MediaFormat.createAudioFormat(track.codec, at.rate, at.channels); } break; case Media.Track.Type.Text: { SubtitleTrack st = (SubtitleTrack) track; mf = android.media.MediaFormat.createSubtitleFormat(track.codec, track.language); mf.setString(VLCTrackKeys.VLC_SUBTITLE_TRACK_ECODING, st.encoding); } break; default: throw new IllegalArgumentException("Unknown track type."); } mf.setInteger(android.media.MediaFormat.KEY_BIT_RATE, track.bitrate); mf.setString(android.media.MediaFormat.KEY_LANGUAGE, track.language);// VLC_TRACK_ORIGINAL_CODEC mf.setString(VLCTrackKeys.VLC_TRACK_DESCRIPTION, track.description); mf.setString(VLCTrackKeys.VLC_TRACK_ORIGINAL_CODEC, track.originalCodec); // TODO /* * Missing maxInputSize = getOptionalIntegerV16(format, * android.media.MediaFormat.KEY_MAX_INPUT_SIZE); pixelWidthHeightRatio * = getOptionalFloatV16(format, KEY_PIXEL_WIDTH_HEIGHT_RATIO); */ return mf; } static int media2vlcVolume(float mediaVolume) { // VLC : 0 .. 100 db // Android Media: .0f .. MaxVomule int v = (int) (mediaVolume * 100); v /= android.media.AudioTrack.getMaxVolume(); return v; } private static final String[] AUDIO_WITNESS = { "aac", "audio", "mp3", "ac3", "wav" }; private static final String[] VIDEO_WITNESS = { "video", "mp4", "h26", "ogg", "avi", "divx" }; private static boolean is_part_of(String[] parts, String of) { for (int i = 0; i < parts.length; i++) if (of.indexOf(parts[i]) != -1) return true; return false; } static boolean isVLCVideoMimeType(String mimeType) { return is_part_of(VIDEO_WITNESS, mimeType.toLowerCase()); } static boolean isVLCAudioMimeType(String mimeType) { return is_part_of(AUDIO_WITNESS, mimeType.toLowerCase()); } }