package com.exovlc;
import org.videolan.libvlc.IVideoPlayer;
import org.videolan.libvlc.LibVLC;
import org.videolan.libvlc.LibVlcUtil;
import android.os.Handler;
import android.os.Looper;
import android.view.Surface;
import android.view.SurfaceHolder;// Fixe me plz
import com.google.android.exoplayer.ExoPlaybackException;
import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
public class VLCVideoSurfaceHandler implements IVideoPlayer {
public enum Start_Type {
START_DELAYED, STARTED_IMMEDIATELY
};
public static interface SurfaceLayoutHandler {
int SURFACE_BEST_FIT = 0;
int SURFACE_FIT_HORIZONTAL = 1;
int SURFACE_FIT_VERTICAL = 2;
int SURFACE_FILL = 3;
int SURFACE_16_9 = 4;
int SURFACE_4_3 = 5;
int SURFACE_ORIGINAL = 6;
/**
* This method is called by native vout to request a new layout.
*
* @param width
* Frame width
* @param height
* Frame height
*/
void setSurfaceLayout(int layout_width,int layout_wheight);
SurfaceHolder getHolder();
int getPreferedSurfaceHeight();
int getPreferedSurfaceWidth();
int getSurfaceFit();
void setNewSurface(Surface surface);
int configureSurface(Surface surface, final int width, final int height, final int hal);
}
private final LibVLC libvlc;
private final Handler eventHandler;
private final MediaCodecVideoTrackRenderer.EventListener eventListener;
private Surface mSurface;
private boolean mSurfaceReady;
private Runnable postStartJob;
private SurfaceLayoutHandler layoutHandler;
public VLCVideoSurfaceHandler( LibVLC libvlc, Handler eventHandler,
MediaCodecVideoTrackRenderer.EventListener eventListener, SurfaceLayoutHandler layoutHandler) throws ExoPlaybackException {
super();
this.libvlc = libvlc;
this.eventHandler = eventHandler;
this.eventListener = eventListener;
if (layoutHandler != null) {
this.layoutHandler = layoutHandler;
SurfaceHolder surfaceHolder = layoutHandler.getHolder();
ExoVlcUtil.log(this, "VLCIVideoSurfaceHandler.VLCIVideoSurfaceHandler()");
ExoVlcUtil.log(this, "## ====> rect= " + surfaceHolder.getSurfaceFrame());
if (com.exovlc.ExoVlcUtil.validSurface(surfaceHolder))
setVlcSurface(surfaceHolder.getSurface(), false);
} else
throw new ExoPlaybackException("layout handler null.");
}
void setVlcSurface(Surface newSurface, boolean forced) {
if (mSurface != newSurface || forced || !mSurfaceReady) {
mSurface = newSurface;
if(this.layoutHandler != null)
this.layoutHandler.setNewSurface(newSurface);
ExoVlcUtil.log(this, "setVlcSurface: " + mSurface);
SurfaceHolder surfaceHolder = layoutHandler.getHolder();
mSurfaceReady = (surfaceHolder.getSurface() == newSurface && ExoVlcUtil.validSurface(surfaceHolder));
ExoVlcUtil.log(this, "VLCIVideoSurfaceHandler.setVlcSurface() set surface s =" + newSurface + " , f="
+ forced + " mSurfaceReady =" + mSurfaceReady + " postStartJob=" + postStartJob);
if (mSurfaceReady && postStartJob != null)
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Thread.dumpStack();
Runnable r = postStartJob;
postStartJob = null;
synchronized (VLCVideoSurfaceHandler.this) {
if (r != null) {
VLCVideoSurfaceHandler.this.attachVlcSurface(mSurface);
r.run();
}
}
}
});
}
}
Start_Type doStart(Runnable toDo) {
ExoVlcUtil.log(this, "doStart(): mSurfaceReady " + mSurfaceReady);
if (isSurfaceReady()) {
attachVlcSurface(mSurface);
return Start_Type.STARTED_IMMEDIATELY;
}
postStartJob = toDo;
return Start_Type.START_DELAYED;
}
boolean isSurfaceReady() {
return mSurfaceReady;
}
@Override
public void setSurfaceLayout(final int width, final int height, final int visible_width, final int visible_height,
final int sar_num, final int sar_den) {
Thread.dumpStack();
ExoVlcUtil.log(this, "> VideoActivity.setSurfaceLayout( " + width + ", " + height + ", " + visible_width + ","
+ visible_height + ", " + sar_num + ", " + sar_den + ")");
int sw;
int sh;
SurfaceLayoutHandler lh =this.layoutHandler;
if(lh ==null)
return;
// get screen size
sw = lh.getPreferedSurfaceWidth();
sh=lh.getPreferedSurfaceHeight();
System.out.println("VLCIVideoSurfaceHandler.changeSurfaceLayout() window = " + sw + " x " + sh);
System.out.println("VLCIVideoSurfaceHandler.changeSurfaceLayout() mVideoWidth=" + width
+ " mVideoHeight=" + height);
System.out.println("VLCIVideoSurfaceHandler.changeSurfaceLayout() mSarDen=" + sar_den + " mSarNum="
+ sar_num);
if (libvlc != null && !libvlc.useCompatSurface())
libvlc.setWindowSize(sw, sh);
double dw = sw, dh = sh;
boolean isPortrait;
isPortrait = false;
if (sw > sh && isPortrait || sw < sh && !isPortrait) {
dw = sh;
dh = sw;
}
// sanity check
if (dw * dh == 0 || width * height == 0) {
ExoVlcUtil.log(this, "Invalid surface size");
return;
}
// compute the aspect ratio
double ar, vw;
if (sar_den == sar_num) {
/* No indication about the density, assuming 1:1 */
vw = visible_width;
ar = (double) visible_width / (double) visible_height;
} else {
/* Use the specified aspect ratio */
vw = visible_width * (double) sar_num / sar_den;
ar = vw / visible_height;
}
// compute the display aspect ratio
double dar = dw / dh;
switch (lh.getSurfaceFit()) {
case SurfaceLayoutHandler.SURFACE_BEST_FIT:
if (dar < ar)
dh = dw / ar;
else
dw = dh * ar;
break;
case SurfaceLayoutHandler.SURFACE_FIT_HORIZONTAL:
dh = dw / ar;
break;
case SurfaceLayoutHandler.SURFACE_FIT_VERTICAL:
dw = dh * ar;
break;
case SurfaceLayoutHandler.SURFACE_FILL:
break;
case SurfaceLayoutHandler.SURFACE_16_9:
ar = 16.0 / 9.0;
if (dar < ar)
dh = dw / ar;
else
dw = dh * ar;
break;
case SurfaceLayoutHandler.SURFACE_4_3:
ar = 4.0 / 3.0;
if (dar < ar)
dh = dw / ar;
else
dw = dh * ar;
break;
case SurfaceLayoutHandler.SURFACE_ORIGINAL:
dh = visible_height;
dw = vw;
break;
}
// set display size
final int layout_width = (int) Math.ceil(dw * width / visible_width);
final int layout_wheight = (int) Math.ceil(dh * height / visible_height);
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
SurfaceLayoutHandler lh = VLCVideoSurfaceHandler.this.layoutHandler;
if (lh != null)
lh.setSurfaceLayout(layout_width,layout_wheight);
}
});
}
private static class ConfigureSurfaceHolder {
private final Surface surface;
private boolean configured;
private ConfigureSurfaceHolder(Surface surface) {
this.surface = surface;
}
}
@Override
public int configureSurface(Surface surface, final int width, final int height, final int hal) {
if (LibVlcUtil.isICSOrLater() || surface == null)
return -1;
if (width * height == 0)
return 0;
ExoVlcUtil.log(this, "configureSurface: " + width + "x" + height);
final ConfigureSurfaceHolder holder = new ConfigureSurfaceHolder(surface);
final Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
if (mSurface == holder.surface) {
SurfaceHolder surfaceHolder = layoutHandler.getHolder();
if (hal != 0)
surfaceHolder.setFormat(hal);
surfaceHolder.setFixedSize(width, height);
}
synchronized (holder) {
holder.configured = true;
holder.notifyAll();
}
}
});
try {
synchronized (holder) {
while (!holder.configured)
holder.wait();
}
} catch (InterruptedException e) {
return 0;
}
return 1;
}
@Override
public void eventHardwareAccelerationError() {
// TODO Auto-generated method stub
ExoVlcUtil.log(this, "Error with hardware acceleration");
release();
notifyDecoderInitializationError(new DecoderInitializationException(null, new RuntimeException(
"Error with hardware acceleration"), 0));
}
private void handlerPost(Runnable postAction) {
if (eventHandler != null && eventListener != null) {
eventHandler.post(postAction);
}
}
private void notifyDecoderInitializationError(final DecoderInitializationException e) {
handlerPost(new Runnable() {
@Override
public void run() {
eventListener.onDecoderInitializationError(e);
}
});
}
void release() {
this.libvlc.detachSurface();
}
private void attachVlcSurface(Surface surface) {
if (mSurfaceReady)
libvlc.detachSurface();
if (surface != null) {
ExoVlcUtil.log(this, " VLCIVideoSurfaceHandler.attachVlcSurface() Setting lib vlc with surface : "
+ surface);
libvlc.attachSurface(surface, this);
}
}
}