Skip to content

[Camera] Camera plugin throwing null object on android.media.CamcorderProfile.videoFrameWidth #40164

@mikhail-karan

Description

@mikhail-karan

Hi, just want to report a strange issue I am having that related to a older Android Tablet and the flutter Camera Plugin.

What happens is when I run the basic Camera plugin code on this device it will give me a blank camera preview and throw the following error in the Android Studio Debugger:

    java.lang.NullPointerException: Attempt to read from field 'int android.media.CamcorderProfile.videoFrameWidth' on a null object reference
        at io.flutter.plugins.camera.Camera.<init>(Camera.java:113)
        at io.flutter.plugins.camera.CameraPlugin.instantiateCamera(CameraPlugin.java:51)
        at io.flutter.plugins.camera.CameraPlugin.lambda$onMethodCall$0$CameraPlugin(CameraPlugin.java:83)
        at io.flutter.plugins.camera.-$$Lambda$CameraPlugin$yA2LM_Usm2rt4SGxnaveLC8c7K0.onResult(lambda)
        at io.flutter.plugins.camera.CameraPermissions.requestPermissions(CameraPermissions.java:38)
        at io.flutter.plugins.camera.CameraPlugin.onMethodCall(CameraPlugin.java:77)
        at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:222)
        at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(DartMessenger.java:96)
        at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(FlutterJNI.java:643)
        at android.os.MessageQueue.nativePollOnce(Native Method)
        at android.os.MessageQueue.next(MessageQueue.java:143)
        at android.os.Looper.loop(Looper.java:122)
        at android.app.ActivityThread.main(ActivityThread.java:5280)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:963)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:758)

Steps to Reproduce

This one will be tough to reproduce since it's device specific. The Camera works fine on all other devices I tested but this one.

The tablet is a 15" Android tablet running android 5.1. It's used for running Ad content in stores. The processor is a RK3 88, Cortex-A , 1. GHz Quad Core. I've found that it isn't a android version specific issue because we have other devices running android 5.1 that work just fine.

I'm just using the Camera plugin example to reproduce this issue but I'll post the main.dart anyway:

import 'dart:io';

import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:path/path.dart' show join;
import 'package:path_provider/path_provider.dart';

Future<void> main() async {
  // Obtain a list of the available cameras on the device.
  final cameras = await availableCameras();

  // Get a specific camera from the list of available cameras.
  final firstCamera = cameras.first;

  runApp(
    MaterialApp(
      theme: ThemeData.dark(),
      home: TakePictureScreen(
        // Pass the appropriate camera to the TakePictureScreen widget.
        camera: firstCamera,
      ),
    ),
  );
}

// A screen that allows users to take a picture using a given camera.
class TakePictureScreen extends StatefulWidget {
  final CameraDescription camera;

  const TakePictureScreen({
    Key key,
    @required this.camera,
  }) : super(key: key);

  @override
  TakePictureScreenState createState() => TakePictureScreenState();
}

class TakePictureScreenState extends State<TakePictureScreen> {
  CameraController _controller;
  Future<void> _initializeControllerFuture;

  @override
  void initState() {
    super.initState();
    // To display the current output from the Camera,
    // create a CameraController.
    _controller = CameraController(
      // Get a specific camera from the list of available cameras.
      widget.camera,
      // Define the resolution to use.
      ResolutionPreset.medium,
    );

    // Next, initialize the controller. This returns a Future.
    _initializeControllerFuture = _controller.initialize();
  }

  @override
  void dispose() {
    // Dispose of the controller when the widget is disposed.
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Take a picture')),
      // Wait until the controller is initialized before displaying the
      // camera preview. Use a FutureBuilder to display a loading spinner
      // until the controller has finished initializing.
      body: FutureBuilder<void>(
        future: _initializeControllerFuture,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            // If the Future is complete, display the preview.
            return CameraPreview(_controller);
          } else {
            // Otherwise, display a loading indicator.
            return Center(child: CircularProgressIndicator());
          }
        },
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.camera_alt),
        // Provide an onPressed callback.
        onPressed: () async {
          // Take the Picture in a try / catch block. If anything goes wrong,
          // catch the error.
          try {
            // Ensure that the camera is initialized.
            await _initializeControllerFuture;

            // Construct the path where the image should be saved using the 
            // pattern package.
            final path = join(
              // Store the picture in the temp directory.
              // Find the temp directory using the `path_provider` plugin.
              (await getTemporaryDirectory()).path,
              '${DateTime.now()}.png',
            );

            // Attempt to take a picture and log where it's been saved.
            await _controller.takePicture(path);

            // If the picture was taken, display it on a new screen.
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => DisplayPictureScreen(imagePath: path),
              ),
            );
          } catch (e) {
            // If an error occurs, log the error to the console.
            print(e);
          }
        },
      ),
    );
  }
}

// A widget that displays the picture taken by the user.
class DisplayPictureScreen extends StatelessWidget {
  final String imagePath;

  const DisplayPictureScreen({Key key, this.imagePath}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Display the Picture')),
      // The image is stored as a file on the device. Use the `Image.file`
      // constructor with the given path to display the image.
      body: Image.file(File(imagePath)),
    );
  }
}

I don't know if you still want me to run flutter doctor or anything since the code is working fine on all other tablets I tested. I believe it is something to do with how the camera is grabbed in the android code, I wonder if theres maybe a different way to grab the camera that will work for this device. I know the camera works as we do have a java camera plugin that we have used in the past and that worked. As well as the preinstalled camera app on the device works.

Thanks in advance for anyone taking a look at this. Let me know if you need any other information from me.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions