Search code examples
flutterandroid-camera

Can i make stream with flutter camera package?


My purpose is stream to a websocket.

Firstly i need the camera data. I used startImageStream func for that. This func return image as yuv format. I found something about yuv to image widget but i couldnt convert it to base 64.

The question is how can i convert this yuv image data to base64 ? Or this is bad way to make a stream with flutter.


Solution

  • controller.startImageStream((image) {
      // convert image here
    
      // assuming it's converted
      final imageBytes = <int>[];
    
      final encodedImage = base64.encode(imageBytes);
    });
    

    as for yuv->rgb conversion, you can do something like this (code copied from https://gist.github.com/Alby-o/fe87e35bc21d534c8220aed7df028e03):

    // imgLib -> Image package from https://pub.dartlang.org/packages/image
    import 'package:image/image.dart' as imglib;
    import 'package:camera/camera.dart';
    
    Future<List<int>> convertImagetoPng(CameraImage image) async {
      try {
        imglib.Image img;
        if (image.format.group == ImageFormatGroup.yuv420) {
          img = _convertYUV420(image);
        } else if (image.format.group == ImageFormatGroup.bgra8888) {
          img = _convertBGRA8888(image);
        }
    
        imglib.PngEncoder pngEncoder = new imglib.PngEncoder();
    
        // Convert to png
        List<int> png = pngEncoder.encodeImage(img);
        return png;
      } catch (e) {
        print(">>>>>>>>>>>> ERROR:" + e.toString());
      }
      return null;
    }
    
    // CameraImage BGRA8888 -> PNG
    // Color
    imglib.Image _convertBGRA8888(CameraImage image) {
      return imglib.Image.fromBytes(
        image.width,
        image.height,
        image.planes[0].bytes,
        format: imglib.Format.bgra,
      );
    }
    
    // CameraImage YUV420_888 -> PNG -> Image (compresion:0, filter: none)
    // Black
    imglib.Image _convertYUV420(CameraImage image) {
      var img = imglib.Image(image.width, image.height); // Create Image buffer
    
      Plane plane = image.planes[0];
      const int shift = (0xFF << 24);
    
      // Fill image buffer with plane[0] from YUV420_888
      for (int x = 0; x < image.width; x++) {
        for (int planeOffset = 0;
            planeOffset < image.height * image.width;
            planeOffset += image.width) {
          final pixelColor = plane.bytes[planeOffset + x];
          // color: 0x FF  FF  FF  FF
          //           A   B   G   R
          // Calculate pixel color
          var newVal = shift | (pixelColor << 16) | (pixelColor << 8) | pixelColor;
    
          img.data[planeOffset + x] = newVal;
        }
      }
    
      return img;
    }
    

    Some background:

    In the latter you can find a comment that links to what appears to be more efficient implementation, it's in YUV_2_RGB project: https://github.com/alexcohn/YUV_2_RGB/blob/master/lib/service/image_result_processor_service.dart