0

首先“谢谢@bbodenmiller!” (使用 AsyncTask 的 Android ICS 和 MJPEG)MJPEG-Viewer 的代码运行良好。但我有一个问题。“MjpegActivity.java”仅适用于新的 ContentView:

private static final String TAG = "MjpegActivity";
public static MjpegView mv;
public static String URL = "http://trackfield.webcam.oregonstate.edu/axis-cgi/mjpg/video.cgi?resolution=800x600&amp%3bdummy=1333689998337";

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.main);

    Button B01 = (Button) findViewById(R.id.btn01);
    B01.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view) 
        {...}});

    Button Cam01 = (Button) findViewById(R.id.btnCam01);
    Cam01.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view) 
        {
            setContentView(mv);
            new DoRead().execute(URL);
                   }});
}

这意味着旧的 ContentView 例如 (setContentView(R.layout.main);) 将被覆盖。:( 有没有人知道我如何在布局中显示 MjpegView?或 MjpegView 上的布局?因为我需要 MjpegView 上布局中的按钮。提前非常感谢!

4

1 回答 1

1

我剥离了 MjpegView 并通过更新图像视图来显示流:

主要活动

public class MainActivity extends Activity {
    IPCamera cam1, cam2;
    ImageView iv1, iv2;    
    DownloadImageTask task1, task2;

    final Handler h = new Handler(new Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            if (msg.what == 1){
                Bitmap bmp = (Bitmap) msg.obj;
                iv1.setImageBitmap(bmp);
            }if(msg.what == 2){
                Bitmap bmp = (Bitmap) msg.obj;
                iv2.setImageBitmap(bmp);
            }
            return false;
        }
    });

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);       
        this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);          
        setContentView(R.layout.activity_main);
        iv1 = ((ImageView) findViewById(R.id.imageView1));
        iv2 = ((ImageView) findViewById(R.id.imageView2));
        cam1 = new IPCamera("http://10.0.0.101/video.cgi", "admin", "admin", this); 
        cam2 = new IPCamera("http://10.0.0.102/video.cgi", "admin", "admin", this);        

        task1 = startTask(cam1, 1, false, h);
        task2 = startTask(cam2, 2, false, h);

    }   

    private DownloadImageTask startTask(IPCamera cam, int id, boolean useParallelExecution, Handler h) {
        DownloadImageTask task = new DownloadImageTask(cam, id);        
        if (useParallelExecution) {            
            task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);            
        } else {           
            task.execute(h);
        }        
        return task;        
    }

    private class DownloadImageTask extends AsyncTask<Handler, Void, Void> {        
        IPCamera cam;
        int id;
        DownloadImageTask(IPCamera cam, int id){
            this.cam = cam;
            this.id = id;
        }



        protected Void doInBackground(Handler... h) {    
            cam.startStream(h[0], id);    
            cam.getFrame();         
            return null;        
        }
    }
}  

IPCamera 类

public class IPCamera{

    private static final String TAG = "MjpegActivity";

    String url;
    String usr;
    String pwd; 
    MjpegInputStream is;
    boolean running = false;
    Handler h;
    Context ctx;
    int id;

    IPCamera(String url, String usr, String pwd, Context ctx){
        this.url = url;
        this.usr = usr;
        this.pwd = pwd;
        this.ctx = ctx;
    }

    public void startStream(Handler h, int id){
    this.h = h;
    this.id = id;
    is = new MjpegInputStream(httpRequest(url,usr,pwd));    
    running = true;
}   

public void getFrame(){     
    while (running){
        Bitmap b;
        try {   
            b = is.readMjpegFrame();
            Message m = h.obtainMessage(id, b);
            m.sendToTarget();
            } catch (IOException e) {
            e.printStackTrace();
        }           
    }   
}

    public InputStream httpRequest(String url, String usr, String pwd){
        HttpResponse res = null;
        DefaultHttpClient httpclient = new DefaultHttpClient(); 
        CredentialsProvider credProvider = new BasicCredentialsProvider();
        credProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
            new UsernamePasswordCredentials(usr, pwd));
        httpclient.setCredentialsProvider(credProvider);
        Log.d(TAG, "1. Sending http request");
        try {
            res = httpclient.execute(new HttpGet(URI.create(url)));
            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 res.getEntity().getContent();  
        } catch (ClientProtocolException e) {
            e.printStackTrace();
            Log.d(TAG, "Request failed-ClientProtocolException", e);
            //Error connecting to camera
        } catch (IOException e) {
            e.printStackTrace();
            Log.d(TAG, "Request failed-IOException", e);
            //Error connecting to camera
        }

        return null;

    }
}

MjpegInputStream

必须将 FRAME_MAX_LENGHT 从 40000 增加到 400000。这样更稳定。

public class MjpegInputStream extends DataInputStream {
    private static final String TAG = "MjpegInputStream";

    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 = 400000 + HEADER_MAX_LENGTH;
    private int mContentLength = -1;

    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));
    }
}

不完全干净,但它有效。刚做了24小时稳定性测试,没有错误。如果相机连接断开并在相机弹回时重新连接,仍然必须想出一种方法来停止流线程。

于 2013-03-07T04:52:13.743 回答