Android MJPEG流
我已经实施了 并且还实现了异步和证书来运行上面提到的。现在我已经成功运行了jpeg视频流,但问题是它在运行流时一直闪烁。它不断地上下波动。我想可能是框架的问题。任何人都知道如何处理这件事。以下是我实现的完整代码: MjpegSample.javaAndroid MJPEG流,android,video-streaming,mjpeg,Android,Video Streaming,Mjpeg,我已经实施了 并且还实现了异步和证书来运行上面提到的。现在我已经成功运行了jpeg视频流,但问题是它在运行流时一直闪烁。它不断地上下波动。我想可能是框架的问题。任何人都知道如何处理这件事。以下是我实现的完整代码: MjpegSample.java public class MjpegSample extends Activity { private static final boolean DEBUG=true; private static final String TAG = "MJPEG
public class MjpegSample extends Activity {
private static final boolean DEBUG=true;
private static final String TAG = "MJPEG";
private MjpegView mv;
private static final int MENU_QUIT = 1;
String URL;
MjpegInputStream inputStream;
/* Creates the menu items */
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, MENU_QUIT, 0, "Quit");
return true;
}
/* Handles item selections */
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_QUIT:
finish();
return true;
}
return false;
}
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
//sample public cam
URL = "https://orangefr-eu-oem-storage11.mios.com/storage/storage/store/81976/archive?Key=2147780009";
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
mv = new MjpegView(this);
setContentView(mv);
new DoRead().execute(URL);
}
public class DoRead extends AsyncTask<String, Void, MjpegInputStream> {
protected MjpegInputStream doInBackground(String... url) {
//TODO: if camera has authentication deal with it and don't just not work
HttpResponse res = null;
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpParams httpParams = httpclient.getParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 5*1000);
HttpConnectionParams.setSoTimeout(httpParams, 5*1000);
if(DEBUG) Log.d(TAG, "1. Sending http request");
try {
res = httpclient.execute(new HttpGet(URI.create(url[0])));
if(DEBUG) Log.d(TAG, "2. Request finished, status = " + res.getStatusLine().getStatusCode());
if(res.getStatusLine().getStatusCode()==401){
//You must turn off camera User Access Control before this will work
return null;
}
return new MjpegInputStream(res.getEntity().getContent());
} catch (ClientProtocolException e) {
if(DEBUG){
e.printStackTrace();
Log.d(TAG, "Request failed-ClientProtocolException", e);
}
//Error connecting to camera
} catch (IOException e) {
if(DEBUG){
e.printStackTrace();
Log.d(TAG, "Request failed-IOException", e);
}
//Error connecting to camera
}
return null;
}
protected void onPostExecute(MjpegInputStream result) {
mv.setSource(result);
/*if(result!=null){
result.setSkip(1);
setTitle(R.string.app_name);
}else{
setTitle(R.string.title_disconnected);
}*/
mv.setDisplayMode(MjpegView.SIZE_FULLSCREEN);
mv.showFps(false);
}
}
public void onPause() {
super.onPause();
mv.stopPlayback();
}
}
MjpegInputStream.java
public class MjpegInputStream extends DataInputStream {
private final byte[] SOI_MARKER = { (byte) 0xFF, (byte) 0xD8 };
private final byte[] EOF_MARKER = { (byte) 0xFF, (byte) 0xD9 };
private final String CONTENT_LENGTH = "Content-Length";
private final static int HEADER_MAX_LENGTH = 100;
private final static int FRAME_MAX_LENGTH = 40000 + HEADER_MAX_LENGTH;
private int mContentLength = -1;
public static MjpegInputStream read(String url) {
HttpResponse res;
DefaultHttpClient httpclient = new DefaultHttpClient();
try {
res = httpclient.execute(new HttpGet(URI.create(url)));
return new MjpegInputStream(res.getEntity().getContent());
} catch (ClientProtocolException e) {
} catch (IOException e) {}
return null;
}
public MjpegInputStream(InputStream in) { super(new BufferedInputStream(in, FRAME_MAX_LENGTH)); }
private int getEndOfSeqeunce(DataInputStream in, byte[] sequence) throws IOException {
int seqIndex = 0;
byte c;
for(int i=0; i < FRAME_MAX_LENGTH; i++) {
c = (byte) in.readUnsignedByte();
if(c == sequence[seqIndex]) {
seqIndex++;
if(seqIndex == sequence.length) return i + 1;
} else seqIndex = 0;
}
return -1;
}
private int getStartOfSequence(DataInputStream in, byte[] sequence) throws IOException {
int end = getEndOfSeqeunce(in, sequence);
return (end < 0) ? (-1) : (end - sequence.length);
}
private int parseContentLength(byte[] headerBytes) throws IOException, NumberFormatException {
ByteArrayInputStream headerIn = new ByteArrayInputStream(headerBytes);
Properties props = new Properties();
props.load(headerIn);
return Integer.parseInt(props.getProperty(CONTENT_LENGTH));
}
public Bitmap readMjpegFrame() throws IOException {
mark(FRAME_MAX_LENGTH);
int headerLen = getStartOfSequence(this, SOI_MARKER);
reset();
byte[] header = new byte[headerLen];
readFully(header);
try {
mContentLength = parseContentLength(header);
} catch (NumberFormatException nfe) {
mContentLength = getEndOfSeqeunce(this, EOF_MARKER);
}
reset();
byte[] frameData = new byte[mContentLength];
skipBytes(headerLen);
readFully(frameData);
return BitmapFactory.decodeStream(new ByteArrayInputStream(frameData));
}}
公共类MjpegInputStream扩展了DataInputStream{
私有最终字节[]SOI_标记={(字节)0xFF,(字节)0xD8};
私有最终字节[]EOF_标记={(字节)0xFF,(字节)0xD9};
私有最终字符串内容\u LENGTH=“CONTENT LENGTH”;
专用最终静态int标头_MAX_LENGTH=100;
私有最终静态整数帧最大长度=40000+标题最大长度;
private int mContentLength=-1;
公共静态输入流读取(字符串url){
HttpResponse;
DefaultHttpClient httpclient=新的DefaultHttpClient();
试一试{
res=httpclient.execute(新的HttpGet(URI.create(url));
返回新的MjpegInputStream(res.getEntity().getContent());
}捕获(客户端协议例外e){
}捕获(IOE){}
返回null;
}
公共MjpegInputStream(InputStream in){super(新的BufferedInputStream(in,FRAME_MAX_LENGTH));}
private int getendofsequnce(DataInputStream in,字节[]序列)引发IOException{
int-seqIndex=0;
字节c;
对于(int i=0;i检查URL,我认为URL有问题。如果您想检查流媒体,您可以使用浏览器或VLC播放器进行检查,后者必须流媒体链接。我使用了相同的代码,从连接到机器人的摄像机上完美地流式播放。我实现了一个库,在Android上播放MJPEG视频流。GitHub上提供了所有源代码
将依赖项添加到应用程序中
compile 'com.github.niqdev:mjpeg-view:0.3.3'
下面是一个如何使用它的示例,将MjpegSurfaceView添加到布局中
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
// ADD THIS
xmlns:stream="http://schemas.android.com/apk/res-auto"
...>
<com.github.niqdev.mjpeg.MjpegSurfaceView
android:id="@+id/VIEW_NAME"
android:layout_width="match_parent"
android:layout_height="match_parent"
stream:type="stream_default OR stream_native" />
</RelativeLayout>
我们如何将lambda表达式转换为android支持的代码?要使用lamda表达式进行转换,您需要向gradle添加plugin
apply plugin:'me.tatarka.retrolambda'
。注意:jackOptions不适用于此。
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
// ADD THIS
xmlns:stream="http://schemas.android.com/apk/res-auto"
...>
<com.github.niqdev.mjpeg.MjpegSurfaceView
android:id="@+id/VIEW_NAME"
android:layout_width="match_parent"
android:layout_height="match_parent"
stream:type="stream_default OR stream_native" />
</RelativeLayout>
Mjpeg.newInstance()
.credential("USERNAME", "PASSWORD")
.open("IPCAM_URL.mjpg")
.subscribe(inputStream -> {
mjpegView.setSource(inputStream);
mjpegView.setDisplayMode(DisplayMode.BEST_FIT);
mjpegView.showFps(true);
});