我知道是否可以在同一布局中使用两个表面并同时查看每个表面。将来我会看一个视频视图的网格视图,但每个视频视图都使用vlc。
我使用片段修改此样本(android-vlc-sample)。
结果是我只看到一个视频......我该如何解决?
从log-cat我看不到重要的错误,但我认为android UIThread存在渲染问题
Java编码
public class MultipleVideoPlayFragmentActivity extends FragmentActivity {
public final static String LOCATION = "com.compdigitec.libvlcandroidsample.MultipleVideoPlayFragmentActivity.location";
private static final String TAG = "MediaPlayer";
public String mFilePatha;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.activity_multiple_video_play_fragment);
Intent intent = getIntent();
mFilePatha = intent.getExtras().getString(LOCATION);
}
public static class VideoFragment extends Fragment implements
SurfaceHolder.Callback, IVideoPlayer {
public final static String TAG = "LibVLCAndroidSample/VideoActivity";
public final static String LOCATION = "com.compdigitec.libvlcandroidsample.VideoFragment.location";
private String mFilePath;
// display surface
private SurfaceView mSurface;
private SurfaceHolder holder;
// media player
private LibVLC libvlc;
private int mVideoWidth;
private int mVideoHeight;
private final static int VideoSizeChanged = -1;
/*************
* Activity
*************/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.sample, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Receive path to play from intent
Log.d(TAG, "Playing back " + mFilePath);
mFilePath = ((MultipleVideoPlayFragmentActivity) getActivity()).mFilePatha;
// mFilePath="rtsp://192.168.4.125:554/0";
// mFilePath="android.resource://it.nexera.visiamobile/raw/sample_mpeg4";
mSurface = (SurfaceView) getView().findViewById(R.id.surface);
holder = mSurface.getHolder();
holder.addCallback(this);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setSize(mVideoWidth, mVideoHeight);
}
@Override
public void onResume() {
super.onResume();
createPlayer(mFilePath);
}
@Override
public void onPause() {
super.onPause();
releasePlayer();
}
@Override
public void onDestroy() {
super.onDestroy();
releasePlayer();
}
/*************
* Surface
*************/
public void surfaceCreated(SurfaceHolder holder) {
}
public void surfaceChanged(SurfaceHolder surfaceholder, int format,
int width, int height) {
if (libvlc != null)
libvlc.attachSurface(holder.getSurface(), this);
}
public void surfaceDestroyed(SurfaceHolder surfaceholder) {
}
private void setSize(int width, int height) {
mVideoWidth = width;
mVideoHeight = height;
if (mVideoWidth * mVideoHeight <= 1)
return;
// get screen size
int w = getActivity().getWindow().getDecorView().getWidth();
int h = getActivity().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();
}
@Override
public void setSurfaceSize(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();
}
/*************
* Player
*************/
private void createPlayer(String media) {
releasePlayer();
try {
if (media.length() > 0) {
Toast toast = Toast.makeText(this.getActivity(), media,
Toast.LENGTH_LONG);
toast.setGravity(
Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);
toast.show();
}
// Create a new media player
libvlc = LibVLC.getInstance();
libvlc.setHardwareAcceleration(LibVLC.HW_ACCELERATION_DISABLED);
libvlc.setSubtitlesEncoding("");
libvlc.setAout(LibVLC.AOUT_OPENSLES);
libvlc.setTimeStretching(true);
libvlc.setChroma("RV32");
libvlc.setVerboseMode(true);
// LibVLC.restart(this.getActivity());
EventHandler.getInstance().addHandler(mHandler);
holder.setFormat(PixelFormat.RGBX_8888);
holder.setKeepScreenOn(true);
MediaList list = libvlc.getMediaList();
list.clear();
list.add(new Media(libvlc, LibVLC.PathToURI(media)), false);
libvlc.playIndex(0);
} catch (Exception e) {
Toast.makeText(this.getActivity(), "Error creating player!",
Toast.LENGTH_LONG).show();
}
}
private void releasePlayer() {
if (libvlc == null)
return;
EventHandler.getInstance().removeHandler(mHandler);
libvlc.stop();
libvlc.detachSurface();
holder = null;
libvlc.closeAout();
libvlc.destroy();
libvlc = null;
mVideoWidth = 0;
mVideoHeight = 0;
}
/*************
* Events
*************/
private Handler mHandler = new MyHandler(this);
private static class MyHandler extends Handler {
private WeakReference<VideoFragment> mOwner;
public MyHandler(VideoFragment owner) {
mOwner = new WeakReference<VideoFragment>(owner);
}
@Override
public void handleMessage(Message msg) {
VideoFragment player = mOwner.get();
// SamplePlayer events
if (msg.what == VideoSizeChanged) {
player.setSize(msg.arg1, msg.arg2);
return;
}
// Libvlc events
Bundle b = msg.getData();
switch (b.getInt("event")) {
case EventHandler.MediaPlayerEndReached:
player.releasePlayer();
break;
case EventHandler.MediaPlayerPlaying:
case EventHandler.MediaPlayerPaused:
case EventHandler.MediaPlayerStopped:
default:
break;
}
}
}
}
}
XML编码
<?xml version="1.0" encoding="utf-8"?>
<fragment
android:id="@+id/video_1_fragment"
android:layout_width="100dp"
android:layout_height="0dp"
android:layout_weight="1"
class="com.compdigitec.libvlcandroidsample.MultipleVideoPlayFragmentActivity$VideoFragment" />
<fragment
android:id="@+id/video_2_fragment"
android:layout_width="100dp"
android:layout_height="0dp"
android:layout_weight="1"
class="com.compdigitec.libvlcandroidsample.MultipleVideoPlayFragmentActivity$VideoFragment" />
单片段布局
<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=".SampleActivity" >
<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>
答案 0 :(得分:0)
请尝试这个:
--- libvlc = LibVLC.getInstance();
+++ libvlc = new LibVLC();
P.S。你正在使用什么版本的LibVLC-android?
P.P.S。 example
答案 1 :(得分:0)
我有同样的问题。我所做的是遵循VLC自己的示例(https://code.videolan.org/videolan/libvlc-android-samples)并进行相同的build.gradle等。
我的代码如下:
MainActivity.java
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import tools.nubicam.com.rtsptest.R;
public class MainActivity extends Activity {
public final static String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button startButton = (Button)findViewById(R.id.buttonStart);
startButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, VideoActivity.class);
EditText textRTSP = (EditText)findViewById(R.id.textRTSPUrl);
intent.putExtra(VideoActivity.RTSP_URL, textRTSP.getText().toString());
startActivity(intent);
}
});
}
}
VideoActivity.java
import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;
import org.videolan.libvlc.IVLCVout;
import org.videolan.libvlc.LibVLC;
import org.videolan.libvlc.Media;
import org.videolan.libvlc.MediaPlayer;
import org.videolan.libvlc.media.VideoView;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import tools.nubicam.com.rtsptest.R;
public class VideoActivity<USE_TEXTURE_VIEW, ENABLE_SUBTITLES, False> extends Activity implements IVLCVout.Callback {
public final static String TAG = "VideoActivity";
public static final String RTSP_URL = "rtspurl";
// 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;
private final MediaPlayer.EventListener mPlayerListener = new MyPlayerListener(this);
private String rtspUrl;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sample);
// Get URL
Intent intent = getIntent();
rtspUrl = intent.getExtras().getString(RTSP_URL);
Log.d(TAG, "Playing back " + rtspUrl);
mSurface = (SurfaceView) findViewById(R.id.surface);
holder = mSurface.getHolder();
//holder.addCallback(this);
}
@Override
protected void onResume() {
super.onResume();
createPlayer(rtspUrl);
}
private void createPlayer(String rtspUrl) {
releasePlayer();
try {
if (rtspUrl.length() > 0) {
Toast toast = Toast.makeText(this, rtspUrl, Toast.LENGTH_LONG);
toast.setGravity( Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0);
toast.show();
}
ArrayList<String> options = new ArrayList<String>();
options.add("-vvv"); // verbosity
//options.add("--aout=opensles");
//options.add("--audio-time-stretch"); // time stretching
//options.add("--avcodec-codec=h264");
//options.add("--file-logging");
//options.add("--logfile=vlc-log.txt");
options.add("--network-caching=150");
options.add("--clock-jitter=0");
options.add("--clock-synchro=0");
//options.add("--http-reconnect");
//options.add("--network-caching="+6*1000);
libvlc = new LibVLC(this, options);
///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, Uri.parse(rtspUrl));
mMediaPlayer.setMedia(m);
mMediaPlayer.play();
// m.setHWDecoderEnabled(true, false);
// m.addOption(":network-caching=150");
// m.addOption(":clock-jitter=0");
// m.addOption(":clock-synchro=0");
} catch (Exception e) {
Toast.makeText(this, "Error creating player!", Toast.LENGTH_LONG).show();
}
}
@Override
protected void onStart() {
super.onStart();
int cnt = 0;
cnt += 1;
Toast.makeText(this, cnt + "", Toast.LENGTH_SHORT).show();
}
@Override
protected void onPause() {
super.onPause();
releasePlayer();
}
@Override
protected void onDestroy() {
super.onDestroy();
releasePlayer();
}
@Override
public void onSurfacesCreated(IVLCVout vlcVout) {
int cnt = 30;
cnt += 1;
Toast.makeText(this, cnt + "", Toast.LENGTH_SHORT).show();
}
@Override
public void onSurfacesDestroyed(IVLCVout vlcVout) {
int cnt = 20;
cnt += 1;
Toast.makeText(this, cnt + "", Toast.LENGTH_SHORT).show();
}
@Override
public void onPointerCaptureChanged(boolean hasCapture) {
int cnt = 10;
cnt += 1;
Toast.makeText(this, cnt + "", Toast.LENGTH_SHORT).show();
}
public 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 static class MyPlayerListener implements MediaPlayer.EventListener {
private WeakReference<VideoActivity> mOwner;
public MyPlayerListener(VideoActivity owner) {
mOwner = new WeakReference<VideoActivity>(owner);
}
@Override
public void onEvent(org.videolan.libvlc.MediaPlayer.Event event) {
VideoActivity player = mOwner.get();
switch(event.type) {
case MediaPlayer.Event.EndReached:
Log.d(TAG, "MediaPlayerEndReached");
Toast.makeText(player.getApplicationContext(), "Event EndReached", Toast.LENGTH_SHORT).show();
player.releasePlayer();
break;
case MediaPlayer.Event.Opening:
Toast.makeText(player.getApplicationContext(), "Event Opening", Toast.LENGTH_SHORT).show();
break;
case MediaPlayer.Event.Buffering:
Toast.makeText(player.getApplicationContext(), "Event Buffering", Toast.LENGTH_SHORT).show();
break;
case MediaPlayer.Event.Playing:
Toast.makeText(player.getApplicationContext(), "Event Playing", Toast.LENGTH_SHORT).show();
break;
case MediaPlayer.Event.Paused:
Toast.makeText(player.getApplicationContext(), "Event Paused", Toast.LENGTH_SHORT).show();
break;
case MediaPlayer.Event.Stopped:
Toast.makeText(player.getApplicationContext(), "Event Stopped", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.nubicam.tools.rtsptest.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="RTSPTest"
android:textStyle="bold"
android:visibility="visible" />
<EditText
android:id="@+id/textRTSPUrl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="rtsp://{user}:{pass}@host:554/{videosource}"
android:inputType="textPersonName"
android:text="rtsp://admin:1625necip@192.168.0.183:554/1" />
<Button
android:id="@+id/buttonStart"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Play stream!"
tools:layout_editor_absoluteX="151dp"
tools:layout_editor_absoluteY="120dp" />
</LinearLayout>
</RelativeLayout>
sample.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:background="@android:color/background_dark"
android:keepScreenOn="true"
tools:context="com.nubicam.tools.rtsptest.VideoActivity" >
<SurfaceView
android:id="@+id/surface"
android:layout_width="fill_parent"
android:layout_height="365dp" />
<org.videolan.libvlc.util.VLCVideoLayout
android:id="@+id/video_layout"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_marginTop="365dp"
android:fitsSystemWindows="false" />
</FrameLayout>
build.gradle(:app)
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "tools.nubicam.com.rtsptest"
minSdkVersion 23
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'org.videolan.android:libvlc-all:3.1.12'
}
build.gradle(vlc ..)
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.1'
//classpath 'com.android.tools.build:gradle:3.4.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
//maven {
// url 'https://jitpack.io'
//}
///maven {
/// url "https://dl.bintray.com/videolan/Android"
///}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
gradle.properties
org.gradle.jvmargs=-Xmx1536m
android.useAndroidX=true
android.enableJetifier=true
gradle-wrapper.properties
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip