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

如何通过Flask服务器在Flutter GUI中实现摄像头流?代码无画面求助

Flask摄像头流在Flutter中无法显示的排查与解决建议

我想在Flutter界面中查看Flask服务器推送的摄像头流,但当前代码没有画面显示,已确认服务器正在发送图片/流,求排查方向和解决办法,原代码如下:

Flask服务器代码

from flask import Flask, render_template, Response
import cv2
import time

app = Flask(__name__)

def generate_frames():
    cap = cv2.VideoCapture(0)
    while True:
        success, frame = cap.read()
        if not success:
            break
        else:
            ret, buffer = cv2.imencode('.jpg', frame)
            frame = buffer.tobytes()
            yield (b'--frame\r\n'
                   b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
        # 等待5秒后发送下一张图片
        time.sleep(5)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/video_feed')
def video_feed():
    return Response(generate_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')

if __name__ == '__main__':
    app.run(debug=True)

Flutter客户端代码

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:typed_data';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Webcam Viewer'),
        ),
        body: WebcamView(),
      ),
    );
  }
}

class WebcamView extends StatefulWidget {
  @override
  _WebcamViewState createState() => _WebcamViewState();
}

class _WebcamViewState extends State<WebcamView> {
  String imageUrl = 'http://127.0.0.1:5000/video_feed';

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Image.network(imageUrl),
    );
  }
}

排查与解决建议

  • 网络连通性与跨域问题

    • 若使用真机测试,127.0.0.1指向设备自身,需替换为电脑的局域网IP(如http://192.168.1.100:5000/video_feed)
    • Flask默认拦截跨域请求,需安装flask-cors并配置:
      from flask_cors import CORS
      app = Flask(__name__)
      CORS(app)  # 生产环境可指定允许的域名
      
  • Flutter Image.network兼容性问题

    • Image.network对multipart/x-mixed-replace流的支持不稳定,建议改用定时请求+手动更新图片的方式:
      import 'package:flutter/material.dart';
      import 'package:http/http.dart' as http;
      import 'dart:typed_data';
      import 'dart:async';
      
      void main() {
        runApp(MyApp());
      }
      
      class MyApp extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
          return MaterialApp(
            home: Scaffold(
              appBar: AppBar(title: Text('Webcam Viewer')),
              body: WebcamView(),
            ),
          );
        }
      }
      
      class WebcamView extends StatefulWidget {
        @override
        _WebcamViewState createState() => _WebcamViewState();
      }
      
      class _WebcamViewState extends State<WebcamView> {
        Uint8List? _imageBytes;
        late Timer _refreshTimer;
        final String _streamUrl = 'http://192.168.1.100:5000/video_feed'; // 替换为实际IP
      
        @override
        void initState() {
          super.initState();
          _fetchFrame();
          // 和服务器的5秒间隔同步
          _refreshTimer = Timer.periodic(Duration(seconds: 5), (_) => _fetchFrame());
        }
      
        Future<void> _fetchFrame() async {
          try {
            final response = await http.get(Uri.parse(_streamUrl));
            if (response.statusCode == 200) {
              setState(() => _imageBytes = response.bodyBytes);
            }
          } catch (e) {
            print('获取帧失败: $e');
          }
        }
      
        @override
        void dispose() {
          _refreshTimer.cancel();
          super.dispose();
        }
      
        @override
        Widget build(BuildContext context) {
          return Center(
            child: _imageBytes != null
                ? Image.memory(_imageBytes!)
                : CircularProgressIndicator(),
          );
        }
      }
      
  • Flask流格式与性能问题

    • 确认yield中的--frame和响应头的boundary=frame完全一致,避免格式不匹配
    • 先注释掉time.sleep(5)测试,排除长间隔导致的超时问题
  • 权限配置

    • 电脑端:确保Python程序已获得摄像头访问权限
    • Flutter端:
      • Android:在AndroidManifest.xml中添加网络权限:<uses-permission android:name="android.permission.INTERNET"/>
      • iOS:在Info.plist中添加允许HTTP请求的配置,避免ATS拦截:
        <key>NSAppTransportSecurity</key>
        <dict>
          <key>NSAllowsArbitraryLoads</key>
          <true/>
        </dict>
        

内容的提问来源于stack exchange,提问作者Adam Ghan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 00:37:02