Commit d150b67c authored by Shivansh Saini's avatar Shivansh Saini

Stubbed Media and LibVLC classes

Used Abstract Factory Manager design pattern for LibVLC components

Tests done: StreamsModel, SubtitlesModel, HistoryModel, FilePickerModel,
       BrowserModel, StorageModel, FileBrowserModel, NetworkModel,
       VideosViewModel

Used CoroutineContextProvider to replace context on-demand.
Added extension function for the child of SingletonHolder used in ExternalSubRepository.
Replaced OpenSubtitleRepository.getInstance to use lazy value, so it can be replaced in tests.
Added Dependency Provider for BrowserProvider
Updated StubDataSource to configure data set to provide
LibVLC: Refactored interfaces
Signed-off-by: Shivansh Saini's avatarShivansh Saini <shivanshs9@gmail.com>
parent c1b9b1ce
......@@ -56,6 +56,7 @@ ext {
espressoVersion = '3.1.1'
livedataTest = '1.1.0'
robolectric = '4.2.1'
mockk = '1.9.3'
supportTest = '1.1.0'
// versionCode scheme is T M NN RR AA
// T: Target/Flavour (1 for Android, 2 for Chrome?)
......
......@@ -31,6 +31,8 @@ import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.TextureView;
import org.videolan.libvlc.interfaces.IVLCVout;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
......
......@@ -24,11 +24,13 @@ import android.os.Handler;
import android.os.Looper;
import androidx.annotation.MainThread;
import org.videolan.libvlc.interfaces.ILibVLC;
@SuppressWarnings("unused, JniMissingFunction")
public abstract class Dialog {
/**
* Dialog Callback, see {@link Dialog#setCallbacks(LibVLC, Callbacks)}
* Dialog Callback, see {@link Dialog#setCallbacks(ILibVLC, Callbacks)}
*/
public interface Callbacks {
/**
......@@ -164,15 +166,15 @@ public abstract class Dialog {
/**
* Register callbacks in order to handle VLC dialogs
*
* @param libVLC valid LibVLC object
* @param ILibVLC valid LibVLC object
* @param callbacks dialog callbacks or null to unregister
*/
@MainThread
public static void setCallbacks(LibVLC libVLC, Callbacks callbacks) {
public static void setCallbacks(ILibVLC ILibVLC, Callbacks callbacks) {
if (callbacks != null && sHandler == null)
sHandler = new Handler(Looper.getMainLooper());
sCallbacks = callbacks;
nativeSetCallbacks(libVLC, callbacks != null);
nativeSetCallbacks(ILibVLC, callbacks != null);
}
/**
......@@ -476,5 +478,5 @@ public abstract class Dialog {
});
}
private static native void nativeSetCallbacks(LibVLC libVLC, boolean enabled);
private static native void nativeSetCallbacks(ILibVLC ILibVLC, boolean enabled);
}
\ No newline at end of file
package org.videolan.libvlc;
import org.videolan.libvlc.interfaces.IComponentFactory;
import java.util.HashMap;
import java.util.Map;
public class FactoryManager {
private static Map<String, IComponentFactory> factories = new HashMap<>();
public static void registerFactory(String factoryId, IComponentFactory factory) {
factories.put(factoryId, factory);
}
public static IComponentFactory getFactory(String factoryId) {
return factories.get(factoryId);
}
}
......@@ -23,18 +23,22 @@ package org.videolan.libvlc;
import android.content.Context;
import android.util.Log;
import androidx.annotation.Nullable;
import org.videolan.libvlc.interfaces.AbstractVLCEvent;
import org.videolan.libvlc.interfaces.ILibVLC;
import org.videolan.libvlc.util.HWDecoderUtil;
import java.util.ArrayList;
import androidx.annotation.Nullable;
import java.util.List;
@SuppressWarnings("unused, JniMissingFunction")
public class LibVLC extends VLCObject<LibVLC.Event> {
public class LibVLC extends VLCObject<ILibVLC.Event> implements ILibVLC {
private static final String TAG = "VLC/LibVLC";
final Context mAppContext;
public static class Event extends VLCEvent {
public static class Event extends AbstractVLCEvent {
protected Event(int type) {
super(type);
}
......@@ -45,12 +49,12 @@ public class LibVLC extends VLCObject<LibVLC.Event> {
*
* @param options
*/
public LibVLC(Context context, ArrayList<String> options) {
public LibVLC(Context context, List<String> options) {
mAppContext = context.getApplicationContext();
loadLibraries();
if (options == null)
options = new ArrayList<String>();
options = new ArrayList<>();
boolean setAout = true, setChroma = true;
// check if aout/vout options are already set
for (String option : options) {
......@@ -88,27 +92,35 @@ public class LibVLC extends VLCObject<LibVLC.Event> {
/**
* Get the libVLC version
*
* @return the libVLC version string
*/
public native String version();
/**
* Get the libVLC compiler
*
* @return the libVLC compiler string
*/
public native String compiler();
/**
* Get the libVLC changeset
*
* @return the libVLC changeset string
*/
public native String changeset();
@Override
protected Event onEventNative(int eventType, long arg1, long arg2, float argf1, @Nullable String args1) {
protected ILibVLC.Event onEventNative(int eventType, long arg1, long arg2, float argf1, @Nullable String args1) {
return null;
}
@Override
public Context getAppContext() {
return mAppContext;
}
@Override
protected void onReleaseNative() {
nativeRelease();
......@@ -121,13 +133,15 @@ public class LibVLC extends VLCObject<LibVLC.Event> {
* @param name human-readable application name, e.g. "FooBar player 1.2.3"
* @param http HTTP User Agent, e.g. "FooBar/1.2.3 Python/2.6.0"
*/
public void setUserAgent(String name, String http){
public void setUserAgent(String name, String http) {
nativeSetUserAgent(name, http);
}
/* JNI */
private native void nativeNew(String[] options, String homePath);
private native void nativeRelease();
private native void nativeSetUserAgent(String name, String http);
private static boolean sLoaded = false;
......
package org.videolan.libvlc;
import android.content.Context;
import org.videolan.libvlc.interfaces.ILibVLC;
import org.videolan.libvlc.interfaces.ILibVLCFactory;
import java.util.List;
public class LibVLCFactory implements ILibVLCFactory {
static {
FactoryManager.registerFactory(ILibVLCFactory.factoryId, new LibVLCFactory());
}
@Override
public ILibVLC getFromOptions(Context context, List<String> options) {
return new LibVLC(context, options);
}
@Override
public ILibVLC getFromContext(Context context) {
return new LibVLC(context, null);
}
}
......@@ -23,6 +23,9 @@ package org.videolan.libvlc;
import android.content.res.AssetFileDescriptor;
import android.net.Uri;
import org.videolan.libvlc.interfaces.ILibVLC;
import org.videolan.libvlc.interfaces.IMedia;
import org.videolan.libvlc.interfaces.IMediaList;
import org.videolan.libvlc.util.AndroidUtil;
import org.videolan.libvlc.util.HWDecoderUtil;
import org.videolan.libvlc.util.VLCUtil;
......@@ -32,171 +35,9 @@ import java.io.FileDescriptor;
import androidx.annotation.Nullable;
@SuppressWarnings("unused, JniMissingFunction")
public class Media extends VLCObject<Media.Event> {
public class Media extends VLCObject<IMedia.Event> implements IMedia {
private final static String TAG = "LibVLC/Media";
public static class Event extends VLCEvent {
public static final int MetaChanged = 0;
public static final int SubItemAdded = 1;
public static final int DurationChanged = 2;
public static final int ParsedChanged = 3;
//public static final int Freed = 4;
public static final int StateChanged = 5;
public static final int SubItemTreeAdded = 6;
protected Event(int type) {
super(type);
}
protected Event(int type, long arg1) {
super(type, arg1);
}
public int getMetaId() {
return (int) arg1;
}
/**
* Get the ParsedStatus in case of {@link Event#ParsedChanged} event
* @return {@link Media.ParsedStatus}
*/
public int getParsedStatus() {
return (int) arg1;
}
}
public interface EventListener extends VLCEvent.Listener<Media.Event> {}
/**
* libvlc_media_type_t
*/
public static class Type {
public static final int Unknown = 0;
public static final int File = 1;
public static final int Directory = 2;
public static final int Disc = 3;
public static final int Stream = 4;
public static final int Playlist = 5;
}
/**
* see libvlc_meta_t
*/
public static class Meta {
public static final int Title = 0;
public static final int Artist = 1;
public static final int Genre = 2;
public static final int Copyright = 3;
public static final int Album = 4;
public static final int TrackNumber = 5;
public static final int Description = 6;
public static final int Rating = 7;
public static final int Date = 8;
public static final int Setting = 9;
public static final int URL = 10;
public static final int Language = 11;
public static final int NowPlaying = 12;
public static final int Publisher = 13;
public static final int EncodedBy = 14;
public static final int ArtworkURL = 15;
public static final int TrackID = 16;
public static final int TrackTotal = 17;
public static final int Director = 18;
public static final int Season = 19;
public static final int Episode = 20;
public static final int ShowName = 21;
public static final int Actors = 22;
public static final int AlbumArtist = 23;
public static final int DiscNumber = 24;
public static final int MAX = 25;
}
/**
* see libvlc_state_t
*/
public static class State {
public static final int NothingSpecial = 0;
public static final int Opening = 1;
/* deprecated public static final int Buffering = 2; */
public static final int Playing = 3;
public static final int Paused = 4;
public static final int Stopped = 5;
public static final int Ended = 6;
public static final int Error = 7;
public static final int MAX = 8;
}
/**
* see libvlc_media_parse_flag_t
*/
public static class Parse {
public static final int ParseLocal = 0;
public static final int ParseNetwork = 0x01;
public static final int FetchLocal = 0x02;
public static final int FetchNetwork = 0x04;
public static final int DoInteract = 0x08;
}
/*
* see libvlc_media_parsed_status_t
*/
public static class ParsedStatus {
public static final int Skipped = 1;
public static final int Failed = 2;
public static final int Timeout = 3;
public static final int Done = 4;
}
/**
* see libvlc_media_track_t
*/
public static abstract class Track {
public static class Type {
public static final int Unknown = -1;
public static final int Audio = 0;
public static final int Video = 1;
public static final int Text = 2;
}
public final int type;
public final String codec;
public final String originalCodec;
public final int id;
public final int profile;
public final int level;
public final int bitrate;
public final String language;
public final String description;
private Track(int type, String codec, String originalCodec, int id, int profile,
int level, int bitrate, String language, String description) {
this.type = type;
this.codec = codec;
this.originalCodec = originalCodec;
this.id = id;
this.profile = profile;
this.level = level;
this.bitrate = bitrate;
this.language = language;
this.description = description;
}
}
/**
* see libvlc_audio_track_t
*/
public static class AudioTrack extends Track {
public final int channels;
public final int rate;
private AudioTrack(String codec, String originalCodec, int id, int profile,
int level, int bitrate, String language, String description,
int channels, int rate) {
super(Type.Audio, codec, originalCodec, id, profile, level, bitrate, language, description);
this.channels = channels;
this.rate = rate;
}
}
@SuppressWarnings("unused") /* Used from JNI */
private static Track createAudioTrackFromNative(String codec, String originalCodec, int id, int profile,
int level, int bitrate, String language, String description,
......@@ -206,61 +47,6 @@ public class Media extends VLCObject<Media.Event> {
channels, rate);
}
/**
* see libvlc_video_track_t
*/
public static class VideoTrack extends Track {
public static final class Orientation {
/** Top line represents top, left column left */
public static final int TopLeft = 0;
/** Flipped horizontally */
public static final int TopRight = 1;
/** Flipped vertically */
public static final int BottomLeft = 2;
/** Rotated 180 degrees */
public static final int BottomRight = 3;
/** Transposed */
public static final int LeftTop = 4;
/** Rotated 90 degrees clockwise (or 270 anti-clockwise) */
public static final int LeftBottom = 5;
/** Rotated 90 degrees anti-clockwise */
public static final int RightTop= 6;
/** Anti-transposed */
public static final int RightBottom = 7;
}
public static final class Projection {
public static final int Rectangular = 0;
/** 360 spherical */
public static final int EquiRectangular = 1;
public static final int CubemapLayoutStandard = 0x100;
}
public final int height;
public final int width;
public final int sarNum;
public final int sarDen;
public final int frameRateNum;
public final int frameRateDen;
public final int orientation;
public final int projection;
private VideoTrack(String codec, String originalCodec, int id, int profile,
int level, int bitrate, String language, String description,
int height, int width, int sarNum, int sarDen, int frameRateNum, int frameRateDen,
int orientation, int projection) {
super(Type.Video, codec, originalCodec, id, profile, level, bitrate, language, description);
this.height = height;
this.width = width;
this.sarNum = sarNum;
this.sarDen = sarDen;
this.frameRateNum = frameRateNum;
this.frameRateDen = frameRateDen;
this.orientation = orientation;
this.projection = projection;
}
}
@SuppressWarnings("unused") /* Used from JNI */
private static Track createVideoTrackFromNative(String codec, String originalCodec, int id, int profile,
int level, int bitrate, String language, String description,
......@@ -271,20 +57,6 @@ public class Media extends VLCObject<Media.Event> {
height, width, sarNum, sarDen, frameRateNum, frameRateDen, orientation, projection);
}
/**
* see libvlc_subtitle_track_t
*/
public static class SubtitleTrack extends Track {
public final String encoding;
private SubtitleTrack(String codec, String originalCodec, int id, int profile,
int level, int bitrate, String language, String description,
String encoding) {
super(Type.Text, codec, originalCodec, id, profile, level, bitrate, language, description);
this.encoding = encoding;
}
}
@SuppressWarnings("unused") /* Used from JNI */
private static Track createSubtitleTrackFromNative(String codec, String originalCodec, int id, int profile,
int level, int bitrate, String language, String description,
......@@ -294,16 +66,6 @@ public class Media extends VLCObject<Media.Event> {
encoding);
}
/**
* see libvlc_subtitle_track_t
*/
public static class UnknownTrack extends Track {
private UnknownTrack(String codec, String originalCodec, int id, int profile,
int level, int bitrate, String language, String description) {
super(Type.Unknown, codec, originalCodec, id, profile, level, bitrate, language, description);
}
}
@SuppressWarnings("unused") /* Used from JNI */
private static Track createUnknownTrackFromNative(String codec, String originalCodec, int id, int profile,
int level, int bitrate, String language, String description) {
......@@ -311,78 +73,11 @@ public class Media extends VLCObject<Media.Event> {
level, bitrate, language, description);
}
/**
* see libvlc_media_slave_t
*/
public static class Slave {
public static class Type {
public static final int Subtitle = 0;
public static final int Audio = 1;
}
/** @see Type */
public final int type;
/** From 0 (low priority) to 4 (high priority) */
public final int priority;
public final String uri;
public Slave(int type, int priority, String uri) {
this.type = type;
this.priority = priority;
this.uri = uri;
}
}
@SuppressWarnings("unused") /* Used from JNI */
private static Slave createSlaveFromNative(int type, int priority, String uri) {
return new Slave(type, priority, uri);
}
/**
* see libvlc_media_stats_t
*/
public static class Stats {
public final int readBytes;
public final float inputBitrate;
public final int demuxReadBytes;
public final float demuxBitrate;
public final int demuxCorrupted;
public final int demuxDiscontinuity;
public final int decodedVideo;
public final int decodedAudio;
public final int displayedPictures;
public final int lostPictures;
public final int playedAbuffers;
public final int lostAbuffers;
public final int sentPackets;
public final int sentBytes;
public final float sendBitrate;
public Stats(int readBytes, float inputBitrate, int demuxReadBytes,
float demuxBitrate, int demuxCorrupted,
int demuxDiscontinuity, int decodedVideo, int decodedAudio,
int displayedPictures, int lostPictures, int playedAbuffers,
int lostAbuffers, int sentPackets, int sentBytes,
float sendBitrate) {
this.readBytes = readBytes;
this.inputBitrate = inputBitrate;
this.demuxReadBytes = demuxReadBytes;
this.demuxBitrate = demuxBitrate;
this.demuxCorrupted = demuxCorrupted;
this.demuxDiscontinuity = demuxDiscontinuity;
this.decodedVideo = decodedVideo;
this.decodedAudio = decodedAudio;
this.displayedPictures = displayedPictures;
this.lostPictures = lostPictures;
this.playedAbuffers = playedAbuffers;
this.lostAbuffers = lostAbuffers;
this.sentPackets = sentPackets;
this.sentBytes = sentBytes;
this.sendBitrate = sendBitrate;
}
}
@SuppressWarnings("unused") /* Used from JNI */
private static Stats createStatsFromNative(int readBytes,
float inputBitrate,
......@@ -426,50 +121,50 @@ public class Media extends VLCObject<Media.Event> {
/**
* Create a Media from libVLC and a local path starting with '/'.
*
* @param libVLC a valid libVLC
* @param ILibVLC a valid libVLC
* @param path an absolute local path
*/
public Media(LibVLC libVLC, String path) {
super(libVLC);
nativeNewFromPath(libVLC, path);
public Media(ILibVLC ILibVLC, String path) {
super(ILibVLC);
nativeNewFromPath(ILibVLC, path);
mUri = VLCUtil.UriFromMrl(nativeGetMrl());
}
/**
* Create a Media from libVLC and a Uri
*
* @param libVLC a valid libVLC
* @param ILibVLC a valid libVLC
* @param uri a valid RFC 2396 Uri
*/
public Media(LibVLC libVLC, Uri uri) {
super(libVLC);
nativeNewFromLocation(libVLC, VLCUtil.encodeVLCUri(uri));
public Media(ILibVLC ILibVLC, Uri uri) {
super(ILibVLC);
nativeNewFromLocation(ILibVLC, VLCUtil.encodeVLCUri(uri));
mUri = uri;
}
/**
* Create a Media from libVLC and a FileDescriptor
*
* @param libVLC a valid LibVLC
* @param ILibVLC a valid LibVLC
* @param fd file descriptor object
*/
public Media(LibVLC libVLC, FileDescriptor fd) {
super(libVLC);
nativeNewFromFd(libVLC, fd);
public Media(ILibVLC ILibVLC, FileDescriptor fd) {
super(ILibVLC);
nativeNewFromFd(ILibVLC, fd);
mUri = VLCUtil.UriFromMrl(nativeGetMrl());
}
/**
* Create a Media from libVLC and an AssetFileDescriptor
*
* @param libVLC a valid LibVLC
* @param ILibVLC a valid LibVLC
* @param afd asset file descriptor object
*/
public Media(LibVLC libVLC, AssetFileDescriptor afd) {
super(libVLC);
public Media(ILibVLC ILibVLC, AssetFileDescriptor afd) {
super(ILibVLC);
long offset = afd.getStartOffset();
long length = afd.getLength();
nativeNewFromFdWithOffsetLength(libVLC, afd.getFileDescriptor(), offset, length);
nativeNewFromFdWithOffsetLength(ILibVLC, afd.getFileDescriptor(), offset, length);
mUri = VLCUtil.UriFromMrl(nativeGetMrl());
}
......@@ -478,7 +173,7 @@ public class Media extends VLCObject<Media.Event> {
* @param ml Should not be released and locked
* @param index index of the Media from the MediaList
*/
protected Media(MediaList ml, int index) {
protected Media(IMediaList ml, int index) {
super(ml);
if (ml == null || ml.isReleased())
throw new IllegalArgumentException("MediaList is null or released");
......@@ -794,7 +489,7 @@ public class Media extends VLCObject<Media.Event> {
/**
* Enable HWDecoder options if not already set
*/
protected void setDefaultMediaPlayerOptions() {
public void setDefaultMediaPlayerOptions() {
boolean codecOptionSet;
synchronized (this) {
codecOptionSet = mCodecOptionSet;
......@@ -875,11 +570,11 @@ public class Media extends VLCObject<Media.Event> {
}
/* JNI */
private native void nativeNewFromPath(LibVLC libVLC, String path);
private native void nativeNewFromLocation(LibVLC libVLC, String location);
private native void nativeNewFromFd(LibVLC libVLC, FileDescriptor fd);
private native void nativeNewFromFdWithOffsetLength(LibVLC libVLC, FileDescriptor fd, long offset, long length);
private native void nativeNewFromMediaList(MediaList ml, int index);
private native void nativeNewFromPath(ILibVLC ILibVLC, String path);
private native void nativeNewFromLocation(ILibVLC ILibVLC, String location);
private native void nativeNewFromFd(ILibVLC ILibVLC, FileDescriptor fd);
private native void nativeNewFromFdWithOffsetLength(ILibVLC ILibVLC, FileDescriptor fd, long offset, long length);
private native void nativeNewFromMediaList(IMediaList ml, int index);
private native void nativeRelease();
private native boolean nativeParseAsync(int flags, int timeout);
private native boolean nativeParse(int flags);
......
......@@ -22,11 +22,14 @@ package org.videolan.libvlc;
import androidx.annotation.Nullable;
import org.videolan.libvlc.interfaces.AbstractVLCEvent;
import org.videolan.libvlc.interfaces.ILibVLC;
@SuppressWarnings("unused, JniMissingFunction")
public class MediaDiscoverer extends VLCObject<MediaDiscoverer.Event> {
private final static String TAG = "LibVLC/MediaDiscoverer";
public static class Event extends VLCEvent {