I am developing app to monitor IP camera using my mobile. Below is my MainActivity. I am using libVLC which uses surfaceview to show the video.
public class MainActivity extends AppCompatActivity {
Button prevButton, nextButton;
private int totalPages, currentPage;
RecyclerView recyclerView;
VideoAdapter videoAdapter;
static List<String> cameraList;
Paginator p;
@SuppressLint("AuthLeak")
private String[] vidUrlList = {
"http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4",
"https://archive.org/download/ksnn_compilation_master_the_internet/ksnn_compilation_master_the_internet_512kb.mp4",
"http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4",
"rtsp://184.72.239.149/vod/mp4:BigBuckBunny_175k.mov",
"http://live.hkstv.hk.lxdns.com/live/hks/playlist.m3u8",
"rtsp://admin:admin@192.0.0.0:200/12"
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
prevButton = (Button) findViewById(R.id.prev_btn);
nextButton = (Button) findViewById(R.id.next_btn);
prevButton.setEnabled(false);
cameraList = new ArrayList<>(Arrays.asList(vidUrlList));
p = new Paginator();
totalPages = Paginator.TOTAL_NUM_ITEMS / Paginator.ITEMS_PER_PAGE;
currentPage = 0;
videoAdapter = new VideoAdapter(this, cameraList);
final RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(this, 2);
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.addItemDecoration(new GridSpacingItemDecoration(2, dpToPx(3),
true));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(new VideoAdapter(MainActivity.this, p.generatePage(currentPage)));
nextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
currentPage += 1;
recyclerView.setAdapter(new VideoAdapter(MainActivity.this, p.generatePage(currentPage)));
toggleButtons();
}
});
prevButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
currentPage -= 1;
recyclerView.setAdapter(new VideoAdapter(MainActivity.this, p.generatePage(currentPage)));
toggleButtons();
}
});
}
@Override
public void onPause() {
super.onPause();
}
@Override
public void onDestroy() {
super.onDestroy();
}
public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
private int spanCount;
private int spacing;
private boolean includeEdge;
public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
this.spanCount = spanCount;
this.spacing = spacing;
this.includeEdge = includeEdge;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
int position = parent.getChildAdapterPosition(view);
int column = position % spanCount;
if (includeEdge) {
outRect.left = spacing - column * spacing / spanCount;
outRect.right = (column + 1) * spacing / spanCount;
if (position < spanCount) {
outRect.top = spacing;
}
outRect.bottom = spacing;
} else {
outRect.left = column * spacing / spanCount;
outRect.right = spacing - (column + 1) * spacing / spanCount;
if (position >= spanCount) {
outRect.top = spacing;
}
}
}
}
private int dpToPx(int dp) {
Resources r = getResources();
return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dp, r.getDisplayMetrics()));
}
private void toggleButtons() {
if (currentPage == totalPages) {
nextButton.setEnabled(false);
prevButton.setEnabled(true);
} else if (currentPage == 0) {
prevButton.setEnabled(false);
nextButton.setEnabled(true);
} else if (currentPage >= 1 && currentPage <= totalPages) {
nextButton.setEnabled(true);
prevButton.setEnabled(true);
}
}
public static List<String> getModifyList() {
return cameraList;
}}
I used RecylerView and CardView with Paginator option for dispaying 4 cards in each page. Since i have n number of cameras to maintain i used Paginator. Below is my Paginator Class.
public class Paginator {
static List<String> arrNewList = MainActivity.getModifyList();
public static final int TOTAL_NUM_ITEMS = arrNewList.size();
public static final int ITEMS_PER_PAGE = 4;
public static final int ITEMS_REMAINING = TOTAL_NUM_ITEMS % ITEMS_PER_PAGE;
public static final int LAST_PAGE = TOTAL_NUM_ITEMS / ITEMS_PER_PAGE;
public ArrayList<String> generatePage(int currentPage) {
int startItem = currentPage * ITEMS_PER_PAGE;
int numOfData = ITEMS_PER_PAGE;
ArrayList<String> pageData = new ArrayList<>();
if (currentPage == LAST_PAGE && ITEMS_REMAINING > 0) {
for (int i = startItem; i < startItem + ITEMS_REMAINING; i++) {
pageData.add(arrNewList.get(i));
}
} else {
for (int i = startItem; i < startItem + numOfData; i++) {
pageData.add(arrNewList.get(i));
}
}
return pageData;
}}
Here i am trying to set adapter in which video is playing only at the last postion of each page. I dont know how to solve this. I am proving my adapter code below. Here i called SurfaceHolder.Callback and IVideoPlayer interfaces. Do come up with the solution.
public class VideoAdapter extends RecyclerView.Adapter<VideoAdapter.ViewHolder>
implements SurfaceHolder.Callback, IVideoPlayer {
Context mContext;
List<String> cameraList;
SurfaceHolder surfaceHolder;
private int mVideoWidth;
private int mVideoHeight;
private final static int VideoSizeChanged = -1;
//private SurfaceView mSurfaceView;
private LibVLC libvlc;
EventHandler mEventHandler;
public VideoAdapter(Context mContext, List<String> cameraList) {
this.mContext = mContext;
this.cameraList = cameraList;
}
@Override
public VideoAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.camera_adapter, parent, false);
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(VideoAdapter.ViewHolder holder, int position) {
surfaceHolder.addCallback(this);
String urlList = cameraList.get(position);
Log.e("List1", "-->" + urlList);
createPlayer(urlList);
}
@Override
public int getItemCount() {
return cameraList.size();
}
public NativeCrashHandler.OnNativeCrashListener nativecrashListener = new NativeCrashHandler.OnNativeCrashListener() {
@Override
public void onNativeCrash() {
Log.e("vlcdebug", "nativecrash");
}
};
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.e("mylog", "surfaceCreated");
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
try {
if (libvlc != null) {
Log.e("mylog", "libvlc != null");
libvlc.attachSurface(surfaceHolder.getSurface(), this);
} else {
Log.e("mylog", "libvlc == null");
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.e("mylog", "surfaceDestroyed");
}
public class ViewHolder extends RecyclerView.ViewHolder {
private SurfaceView mSurfaceView;
public ViewHolder(View itemView) {
super(itemView);
mSurfaceView = itemView.findViewById(R.id.player_surface);
surfaceHolder = mSurfaceView.getHolder();
}
}
private void createPlayer(String vidUrlList) {
//releasePlayer();
try {
libvlc = new LibVLC();
mEventHandler = libvlc.getEventHandler();
libvlc.init(mContext);
libvlc.setHardwareAcceleration(LibVLC.HW_ACCELERATION_FULL);
libvlc.setSubtitlesEncoding("");
libvlc.setAout(LibVLC.AOUT_OPENSLES);
libvlc.setTimeStretching(true);
libvlc.setVerboseMode(true);
libvlc.setNetworkCaching(1000);
NativeCrashHandler.getInstance().setOnNativeCrashListener(
nativecrashListener);
if (LibVlcUtil.isGingerbreadOrLater())
libvlc.setVout(LibVLC.VOUT_ANDROID_WINDOW);
else
libvlc.setVout(LibVLC.VOUT_ANDROID_SURFACE);
LibVLC.restartInstance(mContext);
mEventHandler.addHandler(mHandler);
surfaceHolder.setKeepScreenOn(true);
MediaList list = libvlc.getMediaList();
list.clear();
list.add(new Media(libvlc, LibVLC.PathToURI(vidUrlList)), false);
//list.add(new Media(libvlc, LibVLC.PathToURI(media)), false);
//list.add(new Media(libvlc, LibVLC.PathToURI(media)), false);
libvlc.playIndex(0);
} catch (Exception e) {
Toast.makeText(mContext, "Error creating player!", Toast.LENGTH_SHORT).show();
}
}
private void releasePlayer() {
try {
EventHandler.getInstance().removeHandler(mHandler);
//libvlc.stop();
libvlc.detachSurface();
surfaceHolder = null;
libvlc.closeAout();
libvlc.destroy();
libvlc = null;
mVideoWidth = 0;
mVideoHeight = 0;
} catch (Exception e) {
e.printStackTrace();
}
}
private Handler mHandler = new MyHandler(this);
@Override
public void setSurfaceLayout(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den) {
Message msg = Message.obtain(mHandler, VideoSizeChanged, width,
height);
msg.sendToTarget();
}
@Override
public int configureSurface(Surface surface, int width, int height, int hal) {
Log.d("", "configureSurface: width = " + width + ", height = "
+ height);
if (LibVlcUtil.isICSOrLater() || surface == null)
return -1;
if (width * height == 0)
return 0;
if (hal != 0)
surfaceHolder.setFormat(hal);
surfaceHolder.setFixedSize(width, height);
return 1;
}
@Override
public void eventHardwareAccelerationError() {
//releasePlayer();
Toast.makeText(mContext, "Error with hardware acceleration",
Toast.LENGTH_SHORT).show();
}
@Override
public void setSurfaceSize(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den) {
}
@SuppressLint("HandlerLeak")
private class MyHandler extends Handler {
private WeakReference<VideoAdapter> mOwner;
MyHandler(VideoAdapter owner) {
mOwner = new WeakReference<>(owner);
}
@Override
public void handleMessage(Message msg) {
try {
VideoAdapter player = mOwner.get();
Log.e("mylog", "handleMessage " + msg.toString());
// Libvlc events
Bundle b = msg.getData();
Log.e("mylog", "handleMessage " + msg.getData());
switch (b.getInt("event")) {
case EventHandler.MediaPlayerEndReached:
Log.e("mylog", "MediaPlayerEndReached");
player.releasePlayer();
break;
case EventHandler.MediaPlayerPlaying:
Log.e("mylog", "MediaPlayerPlaying");
break;
case EventHandler.MediaPlayerPaused:
Log.e("mylog", "MediaPlayerPaused");
break;
case EventHandler.MediaPlayerStopped:
Log.e("mylog", "MediaPlayerStopped");
break;
case EventHandler.MediaPlayerPositionChanged:
Log.i("vlc", "MediaPlayerPositionChanged");
//VideoAdapter.this.notify();
break;
case EventHandler.MediaPlayerEncounteredError:
break;
default:
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}}