当前位置: 首页 > 面试题库 >

Android:以mjpeg格式传输相机

祁坚壁
2023-03-14
问题内容

经过几天的搜索SO和Google之后,我开始放弃了,所以我认为最好还是在这里发布。

我正在创建一个应该提供某种视频聊天功能的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; dr: VLC没有播放流,mplayer说“缓存未填充”,问题可能在最后一个代码段中,需要帮助〜:)

非常感谢你!


问题答案:

我知道了。好像我的http- / content-headers被弄乱了。正确的标题应该是:

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\nthingies)…



 类似资料:
  • 问题内容: 使用MVC模型,我想编写一个JsonResult,它将Json字符串流式传输到客户端,而不是一次将所有数据转换成Json字符串,然后将其流回客户端。我有一些动作需要在Json传输时发送非常大的记录(超过300,000条记录),我认为基本的JsonResult实现是不可伸缩的。 我正在使用Json.net,我想知道是否有一种方法可以在转换Json字符串时流化它的块。 但是我不确定如何将这

  • 我已经实现了帖子中的演示:Android和MJPEG 但应用程序总是在一段时间后出现错误,我得到了一个异常:

  • Mjpeg tools 是一套用来捕捉MPEG-1/2 格式视频图像、进行基本编辑、回访以及压缩的工具包。

  • 我正在使用JComboCalendar小部件来让用户选择一个日期。JComboCalendar有一个方法getDate(),它返回一个Date对象。 根据Oracle docs,date.toString应该返回一个格式为yyyy-mm-dd的字符串,但我接收到的字符串如下: 如何才能得到预期的输出?对于如何像dd-mm-yyyy那样格式化它的奖励,因为我只是发现了如何读取给定格式的字符串,而不是

  • 问题内容: 我正在从数据库中获取结果,并希望将数据以表的形式输出到Java的标准输出中 我尝试使用\ t,但是我想要的第一列的长度非常可变。 有没有办法在类似输出的漂亮表格中显示它? 问题答案: 使用。您可以像这样设置字段的长度: 此垫和,10和16个字符,分别。 有关语法的更多信息,请参见 (内部使用)。

  • 我们可以看到格式化就是通过格式字符串得到特定格式: format!("{}", foo) -> "3735928559" format!("0x{:X}", foo) -> "0xDEADBEEF" format!("0o{:o}", foo) -> "0o33653337357" 根据使用的参数类型,同样的变量(foo)能够格式化成不同的形式:X, o 和未指定形式。 这个格式化的功能是通过 t