同Wi-Fi下获取硬件实时视频流(flutter篇)

一个网络请求方法不断的接收stream图片流事件,需要将这些图片流展示在Image控件上,这样就能够实现让图片变成视频的效果:
直接上代码

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

class TestApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'IPCamera'),
    );
  }
}

List<int> _bytes = [];
Uint8List lastImageData = Uint8List(0);

class MyHomePage extends StatefulWidget {
  final String title;

  MyHomePage({this.title});

  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final StreamController _streamController = StreamController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Column(
          children: [
            Container(
              height: 60,
              child: _topButton(),
            ),
            StreamBuilder(
              builder: (BuildContext context, AsyncSnapshot snapshot) {
                return Image.memory(
                    consolidateHttpClientResponseBytes(snapshot.data));
              },
              stream: _streamController.stream,
              initialData: Uint8List(0),
            ),
          ],
        ));
  }

  Future _loadImagesData() async {
    var uri = Uri.parse("http://192.168.4.1:81/stream");
    var response = await http.Client().send(http.Request('GET',uri));
    response.stream.listen((value) {
      print(response.request.toString());
      _bytes.addAll(value);
      if (lastImageData.length == 36) {
        _streamController.sink.add(_bytes);
        _bytes = [];
      }
      lastImageData = Uint8List.fromList(value);
      print('当前数据字节长度${(lastImageData.length)}');
    });
  }

  Widget _topButton() {
    return Center(
      child: TextButton(
          style: ButtonStyle(
            foregroundColor: MaterialStateProperty.resolveWith(
              (states) {
                if (states.contains(MaterialState.focused) &&
                    !states.contains(MaterialState.pressed)) {
                  //获取焦点时的颜色
                  return Colors.green;
                } else if (states.contains(MaterialState.pressed)) {
                  //按下时的颜色
                  return Colors.red;
                }
                //默认状态使用灰色
                return Colors.white;
              },
            ),
            padding: MaterialStateProperty.all(EdgeInsets.all(10)),
            minimumSize: MaterialStateProperty.all(Size(100, 50)),
            backgroundColor: MaterialStateProperty.resolveWith((states) {
              //设置按下时的背景颜色
              if (states.contains(MaterialState.pressed)) {
                return Colors.yellowAccent[200];
              }
              //默认不使用背景颜色
              return Colors.blue;
            }),
          ),
          onPressed: () {
            _loadImagesData();
          },
          child: Text('请求')),
    );
  }

  static consolidateHttpClientResponseBytes(data) {
    // response.contentLength is not trustworthy when GZIP is involved
    // or other cases where an intermediate transformer has been applied
    // to the stream.
    final List<List<int>> chunks = <List<int>>[];
    int contentLength = 0;
    chunks.add(data);
    contentLength += data.length;
    final Uint8List bytes = Uint8List(contentLength);
    int offset = 0;
    for (List<int> chunk in chunks) {
      bytes.setRange(offset, offset + chunk.length, chunk);
      offset += chunk.length;
    }
    return bytes;
  }
}

这里的网络请求用的是http框架,没使用dio框架,不知道是我不会用还是本身就没有这种对流请求的方法。

导入的是http库:

  http: ^0.13.1

其实这里有个问题,我不知道每次传回来的流啥时候是一张完整的图片流,通过观察数据,发现每次刚接收的时候长度是36,于是做了下处理。但实际上这样是不对的,暂时没有找到解决方案,如果有人知道的话,请不吝赐教。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章