android mjpeg ip-camera

Android y MJPEG



ip camera bridge (3)

Necesito obtener la transmisión de mjpeg desde una cámara IP, ¿alguien sabe cómo hacerlo? Busqué en Google un poco y encuentro este ejemplo

http://www.anddev.org/mjpeg_on_android_anyone-t1871.html

pero me sorprendí cuando intenté obtener la transmisión de otra actividad llamada por la actividad principal. Aquí el código:

Actividad principal

package com.test; public class IntentTest extends Activity { /** Called when the activity is first created. */ ListView myListView = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); myListView = (ListView)findViewById(R.id.listView); final ArrayList<String> items = new ArrayList<String>(); items.add("00408C944B9A"); final ArrayAdapter<String> aa; aa = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items); myListView.setAdapter(aa); myListView.setOnItemClickListener(listClicked); } private OnItemClickListener listClicked = new OnItemClickListener() { public void onItemClick(AdapterView<?> arg0, View arg1, int position, long id) { // TODO Auto-generated method stub Intent i = new Intent(IntentTest.this, OtherActivity.class); i.putExtra("MAC", myListView.getItemAtPosition(position).toString()); startActivity(i); } }; }

Segunda actividad

package com.test; import com.test.mjpeg.mjpegsample.MjpegView.*; import com.test.parser.JSONParse; public class OtherActivity extends Activity { /** Called when the activity is first created. */ private MjpegView mv; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle extras = getIntent().getExtras(); if (extras != null){ String mac = (String)extras.get("MAC"); Log.i("Other", "---->" + mac); TextView tv = (TextView)findViewById(R.id.textView); tv.setText(mac); String URL = "myurl"; requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); mv = new MjpegView(this); setContentView(mv); mv.setSource(MjpegInputStream.read(URL)); mv.setDisplayMode(MjpegView.SIZE_BEST_FIT); mv.showFps(true); } } public void onPause() { super.onPause(); mv.stopPlayback(); } }


Encontré este código en Internet hace algún tiempo, quizás sea de alguna ayuda para ti.

MjpegSample Class

package de.mjpegsample; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.Window; import android.view.WindowManager; import de.mjpegsample.MjpegView.MjpegInputStream; import de.mjpegsample.MjpegView.MjpegView; public class MjpegSample extends Activity { private MjpegView mv; private static final int MENU_QUIT = 1; /* 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 String URL = "http://gamic.dnsalias.net:7001/img/video.mjpeg"; 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); mv.setSource(MjpegInputStream.read(URL)); mv.setDisplayMode(MjpegView.SIZE_BEST_FIT); mv.showFps(false); } public void onPause() { super.onPause(); mv.stopPlayback(); } }

Clase MjpegView

package de.mjpegsample.MjpegView; import java.io.IOException; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.Typeface; import android.util.AttributeSet; import android.view.SurfaceHolder; import android.view.SurfaceView; public class MjpegView extends SurfaceView implements SurfaceHolder.Callback { public final static int POSITION_UPPER_LEFT = 9; public final static int POSITION_UPPER_RIGHT = 3; public final static int POSITION_LOWER_LEFT = 12; public final static int POSITION_LOWER_RIGHT = 6; public final static int SIZE_STANDARD = 1; public final static int SIZE_BEST_FIT = 4; public final static int SIZE_FULLSCREEN = 8; private MjpegViewThread thread; private MjpegInputStream mIn = null; private boolean showFps = false; private boolean mRun = false; private boolean surfaceDone = false; private Paint overlayPaint; private int overlayTextColor; private int overlayBackgroundColor; private int ovlPos; private int dispWidth; private int dispHeight; private int displayMode; public class MjpegViewThread extends Thread { private SurfaceHolder mSurfaceHolder; private int frameCounter = 0; private long start; private Bitmap ovl; public MjpegViewThread(SurfaceHolder surfaceHolder, Context context) { mSurfaceHolder = surfaceHolder; } private Rect destRect(int bmw, int bmh) { int tempx; int tempy; if (displayMode == MjpegView.SIZE_STANDARD) { tempx = (dispWidth / 2) - (bmw / 2); tempy = (dispHeight / 2) - (bmh / 2); return new Rect(tempx, tempy, bmw + tempx, bmh + tempy); } if (displayMode == MjpegView.SIZE_BEST_FIT) { float bmasp = (float) bmw / (float) bmh; bmw = dispWidth; bmh = (int) (dispWidth / bmasp); if (bmh > dispHeight) { bmh = dispHeight; bmw = (int) (dispHeight * bmasp); } tempx = (dispWidth / 2) - (bmw / 2); tempy = (dispHeight / 2) - (bmh / 2); return new Rect(tempx, tempy, bmw + tempx, bmh + tempy); } if (displayMode == MjpegView.SIZE_FULLSCREEN) return new Rect(0, 0, dispWidth, dispHeight); return null; } public void setSurfaceSize(int width, int height) { synchronized(mSurfaceHolder) { dispWidth = width; dispHeight = height; } } private Bitmap makeFpsOverlay(Paint p, String text) { Rect b = new Rect(); p.getTextBounds(text, 0, text.length(), b); int bwidth = b.width()+2; int bheight = b.height()+2; Bitmap bm = Bitmap.createBitmap(bwidth, bheight, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); p.setColor(overlayBackgroundColor); c.drawRect(0, 0, bwidth, bheight, p); p.setColor(overlayTextColor); c.drawText(text, -b.left+1, (bheight/2)-((p.ascent()+p.descent())/2)+1, p); return bm; } public void run() { start = System.currentTimeMillis(); PorterDuffXfermode mode = new PorterDuffXfermode(PorterDuff.Mode.DST_OVER); Bitmap bm; int width; int height; Rect destRect; Canvas c = null; Paint p = new Paint(); String fps = ""; while (mRun) { if(surfaceDone) { try { c = mSurfaceHolder.lockCanvas(); synchronized (mSurfaceHolder) { try { bm = mIn.readMjpegFrame(); destRect = destRect(bm.getWidth(),bm.getHeight()); c.drawColor(Color.BLACK); c.drawBitmap(bm, null, destRect, p); if(showFps) { p.setXfermode(mode); if(ovl != null) { height = ((ovlPos & 1) == 1) ? destRect.top : destRect.bottom-ovl.getHeight(); width = ((ovlPos & 8) == 8) ? destRect.left : destRect.right -ovl.getWidth(); c.drawBitmap(ovl, width, height, null); } p.setXfermode(null); frameCounter++; if((System.currentTimeMillis() - start) >= 1000) { fps = String.valueOf(frameCounter)+"fps"; frameCounter = 0; start = System.currentTimeMillis(); ovl = makeFpsOverlay(overlayPaint, fps); } } } catch (IOException e) {} } } finally { if (c != null) mSurfaceHolder.unlockCanvasAndPost(c); } } } } } private void init(Context context) { SurfaceHolder holder = getHolder(); holder.addCallback(this); thread = new MjpegViewThread(holder, context); setFocusable(true); overlayPaint = new Paint(); overlayPaint.setTextAlign(Paint.Align.LEFT); overlayPaint.setTextSize(12); overlayPaint.setTypeface(Typeface.DEFAULT); overlayTextColor = Color.WHITE; overlayBackgroundColor = Color.BLACK; ovlPos = MjpegView.POSITION_LOWER_RIGHT; displayMode = MjpegView.SIZE_STANDARD; dispWidth = getWidth(); dispHeight = getHeight(); } public void startPlayback() { if(mIn != null) { mRun = true; thread.start(); } } public void stopPlayback() { mRun = false; boolean retry = true; while(retry) { try { thread.join(); retry = false; } catch (InterruptedException e) {} } } public MjpegView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public void surfaceChanged(SurfaceHolder holder, int f, int w, int h) { thread.setSurfaceSize(w, h); } public void surfaceDestroyed(SurfaceHolder holder) { surfaceDone = false; stopPlayback(); } public MjpegView(Context context) { super(context); init(context); } public void surfaceCreated(SurfaceHolder holder) { surfaceDone = true; } public void showFps(boolean b) { showFps = b; } public void setSource(MjpegInputStream source) { mIn = source; startPlayback(); } public void setOverlayPaint(Paint p) { overlayPaint = p; } public void setOverlayTextColor(int c) { overlayTextColor = c; } public void setOverlayBackgroundColor(int c) { overlayBackgroundColor = c; } public void setOverlayPosition(int p) { ovlPos = p; } public void setDisplayMode(int s) { displayMode = s; } }

Clase MjpegInputStream

package de.mjpegsample.MjpegView; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.util.Properties; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import android.graphics.Bitmap; import android.graphics.BitmapFactory; 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)); } }

Si necesita más información, hágamelo saber, lo ayudaré de cualquier manera que pueda.

FYI: No escribí SimpleMjpegView, puedes encontrar más código actualizado here



Tuve el mismo problema e intenté usar visores Mjpeg personalizados. Mientras trabajaban, demostraron ser inestables y torpes para mí.

Simplemente estoy usando un WebView. En Android Studio, simplemente arrastre y suelte un WebView. My WebView no cubre toda la pantalla, sino la mitad.

Luego, para que se ajuste mejor al video, en su onCreate:

Si usa Kotlin:

webView.settings.loadWithOverviewMode = true; webView.settings.useWideViewPort = true;

Si usa Java:

webView.getSettings().setLoadWithOverviewMode(true); webView.getSettings().setUseWideViewPort(true);

Y luego, al hacer clic en el botón:

Para comenzar:

webView.loadUrl("http://$id:8081/cam.mjpeg") // start

Para detener:

webView.stopLoading() webView.loadUrl("about:blank")

Espero que esto ayude.