You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从HTTP multipart/x-mixed-replace长连接流保存JPEG至Ubuntu服务器

我来帮你搞定这个问题!要把multipart JPEG流里的图片保存下来,不管是直接在Ubuntu服务器本地处理,还是集成到Ruby on Rails应用里,都有可行的方案,咱们一步步来:

在Ubuntu服务器本地解析并保存流中的JPEG文件

方法1:用Python脚本精细解析每个JPEG帧

如果需要单独保存每一张图片,用Python脚本可以精准处理multipart流的结构:

首先安装依赖:

pip install requests

然后创建解析脚本(比如save_camera_stream.py):

import requests
import re

# 替换成你的相机流地址
STREAM_URL = "http://your-camera-ip/stream"

# 发起流式请求,需要认证就加auth参数
response = requests.get(STREAM_URL, stream=True, auth=('username', 'password'))
# 从响应头提取multipart分隔符(boundary)
content_type = response.headers.get('Content-Type')
boundary = re.search(r'boundary=(.*)', content_type).group(1).encode()

img_count = 0
current_img_data = b''

# 逐块读取流数据
for chunk in response.iter_content(chunk_size=1024):
    if not chunk:
        continue
    
    # 检查是否遇到分隔符
    if boundary in chunk:
        # 如果已有积累的图片数据,尝试保存
        if current_img_data:
            # 定位JPEG的起始(FFD8)和结束(FFD9)标记
            start_pos = current_img_data.find(b'\xff\xd8')
            end_pos = current_img_data.find(b'\xff\xd9')
            if start_pos != -1 and end_pos != -1:
                jpeg_bytes = current_img_data[start_pos:end_pos+2]
                # 保存到本地,按序号命名
                with open(f'camera_frame_{img_count:04d}.jpg', 'wb') as f:
                    f.write(jpeg_bytes)
                print(f"已保存第 {img_count+1} 张图片")
                img_count += 1
        # 重置当前数据,从分隔符后开始积累
        current_img_data = chunk.split(boundary)[1]
    else:
        current_img_data += chunk

运行脚本即可在当前目录生成按顺序命名的JPEG文件。

方法2:用FFmpeg快速处理(适合转视频或定时截图)

如果不需要单独保存每帧,而是想转成视频或者定时截图,FFmpeg更简单高效:

  • 把流保存为MP4视频:
ffmpeg -i http://your-camera-ip/stream -c copy camera_stream.mp4
  • 每隔1秒保存一张截图:
ffmpeg -i http://your-camera-ip/stream -r 1 -f image2 screenshot_%04d.jpg
在Ruby on Rails应用中解析并保存流

控制器主动拉取并解析流

可以在Rails控制器中编写逻辑,主动请求相机流并保存每个JPEG帧到应用的文件系统:

require 'net/http'
require 'uri'

class CameraStreamController < ApplicationController
  skip_before_action :verify_authenticity_token, only: :save_frames

  def save_frames
    stream_uri = URI("http://your-camera-ip/stream")
    http = Net::HTTP.new(stream_uri.host, stream_uri.port)
    
    # 如果相机需要认证,添加基础认证
    http.basic_auth('username', 'password') if stream_uri.userinfo

    http.request_get(stream_uri.path) do |response|
      # 提取multipart分隔符
      content_type = response['Content-Type']
      boundary = content_type.match(/boundary=(.*)/)[1]
      boundary_regex = /--#{Regexp.escape(boundary)}/

      current_frame = ""
      frame_count = 0

      # 流式读取响应体
      response.read_body do |chunk|
        parts = chunk.split(boundary_regex)
        parts.each do |part|
          next if part.strip.empty?

          if current_frame.empty?
            current_frame = part
          else
            current_frame += part
            # 检查是否包含完整的JPEG数据
            if current_frame.include?("\xff\xd8") && current_frame.include?("\xff\xd9")
              start_idx = current_frame.index("\xff\xd8")
              end_idx = current_frame.index("\xff\xd9") + 2
              jpeg_data = current_frame[start_idx...end_idx]

              # 保存到Rails的storage目录(也可以改成public目录)
              filename = "camera_frame_#{frame_count.to_s.rjust(4, '0')}.jpg"
              save_path = Rails.root.join('storage', 'camera_frames', filename)
              FileUtils.mkdir_p(File.dirname(save_path)) # 确保目录存在
              File.open(save_path, 'wb') { |f| f.write(jpeg_data) }

              frame_count += 1
              Rails.logger.info("已保存相机帧:#{filename}")
              current_frame = ""
            end
          end
        end
      end
    end

    render plain: "开始保存相机流帧..."
  end
end

然后在config/routes.rb中添加路由:

get '/camera/save_frames', to: 'camera_stream#save_frames'

关键注意事项

  • 异常处理:要添加相机断开、网络异常的重试逻辑,避免脚本或控制器意外退出。
  • 权限问题:确保保存文件的目录有写入权限(比如Rails的storage目录要给web服务器用户(如www-data)授权)。
  • 性能优化:如果流的帧率很高,要考虑限制保存频率(比如每5帧保存一张),避免磁盘IO过载。

内容的提问来源于stack exchange,提问作者Travis Glover

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 07:50:15