summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libhb/common.h1
-rw-r--r--libhb/hb.c7
-rw-r--r--libhb/hb.h1
-rw-r--r--macosx/Controller.mm74
-rw-r--r--macosx/HBQueueController.h93
-rw-r--r--macosx/HBQueueController.mm572
-rw-r--r--macosx/HandBrake.xcodeproj/project.pbxproj4
-rw-r--r--macosx/icons/EncodeCanceled.pngbin0 -> 558 bytes
8 files changed, 445 insertions, 307 deletions
diff --git a/libhb/common.h b/libhb/common.h
index 2a56701db..682b60c89 100644
--- a/libhb/common.h
+++ b/libhb/common.h
@@ -462,6 +462,7 @@ struct hb_state_s
int hours;
int minutes;
int seconds;
+ int sequence_id;
} working;
struct
diff --git a/libhb/hb.c b/libhb/hb.c
index 6b108bdf0..55e2da646 100644
--- a/libhb/hb.c
+++ b/libhb/hb.c
@@ -964,6 +964,7 @@ void hb_start( hb_handle_t * h )
p.hours = -1;
p.minutes = -1;
p.seconds = -1;
+ p.sequence_id = 0;
#undef p
hb_unlock( h->state_lock );
@@ -1203,6 +1204,12 @@ void hb_set_state( hb_handle_t * h, hb_state_t * s )
h->state.param.working.job_cur =
h->job_count_permanent - hb_list_count( h->jobs );
h->state.param.working.job_count = h->job_count_permanent;
+
+ // Set which job is being worked on
+ if (h->current_job)
+ h->state.param.working.sequence_id = h->current_job->sequence_id;
+ else
+ h->state.param.working.sequence_id = 0;
}
hb_unlock( h->state_lock );
hb_unlock( h->pause_lock );
diff --git a/libhb/hb.h b/libhb/hb.h
index be629505f..9de4af732 100644
--- a/libhb/hb.h
+++ b/libhb/hb.h
@@ -83,7 +83,6 @@ void hb_set_anamorphic_size( hb_job_t * );
/* Handling jobs */
int hb_count( hb_handle_t * );
hb_job_t * hb_job( hb_handle_t *, int );
-hb_job_t * hb_current_job( hb_handle_t * h );
void hb_add( hb_handle_t *, hb_job_t * );
void hb_rem( hb_handle_t *, hb_job_t * );
diff --git a/macosx/Controller.mm b/macosx/Controller.mm
index c16de3fef..260bbc62f 100644
--- a/macosx/Controller.mm
+++ b/macosx/Controller.mm
@@ -172,15 +172,14 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It
// Warn if encoding a movie
hb_state_t s;
hb_get_state( fHandle, &s );
- hb_job_t * job = hb_current_job( fHandle );
- if ( job && ( s.state != HB_STATE_IDLE ) )
+ HBJobGroup * jobGroup = [fQueueController currentJobGroup];
+ if ( jobGroup && ( s.state != HB_STATE_IDLE ) )
{
- hb_job_t * job = hb_current_job( fHandle );
int result = NSRunCriticalAlertPanel(
NSLocalizedString(@"Are you sure you want to quit HandBrake?", nil),
NSLocalizedString(@"%@ is currently encoding. If you quit HandBrake, your movie will be lost. Do you want to quit anyway?", nil),
NSLocalizedString(@"Quit", nil), NSLocalizedString(@"Don't Quit", nil), nil,
- job ? [NSString stringWithUTF8String:job->title->name] : @"A movie" );
+ jobGroup ? [jobGroup name] : @"A movie" );
if (result == NSAlertDefaultReturn)
{
@@ -655,23 +654,11 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It
// or someone calling hb_stop. In the latter case, hb_stop does not clear
// out the remaining passes/jobs in the queue. We'll do that here.
- // Delete all remaining scans of this job, ie, delete whole encodes.
+ // Delete all remaining jobs of this encode.
hb_job_t * job;
- while( ( job = hb_job( fHandle, 0 ) ) && (job->sequence_id != 0) )
+ while( ( job = hb_job( fHandle, 0 ) ) && ( !IsFirstPass(job->sequence_id) ) )
hb_rem( fHandle, job );
- // Start processing back up if jobs still left in queue
- if (hb_count(fHandle) > 0)
- {
- hb_start(fHandle);
- fEncodeState = 1;
- // Validate the toolbar (hack). The toolbar will usually get autovalidated
- // before we had the chance to restart the queue, hence it will now be in
- // the wrong state.
- [toolbar validateVisibleItems];
- break;
- }
-
[fStatusField setStringValue: _( @"Done." )];
[fRipIndicator setIndeterminate: NO];
[fRipIndicator setDoubleValue: 0.0];
@@ -1658,10 +1645,15 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It
hb_title_t * title = (hb_title_t *) hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
hb_job_t * job = title->job;
- // Assign a sequence number, starting at zero, to each job added so they can
- // be lumped together in the UI.
- job->sequence_id = -1;
-
+ // Assign a unique job group ID for all passes of the same encode. This is how the
+ // UI lumps together jobs to form encodes. libhb does not use this id.
+ static int jobGroupID = 0;
+ jobGroupID++;
+
+ // A sequence number, starting at zero, is also used to identifiy to each pass.
+ // This is used by the UI to determine if a pass if the first pass of an encode.
+ int sequenceNum = -1;
+
[self prepareJob];
/* Destination file */
@@ -1697,7 +1689,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It
/*
* Add the pre-scan job
*/
- job->sequence_id++; // for job grouping
+ job->sequence_id = MakeJobID(jobGroupID, ++sequenceNum);
hb_add( fHandle, job );
job->x264opts = x264opts_tmp;
@@ -1722,11 +1714,11 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It
job->select_subtitle = NULL;
job->pass = 1;
- job->sequence_id++; // for job grouping
+ job->sequence_id = MakeJobID(jobGroupID, ++sequenceNum);
hb_add( fHandle, job );
job->pass = 2;
- job->sequence_id++; // for job grouping
+ job->sequence_id = MakeJobID(jobGroupID, ++sequenceNum);
job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */
strcpy(job->x264opts, [[fAdvancedOptions optionsString] UTF8String]);
@@ -1739,7 +1731,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It
{
job->indepth_scan = 0;
job->pass = 0;
- job->sequence_id++; // for job grouping
+ job->sequence_id = MakeJobID(jobGroupID, ++sequenceNum);
hb_add( fHandle, job );
}
@@ -1881,7 +1873,8 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It
}
//------------------------------------------------------------------------------------
-// Cancels the current job and proceeds with the next one in the queue.
+// Cancels and deletes the current job and stops libhb from processing the remaining
+// encodes.
//------------------------------------------------------------------------------------
- (void) doCancelCurrentJob
{
@@ -1906,11 +1899,11 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It
{
if (!fHandle) return;
- hb_job_t * job = hb_current_job(fHandle);
- if (!job) return;
+ HBJobGroup * jobGroup = [fQueueController currentJobGroup];
+ if (!jobGroup) return;
- NSString * alertTitle = [NSString stringWithFormat:NSLocalizedString(@"Do you want to stop encoding of %@?", nil),
- [NSString stringWithUTF8String:job->title->name]];
+ NSString * alertTitle = [NSString stringWithFormat:NSLocalizedString(@"Stop encoding %@?", nil),
+ [jobGroup name]];
// Which window to attach the sheet to?
NSWindow * docWindow;
@@ -1922,32 +1915,19 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It
NSBeginCriticalAlertSheet(
alertTitle,
NSLocalizedString(@"Keep Encoding", nil),
- NSLocalizedString(@"Delete All", nil),
+ nil,
NSLocalizedString(@"Stop Encoding", nil),
docWindow, self,
nil, @selector(didDimissCancelCurrentJob:returnCode:contextInfo:), nil,
- NSLocalizedString(@"Your movie will be lost if you don't continue encoding.", nil),
- [NSString stringWithUTF8String:job->title->name]);
+ NSLocalizedString(@"Your movie will be lost if you don't continue encoding.", nil));
// didDimissCancelCurrentJob:returnCode:contextInfo: will be called when the dialog is dismissed
-
- // N.B.: didDimissCancelCurrentJob:returnCode:contextInfo: is designated as the dismiss
- // selector to prevent a crash. As a dismiss selector, the alert window will
- // have already be dismissed. If we don't do it this way, the dismissing of
- // the alert window will cause the table view to be redrawn at a point where
- // current job has been deleted by hblib but we don't know about it yet. This
- // is a prime example of wy we need to NOT be relying on hb_current_job!!!!
}
- (void) didDimissCancelCurrentJob: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo
{
if (returnCode == NSAlertOtherReturn)
- [self doCancelCurrentJob];
- else if (returnCode == NSAlertAlternateReturn)
- {
- [self doDeleteQueuedJobs];
- [self doCancelCurrentJob];
- }
+ [self doCancelCurrentJob]; // <- this also stops libhb
}
diff --git a/macosx/HBQueueController.h b/macosx/HBQueueController.h
index cab1c201b..ae90acc65 100644
--- a/macosx/HBQueueController.h
+++ b/macosx/HBQueueController.h
@@ -9,10 +9,19 @@
#include "hb.h"
@class HBController;
+@class HBJob;
+@class HBJobGroup;
#define HB_QUEUE_DRAGGING 0 // <--- NOT COMPLETELY FUNCTIONAL YET
#define HB_OUTLINE_METRIC_CONTROLS 1 // for tweaking the outline cell spacings
+// hb_job_t contains a sequence_id field. The high word is a unique job group id.
+// The low word contains the "sequence id" which is a value starting at 0 and
+// incremented for each pass in the job group. Use the function below to create and
+// interpret a sequence_id field.
+int MakeJobID(int jobGroupID, int sequenceNum);
+bool IsFirstPass(int jobID);
+
typedef enum _HBQueueJobGroupStatus
{
HBStatusNone = 0,
@@ -52,17 +61,66 @@ BOOL fIsDragging;
@end
//------------------------------------------------------------------------------------
+// HBJob is the UI's equivalent to libhb's hb_job_t struct. It is used mainly for
+// drawing the job's description. HBJob are referred to in the UI as 'passes'.
+//------------------------------------------------------------------------------------
@interface HBJob : NSObject
{
- hb_job_t *hbJob;
+ HBJobGroup *jobGroup;
+
+ // The following fields match up with similar fields found in hb_job_t and it's
+ // various substructures.
+@public
+ // from hb_job_s
+ int sequence_id; // This is how we xref to the jobs inside libhb
+
+ int chapter_start;
+ int chapter_end;
+ int chapter_markers;
+ int crop[4];
+ int deinterlace;
+ int width;
+ int height;
+ int keep_ratio;
+ int grayscale;
+ int pixel_ratio;
+ int pixel_aspect_width;
+ int pixel_aspect_height;
+ int vcodec;
+ float vquality;
+ int vbitrate;
+ int vrate;
+ int vrate_base;
+ int pass;
+ int h264_level;
+ int crf;
+ NSString *x264opts;
+
+ int audio_mixdowns[8];
+ int acodec;
+ int abitrate;
+ int arate;
+ int subtitle;
+
+ int mux;
+ NSString *file;
+
+ // from hb_title_s
+ NSString *titleName;
+ int titleIndex;
+ int titleWidth;
+ int titleHeight;
+
+ // from hb_subtitle_s
+ NSString *subtitleLang;
}
+ (HBJob*) jobWithJob: (hb_job_t *) job;
- (id) initWithJob: (hb_job_t *) job;
-- (hb_job_t *) job;
-- (NSMutableAttributedString *) attributedDescriptionWithHBHandle: (hb_handle_t *)handle
- withIcon: (BOOL)withIcon
+- (HBJobGroup *) jobGroup;
+- (void) setJobGroup: (HBJobGroup *)aJobGroup;
+- (NSMutableAttributedString *) attributedDescriptionWithIcon: (BOOL)withIcon
withTitle: (BOOL)withTitle
withPassName: (BOOL)withPassName
withFormatInfo: (BOOL)withFormatInfo
@@ -76,6 +134,11 @@ BOOL fIsDragging;
@end
//------------------------------------------------------------------------------------
+// HBJobGroup is what's referred to in the UI as an 'encode'. A job group contains
+// multiple HBJobs, one for each 'pass' of the encode. Whereas libhb keeps a simple
+// list of jobs in it's queue, the queue controller presents them to the user as a
+// series of encodes and passes (HBJObGroups and HBJobs).
+//------------------------------------------------------------------------------------
@interface HBJobGroup : NSObject
{
@@ -85,7 +148,6 @@ BOOL fIsDragging;
float fLastDescriptionHeight;
float fLastDescriptionWidth;
HBQueueJobGroupStatus fStatus;
- NSString *fPath;
}
// Creating a job group
@@ -94,23 +156,20 @@ BOOL fIsDragging;
// Adding jobs
- (void) addJob: (HBJob *)aJob;
-// Removing jobs
-- (void) removeAllJobs;
-
// Querying a job group
- (unsigned int) count;
- (HBJob *) jobAtIndex: (unsigned)index;
-- (unsigned) indexOfJob: (HBJob *)aJob;
+- (unsigned int) indexOfJob: (HBJob *)aJob;
- (NSEnumerator *) jobEnumerator;
- (void) setStatus: (HBQueueJobGroupStatus)status;
- (HBQueueJobGroupStatus) status;
-- (void) setPath: (NSString *)path;
- (NSString *) path;
+- (NSString *) name;
// Creating a description
- (void) setNeedsDescription: (BOOL)flag;
-- (NSMutableAttributedString *) attributedDescriptionWithHBHandle: (hb_handle_t *)handle;
-- (float) heightOfDescriptionForWidth:(float)width withHBHandle: (hb_handle_t *)handle;
+- (NSMutableAttributedString *) attributedDescription;
+- (float) heightOfDescriptionForWidth:(float)width;
- (float) lastDescriptionHeight;
@end
@@ -122,15 +181,16 @@ BOOL fIsDragging;
hb_handle_t *fHandle; // reference to hblib
HBController *fHBController; // reference to HBController
NSMutableArray *fJobGroups; // hblib's job list organized in a hierarchy of HBJobGroup and HBJob
- HBJobGroup *fCurrentJobGroup; // the HJobGroup current being processed by hblib
+ HBJobGroup *fCurrentJobGroup; // the HJobGroup currently being processed by hblib
+ HBJob *fCurrentJob; // the HJob (pass) currently being processed by hblib
+ int fCurrentJobID; // this is how we track when hbib has started processing a different job. This is the job's sequence_id.
BOOL fCurrentJobPaneShown; // NO when fCurrentJobPane has been shifted out of view (see showCurrentJobPane)
- hb_job_t *fLastKnownCurrentJob; // this is how we track when hbib has started processing a different job
NSMutableIndexSet *fSavedExpandedItems; // used by save/restoreOutlineViewState to preserve which items are expanded
NSMutableIndexSet *fSavedSelectedItems; // used by save/restoreOutlineViewState to preserve which items are selected
#if HB_QUEUE_DRAGGING
NSArray *fDraggedNodes;
#endif
- NSMutableArray *fCompleted; // HBJobGroups that have been completed. These also appear in fJobGroups.
+ NSMutableArray *fCompleted; // HBJobGroups that libhb has finihsed with, whether successfully encoded or canceled by the user. These also appear in fJobGroups.
NSTimer *fAnimationTimer; // animates the icon of the current job in the queue outline view
int fAnimationIndex; // used to generate name of image used to animate the current job in the queue outline view
@@ -177,6 +237,9 @@ BOOL fIsDragging;
- (void)hblibStateChanged: (hb_state_t &)state;
- (void)hblibWillStop;
+- (HBJobGroup *) currentJobGroup;
+- (HBJob *) currentJob;
+
- (IBAction)showQueueWindow: (id)sender;
- (IBAction)removeSelectedJobGroups: (id)sender;
- (IBAction)revealSelectedJobGroups: (id)sender;
diff --git a/macosx/HBQueueController.mm b/macosx/HBQueueController.mm
index fa307e837..428956d60 100644
--- a/macosx/HBQueueController.mm
+++ b/macosx/HBQueueController.mm
@@ -13,6 +13,19 @@
// Pasteboard type for or drag operations
#define HBQueuePboardType @"HBQueuePboardType"
+//------------------------------------------------------------------------------------
+// Job ID Utilities
+//------------------------------------------------------------------------------------
+
+int MakeJobID(int jobGroupID, int sequenceNum)
+{
+ return jobGroupID<<16 | sequenceNum;
+}
+
+bool IsFirstPass(int jobID)
+{
+ return LoWord(jobID) == 0;
+}
//------------------------------------------------------------------------------------
// NSMutableAttributedString (HBAdditions)
@@ -100,7 +113,7 @@ static int hb_group_count(hb_handle_t * h)
int index = 0;
while( ( job = hb_job( h, index++ ) ) )
{
- if (job->sequence_id == 0)
+ if (IsFirstPass(job->sequence_id))
count++;
}
return count;
@@ -119,7 +132,7 @@ static hb_job_t * hb_group(hb_handle_t * h, int i)
int index = 0;
while( ( job = hb_job( h, index++ ) ) )
{
- if (job->sequence_id == 0)
+ if (IsFirstPass(job->sequence_id))
{
if (count == i)
return job;
@@ -145,7 +158,7 @@ static void hb_rem_group( hb_handle_t * h, hb_job_t * job )
{
// Delete this job plus the following ones in the sequence
hb_rem( h, job );
- while( ( j = hb_job( h, index ) ) && (j->sequence_id != 0) )
+ while( ( j = hb_job( h, index ) ) && ( !IsFirstPass(j->sequence_id ) ) )
hb_rem( h, j );
return;
}
@@ -189,23 +202,80 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
{
if (self = [super init])
{
- // job is not owned by HBJob. It does not get dealloacted when HBJob is released.
- hbJob = job;
+ sequence_id = job->sequence_id;
+
+ chapter_start = job->chapter_start;
+ chapter_end = job->chapter_end;
+ chapter_markers = job->chapter_markers;
+ memcpy(crop, job->crop, sizeof(crop));
+ deinterlace = job->deinterlace;
+ width = job->width;
+ height = job->height;
+ keep_ratio = job->keep_ratio;
+ grayscale = job->grayscale;
+ pixel_ratio = job->pixel_ratio;
+ pixel_aspect_width = job->pixel_aspect_width;
+ pixel_aspect_height = job->pixel_aspect_height;
+ vcodec = job->vcodec;
+ vquality = job->vquality;
+ vbitrate = job->vbitrate;
+ vrate = job->vrate;
+ vrate_base = job->vrate_base;
+ pass = job->pass;
+ h264_level = job->h264_level;
+ crf = job->crf;
+ if (job->x264opts)
+ x264opts = [[NSString stringWithUTF8String:job->x264opts] retain];
+ memcpy(audio_mixdowns, job->audio_mixdowns, sizeof(audio_mixdowns));
+ acodec = job->acodec;
+ abitrate = job->abitrate;
+ arate = job->arate;
+ subtitle = job->subtitle;
+ mux = job->mux;
+ if (job->file)
+ file = [[NSString stringWithUTF8String:job->file] retain];
+ if (job->title->name)
+ titleName = [[NSString stringWithUTF8String:job->title->name] retain];
+ titleIndex = job->title->index;
+ titleWidth = job->title->width;
+ titleHeight = job->title->height;
+ if (job->subtitle >= 0)
+ {
+ hb_subtitle_t * aSubtitle = (hb_subtitle_t *) hb_list_item(job->title->list_subtitle, 0);
+ if (aSubtitle)
+ subtitleLang = [[NSString stringWithUTF8String:aSubtitle->lang] retain];
+ }
+
}
- return self;
+ return self;
+}
+
+- (void) dealloc
+{
+ // jobGroup is a weak reference and does not need to be deleted
+ [x264opts release];
+ [file release];
+ [titleName release];
+ [subtitleLang release];
+ [super dealloc];
}
-- (hb_job_t*) job
+- (HBJobGroup *) jobGroup
{
- return hbJob;
+ return jobGroup;
+}
+
+- (void) setJobGroup: (HBJobGroup *)aJobGroup
+{
+ // This is a weak reference. We don't retain or release it.
+ jobGroup = aJobGroup;
}
//------------------------------------------------------------------------------------
// Generate string to display in UI.
//------------------------------------------------------------------------------------
-- (NSMutableAttributedString *) attributedDescriptionWithHBHandle: (hb_handle_t *)handle
- withIcon: (BOOL)withIcon
+- (NSMutableAttributedString *) attributedDescriptionWithIcon: (BOOL)withIcon
withTitle: (BOOL)withTitle
withPassName: (BOOL)withPassName
withFormatInfo: (BOOL)withFormatInfo
@@ -219,8 +289,6 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
{
NSMutableAttributedString * finalString = [[[NSMutableAttributedString alloc] initWithString: @""] autorelease];
- hb_title_t * title = hbJob->title;
-
// Attributes
static NSMutableParagraphStyle * ps = NULL;
if (!ps)
@@ -271,15 +339,15 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
// Note: use title->name instead of title->dvd since name is just the chosen
// folder, instead of dvd which is the full path
- [finalString appendString:[NSString stringWithUTF8String:title->name] withAttributes:titleAttribute];
+ [finalString appendString:titleName withAttributes:titleAttribute];
NSString * summaryInfo;
- NSString * chapterString = (hbJob->chapter_start == hbJob->chapter_end) ?
- [NSString stringWithFormat:@"Chapter %d", hbJob->chapter_start] :
- [NSString stringWithFormat:@"Chapters %d through %d", hbJob->chapter_start, hbJob->chapter_end];
+ NSString * chapterString = (chapter_start == chapter_end) ?
+ [NSString stringWithFormat:@"Chapter %d", chapter_start] :
+ [NSString stringWithFormat:@"Chapters %d through %d", chapter_start, chapter_end];
- BOOL hasIndepthScan = (hbJob->pass == -1);
+ BOOL hasIndepthScan = (pass == -1);
int numVideoPasses = 0;
// To determine number of video passes, we need to skip past the subtitle scan.
@@ -287,25 +355,24 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
{
// When job is the one currently being processed, then the next in its group
// is the the first job in the queue.
- hb_job_t * nextjob;
- if (hbJob == hb_current_job(handle))
- nextjob = hb_job(handle, 0);
- else
- nextjob = hb_next_job(handle, hbJob);
+ HBJob * nextjob = nil;
+ unsigned int index = [jobGroup indexOfJob:self];
+ if (index != NSNotFound)
+ nextjob = [jobGroup jobAtIndex:index+1];
if (nextjob) // Overly cautious in case there is no next job!
numVideoPasses = MIN( 2, nextjob->pass + 1 );
}
else
- numVideoPasses = MIN( 2, hbJob->pass + 1 );
+ numVideoPasses = MIN( 2, pass + 1 );
if (hasIndepthScan && numVideoPasses == 1)
- summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, Deep Scan, Single Video Pass)", title->index, chapterString];
+ summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, Deep Scan, Single Video Pass)", titleIndex, chapterString];
else if (hasIndepthScan && numVideoPasses > 1)
- summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, Deep Scan, %d Video Passes)", title->index, chapterString, numVideoPasses];
+ summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, Deep Scan, %d Video Passes)", titleIndex, chapterString, numVideoPasses];
else if (numVideoPasses == 1)
- summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, Single Video Pass)", title->index, chapterString];
+ summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, Single Video Pass)", titleIndex, chapterString];
else
- summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, %d Video Passes)", title->index, chapterString, numVideoPasses];
+ summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, %d Video Passes)", titleIndex, chapterString, numVideoPasses];
[finalString appendString:[NSString stringWithFormat:@"%@\n", summaryInfo] withAttributes:detailAttribute];
@@ -322,7 +389,7 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
if (withIcon)
{
NSString * imageName;
- switch (hbJob->pass)
+ switch (pass)
{
case -1: imageName = @"JobPassSubtitleSmall"; break;
case 0: imageName = @"JobPassFirstSmall"; break;
@@ -348,11 +415,11 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
}
NSString * jobPassName;
- if (hbJob->pass == -1)
+ if (pass == -1)
jobPassName = NSLocalizedString (@"Deep Scan", nil);
else
{
- int passNum = MAX( 1, hbJob->pass );
+ int passNum = MAX( 1, pass );
if (passNum == 0)
jobPassName = NSLocalizedString (@"1st Pass", nil);
else if (passNum == 1)
@@ -371,14 +438,14 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
{
// 2097152
// Video Codec settings (Encoder in the gui)
- if (hbJob->vcodec == HB_VCODEC_FFMPEG)
+ if (vcodec == HB_VCODEC_FFMPEG)
jobVideoCodec = @"FFmpeg"; // HB_VCODEC_FFMPEG
- else if (hbJob->vcodec == HB_VCODEC_XVID)
+ else if (vcodec == HB_VCODEC_XVID)
jobVideoCodec = @"XviD"; // HB_VCODEC_XVID
- else if (hbJob->vcodec == HB_VCODEC_X264)
+ else if (vcodec == HB_VCODEC_X264)
{
// Deterimine for sure how we are now setting iPod uuid atom
- if (hbJob->h264_level) // We are encoding for iPod
+ if (h264_level) // We are encoding for iPod
jobVideoCodec = @"x264 (H.264 iPod)"; // HB_VCODEC_X264
else
jobVideoCodec = @"x264 (H.264 Main)"; // HB_VCODEC_X264
@@ -391,13 +458,13 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
NSString * jobAudioCodec = nil;
if (withFormatInfo || withAudioInfo)
{
- if (hbJob->acodec == 256)
+ if (acodec == 256)
jobAudioCodec = @"AAC"; // HB_ACODEC_FAAC
- else if (hbJob->acodec == 512)
+ else if (acodec == 512)
jobAudioCodec = @"MP3"; // HB_ACODEC_LAME
- else if (hbJob->acodec == 1024)
+ else if (acodec == 1024)
jobAudioCodec = @"Vorbis"; // HB_ACODEC_VORBIS
- else if (hbJob->acodec == 2048)
+ else if (acodec == 2048)
jobAudioCodec = @"AC3"; // HB_ACODEC_AC3
}
if (jobAudioCodec == nil)
@@ -408,18 +475,18 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
{
NSString * jobFormatInfo;
// Muxer settings (File Format in the gui)
- if (hbJob->mux == 65536 || hbJob->mux == 131072 || hbJob->mux == 1048576)
+ if (mux == 65536 || mux == 131072 || mux == 1048576)
jobFormatInfo = @"MP4"; // HB_MUX_MP4,HB_MUX_PSP,HB_MUX_IPOD
- else if (hbJob->mux == 262144)
+ else if (mux == 262144)
jobFormatInfo = @"AVI"; // HB_MUX_AVI
- else if (hbJob->mux == 524288)
+ else if (mux == 524288)
jobFormatInfo = @"OGM"; // HB_MUX_OGM
- else if (hbJob->mux == 2097152)
+ else if (mux == 2097152)
jobFormatInfo = @"MKV"; // HB_MUX_MKV
else
jobFormatInfo = @"unknown";
- if (hbJob->chapter_markers == 1)
+ if (chapter_markers == 1)
jobFormatInfo = [NSString stringWithFormat:@"%@ Container, %@ Video + %@ Audio, Chapter Markers\n", jobFormatInfo, jobVideoCodec, jobAudioCodec];
else
jobFormatInfo = [NSString stringWithFormat:@"%@ Container, %@ Video + %@ Audio\n", jobFormatInfo, jobVideoCodec, jobAudioCodec];
@@ -431,7 +498,7 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
if (withDestination)
{
[finalString appendString: @"Destination: " withAttributes:detailBoldAttribute];
- [finalString appendString:[NSString stringWithFormat:@"%@\n", [NSString stringWithUTF8String:hbJob->file]] withAttributes:detailAttribute];
+ [finalString appendString:[NSString stringWithFormat:@"%@\n", file] withAttributes:detailAttribute];
}
@@ -440,22 +507,22 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
NSString * jobPictureInfo;
// integers for picture values deinterlace, crop[4], keep_ratio, grayscale, pixel_ratio, pixel_aspect_width, pixel_aspect_height,
// maxWidth, maxHeight
- if (hbJob->pixel_ratio == 1)
+ if (pixel_ratio == 1)
{
- int titlewidth = title->width - hbJob->crop[2] - hbJob->crop[3];
- int displayparwidth = titlewidth * hbJob->pixel_aspect_width / hbJob->pixel_aspect_height;
- int displayparheight = title->height - hbJob->crop[0] - hbJob->crop[1];
- jobPictureInfo = [NSString stringWithFormat:@"%dx%d (%dx%d Anamorphic)", displayparwidth, displayparheight, hbJob->width, displayparheight];
+ int croppedWidth = titleWidth - crop[2] - crop[3];
+ int displayparwidth = croppedWidth * pixel_aspect_width / pixel_aspect_height;
+ int displayparheight = titleHeight - crop[0] - crop[1];
+ jobPictureInfo = [NSString stringWithFormat:@"%dx%d (%dx%d Anamorphic)", displayparwidth, displayparheight, width, displayparheight];
}
else
- jobPictureInfo = [NSString stringWithFormat:@"%dx%d", hbJob->width, hbJob->height];
- if (hbJob->keep_ratio == 1)
+ jobPictureInfo = [NSString stringWithFormat:@"%dx%d", width, height];
+ if (keep_ratio == 1)
jobPictureInfo = [jobPictureInfo stringByAppendingString:@" Keep Aspect Ratio"];
- if (hbJob->grayscale == 1)
+ if (grayscale == 1)
jobPictureInfo = [jobPictureInfo stringByAppendingString:@", Grayscale"];
- if (hbJob->deinterlace == 1)
+ if (deinterlace == 1)
jobPictureInfo = [jobPictureInfo stringByAppendingString:@", Deinterlace"];
if (withIcon) // implies indent the info
[finalString appendString: @"\t" withAttributes:detailBoldAttribute];
@@ -468,25 +535,25 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
NSString * jobVideoQuality;
NSString * jobVideoDetail;
- if (hbJob->vquality <= 0 || hbJob->vquality >= 1)
- jobVideoQuality = [NSString stringWithFormat:@"%d kbps", hbJob->vbitrate];
+ if (vquality <= 0 || vquality >= 1)
+ jobVideoQuality = [NSString stringWithFormat:@"%d kbps", vbitrate];
else
{
NSNumber * vidQuality;
- vidQuality = [NSNumber numberWithInt:hbJob->vquality * 100];
+ vidQuality = [NSNumber numberWithInt:vquality * 100];
// this is screwed up kind of. Needs to be formatted properly.
- if (hbJob->crf == 1)
+ if (crf == 1)
jobVideoQuality = [NSString stringWithFormat:@"%@%% CRF", vidQuality];
else
jobVideoQuality = [NSString stringWithFormat:@"%@%% CQP", vidQuality];
}
- if (hbJob->vrate_base == 1126125)
+ if (vrate_base == 1126125)
{
// NTSC FILM 23.976
jobVideoDetail = [NSString stringWithFormat:@"%@, %@, 23.976 fps", jobVideoCodec, jobVideoQuality];
}
- else if (hbJob->vrate_base == 900900)
+ else if (vrate_base == 900900)
{
// NTSC 29.97
jobVideoDetail = [NSString stringWithFormat:@"%@, %@, 29.97 fps", jobVideoCodec, jobVideoQuality];
@@ -494,7 +561,7 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
else
{
// Everything else
- jobVideoDetail = [NSString stringWithFormat:@"%@, %@, %d fps", jobVideoCodec, jobVideoQuality, hbJob->vrate / hbJob->vrate_base];
+ jobVideoDetail = [NSString stringWithFormat:@"%@, %@, %d fps", jobVideoCodec, jobVideoQuality, vrate / vrate_base];
}
if (withIcon) // implies indent the info
[finalString appendString: @"\t" withAttributes:detailBoldAttribute];
@@ -504,12 +571,12 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
if (withx264Info)
{
- if (hbJob->vcodec == HB_VCODEC_X264 && hbJob->x264opts)
+ if (vcodec == HB_VCODEC_X264 && x264opts)
{
if (withIcon) // implies indent the info
[finalString appendString: @"\t" withAttributes:detailBoldAttribute];
[finalString appendString: @"x264 Options: " withAttributes:detailBoldAttribute];
- [finalString appendString:[NSString stringWithFormat:@"%@\n", [NSString stringWithUTF8String:hbJob->x264opts]] withAttributes:detailAttribute];
+ [finalString appendString:[NSString stringWithFormat:@"%@\n", x264opts] withAttributes:detailAttribute];
}
}
@@ -519,7 +586,7 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
if ([jobAudioCodec isEqualToString: @"AC3"])
jobAudioInfo = [NSString stringWithFormat:@"%@, Pass-Through", jobAudioCodec];
else
- jobAudioInfo = [NSString stringWithFormat:@"%@, %d kbps, %d Hz", jobAudioCodec, hbJob->abitrate, hbJob->arate];
+ jobAudioInfo = [NSString stringWithFormat:@"%@, %d kbps, %d Hz", jobAudioCodec, abitrate, arate];
// we now get the audio mixdown info for each of the two gui audio tracks
// lets do it the long way here to get a handle on things.
@@ -527,15 +594,15 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
int ai; // counter for each audios [] , macgui only allows for two audio tracks currently
for( ai = 0; ai < 2; ai++ )
{
- if (hbJob->audio_mixdowns[ai] == HB_AMIXDOWN_MONO)
+ if (audio_mixdowns[ai] == HB_AMIXDOWN_MONO)
jobAudioInfo = [jobAudioInfo stringByAppendingString:[NSString stringWithFormat:@", Track %d: Mono", ai + 1]];
- if (hbJob->audio_mixdowns[ai] == HB_AMIXDOWN_STEREO)
+ if (audio_mixdowns[ai] == HB_AMIXDOWN_STEREO)
jobAudioInfo = [jobAudioInfo stringByAppendingString:[NSString stringWithFormat:@", Track %d: Stereo", ai + 1]];
- if (hbJob->audio_mixdowns[ai] == HB_AMIXDOWN_DOLBY)
+ if (audio_mixdowns[ai] == HB_AMIXDOWN_DOLBY)
jobAudioInfo = [jobAudioInfo stringByAppendingString:[NSString stringWithFormat:@", Track %d: Dolby Surround", ai + 1]];
- if (hbJob->audio_mixdowns[ai] == HB_AMIXDOWN_DOLBYPLII)
+ if (audio_mixdowns[ai] == HB_AMIXDOWN_DOLBYPLII)
jobAudioInfo = [jobAudioInfo stringByAppendingString:[NSString stringWithFormat:@", Track %d: Dolby Pro Logic II", ai + 1]];
- if (hbJob->audio_mixdowns[ai] == HB_AMIXDOWN_6CH)
+ if (audio_mixdowns[ai] == HB_AMIXDOWN_6CH)
jobAudioInfo = [jobAudioInfo stringByAppendingString:[NSString stringWithFormat:@", Track %d: 6-channel discreet", ai + 1]];
}
if (withIcon) // implies indent the info
@@ -546,25 +613,24 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
if (withSubtitleInfo)
{
- // hbJob->subtitle can == -1 in two cases:
+ // subtitle can == -1 in two cases:
// autoselect: when pass == -1
// none: when pass != -1
- if ((hbJob->subtitle == -1) && (hbJob->pass == -1))
+ if ((subtitle == -1) && (pass == -1))
{
if (withIcon) // implies indent the info
[finalString appendString: @"\t" withAttributes:detailBoldAttribute];
[finalString appendString: @"Subtitles: " withAttributes:detailBoldAttribute];
[finalString appendString: @"Autoselect " withAttributes:detailAttribute];
}
- else if (hbJob->subtitle >= 0)
+ else if (subtitle >= 0)
{
- hb_subtitle_t * subtitle = (hb_subtitle_t *) hb_list_item( title->list_subtitle, 0 );
- if (subtitle)
+ if (subtitleLang)
{
if (withIcon) // implies indent the info
[finalString appendString: @"\t" withAttributes:detailBoldAttribute];
[finalString appendString: @"Subtitles: " withAttributes:detailBoldAttribute];
- [finalString appendString: [NSString stringWithCString: subtitle->lang] withAttributes:detailAttribute];
+ [finalString appendString: subtitleLang withAttributes:detailAttribute];
}
}
}
@@ -606,7 +672,6 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
- (void) dealloc
{
[fJobs release];
- [fPath release];
[super dealloc];
}
@@ -617,17 +682,13 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
- (void) addJob: (HBJob *)aJob
{
+ [aJob setJobGroup:self];
[fJobs addObject: aJob];
[self setNeedsDescription: YES];
fLastDescriptionHeight = 0;
fLastDescriptionWidth = 0;
}
-- (void) removeAllJobs
-{
- [fJobs removeAllObjects];
-}
-
- (HBJob *) jobAtIndex: (unsigned)index
{
return [fJobs objectAtIndex: index];
@@ -648,7 +709,7 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
fNeedsDescription = flag;
}
-- (void) updateDescriptionWithHBHandle: (hb_handle_t *)handle
+- (void) updateDescription
{
fNeedsDescription = NO;
@@ -662,8 +723,7 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
HBJob * job = [self jobAtIndex:0];
- [fDescription appendAttributedString: [job attributedDescriptionWithHBHandle: handle
- withIcon: NO
+ [fDescription appendAttributedString: [job attributedDescriptionWithIcon: NO
withTitle: YES
withPassName: NO
withFormatInfo: YES
@@ -679,11 +739,10 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
NSEnumerator * e = [self jobEnumerator];
while ( (job = [e nextObject]) )
{
- int pass = [job job]->pass;
+ int pass = job->pass;
[fDescription appendAttributedString:carriageReturn];
[fDescription appendAttributedString:
- [job attributedDescriptionWithHBHandle: handle
- withIcon: YES
+ [job attributedDescriptionWithIcon: YES
withTitle: NO
withPassName: YES
withFormatInfo: NO
@@ -697,21 +756,21 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
}
-- (NSMutableAttributedString *) attributedDescriptionWithHBHandle: (hb_handle_t *)handle
+- (NSMutableAttributedString *) attributedDescription
{
if (fNeedsDescription)
- [self updateDescriptionWithHBHandle: handle];
+ [self updateDescription];
return fDescription;
}
-- (float) heightOfDescriptionForWidth:(float)width withHBHandle: (hb_handle_t *)handle
+- (float) heightOfDescriptionForWidth:(float)width
{
// Try to return the cached value if no changes have happened since the last time
if ((width == fLastDescriptionWidth) && (fLastDescriptionHeight != 0) && !fNeedsDescription)
return fLastDescriptionHeight;
if (fNeedsDescription)
- [self updateDescriptionWithHBHandle: handle];
+ [self updateDescription];
// Calculate the height
NSRect bounds = [fDescription boundingRectWithSize:NSMakeSize(width, 10000) options:NSStringDrawingUsesLineFragmentOrigin];
@@ -748,16 +807,16 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
return self->fStatus;
}
-- (void) setPath: (NSString *)path
+- (NSString *) name
{
- [path retain];
- [fPath release];
- fPath = path;
+ HBJob * firstJob = [self jobAtIndex:0];
+ return firstJob ? firstJob->titleName : nil;
}
- (NSString *) path
{
- return fPath;
+ HBJob * firstJob = [self jobAtIndex:0];
+ return firstJob ? firstJob->file : nil;
}
@end
@@ -837,6 +896,24 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
}
//------------------------------------------------------------------------------------
+// Returns the HBJobGroup that is currently being encoded; nil if no encoding is
+// occurring.
+//------------------------------------------------------------------------------------
+- (HBJobGroup *) currentJobGroup;
+{
+ return fCurrentJobGroup;
+}
+
+//------------------------------------------------------------------------------------
+// Returns the HBJob (pass) that is currently being encoded; nil if no encoding is
+// occurring.
+//------------------------------------------------------------------------------------
+- (HBJob *) currentJob
+{
+ return fCurrentJob;
+}
+
+//------------------------------------------------------------------------------------
// Displays and brings the queue window to the front
//------------------------------------------------------------------------------------
- (IBAction) showQueueWindow: (id)sender
@@ -845,6 +922,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
[fQueueWindow makeKeyAndOrderFront: self];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"QueueWindowIsOpen"];
}
+
//------------------------------------------------------------------------------------
// Show or hide the current job pane (fCurrentJobPane).
//------------------------------------------------------------------------------------
@@ -897,7 +975,14 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
//------------------------------------------------------------------------------------
- (void)rebuildJobGroups
{
- // Currently, job groups are rdered like this:
+ // This method is called every time we detect that hblib has changed its job list.
+ // It releases the previous job group list and rebuilds it by reading the current
+ // list of jobs from libhb. libhb does not implement job groups/encodes itself. It
+ // just maintains a simply list of jobs. The queue controller however, presents
+ // these jobs to the user organized into encodes where all jobs associated with
+ // the same encode are grouped into a logical job group/encode.
+
+ // Currently, job groups are ordered like this:
// Completed job groups
// Current job group
// Pending job groups
@@ -908,7 +993,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
// Add all the completed job groups
[fJobGroups addObjectsFromArray: fCompleted];
- // Add all the completed job groups
+ // Add the current job group
if (fCurrentJobGroup)
[fJobGroups addObject: fCurrentJobGroup];
@@ -921,7 +1006,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
hb_job_t * nextJob = hb_group( fHandle, 0 );
while( nextJob )
{
- if (nextJob->sequence_id == 0)
+ if (IsFirstPass(nextJob->sequence_id))
{
// Encountered a new group. Add the current one to fJobGroups and then start a new one.
if ([aJobGroup count] > 0)
@@ -932,7 +1017,6 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
}
}
[aJobGroup addJob: [HBJob jobWithJob:nextJob]];
- [aJobGroup setPath: [NSString stringWithUTF8String:nextJob->file]];
nextJob = hb_next_job (fHandle, nextJob);
}
if ([aJobGroup count] > 0)
@@ -943,68 +1027,70 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
}
//------------------------------------------------------------------------------------
-// Adds aJobGroup to the list of completed job groups, marking its status as
-// HBStatusComplete.
+// Adds aJobGroup to the list of completed job groups. The completed list is
+// maintained by the queue, since libhb deletes all its jobs after they are complete.
//------------------------------------------------------------------------------------
- (void) addCompletedJobGroup: (HBJobGroup *)aJobGroup
{
- // Once hblib has completed its work, the hb_job_t objects will be freed, so we
- // can't keep a reference to them.
- [aJobGroup removeAllJobs];
-
- [aJobGroup setStatus: HBStatusComplete];
-
- // Put the group in the completed list for permanent storage, and also rebuild
- // the master job group list which contains completed and pending groups.
+ // Put the group in the completed list for permanent storage.
[fCompleted addObject: aJobGroup];
}
-- (void) setCurrentJobGroupFromJob: (hb_job_t *)aJob
+//------------------------------------------------------------------------------------
+// Sets fCurrentJobGroup to a new job group.
+//------------------------------------------------------------------------------------
+- (void) setCurrentJobGroup: (HBJobGroup *)aJobGroup
{
- HBJobGroup * aJobGroup = nil;
-
- // Try to find this new group in our existing job groups.
- if (aJob)
+ if (aJobGroup)
+ [aJobGroup setStatus: HBStatusWorking];
+
+ [aJobGroup retain];
+ [fCurrentJobGroup release];
+ fCurrentJobGroup = aJobGroup;
+}
+
+//------------------------------------------------------------------------------------
+// Locates and returns a HBJob whose sequence_id matches a specified value.
+//------------------------------------------------------------------------------------
+- (HBJob *) findJobWithID: (int)aJobID
+{
+ HBJobGroup * aJobGroup;
+ NSEnumerator * groupEnum = [fJobGroups objectEnumerator];
+ while ( (aJobGroup = [groupEnum nextObject]) )
{
- BOOL found = NO;
- NSEnumerator * groupEnum = [fJobGroups objectEnumerator];
- while ( !found && (aJobGroup = [groupEnum nextObject]) )
+ HBJob * job;
+ NSEnumerator * jobEnum = [aJobGroup jobEnumerator];
+ while ( (job = [jobEnum nextObject]) )
{
- HBJob * j;
- NSEnumerator * jobEnum = [aJobGroup jobEnumerator];
- while ( !found && (j = [jobEnum nextObject]) )
- {
- if ([j job] == aJob)
- found = YES;
- }
+ if (job->sequence_id == aJobID)
+ return job;
}
-
- // Or create the job group.
- if (!aJobGroup)
- {
- aJobGroup = [HBJobGroup jobGroup];
- [aJobGroup addJob: [HBJob jobWithJob: aJob]];
- [aJobGroup setPath: [NSString stringWithUTF8String:aJob->file]];
- while ( (aJob = hb_next_job(fHandle, aJob)) && (aJob->sequence_id != 0) )
- [aJobGroup addJob: [HBJob jobWithJob: aJob]];
+ }
+ return nil;
+}
- [aJobGroup updateDescriptionWithHBHandle: fHandle];
- }
-
- [aJobGroup setStatus: HBStatusWorking];
+//------------------------------------------------------------------------------------
+// Locates and returns a libhb job whose sequence_id matches a specified value.
+//------------------------------------------------------------------------------------
+- (hb_job_t *) findLibhbJobWithID: (int)aJobID
+{
+ hb_job_t * job;
+ int index = 0;
+ while( ( job = hb_job( fHandle, index++ ) ) )
+ {
+ if (job->sequence_id == aJobID)
+ return job;
}
-
- [aJobGroup retain];
- [fCurrentJobGroup release];
- fCurrentJobGroup = aJobGroup;
+ return nil;
}
#pragma mark -
#pragma mark UI Updating
//------------------------------------------------------------------------------------
-// Saves the state of the items that are currently expanded. Calling restoreOutlineViewState
-// will restore the state of all items to match what was saved by saveOutlineViewState.
+// Saves the state of the items that are currently expanded and selected. Calling
+// restoreOutlineViewState will restore the state of all items to match what was saved
+// by saveOutlineViewState. Nested calls to saveOutlineViewState are not supported.
//------------------------------------------------------------------------------------
- (void) saveOutlineViewState
{
@@ -1013,29 +1099,18 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
else
[fSavedExpandedItems removeAllIndexes];
- // NB: This code is stuffing the address of each job into an index set. While it
- // works 99.9% of the time, it's not the ideal solution. We need unique ids in
- // each job, possibly using the existing sequence_id field. Could use the high
- // word as a unique encode id and the low word the sequence number.
+ // This code stores the sequence_id of the first job of each job group into an
+ // index set. This is sufficient to identify each group uniquely.
HBJobGroup * aJobGroup;
NSEnumerator * e = [fJobGroups objectEnumerator];
while ( (aJobGroup = [e nextObject]) )
{
if ([fOutlineView isItemExpanded: aJobGroup])
- {
- if ([aJobGroup status] == HBStatusComplete)
- [fSavedExpandedItems addIndex: (unsigned int)aJobGroup];
- else
- [fSavedExpandedItems addIndex: (unsigned int)[[aJobGroup jobAtIndex:0] job]];
- }
+ [fSavedExpandedItems addIndex: [aJobGroup jobAtIndex:0]->sequence_id];
}
- // Save the selection also. This is really UGLY code. Since I have to rebuild the
- // entire outline hierachy every time hblib changes its job list, there's no easy
- // way for me to remember the selection state other than saving off the first
- // hb_job_t item in each selected group. This is done by saving the object's
- // address. This could go away if I'd save a unique id in each job object.
+ // Save the selection also.
if (!fSavedSelectedItems)
fSavedSelectedItems = [[NSMutableIndexSet alloc] init];
@@ -1047,10 +1122,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
while (row != NSNotFound)
{
aJobGroup = [fOutlineView itemAtRow: row];
- if ([aJobGroup status] == HBStatusComplete)
- [fSavedSelectedItems addIndex: (unsigned int)aJobGroup];
- else
- [fSavedSelectedItems addIndex: (unsigned int)[[aJobGroup jobAtIndex:0] job]];
+ [fSavedSelectedItems addIndex: [aJobGroup jobAtIndex:0]->sequence_id];
row = [selectedRows indexGreaterThanIndex: row];
}
@@ -1068,40 +1140,24 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
NSEnumerator * e = [fJobGroups objectEnumerator];
while ( (aJobGroup = [e nextObject]) )
{
- if ([aJobGroup status] == HBStatusComplete)
- {
- if ([fSavedExpandedItems containsIndex: (unsigned int)aJobGroup])
- [fOutlineView expandItem: aJobGroup];
- }
- else
- {
- hb_job_t * j = [[aJobGroup jobAtIndex:0] job];
- if ([fSavedExpandedItems containsIndex: (unsigned int)j])
- [fOutlineView expandItem: aJobGroup];
- }
+ HBJob * job = [aJobGroup jobAtIndex:0];
+ if (job && [fSavedExpandedItems containsIndex: job->sequence_id])
+ [fOutlineView expandItem: aJobGroup];
}
}
if (fSavedSelectedItems)
{
- // Ugh. Have to cycle through each row looking for the previously selected job.
- // See the explanation in saveOutlineViewState about the logic here.
-
NSMutableIndexSet * rowsToSelect = [[[NSMutableIndexSet alloc] init] autorelease];
- for (int i = 0; i < [fOutlineView numberOfRows]; i++)
+ HBJobGroup * aJobGroup;
+ NSEnumerator * e = [fJobGroups objectEnumerator];
+ int i = 0;
+ while ( (aJobGroup = [e nextObject]) )
{
- HBJobGroup * aJobGroup = [fOutlineView itemAtRow: i];
- // Test to see if the group or the group's first job is a match
- if ([aJobGroup status] == HBStatusComplete)
- {
- if ([fSavedSelectedItems containsIndex: (unsigned int)aJobGroup])
- [rowsToSelect addIndex: i];
- }
- else
- {
- if ([fSavedSelectedItems containsIndex: (unsigned int)[[aJobGroup jobAtIndex:0] job]])
- [rowsToSelect addIndex: i];
- }
+ HBJob * job = [aJobGroup jobAtIndex:0];
+ if (job && [fSavedSelectedItems containsIndex: job->sequence_id])
+ [rowsToSelect addIndex: i];
+ i++;
}
if ([rowsToSelect count] == 0)
[fOutlineView deselectAll: nil];
@@ -1158,7 +1214,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
//------------------------------------------------------------------------------------
// Generate string to display in UI.
//------------------------------------------------------------------------------------
-- (NSString *) progressStatusStringForJob: (hb_job_t *)job state: (hb_state_t *)s
+- (NSString *) progressStatusStringForJob: (HBJob *)job state: (hb_state_t *)s
{
if (s->state == HB_STATE_WORKING)
{
@@ -1198,7 +1254,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
//------------------------------------------------------------------------------------
// Generate string to display in UI.
//------------------------------------------------------------------------------------
-- (NSString *) progressTimeRemainingStringForJob: (hb_job_t *)job state: (hb_state_t *)s
+- (NSString *) progressTimeRemainingStringForJob: (HBJob *)job state: (hb_state_t *)s
{
if (s->state == HB_STATE_WORKING)
{
@@ -1270,7 +1326,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
//------------------------------------------------------------------------------------
// Refresh progress bar (fProgressTextField) from current state.
//------------------------------------------------------------------------------------
-- (void) updateProgressTextForJob: (hb_job_t *)job state: (hb_state_t *)s
+- (void) updateProgressTextForJob: (HBJob *)job state: (hb_state_t *)s
{
NSString * statusMsg = [self progressStatusStringForJob:job state:s];
NSString * timeMsg = [self progressTimeRemainingStringForJob:job state:s];
@@ -1335,17 +1391,13 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
//------------------------------------------------------------------------------------
- (void)updateCurrentJobDescription
{
- hb_job_t * job = fHandle ? hb_current_job(fHandle) : nil;
-
- if (job)
+ if (fCurrentJob)
{
- HBJob * currentJob = [HBJob jobWithJob: job];
- switch (job->pass)
+ switch (fCurrentJob->pass)
{
case -1: // Subtitle scan
[fJobDescTextField setAttributedStringValue:
- [currentJob attributedDescriptionWithHBHandle:fHandle
- withIcon: NO
+ [fCurrentJob attributedDescriptionWithIcon: NO
withTitle: YES
withPassName: YES
withFormatInfo: NO
@@ -1359,8 +1411,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
case 1: // video 1st pass
[fJobDescTextField setAttributedStringValue:
- [currentJob attributedDescriptionWithHBHandle:fHandle
- withIcon: NO
+ [fCurrentJob attributedDescriptionWithIcon: NO
withTitle: YES
withPassName: YES
withFormatInfo: NO
@@ -1375,8 +1426,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
case 0: // single pass
case 2: // video 2nd pass + audio
[fJobDescTextField setAttributedStringValue:
- [currentJob attributedDescriptionWithHBHandle:fHandle
- withIcon: NO
+ [fCurrentJob attributedDescriptionWithIcon: NO
withTitle: YES
withPassName: YES
withFormatInfo: NO
@@ -1390,8 +1440,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
default: // unknown
[fJobDescTextField setAttributedStringValue:
- [currentJob attributedDescriptionWithHBHandle:fHandle
- withIcon: NO
+ [fCurrentJob attributedDescriptionWithIcon: NO
withTitle: YES
withPassName: YES
withFormatInfo: NO
@@ -1414,10 +1463,9 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
//------------------------------------------------------------------------------------
- (void)updateCurrentJobProgress
{
- hb_job_t * job = fHandle ? hb_current_job(fHandle) : nil;
hb_state_t s;
hb_get_state2( fHandle, &s );
- [self updateProgressTextForJob: job state: &s];
+ [self updateProgressTextForJob: fCurrentJob state: &s];
[self updateProgressBarWithState:&s];
}
@@ -1462,8 +1510,10 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
[self cancelCurrentJob: sender];
break;
case HBStatusPending:
- hb_job_t * job = [[jobGroup jobAtIndex: 0] job];
- hb_rem_group( fHandle, job );
+ HBJob * job = [jobGroup jobAtIndex: 0];
+ hb_job_t * libhbJob = [self findLibhbJobWithID:job->sequence_id];
+ if (libhbJob)
+ hb_rem_group( fHandle, libhbJob );
break;
case HBStatusNone:
break;
@@ -1548,18 +1598,52 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
//------------------------------------------------------------------------------------
// Notifies HBQueueController that hblib's current job has changed
//------------------------------------------------------------------------------------
-- (void)currentJobGroupChanged: (hb_job_t *) currentJob
+- (void)currentJobChanged: (HBJob *) currentJob
{
- if (fCurrentJobGroup && [fCurrentJobGroup status] != HBStatusCanceled)
- [self addCompletedJobGroup: fCurrentJobGroup];
- [self setCurrentJobGroupFromJob: currentJob];
- [self updateCurrentJobDescription];
- [self updateCurrentJobProgress];
- [self showCurrentJobPane: fCurrentJobGroup != nil];
- if (fCurrentJobGroup)
- [self startAnimatingCurrentJobGroupInQueue];
- else
- [self stopAnimatingCurrentJobGroupInQueue];
+ [currentJob retain];
+ [fCurrentJob release];
+ fCurrentJob = currentJob;
+
+ // Check to see if this is also a change in Job Group
+
+ HBJobGroup * theJobGroup = [currentJob jobGroup];
+ if ((theJobGroup == nil) || (theJobGroup != fCurrentJobGroup)) // no more job groups or start of a new group
+ {
+ // Previous job has completed
+ if (fCurrentJobGroup)
+ {
+ // Update the status of the job that just finished. If the user canceled,
+ // the status will have already been set to canceled by hblibWillStop. So
+ // all other cases are assumed to be a successful encode. BTW, libhb
+ // doesn't currently report errors back to the GUI.
+ if ([fCurrentJobGroup status] != HBStatusCanceled)
+ [fCurrentJobGroup setStatus:HBStatusComplete];
+
+ [self addCompletedJobGroup: fCurrentJobGroup];
+ }
+
+ // Set the new group
+ [self setCurrentJobGroup: theJobGroup];
+
+ // Update the UI
+ [self updateCurrentJobDescription];
+ [self updateCurrentJobProgress];
+ [self showCurrentJobPane: fCurrentJobGroup != nil];
+ if (fCurrentJobGroup)
+ [self startAnimatingCurrentJobGroupInQueue];
+ else
+ [self stopAnimatingCurrentJobGroupInQueue];
+
+ [self hblibJobListChanged];
+ }
+
+ else // start a new job/pass in the same group
+ {
+ // Update the UI
+ [self updateCurrentJobDescription];
+ [self updateCurrentJobProgress];
+ }
+
}
//------------------------------------------------------------------------------------
@@ -1590,32 +1674,26 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
//------------------------------------------------------------------------------------
- (void)hblibStateChanged: (hb_state_t &)state
{
- // First check to see if hblib has moved on to another job. We get no direct
- // message when this happens, so we have to detect it ourself. The new job could
- // be either just the next job in the current group, or the start of a new group.
- if (fLastKnownCurrentJob != hb_current_job(fHandle))
- {
- hb_job_t * currentJob = hb_current_job(fHandle);
- if (!currentJob || currentJob->sequence_id == 0) // start of a new group
- {
- [self currentJobGroupChanged: currentJob];
- [self hblibJobListChanged];
- }
- else
- {
- [self updateCurrentJobDescription];
- [self updateCurrentJobProgress];
- }
-
- fLastKnownCurrentJob = currentJob;
- }
-
switch( state.state )
{
case HB_STATE_WORKING:
{
- [self updateCurrentJobProgress];
- [self startAnimatingCurrentJobGroupInQueue];
+ //NSLog(@"job = %x; job_cur = %d; job_count = %d", state.param.working.sequence_id, state.param.working.job_cur, state.param.working.job_count);
+ // First check to see if hblib has moved on to another job. We get no direct
+ // message when this happens, so we have to detect it ourself. The new job could
+ // be either just the next job in the current group, or the start of a new group.
+ if (fCurrentJobID != state.param.working.sequence_id)
+ {
+ fCurrentJobID = state.param.working.sequence_id;
+ HBJob * currentJob = [self findJobWithID:fCurrentJobID];
+ [self currentJobChanged: currentJob];
+ }
+
+ if (fCurrentJob)
+ {
+ [self updateCurrentJobProgress];
+ [self startAnimatingCurrentJobGroupInQueue];
+ }
break;
}
@@ -1637,6 +1715,9 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
// HB_STATE_WORKDONE means that hblib has finished processing all the jobs
// in *its* queue. This message is NOT sent as each individual job is
// completed.
+
+ [self currentJobChanged: nil];
+ fCurrentJobID = 0;
}
}
@@ -1984,7 +2065,7 @@ static float spacingWidth = 3.0;
// Column width is NOT what is ultimately used
width -= 47; // 26 pixels for disclosure triangle, 20 for icon, 1 for intercell spacing
- float height = [item heightOfDescriptionForWidth: width withHBHandle: fHandle];
+ float height = [item heightOfDescriptionForWidth: width];
return height;
}
else
@@ -1997,11 +2078,14 @@ static float spacingWidth = 3.0;
// using the image portion of the cell so we could switch back to a regular NSTextFieldCell.
if ([[tableColumn identifier] isEqualToString:@"desc"])
- return [item attributedDescriptionWithHBHandle: fHandle];
+ return [item attributedDescription];
else if ([[tableColumn identifier] isEqualToString:@"icon"])
{
switch ([(HBJobGroup*)item status])
{
+ case HBStatusCanceled:
+ return [NSImage imageNamed:@"EncodeCanceled"];
+ break;
case HBStatusComplete:
return [NSImage imageNamed:@"EncodeComplete"];
break;
diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj
index 5696d2cef..d99718c38 100644
--- a/macosx/HandBrake.xcodeproj/project.pbxproj
+++ b/macosx/HandBrake.xcodeproj/project.pbxproj
@@ -165,6 +165,7 @@
E3C844F80CA6B3F90013B683 /* RevealHighlight.png in Resources */ = {isa = PBXBuildFile; fileRef = E3C844F40CA6B3F90013B683 /* RevealHighlight.png */; };
E3C844F90CA6B3F90013B683 /* Reveal.png in Resources */ = {isa = PBXBuildFile; fileRef = E3C844F50CA6B3F90013B683 /* Reveal.png */; };
E3C845870CA6E9080013B683 /* EncodeComplete.png in Resources */ = {isa = PBXBuildFile; fileRef = E3C845860CA6E9080013B683 /* EncodeComplete.png */; };
+ E3FC10910D1611EC00470E7B /* EncodeCanceled.png in Resources */ = {isa = PBXBuildFile; fileRef = E3FC10900D1611EC00470E7B /* EncodeCanceled.png */; };
EAA526930C3B25D200944FF2 /* stream.c in Sources */ = {isa = PBXBuildFile; fileRef = EAA526920C3B25D200944FF2 /* stream.c */; };
EAA526940C3B25D200944FF2 /* stream.c in Sources */ = {isa = PBXBuildFile; fileRef = EAA526920C3B25D200944FF2 /* stream.c */; };
FC8519500C59A02C0073812C /* denoise.c in Sources */ = {isa = PBXBuildFile; fileRef = FC85194C0C59A02C0073812C /* denoise.c */; };
@@ -343,6 +344,7 @@
E3C844F40CA6B3F90013B683 /* RevealHighlight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = RevealHighlight.png; sourceTree = "<group>"; };
E3C844F50CA6B3F90013B683 /* Reveal.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Reveal.png; sourceTree = "<group>"; };
E3C845860CA6E9080013B683 /* EncodeComplete.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = EncodeComplete.png; sourceTree = "<group>"; };
+ E3FC10900D1611EC00470E7B /* EncodeCanceled.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = EncodeCanceled.png; sourceTree = "<group>"; };
EAA526920C3B25D200944FF2 /* stream.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = stream.c; path = ../libhb/stream.c; sourceTree = SOURCE_ROOT; };
FC85194C0C59A02C0073812C /* denoise.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = denoise.c; path = ../libhb/denoise.c; sourceTree = SOURCE_ROOT; };
FC85194D0C59A02C0073812C /* deinterlace.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = deinterlace.c; path = ../libhb/deinterlace.c; sourceTree = SOURCE_ROOT; };
@@ -599,6 +601,7 @@
E3C844F20CA6B3F90013B683 /* RevealPressed.png */,
E3C844F40CA6B3F90013B683 /* RevealHighlight.png */,
E3C844F30CA6B3F90013B683 /* RevealHighlightPressed.png */,
+ E3FC10900D1611EC00470E7B /* EncodeCanceled.png */,
E3C845860CA6E9080013B683 /* EncodeComplete.png */,
E3997A290CAB58BC00287239 /* EncodeWorking0.png */,
E3997A280CAB58BC00287239 /* EncodeWorking1.png */,
@@ -823,6 +826,7 @@
E3997A2F0CAB58BC00287239 /* EncodeWorking0.png in Resources */,
E3997A300CAB58BC00287239 /* EncodeWorking2.png in Resources */,
E3997A310CAB58BC00287239 /* EncodeWorking5.png in Resources */,
+ E3FC10910D1611EC00470E7B /* EncodeCanceled.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/macosx/icons/EncodeCanceled.png b/macosx/icons/EncodeCanceled.png
new file mode 100644
index 000000000..66c5bf7c9
--- /dev/null
+++ b/macosx/icons/EncodeCanceled.png
Binary files differ