Open GanZhiXiong opened 4 years ago
phone: huawei Mate7 Android version: 6.0 CPU: Hisilicon Kirin 925
using C elapsed time 170-190ms
using Dart elapsed time 230-250ms
flutter run --release
using C elapsed time 35-46ms
using Dart elapsed time 431-593ms why release slow?
import 'dart:ffi'; import 'dart:io'; import 'dart:typed_data'; import 'package:ffi/ffi.dart'; import 'package:flutter/material.dart'; import 'package:camera/camera.dart'; import 'package:image/image.dart' as imglib; import 'ImagePreview.dart'; import 'image_converter.dart'; typedef convert_func = Pointer<Uint32> Function( Pointer<Uint8>, Pointer<Uint8>, Pointer<Uint8>, Int32, Int32, Int32, Int32); typedef Convert = Pointer<Uint32> Function(Pointer<Uint8>, Pointer<Uint8>, Pointer<Uint8>, int, int, int, int); void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Camera App', theme: ThemeData( primarySwatch: Colors.blue, // visualDensity: VisualDensity.adaptivePlatformDensity, ), home: MyHomePage(title: 'Camera App'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { CameraController _camera; bool _cameraInitialized = false; CameraImage _savedImage; final DynamicLibrary convertImageLib = Platform.isAndroid ? DynamicLibrary.open("libconvertImage.so") : DynamicLibrary.process(); Convert conv; @override void initState() { super.initState(); _initializeCamera(); // Load the convertImage() function from the library conv = convertImageLib.lookup<NativeFunction<convert_func>>('convertImage').asFunction<Convert>(); } void _initializeCamera() async { // Get list of cameras of the device List<CameraDescription> cameras = await availableCameras(); // Create the CameraController _camera = new CameraController(cameras[0], ResolutionPreset.medium); _camera.initialize().then((_) async { // Start ImageStream await _camera.startImageStream((CameraImage image) => _processCameraImage(image)); setState(() { _cameraInitialized = true; }); }); } void _processCameraImage(CameraImage image) async { setState(() { _savedImage = image; }); } List<int> _durations = []; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Stack( children: [ Center( child: (_cameraInitialized) ? AspectRatio( aspectRatio: _camera.value.aspectRatio, child: CameraPreview(_camera), ) : CircularProgressIndicator()), Center( child: CircularProgressIndicator( backgroundColor: Colors.red, )) ], ), floatingActionButton: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ RaisedButton( onPressed: () async { // print(''' // //tap FloatingActionButton get img //'''); // The jump has animation, and all the pushing that you see is not going very fast // Navigator.push(context, MaterialPageRoute(builder: // (context) => new ImagePreview(img: img))); await _convertImageByC(); }, child: Text('ConvertImageByC'), ), RaisedButton( onPressed: () async { await _convertImageByDart(); }, child: Text('ConvertImageByDart'), ), ], ), // This trailing comma makes auto-formatting nicer for build methods. floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, ); } _convertImageByC() { Stopwatch stopwatch = Stopwatch(); stopwatch.start(); // Allocate memory for the 3 planes of the image Pointer<Uint8> p = allocate(count: _savedImage.planes[0].bytes.length); Pointer<Uint8> p1 = allocate(count: _savedImage.planes[1].bytes.length); Pointer<Uint8> p2 = allocate(count: _savedImage.planes[2].bytes.length); // Assign the planes data to the pointers of the image Uint8List pointerList = p.asTypedList(_savedImage.planes[0].bytes.length); Uint8List pointerList1 = p1.asTypedList(_savedImage.planes[1].bytes.length); Uint8List pointerList2 = p2.asTypedList(_savedImage.planes[2].bytes.length); pointerList.setRange(0, _savedImage.planes[0].bytes.length, _savedImage.planes[0].bytes); pointerList1.setRange(0, _savedImage.planes[1].bytes.length, _savedImage.planes[1].bytes); pointerList2.setRange(0, _savedImage.planes[2].bytes.length, _savedImage.planes[2].bytes); // Call the convertImage function and convert the YUV to RGB Pointer<Uint32> imgP = conv(p, p1, p2, _savedImage.planes[1].bytesPerRow, _savedImage.planes[1].bytesPerPixel, _savedImage.width, _savedImage.height); // Get the pointer of the data returned from the function to a List List imgData = imgP.asTypedList((_savedImage.width * _savedImage.height)); stopwatch.stop(); int getImgDataTime = stopwatch.elapsedMilliseconds; stopwatch.reset(); stopwatch.start(); // Generate image from the converted data imglib.Image img = imglib.Image.fromBytes(_savedImage.height, _savedImage.width, imgData); // Free the memory space allocated // from the planes and the converted data free(p); free(p1); free(p2); free(imgP); stopwatch.stop(); print( 'get imgData: ${getImgDataTime}ms, imglib.Image.fromBytes: ${stopwatch.elapsedMilliseconds}ms, total: ${getImgDataTime + stopwatch.elapsedMilliseconds}ms'); _durations.add(getImgDataTime + stopwatch.elapsedMilliseconds); if (_durations.length == 10) { int totalMilliseconds = 0; for (var value in _durations) { totalMilliseconds += value; } double averageMilliseconds = totalMilliseconds / 10; print('Ten takes an average time: ${averageMilliseconds}ms'); _durations.clear(); } } _convertImageByDart() async { Stopwatch stopwatch = Stopwatch(); stopwatch.start(); await convertYUV420toImageColor(_savedImage); stopwatch.stop(); print('convertYUV420toImageColor time: ${stopwatch.elapsedMilliseconds}ms'); _durations.add(stopwatch.elapsedMilliseconds); if (_durations.length == 10) { int totalMilliseconds = 0; for (var value in _durations) { totalMilliseconds += value; } double averageMilliseconds = totalMilliseconds / 10; print('Ten takes an average time: ${averageMilliseconds}ms'); _durations.clear(); } } static const shift = (0xFF << 24); Future<List<int>> convertYUV420toImageColor(CameraImage image) async { try { final int width = image.width; final int height = image.height; final int uvRowStride = image.planes[1].bytesPerRow; final int uvPixelStride = image.planes[1].bytesPerPixel; // print("uvRowStride: " + uvRowStride.toString()); // print("uvPixelStride: " + uvPixelStride.toString()); // imgLib -> Image package from https://pub.dartlang.org/packages/image var img = imglib.Image(width, height); // Create Image buffer // Fill image buffer with plane[0] from YUV420_888 for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { final int uvIndex = uvPixelStride * (x / 2).floor() + uvRowStride * (y / 2).floor(); final int index = y * width + x; final yp = image.planes[0].bytes[index]; final up = image.planes[1].bytes[uvIndex]; final vp = image.planes[2].bytes[uvIndex]; // Calculate pixel color int r = (yp + vp * 1436 / 1024 - 179).round().clamp(0, 255); int g = (yp - up * 46549 / 131072 + 44 - vp * 93604 / 131072 + 91).round().clamp(0, 255); int b = (yp + up * 1814 / 1024 - 227).round().clamp(0, 255); // color: 0x FF FF FF FF // A B G R img.data[index] = shift | (b << 16) | (g << 8) | r; } } return img.getBytes(); } catch (e) { print(">>>>>>>>>>>> ERROR:" + e.toString()); } return null; } }
Great! I actually didn't know that the release version was that fast because I only tested it in debug. Thanks for your share :) Btw, the images you shared are the same
Why is using Dart(convertYUV420toImageColor) slower under release than debug?
Test Environment
phone: huawei Mate7 Android version: 6.0 CPU: Hisilicon Kirin 925
Let's look at the results first
debug result
using C elapsed time 170-190ms
using Dart elapsed time 230-250ms
release result
flutter run --release
using C elapsed time 35-46ms
using Dart elapsed time 431-593ms why release slow?
my code