summaryrefslogtreecommitdiffstats
path: root/libhb
diff options
context:
space:
mode:
authorjstebbins <[email protected]>2015-03-07 22:25:48 +0000
committerjstebbins <[email protected]>2015-03-07 22:25:48 +0000
commit7705413a03a90c16734b40fb7bc492be8b56ab6f (patch)
tree2b3c861e0a7b78e45869a191b20f7dc57c0fe48b /libhb
parenta4ad5062c3fa1787b208389123bb81ea57483142 (diff)
json: automatically scan title when processing json jobs
Simplifies the WinGui. This also changes how jobs are processed. Creating the sub-jobs for multiple passes is delayed until after scanning and immediately before running the job. Working status has also changed. Sub-job passes are identified in status with an ID that allows the frontend to definitively identify what pass is in progress. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@6976 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb')
-rw-r--r--libhb/batch.c6
-rw-r--r--libhb/common.c9
-rw-r--r--libhb/common.h14
-rw-r--r--libhb/encavcodec.c12
-rw-r--r--libhb/enctheora.c20
-rw-r--r--libhb/encx264.c15
-rw-r--r--libhb/encx265.c7
-rw-r--r--libhb/hb.c108
-rw-r--r--libhb/hb_json.c62
-rw-r--r--libhb/hb_json.h1
-rw-r--r--libhb/internal.h1
-rw-r--r--libhb/muxavformat.c2
-rw-r--r--libhb/muxcommon.c11
-rw-r--r--libhb/reader.c1
-rw-r--r--libhb/scan.c23
-rw-r--r--libhb/stream.c2
-rw-r--r--libhb/sync.c5
-rw-r--r--libhb/work.c77
18 files changed, 249 insertions, 127 deletions
diff --git a/libhb/batch.c b/libhb/batch.c
index 3aca6b00e..3a08152bb 100644
--- a/libhb/batch.c
+++ b/libhb/batch.c
@@ -127,7 +127,7 @@ hb_title_t * hb_batch_title_scan( hb_batch_t * d, int t )
return NULL;
hb_log( "batch: scanning %s", filename );
- title = hb_title_init( filename, 0 );
+ title = hb_title_init( filename, t );
stream = hb_stream_open( filename, title, 1 );
if ( stream == NULL )
{
@@ -137,10 +137,6 @@ hb_title_t * hb_batch_title_scan( hb_batch_t * d, int t )
title = hb_stream_title_scan( stream, title );
hb_stream_close( &stream );
- if ( title != NULL )
- {
- title->index = t;
- }
return title;
}
diff --git a/libhb/common.c b/libhb/common.c
index 78b4437c6..339c3919f 100644
--- a/libhb/common.c
+++ b/libhb/common.c
@@ -2582,7 +2582,7 @@ void hb_list_rem( hb_list_t * l, void * p )
*********************************************************************/
void * hb_list_item( const hb_list_t * l, int i )
{
- if( i < 0 || i >= l->items_count )
+ if( l == NULL || i < 0 || i >= l->items_count )
{
return NULL;
}
@@ -2712,6 +2712,9 @@ void hb_list_close( hb_list_t ** _l )
{
hb_list_t * l = *_l;
+ if (l == NULL)
+ return;
+
free( l->items );
free( l );
@@ -3048,7 +3051,7 @@ static void job_setup(hb_job_t * job, hb_title_t * title)
job->vquality = -1.0;
job->vbitrate = 1000;
job->twopass = 0;
- job->pass = 0;
+ job->pass_id = HB_PASS_ENCODE;
job->vrate = title->vrate;
job->mux = HB_MUX_MP4;
@@ -3078,6 +3081,8 @@ static void job_clean( hb_job_t * job )
hb_filter_object_t *filter;
hb_attachment_t *attachment;
+ free((void*)job->json);
+ job->json = NULL;
free(job->encoder_preset);
job->encoder_preset = NULL;
free(job->encoder_tune);
diff --git a/libhb/common.h b/libhb/common.h
index 41c5dd822..a8a699387 100644
--- a/libhb/common.h
+++ b/libhb/common.h
@@ -446,6 +446,8 @@ typedef enum
*****************************************************************************/
struct hb_job_s
{
+ PRIVATE const char * json; // JSON encoded job string
+
/* ID assigned by UI so it can groups job passes together */
int sequence_id;
@@ -494,7 +496,7 @@ struct hb_job_s
int vbitrate;
hb_rational_t vrate;
int cfr;
- PRIVATE int pass;
+ PRIVATE int pass_id;
int twopass; // Enable 2-pass encode. Boolean
int fastfirstpass;
char *encoder_preset;
@@ -605,7 +607,6 @@ struct hb_job_s
#ifdef __LIBHB__
/* Internal data */
hb_handle_t * h;
- hb_lock_t * pause;
volatile hb_error_code * done_error;
volatile int * die;
volatile int done;
@@ -993,9 +994,14 @@ struct hb_state_s
struct
{
/* HB_STATE_WORKING */
+#define HB_PASS_SUBTITLE -1
+#define HB_PASS_ENCODE 0
+#define HB_PASS_ENCODE_1ST 1 // Some code depends on these values being
+#define HB_PASS_ENCODE_2ND 2 // 1 and 2. Do not change.
+ int pass_id;
+ int pass;
+ int pass_count;
float progress;
- int job_cur;
- int job_count;
float rate_cur;
float rate_avg;
int hours;
diff --git a/libhb/encavcodec.c b/libhb/encavcodec.c
index b396f9c70..fe479a393 100644
--- a/libhb/encavcodec.c
+++ b/libhb/encavcodec.c
@@ -99,7 +99,7 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
// Set things in context that we will allow the user to
// override with advanced settings.
- if( job->pass == 2 )
+ if( job->pass_id == HB_PASS_ENCODE_2ND )
{
hb_interjob_t * interjob = hb_interjob_get( job->h );
fps.den = interjob->vrate.den;
@@ -237,12 +237,13 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
context->flags |= CODEC_FLAG_GRAY;
}
- if( job->pass != 0 && job->pass != -1 )
+ if( job->pass_id == HB_PASS_ENCODE_1ST ||
+ job->pass_id == HB_PASS_ENCODE_2ND )
{
char filename[1024]; memset( filename, 0, 1024 );
hb_get_tempory_filename( job->h, filename, "ffmpeg.log" );
- if( job->pass == 1 )
+ if( job->pass_id == HB_PASS_ENCODE_1ST )
{
pv->file = hb_fopen(filename, "wb");
context->flags |= CODEC_FLAG_PASS1;
@@ -287,7 +288,7 @@ int encavcodecInit( hb_work_object_t * w, hb_job_t * job )
{
job->areBframes = 1;
}
- if( ( job->mux & HB_MUX_MASK_MP4 ) && job->pass != 1 )
+ if( ( job->mux & HB_MUX_MASK_MP4 ) && job->pass_id != HB_PASS_ENCODE_1ST )
{
w->config->mpeg4.length = context->extradata_size;
memcpy( w->config->mpeg4.bytes, context->extradata,
@@ -589,7 +590,8 @@ int encavcodecWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
buf_last = buf;
}
/* Write stats */
- if (job->pass == 1 && pv->context->stats_out != NULL)
+ if (job->pass_id == HB_PASS_ENCODE_1ST &&
+ pv->context->stats_out != NULL)
{
fprintf( pv->file, "%s", pv->context->stats_out );
}
diff --git a/libhb/enctheora.c b/libhb/enctheora.c
index 8c9c4cffa..3b9dacebb 100644
--- a/libhb/enctheora.c
+++ b/libhb/enctheora.c
@@ -44,12 +44,13 @@ int enctheoraInit( hb_work_object_t * w, hb_job_t * job )
pv->job = job;
- if( job->pass != 0 && job->pass != -1 )
+ if( job->pass_id == HB_PASS_ENCODE_1ST ||
+ job->pass_id == HB_PASS_ENCODE_2ND )
{
char filename[1024];
memset( filename, 0, 1024 );
hb_get_tempory_filename( job->h, filename, "theroa.log" );
- if ( job->pass == 1 )
+ if ( job->pass_id == HB_PASS_ENCODE_1ST )
{
pv->file = hb_fopen(filename, "wb");
}
@@ -71,7 +72,7 @@ int enctheoraInit( hb_work_object_t * w, hb_job_t * job )
ti.frame_height = (job->height + 0xf) & ~0xf;
ti.pic_x = ti.pic_y = 0;
- if( job->pass == 2 )
+ if( job->pass_id == HB_PASS_ENCODE_2ND )
{
hb_interjob_t * interjob = hb_interjob_get( job->h );
ti.fps_numerator = interjob->vrate.num;
@@ -125,7 +126,8 @@ int enctheoraInit( hb_work_object_t * w, hb_job_t * job )
{
hb_log("theora: Could not set soft ratecontrol");
}
- if( job->pass != 0 && job->pass != -1 )
+ if( job->pass_id == HB_PASS_ENCODE_1ST ||
+ job->pass_id == HB_PASS_ENCODE_2ND )
{
arg = keyframe_frequency * 7 >> 1;
ret = th_encode_ctl(pv->ctx, TH_ENCCTL_SET_RATE_BUFFER, &arg, sizeof(arg));
@@ -135,7 +137,7 @@ int enctheoraInit( hb_work_object_t * w, hb_job_t * job )
}
}
- if( job->pass == 1 )
+ if( job->pass_id == HB_PASS_ENCODE_1ST )
{
unsigned char *buffer;
int bytes;
@@ -153,7 +155,7 @@ int enctheoraInit( hb_work_object_t * w, hb_job_t * job )
}
fflush( pv->file );
}
- if( job->pass == 2 )
+ if( job->pass_id == HB_PASS_ENCODE_2ND )
{
/* Enable the second pass here.
* We make this call just to set the encoder into 2-pass mode, because
@@ -233,7 +235,7 @@ int enctheoraWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
*buf_out = in;
*buf_in = NULL;
th_encode_packetout( pv->ctx, 1, &op );
- if( job->pass == 1 )
+ if( job->pass_id == HB_PASS_ENCODE_1ST )
{
unsigned char *buffer;
int bytes;
@@ -256,7 +258,7 @@ int enctheoraWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
return HB_WORK_DONE;
}
- if( job->pass == 2 )
+ if( job->pass_id == HB_PASS_ENCODE_2ND )
{
for(;;)
{
@@ -335,7 +337,7 @@ int enctheoraWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
th_encode_ycbcr_in( pv->ctx, ycbcr );
- if( job->pass == 1 )
+ if( job->pass_id == HB_PASS_ENCODE_1ST )
{
unsigned char *buffer;
int bytes;
diff --git a/libhb/encx264.c b/libhb/encx264.c
index 8b39ab0ba..780385d7b 100644
--- a/libhb/encx264.c
+++ b/libhb/encx264.c
@@ -123,7 +123,7 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job )
/* Some HandBrake-specific defaults; users can override them
* using the encoder_options string. */
- if( job->pass == 2 && job->cfr != 1 )
+ if( job->pass_id == HB_PASS_ENCODE_2ND && job->cfr != 1 )
{
hb_interjob_t * interjob = hb_interjob_get( job->h );
param.i_fps_num = interjob->vrate.num;
@@ -268,19 +268,20 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job )
param.rc.i_rc_method = X264_RC_ABR;
param.rc.i_bitrate = job->vbitrate;
hb_log( "encx264: encoding at average bitrate %d", param.rc.i_bitrate );
- if( job->pass > 0 && job->pass < 3 )
+ if( job->pass_id == HB_PASS_ENCODE_1ST ||
+ job->pass_id == HB_PASS_ENCODE_2ND )
{
memset( pv->filename, 0, 1024 );
hb_get_tempory_filename( job->h, pv->filename, "x264.log" );
}
- switch( job->pass )
+ switch( job->pass_id )
{
- case 1:
+ case HB_PASS_ENCODE_1ST:
param.rc.b_stat_read = 0;
param.rc.b_stat_write = 1;
param.rc.psz_stat_out = pv->filename;
break;
- case 2:
+ case HB_PASS_ENCODE_2ND:
param.rc.b_stat_read = 1;
param.rc.b_stat_write = 0;
param.rc.psz_stat_in = pv->filename;
@@ -310,7 +311,7 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job )
}
/* Turbo first pass */
- if( job->pass == 1 && job->fastfirstpass == 1 )
+ if( job->pass_id == HB_PASS_ENCODE_1ST && job->fastfirstpass == 1 )
{
x264_param_apply_fastfirstpass( &param );
}
@@ -341,7 +342,7 @@ int encx264Init( hb_work_object_t * w, hb_job_t * job )
}
free( x264_opts_unparsed );
- hb_deep_log( 2, "encx264: opening libx264 (pass %d)", job->pass );
+ hb_deep_log( 2, "encx264: opening libx264 (pass %d)", job->pass_id );
pv->x264 = x264_encoder_open( &param );
if ( pv->x264 == NULL )
{
diff --git a/libhb/encx265.c b/libhb/encx265.c
index d9b4be64e..324c07e5b 100644
--- a/libhb/encx265.c
+++ b/libhb/encx265.c
@@ -234,18 +234,19 @@ int encx265Init(hb_work_object_t *w, hb_job_t *job)
{
param->rc.rateControlMode = X265_RC_ABR;
param->rc.bitrate = job->vbitrate;
- if (job->pass > 0 && job->pass < 3)
+ if (job->pass_id == HB_PASS_ENCODE_1ST ||
+ job->pass_id == HB_PASS_ENCODE_2ND)
{
char stats_file[1024] = "";
char pass[2];
- snprintf(pass, sizeof(pass), "%d", job->pass);
+ snprintf(pass, sizeof(pass), "%d", job->pass_id);
hb_get_tempory_filename(job->h, stats_file, "x265.log");
if (param_parse(param, "stats", stats_file) ||
param_parse(param, "pass", pass))
{
goto fail;
}
- if (job->pass == 1 && job->fastfirstpass == 0 &&
+ if (job->pass_id == HB_PASS_ENCODE_1ST && job->fastfirstpass == 0 &&
param_parse(param, "slow-firstpass", "1"))
{
goto fail;
diff --git a/libhb/hb.c b/libhb/hb.c
index 9514de3ee..84347d768 100644
--- a/libhb/hb.c
+++ b/libhb/hb.c
@@ -48,8 +48,6 @@ struct hb_handle_s
from this one (see work.c) */
hb_list_t * jobs;
hb_job_t * current_job;
- int job_count;
- int job_count_permanent;
volatile int work_die;
hb_error_code work_error;
hb_thread_t * work_thread;
@@ -1255,7 +1253,7 @@ hb_job_t * hb_current_job( hb_handle_t * h )
* @param h Handle to hb_handle_t.
* @param job Handle to hb_job_t.
*/
-static void hb_add_internal( hb_handle_t * h, hb_job_t * job )
+static void hb_add_internal( hb_handle_t * h, hb_job_t * job, hb_list_t *list_pass )
{
hb_job_t * job_copy;
hb_audio_t * audio;
@@ -1336,21 +1334,64 @@ static void hb_add_internal( hb_handle_t * h, hb_job_t * job )
job_copy->file = strdup(job->file);
job_copy->h = h;
- job_copy->pause = h->pause_lock;
/* Copy the job filter list */
job_copy->list_filter = hb_filter_list_copy( job->list_filter );
/* Add the job to the list */
- hb_list_add( h->jobs, job_copy );
- h->job_count = hb_count(h);
- h->job_count_permanent++;
+ hb_list_add( list_pass, job_copy );
+}
+
+hb_job_t* hb_job_copy(hb_job_t * job)
+{
+ hb_job_t * job_copy;
+
+ /* Copy the job */
+ job_copy = calloc( sizeof( hb_job_t ), 1 );
+ if (job_copy == NULL)
+ return NULL;
+
+ if (job->json != NULL)
+ {
+ // JSON jobs should only have the json string set.
+ job_copy->json = strdup(job->json);
+ return job_copy;
+ }
+ memcpy( job_copy, job, sizeof( hb_job_t ) );
+
+ job_copy->list_subtitle = hb_subtitle_list_copy( job->list_subtitle );
+ job_copy->list_chapter = hb_chapter_list_copy( job->list_chapter );
+ job_copy->list_audio = hb_audio_list_copy( job->list_audio );
+ job_copy->list_attachment = hb_attachment_list_copy( job->list_attachment );
+ job_copy->metadata = hb_metadata_copy( job->metadata );
+
+ if (job->encoder_preset != NULL)
+ job_copy->encoder_preset = strdup(job->encoder_preset);
+ if (job->encoder_tune != NULL)
+ job_copy->encoder_tune = strdup(job->encoder_tune);
+ if (job->encoder_options != NULL)
+ job_copy->encoder_options = strdup(job->encoder_options);
+ if (job->encoder_profile != NULL)
+ job_copy->encoder_profile = strdup(job->encoder_profile);
+ if (job->encoder_level != NULL)
+ job_copy->encoder_level = strdup(job->encoder_level);
+ if (job->file != NULL)
+ job_copy->file = strdup(job->file);
+
+ job_copy->list_filter = hb_filter_list_copy( job->list_filter );
+
+ return job_copy;
}
void hb_add( hb_handle_t * h, hb_job_t * job )
{
- int sub_id = 0;
+ hb_job_t *job_copy = hb_job_copy(job);
+ job_copy->h = h;
+ hb_list_add(h->jobs, job_copy);
+}
+void hb_job_setup_passes(hb_handle_t * h, hb_job_t * job, hb_list_t * list_pass)
+{
if (job->vquality >= 0)
{
job->twopass = 0;
@@ -1358,26 +1399,22 @@ void hb_add( hb_handle_t * h, hb_job_t * job )
if (job->indepth_scan)
{
hb_deep_log(2, "Adding subtitle scan pass");
- job->pass = -1;
- job->sequence_id = (job->sequence_id & 0xFFFFFF) | (sub_id++ << 24);
- hb_add_internal(h, job);
+ job->pass_id = HB_PASS_SUBTITLE;
+ hb_add_internal(h, job, list_pass);
job->indepth_scan = 0;
}
if (job->twopass)
{
hb_deep_log(2, "Adding two-pass encode");
- job->pass = 1;
- job->sequence_id = (job->sequence_id & 0xFFFFFF) | (sub_id++ << 24);
- hb_add_internal(h, job);
- job->pass = 2;
- job->sequence_id = (job->sequence_id & 0xFFFFFF) | (sub_id++ << 24);
- hb_add_internal(h, job);
+ job->pass_id = HB_PASS_ENCODE_1ST;
+ hb_add_internal(h, job, list_pass);
+ job->pass_id = HB_PASS_ENCODE_2ND;
+ hb_add_internal(h, job, list_pass);
}
else
{
- job->pass = 0;
- job->sequence_id = (job->sequence_id & 0xFFFFFF) | (sub_id++ << 24);
- hb_add_internal(h, job);
+ job->pass_id = HB_PASS_ENCODE;
+ hb_add_internal(h, job, list_pass);
}
}
@@ -1389,12 +1426,6 @@ void hb_add( hb_handle_t * h, hb_job_t * job )
void hb_rem( hb_handle_t * h, hb_job_t * job )
{
hb_list_rem( h->jobs, job );
-
- h->job_count = hb_count(h);
- if (h->job_count_permanent)
- h->job_count_permanent--;
-
- /* XXX free everything XXX */
}
/**
@@ -1405,16 +1436,10 @@ void hb_rem( hb_handle_t * h, hb_job_t * job )
*/
void hb_start( hb_handle_t * h )
{
- /* XXX Hack */
- h->job_count = hb_list_count( h->jobs );
- h->job_count_permanent = h->job_count;
-
hb_lock( h->state_lock );
h->state.state = HB_STATE_WORKING;
#define p h->state.param.working
p.progress = 0.0;
- p.job_cur = 1;
- p.job_count = h->job_count;
p.rate_cur = 0.0;
p.rate_avg = 0.0;
p.hours = -1;
@@ -1477,10 +1502,6 @@ void hb_resume( hb_handle_t * h )
void hb_stop( hb_handle_t * h )
{
h->work_die = 1;
-
- h->job_count = hb_count(h);
- h->job_count_permanent = 0;
-
hb_resume( h );
}
@@ -1491,10 +1512,6 @@ void hb_stop( hb_handle_t * h )
void hb_scan_stop( hb_handle_t * h )
{
h->scan_die = 1;
-
- h->job_count = hb_count(h);
- h->job_count_permanent = 0;
-
hb_resume( h );
}
@@ -1735,9 +1752,6 @@ static void thread_func( void * _h )
h->state.state = HB_STATE_WORKDONE;
h->state.param.workdone.error = h->work_error;
- h->job_count = hb_count(h);
- if (h->job_count < 1)
- h->job_count_permanent = 0;
hb_unlock( h->state_lock );
}
@@ -1813,14 +1827,6 @@ void hb_set_state( hb_handle_t * h, hb_state_t * s )
if( h->state.state == HB_STATE_WORKING ||
h->state.state == HB_STATE_SEARCHING )
{
- /* XXX Hack */
- if (h->job_count < 1)
- h->job_count_permanent = 1;
-
- 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 & 0xFFFFFF;
diff --git a/libhb/hb_json.c b/libhb/hb_json.c
index f374dbb50..f4b1bb814 100644
--- a/libhb/hb_json.c
+++ b/libhb/hb_json.c
@@ -42,12 +42,13 @@ static json_t* hb_state_to_dict( hb_state_t * state)
case HB_STATE_PAUSED:
case HB_STATE_SEARCHING:
dict = json_pack_ex(&error, 0,
- "{s:o, s{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}}",
+ "{s:o, s{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}}",
"State", json_integer(state->state),
"Working",
"Progress", json_real(state->param.working.progress),
- "Job", json_integer(state->param.working.job_cur),
- "JobCount", json_integer(state->param.working.job_count),
+ "PassID", json_integer(state->param.working.pass_id),
+ "Pass", json_integer(state->param.working.pass),
+ "PassCount", json_integer(state->param.working.pass_count),
"Rate", json_real(state->param.working.rate_cur),
"RateAvg", json_real(state->param.working.rate_avg),
"Hours", json_integer(state->param.working.hours),
@@ -217,6 +218,11 @@ static json_t* hb_title_to_dict( const hb_title_t * title )
json_object_set_new(meta_dict, "LongDescription",
json_string(title->metadata->long_description));
}
+ if (title->metadata->release_date != NULL)
+ {
+ json_object_set_new(meta_dict, "ReleaseDate",
+ json_string(title->metadata->release_date));
+ }
// process chapter list
json_t * chapter_list = json_array();
@@ -554,6 +560,11 @@ char* hb_job_to_json( const hb_job_t * job )
json_object_set_new(meta_dict, "LongDescription",
json_string(job->metadata->long_description));
}
+ if (job->metadata->release_date != NULL)
+ {
+ json_object_set_new(meta_dict, "ReleaseDate",
+ json_string(job->metadata->release_date));
+ }
// process chapter list
json_t *chapter_list = json_object_get(dest_dict, "ChapterList");
@@ -641,8 +652,7 @@ char* hb_job_to_json( const hb_job_t * job )
else
{
subtitle_dict = json_pack_ex(&error, 0,
- "{s:o, s:o, s:o, s:o, s:o, s:o}",
- "ID", json_integer(subtitle->id),
+ "{s:o, s:o, s:o, s:o, s:o}",
"Track", json_integer(subtitle->track),
"Default", json_boolean(subtitle->config.default_track),
"Force", json_boolean(subtitle->config.force),
@@ -667,6 +677,40 @@ static int * unpack_b(int *b) { return b; }
static char** unpack_s(char **s) { return s; }
static json_t** unpack_o(json_t** o) { return o; }
+void hb_json_job_scan( hb_handle_t * h, const char * json_job )
+{
+ json_t * dict;
+ int result;
+ json_error_t error;
+
+ dict = json_loads(json_job, 0, NULL);
+
+ int title_index;
+ char *path = NULL;
+
+ result = json_unpack_ex(dict, &error, 0, "{s:{s:s, s:i}}",
+ "Source",
+ "Path", unpack_s(&path),
+ "Title", unpack_i(&title_index));
+ if (result < 0)
+ {
+ hb_error("json unpack failure, failed to find title: %s", error.text);
+ return;
+ }
+
+ hb_scan(h, path, title_index, 10, 0, 0);
+
+ // Wait for scan to complete
+ hb_state_t state;
+ do
+ {
+ hb_snooze(50);
+ hb_get_state2(h, &state);
+ } while (state.state == HB_STATE_SCANNING);
+
+ json_decref(dict);
+}
+
/**
* Convert a json string representation of a job to an hb_job_t
* @param h - Pointer to the hb_hanle_t hb instance which contains the
@@ -1084,12 +1128,10 @@ char* hb_job_init_json(hb_handle_t *h, int title_index)
*/
int hb_add_json( hb_handle_t * h, const char * json_job )
{
- hb_job_t *job = hb_json_to_job(h, json_job);
- if (job == NULL)
- return -1;
+ hb_job_t job;
- hb_add(h, job);
- hb_job_close(&job);
+ job.json = json_job;
+ hb_add(h, &job);
return 0;
}
diff --git a/libhb/hb_json.h b/libhb/hb_json.h
index fcd1683ce..b5025a6c2 100644
--- a/libhb/hb_json.h
+++ b/libhb/hb_json.h
@@ -28,6 +28,7 @@ hb_image_t * hb_json_to_image(char *json_image);
char * hb_get_preview_params_json(int title_idx, int preview_idx,
int deinterlace, hb_geometry_settings_t *settings);
char * hb_get_preview_json(hb_handle_t * h, const char *json_param);
+void hb_json_job_scan( hb_handle_t * h, const char * json_job );
#ifdef __cplusplus
}
diff --git a/libhb/internal.h b/libhb/internal.h
index 13d12be29..759f1beb8 100644
--- a/libhb/internal.h
+++ b/libhb/internal.h
@@ -40,6 +40,7 @@ void hb_title_close( hb_title_t ** );
**********************************************************************/
int hb_get_pid( hb_handle_t * );
void hb_set_state( hb_handle_t *, hb_state_t * );
+void hb_job_setup_passes(hb_handle_t *h, hb_job_t *job, hb_list_t *list_pass);
/***********************************************************************
* fifo.c
diff --git a/libhb/muxavformat.c b/libhb/muxavformat.c
index 44993c27c..fb6326d1d 100644
--- a/libhb/muxavformat.c
+++ b/libhb/muxavformat.c
@@ -352,7 +352,7 @@ static int avformatInit( hb_mux_object_t * m )
track->st->disposition |= AV_DISPOSITION_DEFAULT;
hb_rational_t vrate;
- if( job->pass == 2 )
+ if( job->pass_id == HB_PASS_ENCODE_2ND )
{
hb_interjob_t * interjob = hb_interjob_get( job->h );
vrate = interjob->vrate;
diff --git a/libhb/muxcommon.c b/libhb/muxcommon.c
index c66bf0012..ca9502e4c 100644
--- a/libhb/muxcommon.c
+++ b/libhb/muxcommon.c
@@ -373,7 +373,8 @@ static int muxWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
hb_bitvec_set(mux->eof, pv->track);
hb_bitvec_set(mux->rdy, pv->track);
}
- else if ((job->pass != 0 && job->pass != 2) ||
+ else if ((job->pass_id != HB_PASS_ENCODE &&
+ job->pass_id != HB_PASS_ENCODE_2ND) ||
hb_bitvec_bit(mux->eof, pv->track))
{
hb_buffer_close( &buf );
@@ -471,7 +472,8 @@ void muxClose( hb_work_object_t * w )
// may initiate optimization which can take a while and
// we want the muxing state to be visible while this is
// happening.
- if( job->pass == 0 || job->pass == 2 )
+ if( job->pass_id == HB_PASS_ENCODE ||
+ job->pass_id == HB_PASS_ENCODE_2ND )
{
/* Update the UI */
hb_state_t state;
@@ -487,7 +489,8 @@ void muxClose( hb_work_object_t * w )
}
// we're all done muxing -- print final stats and cleanup.
- if( job->pass == 0 || job->pass == 2 )
+ if( job->pass_id == HB_PASS_ENCODE ||
+ job->pass_id == HB_PASS_ENCODE_2ND )
{
hb_stat_t sb;
uint64_t bytes_total, frames_total;
@@ -612,7 +615,7 @@ hb_work_object_t * hb_muxer_init( hb_job_t * job )
mux->pts = mux->interleave;
/* Get a real muxer */
- if( job->pass == 0 || job->pass == 2)
+ if( job->pass_id == HB_PASS_ENCODE || job->pass_id == HB_PASS_ENCODE_2ND )
{
switch( job->mux )
{
diff --git a/libhb/reader.c b/libhb/reader.c
index 80e967959..530196e48 100644
--- a/libhb/reader.c
+++ b/libhb/reader.c
@@ -751,6 +751,7 @@ static void UpdateState( hb_work_private_t * r, int64_t start)
r->st_first = now;
}
+ hb_get_state2(r->job->h, &state);
#define p state.param.working
if ( !r->job->indepth_scan )
{
diff --git a/libhb/scan.c b/libhb/scan.c
index 55c9bfc90..32a5c60bb 100644
--- a/libhb/scan.c
+++ b/libhb/scan.c
@@ -74,7 +74,19 @@ hb_thread_t * hb_scan_init( hb_handle_t * handle, volatile int * die,
data->preview_count = preview_count;
data->store_previews = store_previews;
data->min_title_duration = min_duration;
-
+
+ // Initialize scan state
+ hb_state_t state;
+#define p state.param.scanning
+ state.state = HB_STATE_SCANNING;
+ p.title_cur = 1;
+ p.title_count = 1;
+ p.preview_cur = 0;
+ p.preview_count = 1;
+ p.progress = 0.0;
+#undef p
+ hb_set_state(handle, &state);
+
return hb_thread_init( "scan", ScanFunc, data, HB_NORMAL_PRIORITY );
}
@@ -169,7 +181,14 @@ static void ScanFunc( void * _data )
}
else
{
- data->title_index = 1;
+ // Title index 0 is not a valid title number and means scan all titles.
+ // So set title index to 1 in this scenario.
+ //
+ // Otherwise, set title index in new title to the index that was
+ // requested. This preserves the original index created in batch
+ // mode.
+ if (data->title_index == 0)
+ data->title_index = 1;
hb_title_t * title = hb_title_init( data->path, data->title_index );
if ( (data->stream = hb_stream_open( data->path, title, 1 ) ) != NULL )
{
diff --git a/libhb/stream.c b/libhb/stream.c
index 81d8da2fc..9d01c1d00 100644
--- a/libhb/stream.c
+++ b/libhb/stream.c
@@ -1039,7 +1039,6 @@ hb_title_t * hb_stream_title_scan(hb_stream_t *stream, hb_title_t * title)
// 'Barebones Title'
title->type = HB_STREAM_TYPE;
- title->index = 1;
// Copy part of the stream path to the title name
char *sep = hb_strr_dir_sep(stream->path);
@@ -5428,7 +5427,6 @@ static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream, hb_title_t *title )
// 'Barebones Title'
title->type = HB_FF_STREAM_TYPE;
- title->index = 1;
// Copy part of the stream path to the title name
char *sep = hb_strr_dir_sep(stream->path);
diff --git a/libhb/sync.c b/libhb/sync.c
index 21fe8c2ae..ac826584e 100644
--- a/libhb/sync.c
+++ b/libhb/sync.c
@@ -155,7 +155,7 @@ hb_work_object_t * hb_sync_init( hb_job_t * job )
pv->common->pts_offset = INT64_MIN;
sync->first_frame = 1;
- if( job->pass == 2 )
+ if( job->pass_id == HB_PASS_ENCODE_2ND )
{
/* We already have an accurate frame count from pass 1 */
hb_interjob_t * interjob = hb_interjob_get( job->h );
@@ -263,7 +263,7 @@ void syncVideoClose( hb_work_object_t * w )
pv->common->count_frames, sync->count_frames_max );
/* save data for second pass */
- if( job->pass == 1 )
+ if( job->pass_id == HB_PASS_ENCODE_1ST )
{
/* Preserve frame count for better accuracy in pass 2 */
hb_interjob_t * interjob = hb_interjob_get( job->h );
@@ -1638,6 +1638,7 @@ static void UpdateState( hb_work_object_t * w )
hb_sync_video_t * sync = &pv->type.video;
hb_state_t state;
+ hb_get_state2( pv->job->h, &state );
if( !pv->common->count_frames )
{
sync->st_first = hb_get_date();
diff --git a/libhb/work.c b/libhb/work.c
index 4792c42b3..01060c01f 100644
--- a/libhb/work.c
+++ b/libhb/work.c
@@ -58,18 +58,21 @@ hb_thread_t * hb_work_init( hb_list_t * jobs, volatile int * die, hb_error_code
return hb_thread_init( "work", work_func, work, HB_LOW_PRIORITY );
}
-static void InitWorkState( hb_handle_t * h )
+static void InitWorkState(hb_handle_t *h, int pass_id, int pass, int pass_count)
{
hb_state_t state;
- state.state = HB_STATE_WORKING;
+ state.state = HB_STATE_WORKING;
#define p state.param.working
- p.progress = 0.0;
- p.rate_cur = 0.0;
- p.rate_avg = 0.0;
- p.hours = -1;
- p.minutes = -1;
- p.seconds = -1;
+ p.pass_id = pass_id;
+ p.pass = pass;
+ p.pass_count = pass_count;
+ p.progress = 0.0;
+ p.rate_cur = 0.0;
+ p.rate_avg = 0.0;
+ p.hours = -1;
+ p.minutes = -1;
+ p.seconds = -1;
#undef p
hb_set_state( h, &state );
@@ -90,12 +93,45 @@ static void work_func( void * _work )
while( !*work->die && ( job = hb_list_item( work->jobs, 0 ) ) )
{
hb_list_rem( work->jobs, job );
- job->die = work->die;
- job->done_error = work->error;
- *(work->current_job) = job;
- InitWorkState( job->h );
- do_job( job );
- *(work->current_job) = NULL;
+ hb_list_t * passes = hb_list_init();
+
+ // JSON jobs get special treatment. We want to perform the title
+ // scan for the JSON job automatically. This requires that we delay
+ // filling the job struct till we have performed the title scan
+ // because the default values for the job come from the title.
+ if (job->json != NULL)
+ {
+ // Perform title scan for json job
+ hb_json_job_scan(job->h, job->json);
+
+ // Expand json string to full job struct
+ hb_job_t *new_job = hb_json_to_job(job->h, job->json);
+ new_job->h = job->h;
+ hb_job_close(&job);
+ job = new_job;
+ }
+ hb_job_setup_passes(job->h, job, passes);
+ hb_job_close(&job);
+
+ int pass_count, pass;
+ pass_count = hb_list_count(passes);
+ for (pass = 0; pass < pass_count && !*work->die; pass++)
+ {
+ job = hb_list_item(passes, pass);
+ job->die = work->die;
+ job->done_error = work->error;
+ *(work->current_job) = job;
+ InitWorkState(job->h, job->pass_id, pass + 1, pass_count);
+ do_job( job );
+ *(work->current_job) = NULL;
+ }
+ // Clean up any incomplete jobs
+ for (; pass < pass_count; pass++)
+ {
+ job = hb_list_item(passes, pass);
+ hb_job_close(&job);
+ }
+ hb_list_close(&passes);
}
free( work );
@@ -346,8 +382,8 @@ void hb_display_job_info(hb_job_t *job)
}
else
{
- hb_log( " + bitrate: %d kbps, pass: %d", job->vbitrate, job->pass );
- if(job->pass == 1 && job->fastfirstpass == 1 &&
+ hb_log( " + bitrate: %d kbps, pass: %d", job->vbitrate, job->pass_id );
+ if(job->pass_id == HB_PASS_ENCODE_1ST && job->fastfirstpass == 1 &&
(job->vcodec == HB_VCODEC_X264 || job->vcodec == HB_VCODEC_X265))
{
hb_log( " + fast first pass" );
@@ -538,7 +574,7 @@ static void do_job(hb_job_t *job)
title = job->title;
interjob = hb_interjob_get( job->h );
- if( job->pass == 2 )
+ if( job->pass_id == HB_PASS_ENCODE_2ND )
{
correct_framerate( job );
}
@@ -606,7 +642,8 @@ static void do_job(hb_job_t *job)
* first burned subtitle (explicitly or after sanitizing) - which should
* ensure that it doesn't get dropped. */
interjob->select_subtitle->out_track = 1;
- if (job->pass == 0 || job->pass == 2)
+ if (job->pass_id == HB_PASS_ENCODE ||
+ job->pass_id == HB_PASS_ENCODE_2ND)
{
// final pass, interjob->select_subtitle is no longer needed
hb_list_insert(job->list_subtitle, 0, interjob->select_subtitle);
@@ -1463,8 +1500,8 @@ static void do_job(hb_job_t *job)
hb_handle_t * h = job->h;
hb_state_t state;
- hb_get_state( h, &state );
-
+ hb_get_state2( h, &state );
+
hb_log("work: average encoding speed for job is %f fps", state.param.working.rate_avg);
job->done = 1;