[vlc-commits] [Git][videolan/vlc][master] 9 commits: macosx: Add NSImage extension method to get thumbnail from localUrl asynchronously
Jean-Baptiste Kempf (@jbk)
gitlab at videolan.org
Sun May 5 17:54:36 UTC 2024
Jean-Baptiste Kempf pushed to branch master at VideoLAN / VLC
Commits:
530a8554 by Claudio Cambra at 2024-05-05T17:15:36+00:00
macosx: Add NSImage extension method to get thumbnail from localUrl asynchronously
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
ab2e9a10 by Claudio Cambra at 2024-05-05T17:15:36+00:00
macosx: Make getting thumbnail image for input item async
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
8ee07689 by Claudio Cambra at 2024-05-05T17:15:36+00:00
macosx: Enforce use of async thumbnailing
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
64ae7930 by Claudio Cambra at 2024-05-05T17:15:36+00:00
macosx: Actually fetch the thumbnail in QuickLook thumbnail generator
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
0444ac77 by Claudio Cambra at 2024-05-05T17:15:36+00:00
macosx: Fix check for stream in input item thumbnail generation
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
5dc72cd2 by Claudio Cambra at 2024-05-05T17:15:36+00:00
macosx: Store async input item thumbnail in image cache
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
0a46015f by Claudio Cambra at 2024-05-05T17:15:36+00:00
macosx: Just use folder icon for the input node path control item
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
b11661f1 by Claudio Cambra at 2024-05-05T17:15:36+00:00
macosx: Be more permissive with QL thumbnail representations
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
3634ea93 by Claudio Cambra at 2024-05-05T17:15:36+00:00
macosx: Set image on cache for input item thumbnail on main queue
Signed-off-by: Claudio Cambra <developer at claudiocambra.com>
- - - - -
10 changed files:
- modules/gui/macosx/Makefile.am
- modules/gui/macosx/extensions/NSImage+VLCAdditions.h
- modules/gui/macosx/extensions/NSImage+VLCAdditions.m
- modules/gui/macosx/library/VLCInputItem.h
- modules/gui/macosx/library/VLCInputItem.m
- modules/gui/macosx/library/VLCInputNodePathControlItem.m
- modules/gui/macosx/library/VLCLibraryHeroView.m
- modules/gui/macosx/library/VLCLibraryImageCache.h
- modules/gui/macosx/library/VLCLibraryImageCache.m
- modules/gui/macosx/panels/VLCInformationWindowController.m
Changes:
=====================================
modules/gui/macosx/Makefile.am
=====================================
@@ -48,6 +48,7 @@ libmacosx_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(guidir)' \
-Wl,-framework,ScriptingBridge \
-Wl,-framework,WebKit \
-Wl,-framework,QuickLook \
+ -Wl,-framework,QuickLookThumbnailing \
-Wl,-weak_framework,MediaPlayer
if HAVE_SPARKLE
=====================================
modules/gui/macosx/extensions/NSImage+VLCAdditions.h
=====================================
@@ -26,6 +26,12 @@ NS_ASSUME_NONNULL_BEGIN
@interface NSImage (VLCAdditions)
++ (void)quickLookPreviewForLocalPath:(NSString *)path
+ withSize:(NSSize)size
+ completionHandler:(void (^)(NSImage * _Nullable))completionHandler;
++ (void)quickLookPreviewForLocalURL:(NSURL *)url
+ withSize:(NSSize)size
+ completionHandler:(void (^)(NSImage * _Nullable))completionHandler;
+ (instancetype)quickLookPreviewForLocalPath:(NSString*)path withSize:(NSSize)size;
+ (instancetype)quickLookPreviewForLocalURL:(NSURL*)url withSize:(NSSize)size;
+ (instancetype)compositeImageWithImages:(NSArray<NSImage *> * const)images
=====================================
modules/gui/macosx/extensions/NSImage+VLCAdditions.m
=====================================
@@ -23,9 +23,51 @@
#import "NSImage+VLCAdditions.h"
#import <QuickLook/QuickLook.h>
+#import <QuickLookThumbnailing/QuickLookThumbnailing.h>
@implementation NSImage(VLCAdditions)
++ (void)quickLookPreviewForLocalPath:(NSString *)path
+ withSize:(NSSize)size
+ completionHandler:(void (^)(NSImage *))completionHandler
+{
+ NSURL * const pathUrl = [NSURL fileURLWithPath:path];
+ [self quickLookPreviewForLocalURL:pathUrl withSize:size completionHandler:completionHandler];
+}
+
++ (void)quickLookPreviewForLocalURL:(NSURL *)url
+ withSize:(NSSize)size
+ completionHandler:(void (^)(NSImage *))completionHandler
+{
+ if (@available(macOS 10.15, *)) {
+ const QLThumbnailGenerationRequestRepresentationTypes type =
+ QLThumbnailGenerationRequestRepresentationTypeAll;
+ QLThumbnailGenerator * const generator = QLThumbnailGenerator.sharedGenerator;
+ QLThumbnailGenerationRequest * const request =
+ [[QLThumbnailGenerationRequest alloc] initWithFileAtURL:url
+ size:size
+ scale:1.
+ representationTypes:type];
+ [generator generateBestRepresentationForRequest:request
+ completionHandler:^(QLThumbnailRepresentation * const thumbnail,
+ NSError * const error) {
+ if (error != nil) {
+ NSLog(@"Error generating thumbnail: %@", error);
+ completionHandler(nil);
+ return;
+ }
+ completionHandler(thumbnail.NSImage);
+ }];
+ } else {
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
+ NSImage * const image = [self quickLookPreviewForLocalURL:url withSize:size];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ completionHandler(image);
+ });
+ });
+ }
+}
+
+ (instancetype)quickLookPreviewForLocalPath:(NSString *)path withSize:(NSSize)size
{
NSURL *pathUrl = [NSURL fileURLWithPath:path];
=====================================
modules/gui/macosx/library/VLCInputItem.h
=====================================
@@ -81,7 +81,8 @@ extern NSString *VLCInputItemPreparsingSucceeded;
- (int)preparseInputItem;
- (int)writeMetadataToFile;
-- (NSImage*)thumbnailWithSize:(NSSize)size;
+- (void)thumbnailWithSize:(NSSize)size
+ completionHandler:(void (^)(NSImage * _Nullable))completionHandler;
@end
=====================================
modules/gui/macosx/library/VLCInputItem.m
=====================================
@@ -606,32 +606,46 @@ static const struct vlc_metadata_cbs preparseCallbacks = {
return input_item_WriteMeta(VLC_OBJECT(getIntf()), _vlcInputItem);
}
-- (NSImage*)thumbnailWithSize:(NSSize)size
+- (void)thumbnailWithSize:(NSSize)size completionHandler:(void(^)(NSImage * image))completionHandler
{
- NSImage *image;
- if (!self.isStream && _vlcInputItem != NULL) {
- char *psz_url = input_item_GetURI(_vlcInputItem);
- if (psz_url) {
- char *psz_path = vlc_uri2path(psz_url);
- if (psz_path) {
- NSString *path = toNSStr(psz_path);
- free(psz_path);
- image = [NSImage quickLookPreviewForLocalPath:path
- withSize:size];
-
- if (!image) {
- image = [NSWorkspace.sharedWorkspace iconForFile:path];
- image.size = size;
- }
- }
- free(psz_url);
- }
+ if (self.isStream || _vlcInputItem == NULL) {
+ completionHandler(nil);
+ return;
}
- if (!image) {
- image = [NSImage imageNamed: @"noart.png"];
+ char * const psz_url = input_item_GetURI(_vlcInputItem);
+ if (psz_url == NULL) {
+ completionHandler(nil);
+ return;
+ }
+
+ char * const psz_path = vlc_uri2path(psz_url);
+ free(psz_url);
+ if (psz_path == NULL) {
+ completionHandler(nil);
+ return;
}
- return image;
+
+ NSString * const path = toNSStr(psz_path);
+ free(psz_path);
+
+ [NSImage quickLookPreviewForLocalPath:path
+ withSize:size
+ completionHandler:^(NSImage * image) {
+ if (image) {
+ completionHandler(image);
+ return;
+ }
+
+ NSImage * const workspaceImage = [NSWorkspace.sharedWorkspace iconForFile:path];
+ if (workspaceImage) {
+ image.size = size;
+ completionHandler(image);
+ return;
+ }
+
+ completionHandler(nil);
+ }];
}
- (void)moveToTrash
=====================================
modules/gui/macosx/library/VLCInputNodePathControlItem.m
=====================================
@@ -36,8 +36,7 @@
VLCInputItem * const inputItem = inputNode.inputItem;
self.title = inputItem.name;
- self.image = [VLCLibraryImageCache thumbnailForInputItem:inputItem];;
-
+ self.image = [NSImage imageNamed:NSImageNameFolder];
// HACK: We have no way when we get the clicked item from the path control
// of knowing specifically which input node this path item corresponds to,
// as the path control returns a copy for clickedPathItem that is not of
=====================================
modules/gui/macosx/library/VLCLibraryHeroView.m
=====================================
@@ -54,9 +54,11 @@
{
NSAssert(self.representedItem != nil, @"Should not update nil represented item!");
const id<VLCMediaLibraryItemProtocol> actualItem = self.representedItem.item;
- self.largeImageView.image = [VLCLibraryImageCache thumbnailForLibraryItem:actualItem];
self.titleTextField.stringValue = actualItem.displayString;
self.detailTextField.stringValue = actualItem.primaryDetailString;
+ [VLCLibraryImageCache thumbnailForLibraryItem:actualItem withCompletion:^(NSImage * const image) {
+ self.largeImageView.image = image;
+ }];
}
- (void)setRepresentedItem:(VLCLibraryRepresentedItem *)representedItem
=====================================
modules/gui/macosx/library/VLCLibraryImageCache.h
=====================================
@@ -30,10 +30,6 @@ NS_ASSUME_NONNULL_BEGIN
@interface VLCLibraryImageCache : NSObject
-+ (nullable NSImage *)thumbnailForLibraryItem:(id<VLCMediaLibraryItemProtocol>)libraryItem;
-+ (nullable NSImage *)thumbnailForInputItem:(VLCInputItem*)inputItem;
-+ (nullable NSImage *)thumbnailForPlaylistItem:(VLCPlaylistItem*)playlistItem;
-
+ (void)thumbnailForLibraryItem:(id<VLCMediaLibraryItemProtocol>)libraryItem
withCompletion:(void(^)(const NSImage *))completionHandler;
+ (void)thumbnailForInputItem:(VLCInputItem *)inputItem
=====================================
modules/gui/macosx/library/VLCLibraryImageCache.m
=====================================
@@ -119,50 +119,58 @@ const NSUInteger kVLCCompositeImageDefaultCompositedGridItemCount = 4;
kVLCDefaultThumbnailPosition);
}
-+ (NSImage *)thumbnailForInputItem:(VLCInputItem *)inputItem
++ (void)thumbnailForInputItem:(VLCInputItem *)inputItem
+ withCompletion:(nonnull void (^)(const NSImage * _Nonnull))completionHandler
{
- return [VLCLibraryImageCache.sharedImageCache imageForInputItem:inputItem];
+ [VLCLibraryImageCache.sharedImageCache imageForInputItem:inputItem withCompletion:completionHandler];
}
-- (NSImage *)imageForInputItem:(VLCInputItem *)inputItem
+- (void)imageForInputItem:(VLCInputItem *)inputItem
+ withCompletion:(nonnull void (^)(const NSImage * _Nonnull))completionHandler
{
- NSImage *cachedImage = [_imageCache objectForKey:inputItem.MRL];
+ NSImage * const cachedImage = [_imageCache objectForKey:inputItem.MRL];
if (cachedImage) {
- return cachedImage;
+ completionHandler(cachedImage);
+ return;
}
- return [self generateImageForInputItem:inputItem];
+ [self generateImageForInputItem:inputItem withCompletion:completionHandler];
}
-- (NSImage *)generateImageForInputItem:(VLCInputItem *)inputItem
+- (void)generateImageForInputItem:(VLCInputItem *)inputItem
+ withCompletion:(void(^)(const NSImage *))completionHandler
{
- NSImage *image;
NSURL * const artworkURL = inputItem.artworkURL;
+ NSImage * const image = [[NSImage alloc] initWithContentsOfURL:artworkURL];
const NSSize imageSize = NSMakeSize(kVLCDesiredThumbnailWidth, kVLCDesiredThumbnailHeight);
- if (artworkURL) {
- image = [[NSImage alloc] initWithContentsOfURL:artworkURL];
- }
-
- if (image == nil) {
- image = [inputItem thumbnailWithSize:imageSize];
- }
-
if (image) {
+ image.size = imageSize;
[_imageCache setObject:image forKey:inputItem.MRL];
- } else { // If nothing so far worked, then fall back on default image
- image = [NSImage imageNamed:@"noart.png"];
+ completionHandler(image);
+ } else {
+ [inputItem thumbnailWithSize:imageSize completionHandler:^(NSImage * const image) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ if (image) {
+ [_imageCache setObject:image forKey:inputItem.MRL];
+ completionHandler(image);
+ } else {
+ NSLog(@"Failed to generate thumbnail for input item %@", inputItem.MRL);
+ completionHandler([NSImage imageNamed:@"noart.png"]);
+ }
+ });
+ }];
}
-
- return image;
}
-+ (NSImage *)thumbnailForPlaylistItem:(VLCPlaylistItem *)playlistItem
++ (void)thumbnailForPlaylistItem:(VLCPlaylistItem *)playlistItem
+ withCompletion:(nonnull void (^)(const NSImage * _Nonnull))completionHandler
{
- return [VLCLibraryImageCache.sharedImageCache imageForInputItem:playlistItem.inputItem];
+ return [VLCLibraryImageCache.sharedImageCache imageForInputItem:playlistItem.inputItem
+ withCompletion:completionHandler];
}
+ (void)thumbnailForLibraryItem:(id<VLCMediaLibraryItemProtocol>)libraryItem
- withCompletion:(void(^)(const NSImage *))completionHandler
+ withCompletion:(void(^)(const NSImage *))completionHandler
{
if ([libraryItem isKindOfClass:VLCAbstractMediaLibraryAudioGroup.class] && ![libraryItem isKindOfClass:VLCMediaLibraryAlbum.class]) {
@@ -200,21 +208,4 @@ const NSUInteger kVLCCompositeImageDefaultCompositedGridItemCount = 4;
}
}
-+ (void)thumbnailForInputItem:(VLCInputItem *)inputItem
- withCompletion:(void(^)(const NSImage *))completionHandler
-{
- dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
- NSImage * const image = [VLCLibraryImageCache thumbnailForInputItem:inputItem];
- dispatch_async(dispatch_get_main_queue(), ^{
- completionHandler(image);
- });
- });
-}
-
-+ (void)thumbnailForPlaylistItem:(VLCPlaylistItem *)playlistItem
- withCompletion:(void(^)(const NSImage *))completionHandler
-{
- [self thumbnailForInputItem:playlistItem.inputItem withCompletion:completionHandler];
-}
-
@end
=====================================
modules/gui/macosx/panels/VLCInformationWindowController.m
=====================================
@@ -265,7 +265,10 @@ _##field##TextField.delegate = self
- (void)setRepresentedInputItem:(VLCInputItem *)representedInputItem
{
_representedInputItems = (representedInputItem == nil) ? @[] : @[representedInputItem];
- _artwork = [VLCLibraryImageCache thumbnailForInputItem:representedInputItem];
+ [VLCLibraryImageCache thumbnailForInputItem:representedInputItem
+ withCompletion:^(NSImage * const image) {
+ self->_artwork = image;
+ }];
[self updateRepresentation];
}
@@ -278,9 +281,12 @@ _##field##TextField.delegate = self
_representedInputItems = [inputItems copy];
- // HACK: Input items retrieved via an audio group do not acquire an artwork URL.
- // To show something in the information window, set the small artwork from the audio group.
- _artwork = [VLCLibraryImageCache thumbnailForLibraryItem:representedMediaLibraryAudioGroup];
+ [VLCLibraryImageCache thumbnailForLibraryItem:representedMediaLibraryAudioGroup
+ withCompletion:^(NSImage * const image) {
+ // HACK: Input items retrieved via an audio group do not acquire an artwork URL.
+ // To show something in the information window, set the small artwork from the audio group.
+ self->_artwork = image;
+ }];
[self updateRepresentation];
}
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/bcd5247fb75f7c56ce02e4adaf927bbfcd61fce1...3634ea930bf00008e18ba203f85188529897b1b8
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/bcd5247fb75f7c56ce02e4adaf927bbfcd61fce1...3634ea930bf00008e18ba203f85188529897b1b8
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list