Skip to content

Instantly share code, notes, and snippets.

@AmSmart
Last active September 28, 2020 23:16
Show Gist options
  • Save AmSmart/8371b15ba089b44e19aede3e78bb8569 to your computer and use it in GitHub Desktop.
Save AmSmart/8371b15ba089b44e19aede3e78bb8569 to your computer and use it in GitHub Desktop.
Xamarin.Android dependency service to extract a thumbnail from a video
using Xamarin.Forms;
namespace YourApp.Shared.DependencyServices
{
public interface IThumbnailGenerator
{
ImageSource GenerateThumbnailImageSource(string url, long usecond);
string GenerateThumbnailAsPath(string url, long usecond, string appCachePath);
}
}
// This is a simple interface in the shared Xamarin.Forms project.
using Android.Graphics;
using Android.Media;
using StatusSaver.DependencyServices;
using StatusSaver.Droid.DependencyServices;
using System.IO;
using Xamarin.Forms;
[assembly: Dependency(typeof(ThumbnailGeneratorAndroid))]
namespace YourApp.Android.DependencyServices
{
public class ThumbnailGeneratorAndroid : IThumbnailGenerator
{
public ImageSource GenerateThumbnailImageSource(string url, long usecond)
{
// Extract thumbnail from video into a bitmap
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.SetDataSource(url);
Bitmap bitmap = retriever.GetFrameAtTime(usecond);
//Convert bitmap to a 'Stream' and then to an 'ImageSource'
if (bitmap != null)
{
MemoryStream stream = new MemoryStream();
bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
byte[] bitmapData = stream.ToArray();
return ImageSource.FromStream(() => new MemoryStream(bitmapData));
}
return null;
}
public string GenerateThumbnailAsPath(string url, long usecond, string appCachePath)
{
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.SetDataSource(url);
Bitmap bitmap = retriever.GetFrameAtTime(usecond);
//Convert bitmap to a 'Stream', save to a cache folder and then return it's output path
if (bitmap != null)
{
int slashLastIndex = url.LastIndexOf('/');
int dotLastIndex = url.LastIndexOf('.');
int fileNameLength = url.Length - (url.Length - dotLastIndex) - slashLastIndex - 1;
string fileName = url.Substring(slashLastIndex + 1, fileNameLength);
string outputPath = System.IO.Path.Combine(appCachePath, fileName + ".png");
FileStream stream = new FileStream(outputPath, FileMode.CreateNew);
bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
stream.Flush();
stream.Close();
return outputPath;
}
return null;
}
}
}
/*
This is the implementation of the interface below in the Android project.
Both methods above essentially do the same thing in different ways.
You can use the first method by binding your ImageView's source to the ImageSource object returned.
You can use the second method by setting your ImageView's source to the path it returns
You can also ignore all the processing I did after coverting the bitmap into a stream and return the
Stream object directly if it fits your scenario
I found out that using the second method(caching the bitmap and returning a path to it) was more performant in my case,
this was probably because I was dealing with a lot of images being loaded into a CollectionView. Use any one that suits you. Remember
to clean up your cache folder just in case you use this😉
Do whatever works for you.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment