/* HBQueue.m $
This file is part of the HandBrake source code.
Homepage: .
It may be used under the terms of the GNU General Public License. */
#import "HBQueue.h"
#import "HBRemoteCore.h"
#import "HBPreferencesKeys.h"
#import "NSArray+HBAdditions.h"
#import "HBJobOutputFileWriter.h"
static void *HBQueueContext = &HBQueueContext;
static void *HBQueueLogLevelContext = &HBQueueLogLevelContext;
NSString * const HBQueueDidChangeStateNotification = @"HBQueueDidChangeStateNotification";
NSString * const HBQueueDidAddItemNotification = @"HBQueueDidAddItemNotification";
NSString * const HBQueueDidRemoveItemNotification = @"HBQueueDidRemoveItemNotification";
NSString * const HBQueueDidChangeItemNotification = @"HBQueueDidChangeItemNotification";
NSString * const HBQueueItemNotificationIndexesKey = @"HBQueueReloadItemsNotification";
NSString * const HBQueueDidMoveItemNotification = @"HBQueueDidMoveItemNotification";
NSString * const HBQueueItemNotificationSourceIndexesKey = @"HBQueueItemNotificationSourceIndexesKey";
NSString * const HBQueueItemNotificationTargetIndexesKey = @"HBQueueItemNotificationTargetIndexesKey";
NSString * const HBQueueReloadItemsNotification = @"HBQueueReloadItemsNotification";
NSString * const HBQueueLowSpaceAlertNotification = @"HBQueueLowSpaceAlertNotification";
NSString * const HBQueueProgressNotification = @"HBQueueProgressNotification";
NSString * const HBQueueProgressNotificationPercentKey = @"HBQueueProgressNotificationPercentKey";
NSString * const HBQueueProgressNotificationHoursKey = @"HBQueueProgressNotificationHoursKey";
NSString * const HBQueueProgressNotificationMinutesKey = @"HBQueueProgressNotificationMinutesKey";
NSString * const HBQueueProgressNotificationSecondsKey = @"HBQueueProgressNotificationSecondsKey";
NSString * const HBQueueProgressNotificationInfoKey = @"HBQueueProgressNotificationInfoKey";
NSString * const HBQueueDidStartNotification = @"HBQueueDidStartNotification";
NSString * const HBQueueDidCompleteNotification = @"HBQueueDidCompleteNotification";
NSString * const HBQueueDidStartItemNotification = @"HBQueueDidStartItemNotification";
NSString * const HBQueueDidCompleteItemNotification = @"HBQueueDidCompleteItemNotification";
NSString * const HBQueueItemNotificationItemKey = @"HBQueueItemNotificationItemKey";
@interface HBQueue ()
@property (nonatomic, readonly) HBRemoteCore *core;
@property (nonatomic) BOOL stop;
@property (nonatomic, nullable) HBJobOutputFileWriter *currentLog;
@end
@implementation HBQueue
- (instancetype)initWithURL:(NSURL *)queueURL
{
self = [super init];
if (self)
{
NSInteger loggingLevel = [NSUserDefaults.standardUserDefaults integerForKey:HBLoggingLevel];
// Init a separate instance of libhb for the queue
_core = [[HBRemoteCore alloc] initWithLogLevel:loggingLevel name:@"QueueCore"];
_core.automaticallyPreventSleep = NO;
_items = [[HBDistributedArray alloc] initWithURL:queueURL class:[HBQueueItem class]];
_undoManager = [[NSUndoManager alloc] init];
// Set up the observers
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadQueue) name:HBDistributedArrayChanged object:_items];
[self updateStats];
// Set up observers
[self.core addObserver:self forKeyPath:@"state"
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial
context:HBQueueContext];
[NSUserDefaultsController.sharedUserDefaultsController addObserver:self forKeyPath:@"values.LoggingLevel"
options:0 context:HBQueueLogLevelContext];
}
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == HBQueueContext)
{
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueDidChangeStateNotification object:self];
}
else if (context == HBQueueLogLevelContext)
{
self.core.logLevel = [NSUserDefaults.standardUserDefaults integerForKey:HBLoggingLevel];
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)dealloc
{
[self.core removeObserver:self forKeyPath:@"state"];
[self.core invalidate];
}
#pragma mark - Public methods
- (void)addJob:(HBJob *)item
{
NSParameterAssert(item);
[self addJobs:@[item]];
}
- (void)addJobs:(NSArray *)jobs
{
NSParameterAssert(jobs);
NSMutableArray *itemsToAdd = [NSMutableArray array];
for (HBJob *job in jobs)
{
HBQueueItem *item = [[HBQueueItem alloc] initWithJob:job];
[itemsToAdd addObject:item];
}
if (itemsToAdd.count)
{
NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(self.items.count, itemsToAdd.count)];
[self addItems:itemsToAdd atIndexes:indexes];
}
}
- (BOOL)itemExistAtURL:(NSURL *)url
{
NSParameterAssert(url);
for (HBQueueItem *item in self.items)
{
if ((item.state == HBQueueItemStateReady || item.state == HBQueueItemStateWorking)
&& [item.completeOutputURL isEqualTo:url])
{
return YES;
}
}
return NO;
}
- (void)addItems:(NSArray *)items atIndexes:(NSIndexSet *)indexes
{
NSParameterAssert(items);
NSParameterAssert(indexes);
[self.items beginTransaction];
// Forward
NSUInteger currentIndex = indexes.firstIndex;
NSUInteger currentObjectIndex = 0;
while (currentIndex != NSNotFound)
{
[self.items insertObject:items[currentObjectIndex] atIndex:currentIndex];
currentIndex = [indexes indexGreaterThanIndex:currentIndex];
currentObjectIndex++;
}
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueDidAddItemNotification object:self userInfo:@{HBQueueItemNotificationIndexesKey: indexes}];
NSUndoManager *undo = self.undoManager;
[[undo prepareWithInvocationTarget:self] removeItemsAtIndexes:indexes];
if (!undo.isUndoing)
{
if (items.count == 1)
{
[undo setActionName:NSLocalizedString(@"Add Job To Queue", @"Queue undo action name")];
}
else
{
[undo setActionName:NSLocalizedString(@"Add Jobs To Queue", @"Queue undo action name")];
}
}
[self updateStats];
[self.items commit];
}
- (void)removeItemAtIndex:(NSUInteger)index
{
[self removeItemsAtIndexes:[NSIndexSet indexSetWithIndex:index]];
}
- (void)removeItemsAtIndexes:(NSIndexSet *)indexes
{
NSParameterAssert(indexes);
if (indexes.count == 0)
{
return;
}
[self.items beginTransaction];
NSArray *removeItems = [self.items objectsAtIndexes:indexes];
if (self.items.count > indexes.lastIndex)
{
[self.items removeObjectsAtIndexes:indexes];
}
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueDidRemoveItemNotification object:self userInfo:@{HBQueueItemNotificationIndexesKey: indexes}];
NSUndoManager *undo = self.undoManager;
[[undo prepareWithInvocationTarget:self] addItems:removeItems atIndexes:indexes];
if (!undo.isUndoing)
{
if (indexes.count == 1)
{
[undo setActionName:NSLocalizedString(@"Remove Job From Queue", @"Queue undo action name")];
}
else
{
[undo setActionName:NSLocalizedString(@"Remove Jobs From Queue", @"Queue undo action name")];
}
}
[self updateStats];
[self.items commit];
}
- (void)moveItems:(NSArray *)items toIndex:(NSUInteger)index
{
[self.items beginTransaction];
NSMutableArray *source = [NSMutableArray array];
NSMutableArray *dest = [NSMutableArray array];
for (id object in items.reverseObjectEnumerator)
{
NSUInteger sourceIndex = [self.items indexOfObject:object];
[self.items removeObjectAtIndex:sourceIndex];
if (sourceIndex < index)
{
index--;
}
[self.items insertObject:object atIndex:index];
[source addObject:@(index)];
[dest addObject:@(sourceIndex)];
}
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueDidMoveItemNotification
object:self
userInfo:@{HBQueueItemNotificationSourceIndexesKey: dest,
HBQueueItemNotificationTargetIndexesKey: source}];
NSUndoManager *undo = self.undoManager;
[[undo prepareWithInvocationTarget:self] moveQueueItemsAtIndexes:source toIndexes:dest];
if (!undo.isUndoing)
{
if (items.count == 1)
{
[undo setActionName:NSLocalizedString(@"Move Job in Queue", @"Queue undo action name")];
}
else
{
[undo setActionName:NSLocalizedString(@"Move Jobs in Queue", @"Queue undo action name")];
}
}
[self.items commit];
}
- (void)moveQueueItemsAtIndexes:(NSArray *)source toIndexes:(NSArray *)dest
{
[self.items beginTransaction];
NSMutableArray *newSource = [NSMutableArray array];
NSMutableArray *newDest = [NSMutableArray array];
for (NSInteger idx = source.count - 1; idx >= 0; idx--)
{
NSUInteger sourceIndex = [source[idx] integerValue];
NSUInteger destIndex = [dest[idx] integerValue];
[newSource addObject:@(destIndex)];
[newDest addObject:@(sourceIndex)];
id obj = [self.items objectAtIndex:sourceIndex];
[self.items removeObjectAtIndex:sourceIndex];
[self.items insertObject:obj atIndex:destIndex];
}
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueDidMoveItemNotification
object:self
userInfo:@{HBQueueItemNotificationSourceIndexesKey: newDest,
HBQueueItemNotificationTargetIndexesKey: newSource}];
NSUndoManager *undo = self.undoManager;
[[undo prepareWithInvocationTarget:self] moveQueueItemsAtIndexes:newSource toIndexes:newDest];
if (!undo.isUndoing)
{
if (source.count == 1)
{
[undo setActionName:NSLocalizedString(@"Move Job in Queue", @"Queue undo action name")];
}
else
{
[undo setActionName:NSLocalizedString(@"Move Jobs in Queue", @"Queue undo action name")];
}
}
[self.items commit];
}
/**
* This method will clear the queue of any encodes that are not still pending
* this includes both successfully completed encodes as well as canceled encodes
*/
- (void)removeCompletedAndCancelledItems
{
[self.items beginTransaction];
NSIndexSet *indexes = [self.items indexesOfObjectsUsingBlock:^BOOL(HBQueueItem *item) {
return (item.state == HBQueueItemStateCompleted || item.state == HBQueueItemStateCanceled);
}];
[self removeItemsAtIndexes:indexes];
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueDidRemoveItemNotification object:self userInfo:@{@"indexes": indexes}];
[self.items commit];
}
/**
* This method will clear the queue of all encodes. effectively creating an empty queue
*/
- (void)removeAllItems
{
[self.items beginTransaction];
[self removeItemsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.items.count)]];
[self.items commit];
}
- (void)removeNotWorkingItems
{
[self.items beginTransaction];
NSIndexSet *indexes = [self.items indexesOfObjectsUsingBlock:^BOOL(HBQueueItem *item) {
return (item.state != HBQueueItemStateWorking);
}];
[self removeItemsAtIndexes:indexes];
[self.items commit];
}
- (void)removeCompletedItems
{
[self.items beginTransaction];
NSIndexSet *indexes = [self.items indexesOfObjectsUsingBlock:^BOOL(HBQueueItem *item) {
return (item.state == HBQueueItemStateCompleted);
}];
[self removeItemsAtIndexes:indexes];
[self.items commit];
}
- (void)resetItemsAtIndexes:(NSIndexSet *)indexes
{
if ([self.items beginTransaction] == HBDistributedArrayContentReload)
{
// Do not execute the action if the array changed.
[self.items commit];
return;
}
NSMutableIndexSet *updatedIndexes = [NSMutableIndexSet indexSet];
NSUInteger currentIndex = indexes.firstIndex;
while (currentIndex != NSNotFound) {
HBQueueItem *item = self.items[currentIndex];
if (item.state == HBQueueItemStateCanceled || item.state == HBQueueItemStateCompleted || item.state == HBQueueItemStateFailed)
{
item.state = HBQueueItemStateReady;
[updatedIndexes addIndex:currentIndex];
}
currentIndex = [indexes indexGreaterThanIndex:currentIndex];
}
[self updateStats];
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueDidChangeItemNotification object:self userInfo:@{HBQueueItemNotificationIndexesKey: indexes}];
[self.items commit];
}
- (void)resetAllItems
{
[self.items beginTransaction];
NSIndexSet *indexes = [self.items indexesOfObjectsUsingBlock:^BOOL(HBQueueItem *item) {
return (item.state != HBQueueItemStateWorking);
}];
[self resetItemsAtIndexes:indexes];
[self.items commit];
}
- (void)resetFailedItems
{
[self.items beginTransaction];
NSIndexSet *indexes = [self.items indexesOfObjectsUsingBlock:^BOOL(HBQueueItem *item) {
return (item.state == HBQueueItemStateFailed);
}];
[self resetItemsAtIndexes:indexes];
[self.items commit];
}
/**
* This method will set any item marked as encoding back to pending
* currently used right after a queue reload
*/
- (void)setEncodingJobsAsPending
{
[self.items beginTransaction];
NSMutableIndexSet *indexes = [NSMutableIndexSet indexSet];
NSUInteger idx = 0;
for (HBQueueItem *item in self.items)
{
// We want to keep any queue item that is pending or was previously being encoded
if (item.state == HBQueueItemStateWorking)
{
item.state = HBQueueItemStateReady;
[indexes addIndex:idx];
}
idx++;
}
[self updateStats];
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueDidChangeItemNotification object:self userInfo:@{HBQueueItemNotificationIndexesKey: indexes}];
[self.items commit];
}
- (BOOL)canEncode
{
return self.pendingItemsCount > 0 && ![self isEncoding];
}
- (BOOL)isEncoding
{
HBState s = self.core.state;
return self.currentItem || (s == HBStateScanning) || (s == HBStatePaused) || (s == HBStateWorking) || (s == HBStateMuxing) || (s == HBStateSearching);
}
- (BOOL)canPause
{
HBState s = self.core.state;
return (s == HBStateWorking || s == HBStateMuxing);
}
- (void)pause
{
[self.currentItem pausedAtDate:[NSDate date]];
[self.core pause];
[self.core allowSleep];
}
- (BOOL)canResume
{
return self.core.state == HBStatePaused;
}
- (void)resume
{
[self.currentItem resumedAtDate:[NSDate date]];
[self.core resume];
[self.core preventSleep];
}
#pragma mark - Private queue editing methods
/**
* Reloads the queue, this is called
* when another HandBrake instance modifies the queue
*/
- (void)reloadQueue
{
[self updateStats];
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueReloadItemsNotification object:self];
}
- (void)updateStats
{
NSUInteger pendingCount = 0, failedCount = 0, completedCount = 0;
for (HBQueueItem *item in self.items)
{
if (item.state == HBQueueItemStateReady)
{
pendingCount++;
}
else if (item.state == HBQueueItemStateCompleted)
{
completedCount++;
}
else if (item.state == HBQueueItemStateFailed)
{
failedCount++;
}
}
self.pendingItemsCount = pendingCount;
self.failedItemsCount = failedCount;
self.completedItemsCount = completedCount;
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueDidChangeStateNotification object:self];
}
- (BOOL)isDiskSpaceLowAtURL:(NSURL *)url
{
if ([NSUserDefaults.standardUserDefaults boolForKey:HBQueuePauseIfLowSpace])
{
NSURL *volumeURL = nil;
NSDictionary *attrs = [url resourceValuesForKeys:@[NSURLIsVolumeKey, NSURLVolumeURLKey] error:NULL];
long long minCapacity = [[NSUserDefaults.standardUserDefaults stringForKey:HBQueueMinFreeSpace] longLongValue] * 1000000000;
volumeURL = [attrs[NSURLIsVolumeKey] boolValue] ? url : attrs[NSURLVolumeURLKey];
if (volumeURL)
{
[volumeURL removeCachedResourceValueForKey:NSURLVolumeAvailableCapacityKey];
attrs = [volumeURL resourceValuesForKeys:@[NSURLVolumeAvailableCapacityKey] error:NULL];
if (attrs[NSURLVolumeAvailableCapacityKey])
{
if ([attrs[NSURLVolumeAvailableCapacityKey] longLongValue] < minCapacity)
{
return YES;
}
}
}
}
return NO;
}
/**
* Used to get the next pending queue item and return it if found
*/
- (HBQueueItem *)getNextPendingQueueItem
{
for (HBQueueItem *item in self.items)
{
if (item.state == HBQueueItemStateReady)
{
return item;
}
}
return nil;
}
- (void)start
{
if (self.canEncode)
{
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueDidStartNotification object:self];
[self.core preventSleep];
[self encodeNextQueueItem];
}
}
/**
* Starts the queue
*/
- (void)encodeNextQueueItem
{
[self.items beginTransaction];
// since we have completed an encode, we go to the next
if (self.stop)
{
[HBUtilities writeToActivityLog:"Queue manually stopped"];
self.stop = NO;
[self.core allowSleep];
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueDidCompleteNotification object:self];
}
else
{
// Check to see if there are any more pending items in the queue
HBQueueItem *nextItem = [self getNextPendingQueueItem];
if (nextItem && [self isDiskSpaceLowAtURL:nextItem.outputURL])
{
// Disk space is low, show an alert
[HBUtilities writeToActivityLog:"Queue Stopped, low space on destination disk"];
[self.core allowSleep];
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueDidCompleteNotification object:self];
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueLowSpaceAlertNotification object:self];
}
// If we still have more pending items in our queue, lets go to the next one
else if (nextItem)
{
// now we mark the queue item as working so another instance can not come along and try to scan it while we are scanning
nextItem.startedDate = [NSDate date];
nextItem.state = HBQueueItemStateWorking;
// Tell HB to output a new activity log file for this encode
self.currentLog = [[HBJobOutputFileWriter alloc] initWithJob:nextItem.job];
if (self.currentLog)
{
nextItem.activityLogURL = self.currentLog.url;
dispatch_queue_t mainQueue = dispatch_get_main_queue();
[self.core.stderrRedirect addListener:self.currentLog queue:mainQueue];
[self.core.stdoutRedirect addListener:self.currentLog queue:mainQueue];
}
self.currentItem = nextItem;
NSIndexSet *indexes = [NSIndexSet indexSetWithIndex:[self.items indexOfObject:nextItem]];
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueDidStartItemNotification object:self userInfo:@{HBQueueItemNotificationItemKey: nextItem,
HBQueueItemNotificationIndexesKey: indexes}];
// now we can go ahead and scan the new pending queue item
[self encodeItem:nextItem];
// erase undo manager history
[self.undoManager removeAllActions];
}
else
{
[HBUtilities writeToActivityLog:"Queue Done, there are no more pending encodes"];
[self.core allowSleep];
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueDidCompleteNotification object:self];
}
}
[self updateStats];
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueDidChangeStateNotification object:self];
[self.items commit];
}
- (void)completedItem:(HBQueueItem *)item result:(HBCoreResult)result
{
NSParameterAssert(item);
[self.items beginTransaction];
item.endedDate = [NSDate date];
// Since we are done with this encode, tell output to stop writing to the
// individual encode log.
[self.core.stderrRedirect removeListener:self.currentLog];
[self.core.stdoutRedirect removeListener:self.currentLog];
self.currentLog = nil;
// Mark the encode just finished
switch (result) {
case HBCoreResultDone:
item.state = HBQueueItemStateCompleted;
break;
case HBCoreResultCanceled:
item.state = HBQueueItemStateCanceled;
break;
default:
item.state = HBQueueItemStateFailed;
break;
}
// Update UI
NSString *info = nil;
switch (result) {
case HBCoreResultDone:
info = NSLocalizedString(@"Encode Finished.", @"Queue status");
break;
case HBCoreResultCanceled:
info = NSLocalizedString(@"Encode Canceled.", @"Queue status");
break;
default:
info = NSLocalizedString(@"Encode Failed.", @"Queue status");
break;
}
self.currentItem = nil;
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueProgressNotification object:self userInfo:@{HBQueueProgressNotificationPercentKey: @1.0,
HBQueueProgressNotificationInfoKey: info}];
NSUInteger index = [self.items indexOfObject:item];
NSIndexSet *indexes = index != NSNotFound ? [NSIndexSet indexSetWithIndex:index] : [NSIndexSet indexSet];
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueDidCompleteItemNotification object:self userInfo:@{HBQueueItemNotificationItemKey: item,
HBQueueItemNotificationIndexesKey: indexes}];
[self.items commit];
}
/**
* Here we actually tell hb_scan to perform the source scan, using the path to source and title number
*/
- (void)encodeItem:(HBQueueItem *)item
{
NSParameterAssert(item);
// Progress handler
void (^progressHandler)(HBState state, HBProgress progress, NSString *info) = ^(HBState state, HBProgress progress, NSString *info)
{
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueProgressNotification object:self userInfo:@{HBQueueProgressNotificationPercentKey: @0,
HBQueueProgressNotificationInfoKey: info}];
};
// Completion handler
void (^completionHandler)(HBCoreResult result) = ^(HBCoreResult result)
{
if (result == HBCoreResultDone)
{
[self realEncodeItem:item];
}
else
{
[self completedItem:item result:result];
[self encodeNextQueueItem];
}
};
[item.job refreshSecurityScopedResources];
// Only scan 10 previews before an encode - additional previews are
// only useful for autocrop and static previews, which are already taken care of at this point
[self.core scanURL:item.fileURL
titleIndex:item.job.titleIdx
previews:10
minDuration:0
keepPreviews:NO
progressHandler:progressHandler
completionHandler:completionHandler];
}
/**
* This assumes that we have re-scanned and loaded up a new queue item to send to libhb
*/
- (void)realEncodeItem:(HBQueueItem *)item
{
NSParameterAssert(item);
HBJob *job = item.job;
NSParameterAssert(job);
// Progress handler
void (^progressHandler)(HBState state, HBProgress progress, NSString *info) = ^(HBState state, HBProgress progress, NSString *info)
{
if (state == HBStateMuxing)
{
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueProgressNotification
object:self
userInfo:@{HBQueueProgressNotificationPercentKey: @1,
HBQueueProgressNotificationInfoKey: info}];
}
else
{
[NSNotificationCenter.defaultCenter postNotificationName:HBQueueProgressNotification
object:self
userInfo:@{HBQueueProgressNotificationPercentKey: @(progress.percent),
HBQueueProgressNotificationHoursKey: @(progress.hours),
HBQueueProgressNotificationMinutesKey: @(progress.minutes),
HBQueueProgressNotificationSecondsKey: @(progress.seconds),
HBQueueProgressNotificationInfoKey: info}];
}
};
// Completion handler
void (^completionHandler)(HBCoreResult result) = ^(HBCoreResult result)
{
[self completedItem:item result:result];
if ([NSUserDefaults.standardUserDefaults boolForKey:HBQueueAutoClearCompletedItems])
{
[self removeCompletedItems];
}
[self encodeNextQueueItem];
};
// We should be all setup so let 'er rip
[self.core encodeJob:job progressHandler:progressHandler completionHandler:completionHandler];
}
/**
* Cancels the current job
*/
- (void)doCancelCurrentItem
{
if (self.core.state == HBStateScanning)
{
[self.core cancelScan];
}
else
{
[self.core cancelEncode];
}
}
/**
* Cancels the current job and starts processing the next in queue.
*/
- (void)cancelCurrentItemAndContinue
{
[self doCancelCurrentItem];
}
/**
* Cancels the current job and stops libhb from processing the remaining encodes.
*/
- (void)cancelCurrentItemAndStop
{
if (self.core.state != HBStateIdle)
{
self.stop = YES;
[self doCancelCurrentItem];
}
}
/**
* Finishes the current job and stops libhb from processing the remaining encodes.
*/
- (void)finishCurrentAndStop
{
if (self.core.state != HBStateIdle)
{
self.stop = YES;
}
}
@end