1

I have a video file and want to generate 10 different thumbnails for the whole video. I use video_thumbnail package and VideoThumbnail.fromFile() constructor. This constructor has an argument called timeMs and is for, as the documentation states: generates the thumbnail from the frame around the specified millisecond. My code is as follows:

List<String> recordingThumbnailsPaths =
      List<String>.generate(10, (int index) => '');

  Future<void> getRecordingThumbnailsPaths() async {
    final int totalMilliSecs =
        (await FlutterVideoInfo().getVideoInfo(videoFile!.path))!
            .duration!
            .toInt();
    // For debug purpose
    print('Total (ms): $totalMilliSecs');

    for (int i = 0; i < 10; i++) {
      int ms = totalMilliSecs ~/ 10 * i;
      recordingThumbnailsPaths[i] = (await VideoThumbnail.thumbnailFile(
          video: videoFile!.path, timeMs: ms))!;
      // For debug purpose
      print('Iteration $i\nCurrent (ms): $ms');
    }
  }

And here is the log output for each iteration:

Total (ms): 17480

Iteration 0
Current (ms): 0

Iteration 1
Current (ms): 1748

Iteration 2
Current (ms): 3496

Iteration 3
Current (ms): 5244
...
Iteration 9
Current (ms): 15732

But it generates the same first thumbnail for each time frame. So what is the solution? Thanks in advance for your help!

sm_sayedi
  • 326
  • 2
  • 17

1 Answers1

1

I made some edits to the code, and it works fine:

enter code here

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path/path.dart';
import 'package:video_thumbnail/video_thumbnail.dart';

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

  @override
  State<TestPage> createState() => _TestPageState();
}

class _TestPageState extends State<TestPage> {
  List<String> recordingThumbnailsPaths = [];

  Future<void> getRecordingThumbnailsPaths() async {
    final videoFile = /* Your Video File*/;

    final int totalMilliSecs = 15000;
    for (int i = 0; i < 10; i++) {
      int ms = totalMilliSecs ~/ 100 * i;
      final current = (await VideoThumbnail.thumbnailFile(
        video: videoFile!.path!,
        timeMs: ms,
        thumbnailPath: dirname(videoFile!.path!) + "/$i.png",
      ))!;
      recordingThumbnailsPaths.add(current);
    }
    setState(() {});
    print(recordingThumbnailsPaths);
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {},
      child: Scaffold(
        resizeToAvoidBottomInset: true,
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: () async {
                  await getRecordingThumbnailsPaths();
                },
                child: Text("click"),
              ),
              Wrap(
                children: [
                  ...List.generate(
                    recordingThumbnailsPaths.length,
                    (index) => Image.file(
                      File(
                        recordingThumbnailsPaths[index],
                      ),
                      width: 100,
                    ),
                  ),
                ],
              )
            ],
          ),
        ),
      ),
    );
  }
}

I tried before, with you sample of code, and had the same issue, then I found that the video is the one having the same screenshots on those `int ms = totalMilliSecs ~/ 10 * I; duration values.

so first make sure the video have different frames on those duration, or just make the ms differences bigger.

Gwhyyy
  • 7,554
  • 3
  • 8
  • 35
  • 1
    Thanks for the answer. The problem was with the thumbnailPath, because in every iteration it was the same as the video file name with a .png extension, so giving it a custom path with indexes solved the problem. – sm_sayedi Dec 05 '22 at 10:08