我几乎有一个成功运行的 vlc for android 代码示例。我一直以 VideoPlayerActivity 为例。
目前我通过surfacehandler显示了表面,我看到了一个黑色的视频图像背景框(SurfaceView)。我也有工作音频。但是由于某种原因,我无法获得任何视频。Logcat 连续说以下内容:
yuv_rgb_neon:无法获取视频图片。
我认为这是我的代码中的一个非常小的问题。我几乎尝试了我能想到的任何东西,但我无法让它发挥作用。
谁能指出我正确的方向?
这是我使用的核心 libvlc 代码:我认为 init 上下文参数有问题,但我似乎无法找出它是什么。(我与位于 org.videloan.vlc.gui.video 中的原始 VideoPlayerActivity 具有相同的表面处理程序)
mLibVLC = LibVLC.getInstance();
mLibVLC.setIomx(false);
mLibVLC.setSubtitlesEncoding("");
mLibVLC.setTimeStretching(false);
mLibVLC.setFrameSkip(true);
mLibVLC.setChroma("RV16");
mLibVLC.setVerboseMode(true);
mLibVLC.setAout(-1);
mLibVLC.setDeblocking(0);
mLibVLC.setNetworkCaching(0);
mLibVLC.init(this.getApplicationContext());
完整的代码片段:
/* VideoPlayerActivity.java */
package com.example.mp2;
import java.lang.reflect.Method;
import org.videolan.libvlc.EventHandler;
import org.videolan.libvlc.IVideoPlayer;
import org.videolan.libvlc.LibVLC;
import org.videolan.libvlc.LibVlcException;
import org.videolan.vlc.Util;
import org.videolan.vlc.WeakHandler;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View.OnSystemUiVisibilityChangeListener;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.widget.FrameLayout;
public class VideoPlayerActivity extends Activity implements IVideoPlayer {
public final static String TAG = "VLC/VideoPlayerActivity";
// Internal intent identifier to distinguish between internal launch and
// external intent.
private SurfaceView mSurface;
private SurfaceHolder mSurfaceHolder;
private FrameLayout mSurfaceFrame;
private LibVLC mLibVLC;
private String mLocation;
private static final int SURFACE_BEST_FIT = 0;
private static final int SURFACE_FIT_HORIZONTAL = 1;
private static final int SURFACE_FIT_VERTICAL = 2;
private static final int SURFACE_FILL = 3;
private static final int SURFACE_16_9 = 4;
private static final int SURFACE_4_3 = 5;
private static final int SURFACE_ORIGINAL = 6;
private int mCurrentSize = SURFACE_BEST_FIT;
/** Overlay */
private static final int SURFACE_SIZE = 3;
// size of the video
private int mVideoHeight;
private int mVideoWidth;
private int mVideoVisibleHeight;
private int mVideoVisibleWidth;
private int mSarNum;
private int mSarDen;
private static VideoPlayerActivity context;
public static VideoPlayerActivity getContext() {
return context;
}
/**
* Used to store a selected subtitle; see onActivityResult. It is possible
* to have multiple custom subs in one session (just like desktop VLC allows
* you as well.)
*/@Override@TargetApi(Build.VERSION_CODES.HONEYCOMB)
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.player);
if (Util.isICSOrLater()) getWindow().getDecorView().findViewById(android.R.id.content).setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() {@Override
public void onSystemUiVisibilityChange(int visibility) {
setSurfaceSize(mVideoWidth, mVideoHeight, mVideoVisibleWidth, mVideoVisibleHeight, mSarNum, mSarDen);
}
});
mSurface = (SurfaceView) findViewById(R.id.player_surface);
mSurfaceHolder = mSurface.getHolder();
mSurfaceFrame = (FrameLayout) findViewById(R.id.player_surface_frame);
String chroma = "RV16";
context = this;
if (Util.isGingerbreadOrLater() && chroma.equals("YV12")) {
mSurfaceHolder.setFormat(ImageFormat.YV12);
} else if (chroma.equals("RV16")) {
mSurfaceHolder.setFormat(PixelFormat.RGB_565);
} else {
mSurfaceHolder.setFormat(PixelFormat.RGBX_8888);
}
mSurfaceHolder.addCallback(mSurfaceCallback);
try {
mLibVLC = LibVLC.getInstance();
mLibVLC.setIomx(false);
mLibVLC.setSubtitlesEncoding("");
mLibVLC.setTimeStretching(false);
mLibVLC.setFrameSkip(true);
mLibVLC.setChroma("RV16");
mLibVLC.setVerboseMode(true);
mLibVLC.setAout(-1);
mLibVLC.setDeblocking(0);
mLibVLC.setNetworkCaching(0);
mLibVLC.init(this.getApplicationContext());
} catch (LibVlcException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
EventHandler em = EventHandler.getInstance();
em.addHandler(eventHandler);
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onPause() {
super.onPause();
mLibVLC.stop();
mSurface.setKeepScreenOn(false);
}
@Override
protected void onStop() {
super.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mLibVLC != null) {
mLibVLC.stop();
}
}
@Override
protected void onResume() {
super.onResume();
load();
}
private final Handler eventHandler = new VideoPlayerEventHandler(this);
private static class VideoPlayerEventHandler extends WeakHandler < VideoPlayerActivity > {
public VideoPlayerEventHandler(VideoPlayerActivity owner) {
super(owner);
}
@Override
public void handleMessage(Message msg) {
VideoPlayerActivity activity = getOwner();
if (activity == null) return;
switch (msg.getData().getInt("event")) {
case EventHandler.MediaPlayerPlaying:
Log.i(TAG, "MediaPlayerPlaying");
// activity.setESTracks();
// activity.setESTracks();
break;
case EventHandler.MediaPlayerPaused:
Log.i(TAG, "MediaPlayerPaused");
break;
case EventHandler.MediaPlayerStopped:
Log.i(TAG, "MediaPlayerStopped");
break;
case EventHandler.MediaPlayerEndReached:
Log.i(TAG, "MediaPlayerEndReached");
// activity.endReached();
break;
case EventHandler.MediaPlayerVout:
// activity.handleVout(msg);
break;
case EventHandler.MediaPlayerPositionChanged:
// don't spam the logs
break;
case EventHandler.MediaPlayerEncounteredError:
Log.i(TAG, "MediaPlayerEncounteredError");
// activity.encounteredError();
break;
default:
Log.e(TAG, String.format("Event not handled (0x%x)", msg.getData().getInt("event")));
break;
}
// activity.updateOverlayPausePlay();
}
};
private final Handler mHandler = new VideoPlayerHandler(this);
private static class VideoPlayerHandler extends WeakHandler < VideoPlayerActivity > {
public VideoPlayerHandler(VideoPlayerActivity owner) {
super(owner);
}
@Override
public void handleMessage(Message msg) {
VideoPlayerActivity activity = getOwner();
if (activity == null) // WeakReference could be GC'ed early
return;
switch (msg.what) {
case SURFACE_SIZE:
activity.changeSurfaceSize();
break;
}
}
};
@Override
public void setSurfaceSize(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den) {
if (width * height == 0) return;
// store video size
mVideoHeight = height;
mVideoWidth = width;
mVideoVisibleHeight = visible_height;
mVideoVisibleWidth = visible_width;
mSarNum = sar_num;
mSarDen = sar_den;
Message msg = mHandler.obtainMessage(SURFACE_SIZE);
mHandler.sendMessage(msg);
}
private void changeSurfaceSize() {
// get screen size
int dw = getWindow().getDecorView().getWidth();
int dh = getWindow().getDecorView().getHeight();
// getWindow().getDecorView() doesn't always take orientation into
// account, we have to correct the values
boolean isPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
if (dw > dh && isPortrait || dw < dh && !isPortrait) {
int d = dw;
dw = dh;
dh = d;
}
// sanity check
if (dw * dh == 0 || mVideoWidth * mVideoHeight == 0) {
Log.e(TAG, "Invalid surface size");
return;
}
// compute the aspect ratio
double ar, vw;
double density = (double) mSarNum / (double) mSarDen;
if (density == 1.0) {
/* No indication about the density, assuming 1:1 */
vw = mVideoVisibleWidth;
ar = (double) mVideoVisibleWidth / (double) mVideoVisibleHeight;
} else {
/* Use the specified aspect ratio */
vw = mVideoVisibleWidth * density;
ar = vw / mVideoVisibleHeight;
}
// compute the display aspect ratio
double dar = (double) dw / (double) dh;
switch (mCurrentSize) {
case SURFACE_BEST_FIT:
if (dar < ar) dh = (int)(dw / ar);
else dw = (int)(dh * ar);
break;
case SURFACE_FIT_HORIZONTAL:
dh = (int)(dw / ar);
break;
case SURFACE_FIT_VERTICAL:
dw = (int)(dh * ar);
break;
case SURFACE_FILL:
break;
case SURFACE_16_9:
ar = 16.0 / 9.0;
if (dar < ar) dh = (int)(dw / ar);
else dw = (int)(dh * ar);
break;
case SURFACE_4_3:
ar = 4.0 / 3.0;
if (dar < ar) dh = (int)(dw / ar);
else dw = (int)(dh * ar);
break;
case SURFACE_ORIGINAL:
dh = mVideoVisibleHeight;
dw = (int) vw;
break;
}
// force surface buffer size
// mSurfaceHolder.setFixedSize(mVideoWidth, mVideoHeight);
// set display size
LayoutParams lp = mSurface.getLayoutParams();
lp.width = dw * mVideoWidth / mVideoVisibleWidth;
lp.height = dh * mVideoHeight / mVideoVisibleHeight;
mSurface.setLayoutParams(lp);
// set frame size (crop if necessary)
lp = mSurfaceFrame.getLayoutParams();
lp.width = dw;
lp.height = dh;
mSurfaceFrame.setLayoutParams(lp);
mSurface.invalidate();
}
private final SurfaceHolder.Callback mSurfaceCallback = new Callback() {@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (format == PixelFormat.RGBX_8888) Log.d(TAG, "Pixel format is RGBX_8888");
else if (format == PixelFormat.RGB_565) Log.d(TAG, "Pixel format is RGB_565");
else if (format == ImageFormat.YV12) Log.d(TAG, "Pixel format is YV12");
else Log.d(TAG, "Pixel format is other/unknown");
mLibVLC.attachSurface(holder.getSurface(), VideoPlayerActivity.this, width, height);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mLibVLC.detachSurface();
}
};
/**
* External extras: - position (long) - position of the video to start with
* (in ms)
*/
private void load() {
mLocation = "file:///sdcard/fam.mp4";
mSurface.setKeepScreenOn(true);
// MediaList mediaList = new MediaList(mLibVLC);
// mLibVLC.setMediaList();
mLibVLC.readMedia(mLocation, false);
mLibVLC.setTime(0);
mLibVLC.play();
}
@SuppressWarnings("deprecation")
private int getScreenRotation() {
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO
/*
* Android 2.2
* has
* getRotation
*/
) {
try {
Method m = display.getClass().getDeclaredMethod("getRotation");
return (Integer) m.invoke(display);
} catch (Exception e) {
return Surface.ROTATION_0;
}
} else {
return display.getOrientation();
}
}
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
private int getScreenOrientation() {
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
int rot = getScreenRotation();
/*
* Since getRotation() returns the screen's "natural" orientation, which
* is not guaranteed to be SCREEN_ORIENTATION_PORTRAIT, we have to
* invert the SCREEN_ORIENTATION value if it is "naturally" landscape.
*/@SuppressWarnings("deprecation")
boolean defaultWide = display.getWidth() > display.getHeight();
if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) defaultWide = !defaultWide;
if (defaultWide) {
switch (rot) {
case Surface.ROTATION_0:
return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
case Surface.ROTATION_90:
return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
case Surface.ROTATION_180:
// SCREEN_ORIENTATION_REVERSE_PORTRAIT only available since API
// Level 9+
return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
case Surface.ROTATION_270:
// SCREEN_ORIENTATION_REVERSE_LANDSCAPE only available since API
// Level 9+
return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
default:
return 0;
}
} else {
switch (rot) {
case Surface.ROTATION_0:
return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
case Surface.ROTATION_90:
return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
case Surface.ROTATION_180:
// SCREEN_ORIENTATION_REVERSE_PORTRAIT only available since API
// Level 9+
return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
case Surface.ROTATION_270:
// SCREEN_ORIENTATION_REVERSE_LANDSCAPE only available since API
// Level 9+
return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO ? ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE : ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
default:
return 0;
}
}
}
}