justsoft / video_thumbnail

This plugin generates thumbnail from video file or URL. It returns image in memory or writes into a file. It offers rich options to control the image format, resolution and quality. Supports iOS and Android.
MIT License
187 stars 286 forks source link

[feature/web]: Add Support for Flutter Web (sample provided) #14

Open Ahmadre opened 4 years ago

Ahmadre commented 4 years ago

I encountered,. that this package only works for ios and android.

I got pure 100% dart solution for flutter web:

  void getVideoThumbnail(String path, callback) {
    html.VideoElement video = html.document.createElement('video');
    video.src = path;

    video.onSeeked.listen((html.Event e) {
      html.CanvasElement canvas = html.document.createElement('canvas');
      canvas.height = video.videoHeight;
      canvas.width = video.videoWidth;
      html.CanvasRenderingContext2D ctx = canvas.getContext('2d');
      ctx.drawImage(video, canvas.width, canvas.height);
      html.ImageElement img = new html.ImageElement();
      img.src = canvas.toDataUrl();
      callback.call(img, e);
    });
    video.onError.listen((html.Event e) {
      callback.call(null, e);
    });
  }

Maybe you can combine that with your platform channels and create a platform interface :).

Code ported from: https://cwestblog.com/2017/05/03/javascript-snippet-get-video-frame-as-an-image/

justsoft commented 4 years ago

Thanks, will take a deep look once find some free time.

Ahmadre commented 4 years ago

I encountered that video_player package itself is supporting thumbnails on init:

Bildschirmfoto 2020-02-28 um 21 09 16

You only need to:

VideoPlayerController controller =
            VideoPlayerController.network(snapshot.data()['mediaURL'])..initialize();
return VideoPlayer(controller);
markgrancapal commented 4 years ago

I encountered that video_player package itself is supporting thumbnails on init:

Bildschirmfoto 2020-02-28 um 21 09 16

You only need to:

VideoPlayerController controller =
            VideoPlayerController.network(snapshot.data()['mediaURL'])..initialize();
return VideoPlayer(controller);

Hello @Ahmadre , I'm trying to find a way to create thumbnail on Flutter Web. can you explain how I can achieve it using this? I had two data that can hold my video, using image_picker_for_web that gives a network path or a byte data.

markgrancapal commented 4 years ago

I encountered,. that this package only works for ios and android.

I got pure 100% dart solution for flutter web:

  void getVideoThumbnail(String path, callback) {
    html.VideoElement video = html.document.createElement('video');
    video.src = path;

    video.onSeeked.listen((html.Event e) {
      html.CanvasElement canvas = html.document.createElement('canvas');
      canvas.height = video.videoHeight;
      canvas.width = video.videoWidth;
      html.CanvasRenderingContext2D ctx = canvas.getContext('2d');
      ctx.drawImage(video, canvas.width, canvas.height);
      html.ImageElement img = new html.ImageElement();
      img.src = canvas.toDataUrl();
      callback.call(img, e);
    });
    video.onError.listen((html.Event e) {
      callback.call(null, e);
    });
  }

Maybe you can combine that with your platform channels and create a platform interface :).

Code ported from: https://cwestblog.com/2017/05/03/javascript-snippet-get-video-frame-as-an-image/

I see that you are the one who develop image_picker_web, how can I use this code using your package? can I use html.File for the path? Thank you for the help @Ahmadre

allcui commented 3 years ago

Hi, any updates on this one? Are we planning to add Flutter web support to this package?

abdullah432 commented 3 years ago

I encountered,. that this package only works for ios and android. I got pure 100% dart solution for flutter web:

  void getVideoThumbnail(String path, callback) {
    html.VideoElement video = html.document.createElement('video');
    video.src = path;

    video.onSeeked.listen((html.Event e) {
      html.CanvasElement canvas = html.document.createElement('canvas');
      canvas.height = video.videoHeight;
      canvas.width = video.videoWidth;
      html.CanvasRenderingContext2D ctx = canvas.getContext('2d');
      ctx.drawImage(video, canvas.width, canvas.height);
      html.ImageElement img = new html.ImageElement();
      img.src = canvas.toDataUrl();
      callback.call(img, e);
    });
    video.onError.listen((html.Event e) {
      callback.call(null, e);
    });
  }

Maybe you can combine that with your platform channels and create a platform interface :). Code ported from: https://cwestblog.com/2017/05/03/javascript-snippet-get-video-frame-as-an-image/

I see that you are the one who develop image_picker_web, how can I use this code using your package? can I use html.File for the path? Thank you for the help @Ahmadre

Not working with latest html version

bismarabia commented 3 years ago

Any updates on this?

Alvarocda commented 2 years ago

Any updates on this?

jcblancomartinez commented 2 years ago

Any update?

Thanks.

nathansdev commented 2 years ago

did any one figure out this?

jcblancomartinez commented 2 years ago

Hi,

Here you have a newer working version with CORS enabled:

Future<void> _getVideoThumbnail(
      String path, void Function(Uint8List? imageBytes) callback) async {
    VideoElement video = VideoElement()
      ..crossOrigin = 'anonymous'
      ..src = path
      ..muted = true;
    CanvasElement canvas = CanvasElement();
    video.onLoadedMetadata.listen((Event event) async {
      canvas.width = video.videoWidth;
      canvas.height = video.videoHeight;
      video.currentTime = 0;
    });
    video.onSeeked.listen((Event event) async {
      CanvasRenderingContext2D ctx = canvas.context2D;
      ctx.drawImage(video, 0, 0);
      Blob blob = await canvas.toBlob('image/png', 0.95);
      XFile xFile = XFile(Url.createObjectUrlFromBlob(blob),
          mimeType: 'image/png',
          lastModified: DateTime.now(),
          length: blob.size);
      debugPrint('Obtained xFile=[${xFile.path}] for path=[$path].');
      callback.call(await xFile.readAsBytes());
    });
    video.onError.listen((Event event) async {
      debugPrint('Error processing path=[$path] with event=[$event].');
      callback.call(null);
    });
  }

Regards.

maRci002 commented 1 year ago

Check out #135 PR.

Clone the repo (_unfortunately dependency_overrides doesn't work since the PR contains local path_)

git clone -b feat-web_implementation https://github.com/maRci002/video_thumbnail.git

Add it to your pubspec.yaml

dependencies:
  video_thumbnail:
    path: ../video_thumbnail/video_thumbnail

I have already tested it with video_editor package:

https://user-images.githubusercontent.com/8436039/229935809-2f146b7e-fe0a-4b50-99bc-a78ee63266a0.mp4

mehmetemregokberk commented 1 year ago

Can you give us a sample project for web?

I'm getting error when i run git clone code:

[video_thumbnail/video_thumbnail_web] flutter pub get Resolving dependencies... Git error. Command: git clone --mirror git@github.com:maRci002/video_thumbnail.git /Users/emre/.pub-cache/git/cache/video_thumbnail-eeb03d34cb54759a210a222943f9e014ba59971c stdout: stderr: Cloning into bare repository '/Users/emre/.pub-cache/git/cache/video_thumbnail-eeb03d34cb54759a210a222943f9e014ba59971c'... git@github.com: Permission denied (publickey). fatal: Could not read from remote repository.

Please make sure you have the correct access rights and the repository exists. exit code: 128 exit code 69

maRci002 commented 1 year ago

I'm getting error when i run git clone code:

https://stackoverflow.com/a/51820472/4609658

use https link ( instead of git@github.com ): git clone --mirror https://github.com/maRci002/video_thumbnail.git

mehmetemregokberk commented 1 year ago

I'm getting error when i run git clone code:

https://stackoverflow.com/a/51820472/4609658

use https link ( instead of git@github.com ): git clone --mirror https://github.com/maRci002/video_thumbnail.git

Actually i'm running https url (git clone -b feat-web_implementation https://github.com/maRci002/video_thumbnail.git)

This is my vscode terminal output:

emre@Emres-MBP kindergarten % git clone -b feat-web_implementation https://github.com/maRci002/video_thumbnail.git
Cloning into 'video_thumbnail'...
remote: Enumerating objects: 820, done.
remote: Counting objects: 100% (201/201), done.
remote: Compressing objects: 100% (111/111), done.
remote: Total 820 (delta 83), reused 163 (delta 68), pack-reused 619
Receiving objects: 100% (820/820), 422.72 KiB | 2.04 MiB/s, done.
Resolving deltas: 100% (368/368), done.
emre@Emres-MBP kindergarten % 

And this is my Output window:

[video_thumbnail/video_thumbnail_web] flutter pub get
Resolving dependencies...
Git error. Command: `git clone --mirror git@github.com:maRci002/video_thumbnail.git /Users/emre/.pub-cache/git/cache/video_thumbnail-eeb03d34cb54759a210a222943f9e014ba59971c`
stdout: 
stderr: Cloning into bare repository '/Users/emre/.pub-cache/git/cache/video_thumbnail-eeb03d34cb54759a210a222943f9e014ba59971c'...
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
exit code: 128
exit code 69
maRci002 commented 1 year ago

Okay I think I got it. Recently I made a commit to avoid local path and replace with git path and your output window using different SSH agent than the terminal https://github.com/justsoft/video_thumbnail/pull/135/commits/47435c7933c0b0b148acb9d79100e2e4aa369fae

I think if you run flutter pub get in the terminal your problem will be solved (because therminal has registered SSH key in your Github account)

So currently you do not need to manually clone the project and configuring local path, instead you can use this:

  video_thumbnail:
    git:
      url: git@github.com:maRci002/video_thumbnail.git
      ref: feat-web_implementation
      path: video_thumbnail

But I think this way you will get the same error, since the SSH agent which is used by Output window is not registered in your Github's SSH keys. https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account

If you cannot add SSH key to your github account for output window then

mehmetemregokberk commented 1 year ago

Thank you so much. Your last opinion worked!

I'm normally call thumnail data like "final thumbData = await VideoThumbnail.thumbnailData(.." for ios-android. Do i need call differently for web?

maRci002 commented 1 year ago

I think example is updated, you can also check out readme. https://github.com/justsoft/video_thumbnail/blob/47435c7933c0b0b148acb9d79100e2e4aa369fae/video_thumbnail/README.md

XFile thumbnailFile = await VideoThumbnail.thumbnailFile( ... );

final image = kIsWeb ? Image.network(thumbnailFile.path) : Image.file(File(thumbnailFile.path));

final uint8list = await VideoThumbnail.thumbnailData( ... );

final image = Image.memory(uint8list );
mehmetemregokberk commented 1 year ago

If I'm not mistaken, the video needs to be called via the url to be able to create thumbnails on the web? I choose videos from gallery on ios and android. In the same way, I plan to select videos on the web from the computer. But as you mentioned, in the documentation "This plugin requires the server hosting the video to support HTTP range headers." specified as. As I understand from here, there is no way to use it other than the url on the web?

maRci002 commented 1 year ago

You can use localy picked files too since it lives on the filesystem and in that case the underlying VideoElement is smart enough to not create network calls with range headers.

In the example you can pick a media, for test choose a long one. https://github.com/maRci002/video_thumbnail/blob/47435c7933c0b0b148acb9d79100e2e4aa369fae/video_thumbnail/example/lib/main.dart#L381C1-L405C13

mehmetemregokberk commented 1 year ago

@maRci002 Sorry for the late reply due to the holiday. I was able to create thumbnail on web in debug mode but when i send it to hosting chrome gives below error. I think I'm getting this error because the plugin folder is on root? If so how can I include this folder in release?

Uncaught MissingPluginException(No implementation found for method data on channel plugins.justsoft.xyz/video_thumbnail) at Object.c (https://app.xyz.com.tr/main.dart.js:5341:3) at https://app.xyz.com.tr/main.dart.js:115732:15 at bQe.a (https://app.xyz.com.tr/main.dart.js:6674:62) at bQe.$2 (https://app.xyz.com.tr/main.dart.js:71952:14) at bOK.$1 (https://app.xyz.com.tr/main.dart.js:71946:21) at bKW.bvY (https://app.xyz.com.tr/main.dart.js:73065:34) at bKW.abA (https://app.xyz.com.tr/main.dart.js:73067:22) at bEy.$0 (https://app.xyz.com.tr/main.dart.js:72365:11) at Object.RJ (https://app.xyz.com.tr/main.dart.js:6810:40) at aA.yN (https://app.xyz.com.tr/main.dart.js:72289:3)

louisdeveseleer commented 1 year ago

@maRci002 Thank you for making this addition to support thumbnail generation on the web! I just tried your branch and it works perfectly.

Do you know what's the timeline to merge your PR ?

maRci002 commented 1 year ago

Unfortunately, I don't have a timeline for the merge since I've just made the PR. It appears that the author of this package is no longer active.

louisdeveseleer commented 1 year ago

Ok thank you for the information and for your work!

louisdeveseleer commented 1 year ago

@maRci002 If this package is abandoned and you feel like creating your own package from this one, I think it would be popular, because I've met many comments online from people looking for a solution to generate thumbnails for videos on the web.

lucho-dev commented 1 year ago

I'm getting error when i run git clone code:

https://stackoverflow.com/a/51820472/4609658 use https link ( instead of git@github.com ): git clone --mirror https://github.com/maRci002/video_thumbnail.git

Actually i'm running https url (git clone -b feat-web_implementation https://github.com/maRci002/video_thumbnail.git)

This is my vscode terminal output:

emre@Emres-MBP kindergarten % git clone -b feat-web_implementation https://github.com/maRci002/video_thumbnail.git
Cloning into 'video_thumbnail'...
remote: Enumerating objects: 820, done.
remote: Counting objects: 100% (201/201), done.
remote: Compressing objects: 100% (111/111), done.
remote: Total 820 (delta 83), reused 163 (delta 68), pack-reused 619
Receiving objects: 100% (820/820), 422.72 KiB | 2.04 MiB/s, done.
Resolving deltas: 100% (368/368), done.
emre@Emres-MBP kindergarten % 

And this is my Output window:

[video_thumbnail/video_thumbnail_web] flutter pub get
Resolving dependencies...
Git error. Command: `git clone --mirror git@github.com:maRci002/video_thumbnail.git /Users/emre/.pub-cache/git/cache/video_thumbnail-eeb03d34cb54759a210a222943f9e014ba59971c`
stdout: 
stderr: Cloning into bare repository '/Users/emre/.pub-cache/git/cache/video_thumbnail-eeb03d34cb54759a210a222943f9e014ba59971c'...
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
exit code: 128
exit code 69

@mehmetemregokberk sorry to go back to this but I had the same issue with the same responses and all. As @maRci002 said is a problem with the SSH key, in my case the Key on my mac to authenticate to GitHub was outdated (you can check by running ssh -vT git@github.com in your terminal)

What worked for me was removing the old key following this official instructions: https://github.blog/2023-03-23-we-updated-our-rsa-ssh-host-key/ (from https://github.com/orgs/community/discussions/50878) and then adding new SSH keys to my account following the instructions on the link that maRci002 provided: https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account there are a lot of steps but they are easy to follow.

maRci002 commented 1 year ago

Playing with SSH is not fun at all. In my case, Git Bash was configured while PowerShell was not. Git, during the installation phase, asks if it should use the operating system's SSH agent or its own, so every terminal might work differently. Furthermore, if your project is managed via CI/CD on the cloud, it has its own terminal.

https://dart.dev/tools/pub/dependencies#git-packages So, I decided to use the HTTPS Git link instead of SSH, so you can use this in your pubspec.yaml:

dependencies:
  video_thumbnail:
    git:
      url: https://github.com/maRci002/video_thumbnail.git
      ref: feat-web_implementation
      path: video_thumbnail