polarby / render

A package to render any native static and moving flutter widgets to exportable formats
https://pub.dev/packages/render
MIT License
49 stars 26 forks source link

Output files return with 0 bytes (0B) #9

Closed MirzaIkhsan closed 1 year ago

MirzaIkhsan commented 1 year ago

I created a simple animation and start recording it using captureMotionWithStream with expected result as MP4. But I don't know what's wrong since I follow the example. It's a simple app, so I think I'm gonna attach the code here

Code

class RenderAnimationPage extends StatefulWidget {
  const RenderAnimationPage({super.key});

  @override
  State<RenderAnimationPage> createState() => _RenderAnimationPageState();
}

class _RenderAnimationPageState extends State<RenderAnimationPage> {
  final renderController = RenderController(logLevel: LogLevel.debug);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      floatingActionButton: Padding(
        padding: const EdgeInsets.only(bottom: 32),
        child: FloatingActionButton.extended(
          onPressed: onRecord,
          backgroundColor: Colors.green,
          label: const Text('RECORD'),
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      body: SafeArea(
        child: Render(
          controller: renderController,
          child: Stack(
            fit: StackFit.expand,
            children: [
              animationWidget,
            ],
          ),
        ),
      ),
    );
  }

  void onRecord() async {
    final stream = renderController.captureMotionWithStream(
      const Duration(seconds: 5),
      settings: const MotionSettings(pixelRatio: 5),
      format: const MovFormat(),
    );

    stream.listen((event) {
      if (event.isActivity) {
        final activity = event as RenderActivity;
        log("Process: ${activity.progressPercentage}");
      }
    });

    final result = await stream.firstWhere((element) => element.isResult);

    saveToGallery(result as RenderResult);
  }

  void saveToGallery(RenderResult renderResult) {
    log(renderResult.output.path);
    GallerySaver.saveVideo(renderResult.output.path, toDcim: true).then((value) {
      if (value != null && value) {
        print("saved export to gallery");
      } else {
        print("failed to save it to gallery");
      }
    });
  }

  Widget get animationWidget {
    return MirrorAnimationBuilder<double>(
      tween: Tween(begin: 10, end: 100),
      duration: const Duration(seconds: 2),
      builder: (context, value, child) {
        return Positioned(
          left: value,
          top: 100,
          child: Container(
            width: 100,
            height: 100,
            color: Colors.red,
            child: child,
          ),
        );
      },
      curve: Curves.easeInOut,
      child: const Text('Hello World'),
    );
  }
}

Current Result An MP4 file with 0B, so it can't be played using Media Player

Expected behavior A playable MP4 video

Package version I use the Render v.0.0.7

polarby commented 1 year ago

Thanks for opening this issue. The code seems to be alright, but I am currently on vacation till next week with no way to debug.

Have you tried to to use different output formats or render functions? Also check if the example of my plugin works for you!

This seems to be a valid concern and I will be debugging on that as soon as I am back to work! Sorry for the waiting time. Until then I might be able to help you out by providing me with the debug log (not necessarily for each frame)?!

MirzaIkhsan commented 1 year ago

Thanks for replying this issue. I already tried different output formats and render functions. But I found some interesting thing. It seems that if I record widget with bigger dimensions I have to increase the pixelRatio and also decrease simultaneousCaptureHandlers. But the probability of the video successfully rendering is no more than 20%. Sometime it works and sometime it doesn't. Also the bigger pixelRatio will make the rendering animation will go laggy.

MirzaIkhsan commented 1 year ago

Thanks for opening this issue. The code seems to be alright, but I am currently on vacation till next week with no way to debug.

Have you tried to to use different output formats or render functions? Also check if the example of my plugin works for you!

This seems to be a valid concern and I will be debugging on that as soon as I am back to work! Sorry for the waiting time. Until then I might be able to help you out by providing me with the debug log (not necessarily for each frame)?!

Yes I already tried the example of your code. It works fine, but if I increase the size of the widget from width=100 to width=500 it will returns the MP4 with 0B. But it will works fine if I increase the pixelRatio=8 but it will going to be laggy

polarby commented 1 year ago

The laggy rendering when capturing at high quality is a known device limitation, described under "limitation" in the docs. (Including the reason)

The result should never be 0bytes though. Is the process capturing the frames? It might be a conversation issue of FFmpeg, which I am unaware until now. It might very well help if you send me the logs with the logLevel = LogLevel.debug.

polarby commented 1 year ago

Thanks for the issue. I was able to reproduce the problem. The problem is with an expanded widgets, that the first frame somehow has a different size than the others. A temporary fix for you is to give your widget fixed constraints. I will address the issue within an update in the next days, by forcing(converting) same-size frames.

MirzaIkhsan commented 1 year ago

Thanks for the response. I think there is another problem, that is if I use Container(width=200, height=200) with RenderSetting(pixelRatio=1, frameRate=30) it will also make the output become 0B too. I don't really know what's going on since the debug didn't say anything.

polarby commented 1 year ago

Alright, I was wrong in my assumption that this is a different-size-frame issue.

The problem you are probably experiencing is due to frame sizes not being dividable by two, which throws an error on the FFmpeg (the conversion engine) side. With the ca8fed7a3fac2af1544fc6c8107bd79789d38b96 release (or render: ^0.0.9) I have addressed all issues you had and side issues, that appeared while debugging your case:

PS.: You should not have any problems with expandable widgets anymore. Just make sure that pixelRatio is not too big, so the player cant visualize it anymore