安卓:流媒体与相机MJPEG(Android: streaming the camera as mj

2019-08-16 21:56发布

经过这么搜索和谷歌我开始放弃,所以我想我也可以张贴在这里的几天。

我创建一个Android应用程序应该提供某种形式的视频聊天。 由于这应该是尽可能接近到实时的,我也读到了各种协议,并决定尝试MJPEG对于初学者(不与音频有关现在)。

现在流的数据我发疯。 连接被建立后,应用程序启动写入相机预览画面流中,但既不VLC也不mplayer的开始播放视频。 监控连接揭示了数据到达。

连接这些代码是一个异步任务执行,侦听器已成功通知:

try
    {
        ServerSocket server = new ServerSocket(8080);

        socket = server.accept();

        server.close();

        Log.i(TAG, "New connection to :" + socket.getInetAddress());

        stream = new DataOutputStream(socket.getOutputStream());
        prepared = true;
    }
    catch (IOException e)
    {
        Log.e(TAG, e.getMessage();
    }

在我的PC我执行“mplayer的http://tabletIP:8080 ”和平板注册一个连接(因此我开始拖缆与摄像头预览)。 这也适用于VLC。

这写头流:

if (stream != null)
{
    try
    {
        // send the header
        stream.write(("HTTP/1.0 200 OK\r\n" +
                      "Server: iRecon\r\n" +
                      "Connection: close\r\n" +
                      "Max-Age: 0\r\n" +
                      "Expires: 0\r\n" +
                      "Cache-Control: no-cache, private\r\n" + 
                      "Pragma: no-cache\r\n" + 
                      "Content-Type: multipart/x-mixed-replace; " +
                      "boundary=--" + boundary +
                      "\r\n\r\n").getBytes());

        stream.flush();

        streaming = true;
    }
    catch (IOException e)
    {
        notifyOnEncoderError(this, "Error while writing header: " + e.getMessage());
        stop();
    }
}

此后数据流是通过Camera.onPreviewFrame()回调触发:

@Override
public void onPreviewFrame(byte[] data, Camera camera)
{
    frame = data;

    if (streaming)
        mHandler.post(this);
}

@Override
public void run()
{
    // TODO: cache not filling?
    try
    {
                    // buffer is a ByteArrayOutputStream
        buffer.reset();

        switch (imageFormat)
        {
            case ImageFormat.JPEG:
                // nothing to do, leave it that way
                buffer.write(frame);
                break;

            case ImageFormat.NV16:
            case ImageFormat.NV21:
            case ImageFormat.YUY2:
            case ImageFormat.YV12:
                new YuvImage(frame, imageFormat, w, h, null).compressToJpeg(area, 100, buffer);
                break;

            default:
                throw new IOException("Error while encoding: unsupported image format");
        }

        buffer.flush();

        // write the content header
        stream.write(("--" + boundary + "\r\n" + 
                      "Content-type: image/jpg\r\n" + 
                      "Content-Length: " + buffer.size() + 
                      "\r\n\r\n").getBytes());

        // Should omit the array copy
        buffer.writeTo(stream);

        stream.write("\r\n\r\n".getBytes());
        stream.flush();
    }
    catch (IOException e)
    {
        stop();
        notifyOnEncoderError(this, e.getMessage());
    }
}

有没有例外抛出。 该mHandler运行在它自己的HandlerThread。 只是要确定我试着使用的AsyncTask,无果(顺便说一句,这是更好?)。

该编码的帧是在Android方面很好,我救了他们为JPG文件,可以打开它们。

我的猜测是,我必须以某种方式聚集数据或必须设置的插座什么的一些选择,但是....好,我坚持。

TL;博士:VLC不打流,mplayer的说“不缓存填充”,可能是在最后的代码段的问题,需要帮助〜:)

非常感谢你!

Answer 1:

我知道了。 看来,像我的基于HTTP /内容头被搞砸了。 正确的标题应该是:

stream.write(("HTTP/1.0 200 OK\r\n" +
                          "Server: iRecon\r\n" +
                          "Connection: close\r\n" +
                          "Max-Age: 0\r\n" +
                          "Expires: 0\r\n" +
                          "Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n" +
                          "Pragma: no-cache\r\n" + 
                          "Content-Type: multipart/x-mixed-replace; " +
                          "boundary=" + boundary + "\r\n" +
                          "\r\n" +
                          "--" + boundary + "\r\n").getBytes());

stream.write(("Content-type: image/jpeg\r\n" +
                      "Content-Length: " + buffer.size() + "\r\n" +
                      "X-Timestamp:" + timestamp + "\r\n" +
                      "\r\n").getBytes());

buffer.writeTo(stream);
stream.write(("\r\n--" + boundary + "\r\n").getBytes());

当然,如果把边界是你自己的选择。 也有可能是某些领域哪些是可选的(例如,大多数在的Cache-Control),但这并工作到现在我才懒得剥离下来。 最重要的部分是要记住的换行符( \r\n一样的东西)...



文章来源: Android: streaming the camera as mjpeg