同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,於是做了下處理。但實際上這樣是不對的,暫時沒有找到解決方案,如果有人知道的話,請不吝賜教。

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