我正在尝试使用Android应用中附加到树莓派的相机创建实时流。
以下是活动的代码:
public class Stream extends AppCompatActivity implements IVLCVout.Callback, LibVLC.OnNativeCrashListener {
public final static String TAG = "LibVLCAndroid/Stream";
//public final static String LOCATION = "com.compdigitec.libvlcandroidsample.VideoActivity.location";
private String mFilePath;
// display surface
private SurfaceView mSurface;
private SurfaceHolder holder;
// media player
private LibVLC libvlc;
private MediaPlayer mMediaPlayer = null;
private int mVideoWidth;
private int mVideoHeight;
private final static int VideoSizeChanged = -1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stream);
// Receive path to play from intent
Intent intent = getIntent();
mFilePath = "http://70.122.174.124:691";
Log.d(TAG, "Playing back " + mFilePath);
mSurface = (SurfaceView) findViewById(R.id.surface);
holder = mSurface.getHolder();
//holder.addCallback(this);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setSize(mVideoWidth, mVideoHeight);
}
@Override
protected void onResume() {
super.onResume();
createPlayer(mFilePath);
}
@Override
protected void onPause() {
super.onPause();
releasePlayer();
}
@Override
protected void onDestroy() {
super.onDestroy();
releasePlayer();
}
private void setSize(int width, int height) {
mVideoWidth = width;
mVideoHeight = height;
if (mVideoWidth * mVideoHeight <= 1)
return;
if(holder == null || mSurface == null)
return;
// get screen size
int w = getWindow().getDecorView().getWidth();
int h = 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 (w > h && isPortrait || w < h && !isPortrait) {
int i = w;
w = h;
h = i;
}
float videoAR = (float) mVideoWidth / (float) mVideoHeight;
float screenAR = (float) w / (float) h;
if (screenAR < videoAR)
h = (int) (w / videoAR);
else
w = (int) (h * videoAR);
// force surface buffer size
holder.setFixedSize(mVideoWidth, mVideoHeight);
// set display size
LayoutParams lp = mSurface.getLayoutParams();
lp.width = w;
lp.height = h;
mSurface.setLayoutParams(lp);
mSurface.invalidate();
}
private void createPlayer(String media) {
releasePlayer();
try {
if (media.length() > 0) {
Toast toast = Toast.makeText(this, media, Toast.LENGTH_LONG);
toast.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0,
0);
toast.show();
}
// Create LibVLC
// TODO: make this more robust, and sync with audio demo
ArrayList<String> options = new ArrayList<>();
//options.add("--subsdec-encoding <encoding>");
options.add("-vvv"); // verbosity
libvlc = new LibVLC(options);
libvlc.setOnNativeCrashListener(this);
holder.setKeepScreenOn(true);
// Create media player
mMediaPlayer = new MediaPlayer(libvlc);
mMediaPlayer.setEventListener(mPlayerListener);
// Set up video output
final IVLCVout vout = mMediaPlayer.getVLCVout();
vout.setVideoView(mSurface);
//vout.setSubtitlesView(mSurfaceSubtitles);
vout.addCallback(this);
vout.attachViews();
Media m = new Media(libvlc, media);
mMediaPlayer.setMedia(m);
mMediaPlayer.play();
} catch (Exception e) {
Toast.makeText(this, "Error creating player!", Toast.LENGTH_LONG).show();
}
}
// TODO: handle this cleaner
private void releasePlayer() {
if (libvlc == null)
return;
mMediaPlayer.stop();
final IVLCVout vout = mMediaPlayer.getVLCVout();
vout.removeCallback(this);
vout.detachViews();
holder = null;
libvlc.release();
libvlc = null;
mVideoWidth = 0;
mVideoHeight = 0;
}
private MediaPlayer.EventListener mPlayerListener = new MyPlayerListener(this);
@Override
public void onNewLayout(IVLCVout vout, int width, int height, int visibleWidth, int visibleHeight, int sarNum, int sarDen) {
if (width * height == 0)
return;
// store video size
mVideoWidth = width;
mVideoHeight = height;
setSize(mVideoWidth, mVideoHeight);
}
@Override
public void onHardwareAccelerationError(IVLCVout vlcVout) {
// Handle errors with hardware acceleration
Log.e(TAG, "Error with hardware acceleration");
this.releasePlayer();
Toast.makeText(this, "Error with hardware acceleration", Toast.LENGTH_LONG).show();
}
@Override
public void onSurfacesCreated(IVLCVout vout) {
}
@Override
public void onSurfacesDestroyed(IVLCVout vout) {
}
private static class MyPlayerListener implements MediaPlayer.EventListener {
private WeakReference<Stream> mOwner;
public MyPlayerListener(Stream owner) {
mOwner = new WeakReference<>(owner);
}
@Override
public void onEvent(MediaPlayer.Event event) {
Stream player = mOwner.get();
switch(event.type) {
case MediaPlayer.Event.EndReached:
Log.d(TAG, "MediaPlayerEndReached");
player.releasePlayer();
break;
case MediaPlayer.Event.Playing:
case MediaPlayer.Event.Paused:
case MediaPlayer.Event.Stopped:
default:
break;
}
}
}
@Override
public void onNativeCrash() {
// Handle errors with hardware acceleration
Log.e(TAG, "Native Crash");
this.releasePlayer();
Toast.makeText(this, "Native Crash", Toast.LENGTH_LONG).show();
}
}
和XML:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
android:orientation="vertical"
tools:context="rpi.rpicam.Stream" >
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<SurfaceView
android:id="@+id/surface"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center" />
</FrameLayout>
</LinearLayout>
但是,当我运行应用程序时,我在日志中遇到以下错误:
12-20 14:23:03.790 7775-1067/rpi.rpicam E/VLC: [0000007f4a5df0b8] filesystem access: cannot open file //http://70.122.174.124:691 (No such file or directory)
12-20 14:23:03.790 7775-1067/rpi.rpicam E/VLC: [0000007f4a5df0b8] core access: File reading failed
12-20 14:23:03.790 7775-1067/rpi.rpicam E/VLC: [0000007f4a5df0b8] core access: VLC could not open the file "//http://70.122.174.124:691" (No such file or directory).
12-20 14:23:03.790 7775-1067/rpi.rpicam D/VLC: [0000007f4a5df0b8] core access: no access modules matched
12-20 14:23:03.790 7775-1067/rpi.rpicam E/VLC: [0000007f7bf759b8] core input source: cannot access file:////http%3A//70.122.174.124%3A691
12-20 14:23:03.790 7775-1067/rpi.rpicam E/VLC: [0000007f70a3f4b8] core input: Your input can't be opened
12-20 14:23:03.790 7775-1067/rpi.rpicam E/VLC: [0000007f70a3f4b8] core input: VLC is unable to open the MRL 'file:////http%3A//70.122.174.124%3A691'. Check the log for details.
我很清楚,问题是VLC认为我正在尝试访问存储在设备上的文件,而不是从http流式传输视频。
我试过搜索堆栈溢出和VLC文档,但似乎没有太多文档,我无法弄清楚如何让VLC识别出这是一个http流。
其他细节: 我已经通过我的Ubuntu桌面上的VLC和官方VLC Android应用程序测试了流正在工作
当我开始对应上面代码的活动时,我看到的只是一个黑屏
答案 0 :(得分:0)
有一些Media
构造函数。将String
作为第二个参数的文档记录为期望该参数为本地文件路径。
(恕我直言,这不是一个很棒的API设计 - 使用File
个对象)
还有另一个Media
构造函数,它将Uri
作为参数;这可能适用于其他类型的方案,例如https
。