]> git.sesse.net Git - vlc/commitdiff
VLCKit: Protect against file that takes forever to thumbnail.
authorPierre d'Herbemont <pdherbemont@free.fr>
Sat, 25 Sep 2010 18:56:33 +0000 (20:56 +0200)
committerPierre d'Herbemont <pdherbemont@free.fr>
Sat, 25 Sep 2010 21:08:13 +0000 (23:08 +0200)
projects/macosx/framework/Headers/Public/VLCMediaThumbnailer.h
projects/macosx/framework/Sources/VLCMediaThumbnailer.m

index e27c344989907692ec1923ee735d7b0c7b5a5640..a18b4fcdcad2a2a2284e7204ed0928b246b3625c 100644 (file)
     CGImageRef _thumbnail;
     void *_data;
     NSTimer *_parsingTimeoutTimer;
+    NSTimer *_thumbnailingTimeoutTimer;
 
     CGFloat _thumbnailHeight,_thumbnailWidth;
     CGFloat _effectiveThumbnailHeight,_effectiveThumbnailWidth;
+    int _numberOfReceivedFrames;
+    BOOL _shouldRejectFrames;
 }
 
 + (VLCMediaThumbnailer *)thumbnailerWithMedia:(VLCMedia *)media andDelegate:(id<VLCMediaThumbnailerDelegate>)delegate;
@@ -52,5 +55,6 @@
 
 @protocol VLCMediaThumbnailerDelegate
 @required
+- (void)mediaThumbnailerDidTimeOut:(VLCMediaThumbnailer *)mediaThumbnailer;
 - (void)mediaThumbnailer:(VLCMediaThumbnailer *)mediaThumbnailer didFinishThumbnail:(CGImageRef)thumbnail;
 @end
index 71ad3d1cb0bc61a307f81f7b9c9d325304bb54cb..133dfc9b5beac33aaae39788375377c368cc86b1 100644 (file)
@@ -18,6 +18,7 @@
 - (void)fetchThumbnail;
 - (void)startFetchingThumbnail;
 @property (readonly, assign) void *dataPointer;
+@property (readonly, assign) BOOL shouldRejectFrames;
 @end
 
 static void *lock(void *opaque, void **pixels)
@@ -42,7 +43,7 @@ void unlock(void *opaque, void *picture, void *const *p_pixels)
 
     // We may already have a thumbnail if we are receiving picture after the first one.
     // Just ignore.
-    if ([thumbnailer thumbnail])
+    if ([thumbnailer thumbnail] || [thumbnailer shouldRejectFrames])
         return;
 
     [thumbnailer performSelectorOnMainThread:@selector(didFetchThumbnail) withObject:nil waitUntilDone:YES];
@@ -59,6 +60,7 @@ void display(void *opaque, void *picture)
 @synthesize dataPointer=_data;
 @synthesize thumbnailWidth=_thumbnailWidth;
 @synthesize thumbnailHeight=_thumbnailHeight;
+@synthesize shouldRejectFrames=_shouldRejectFrames;
 
 + (VLCMediaThumbnailer *)thumbnailerWithMedia:(VLCMedia *)media andDelegate:(id<VLCMediaThumbnailerDelegate>)delegate
 {
@@ -70,6 +72,8 @@ void display(void *opaque, void *picture)
 
 - (void)dealloc
 {
+    NSAssert(!_thumbnailingTimeoutTimer, @"Timer not released");
+    NSAssert(!_parsingTimeoutTimer, @"Timer not released");
     NSAssert(!_data, @"Data not released");
     NSAssert(!_mp, @"Not properly retained");
     if (_thumbnail)
@@ -101,6 +105,7 @@ void display(void *opaque, void *picture)
 {
     NSArray *tracks = [_media tracksInformation];
 
+
     // Find the video track
     NSDictionary *videoTrack = nil;
     for (NSDictionary *track in tracks) {
@@ -129,11 +134,14 @@ void display(void *opaque, void *picture)
 
         int newWidth = round(videoWidth * ratio);
         int newHeight = round(videoHeight * ratio);
-        NSLog(@"video %dx%d from %dx%d or %dx%d", newWidth, newHeight, videoWidth, videoHeight, imageWidth, imageHeight);
+
         imageWidth = newWidth > 0 ? newWidth : imageWidth;
         imageHeight = newHeight > 0 ? newHeight : imageHeight;
     }
 
+    _numberOfReceivedFrames = 0;
+    NSAssert(!_shouldRejectFrames, @"Are we still running?");
+
     _effectiveThumbnailHeight = imageHeight;
     _effectiveThumbnailWidth = imageWidth;
 
@@ -150,6 +158,9 @@ void display(void *opaque, void *picture)
     libvlc_video_set_callbacks(_mp, lock, unlock, display, self);
     libvlc_media_player_play(_mp);
     libvlc_media_player_set_position(_mp, kSnapshotPosition);
+
+    NSAssert(!_thumbnailingTimeoutTimer, @"We already have a timer around");
+    _thumbnailingTimeoutTimer = [[NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(mediaThumbnailingTimedOut) userInfo:nil repeats:NO] retain];
 }
 
 - (void)mediaParsingTimedOut
@@ -177,13 +188,21 @@ void display(void *opaque, void *picture)
 
 - (void)didFetchThumbnail
 {
+    if (_shouldRejectFrames)
+        return;
+
     // The video thread is blocking on us. Beware not to do too much work.
 
+    _numberOfReceivedFrames++;
+
     // Make sure we are getting the right frame
-    if (libvlc_media_player_get_position(_mp) < kSnapshotPosition &&
+    if (libvlc_media_player_get_position(_mp) < kSnapshotPosition / 2 &&
         // Arbitrary choice to work around broken files.
-        libvlc_media_player_get_length(_mp) > 1000)
+        libvlc_media_player_get_length(_mp) > 1000 &&
+        _numberOfReceivedFrames < 10)
+    {
         return;
+    }
 
     NSAssert(_data, @"We have no data");
     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
@@ -214,10 +233,8 @@ void display(void *opaque, void *picture)
     [self performSelector:@selector(notifyDelegate) withObject:nil afterDelay:0];
 }
 
-- (void)notifyDelegate
+- (void)stopAsync
 {
-    // Stop the media player
-    NSAssert(_mp, @"We have already destroyed mp");
     libvlc_media_player_stop(_mp);
     libvlc_media_player_release(_mp);
     _mp = NULL;
@@ -226,10 +243,39 @@ void display(void *opaque, void *picture)
     free(_data);
     _data = NULL;
 
+    _shouldRejectFrames = NO;
+}
+
+- (void)endThumbnailing
+{
+    _shouldRejectFrames = YES;
+
+    [_thumbnailingTimeoutTimer invalidate];
+    [_thumbnailingTimeoutTimer release];
+    _thumbnailingTimeoutTimer = nil;
+
+    // Stop the media player
+    NSAssert(_mp, @"We have already destroyed mp");
+
+    [self performSelectorInBackground:@selector(stopAsync) withObject:nil];
+
+    [self autorelease]; // Balancing -fetchThumbnail
+}
+
+- (void)notifyDelegate
+{
+    [self endThumbnailing];
+
     // Call delegate
     [_delegate mediaThumbnailer:self didFinishThumbnail:_thumbnail];
 
-    [self release]; // Balancing -fetchThumbnail
 }
 
+- (void)mediaThumbnailingTimedOut
+{
+    [self endThumbnailing];
+
+    // Call delegate
+    [_delegate mediaThumbnailerDidTimeOut:self];
+}
 @end