1 /* hb.c
2
3 Copyright (c) 2003-2021 HandBrake Team
4 This file is part of the HandBrake source code
5 Homepage: <http://handbrake.fr/>.
6 It may be used under the terms of the GNU General Public License v2.
7 For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
8 */
9
10 #include "handbrake/handbrake.h"
11 #include "handbrake/hbffmpeg.h"
12 #include "handbrake/hbavfilter.h"
13 #include "handbrake/encx264.h"
14 #include "libavfilter/avfilter.h"
15 #include <stdio.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <turbojpeg.h>
19
20 #if HB_PROJECT_FEATURE_QSV
21 #include "handbrake/qsv_common.h"
22 #endif
23
24 #if defined( SYS_MINGW )
25 #include <io.h>
26 #if defined(PTW32_VERSION)
27 #include <pthread.h>
28 #endif
29 #endif
30
31 struct hb_handle_s
32 {
33 int id;
34
35 /* This thread's only purpose is to check other threads'
36 states */
37 volatile int die;
38 hb_thread_t * main_thread;
39 int pid;
40
41 /* DVD/file scan thread */
42 hb_title_set_t title_set;
43 hb_thread_t * scan_thread;
44
45 /* The thread which processes the jobs. Others threads are launched
46 from this one (see work.c) */
47 int sequence_id;
48 hb_list_t * jobs;
49 hb_job_t * current_job;
50 volatile int work_die;
51 hb_error_code work_error;
52 hb_thread_t * work_thread;
53
54 hb_lock_t * state_lock;
55 hb_state_t state;
56
57 int paused;
58 hb_lock_t * pause_lock;
59 int64_t pause_date;
60 int64_t pause_duration;
61
62 volatile int scan_die;
63
64 /* Stash of persistent data between jobs, for stuff
65 like correcting frame count and framerate estimates
66 on multi-pass encodes where frames get dropped. */
67 hb_interjob_t * interjob;
68
69 // power management opaque pointer
70 void * system_sleep_opaque;
71 };
72
73 hb_work_object_t * hb_objects = NULL;
74 int hb_instance_counter = 0;
75 int disable_hardware = 0;
76
77 static void thread_func( void * );
78
hb_avcodec_init()79 void hb_avcodec_init()
80 {
81 }
82
hb_avcodec_open(AVCodecContext * avctx,AVCodec * codec,AVDictionary ** av_opts,int thread_count)83 int hb_avcodec_open(AVCodecContext *avctx, AVCodec *codec,
84 AVDictionary **av_opts, int thread_count)
85 {
86 int ret;
87
88 if ((thread_count == HB_FFMPEG_THREADS_AUTO || thread_count > 0) &&
89 (codec->type == AVMEDIA_TYPE_VIDEO))
90 {
91 avctx->thread_count = (thread_count == HB_FFMPEG_THREADS_AUTO) ?
92 hb_get_cpu_count() / 2 + 1 : thread_count;
93 avctx->thread_type = FF_THREAD_FRAME|FF_THREAD_SLICE;
94 }
95 else
96 {
97 avctx->thread_count = 1;
98 }
99
100 if (codec->capabilities & AV_CODEC_CAP_EXPERIMENTAL)
101 {
102 // "experimental" encoders will not open without this
103 avctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
104 }
105
106 ret = avcodec_open2(avctx, codec, av_opts);
107 return ret;
108 }
109
hb_avcodec_free_context(AVCodecContext ** avctx)110 void hb_avcodec_free_context(AVCodecContext **avctx)
111 {
112 avcodec_free_context(avctx);
113 }
114
115
hb_picture_fill(uint8_t * data[],int stride[],hb_buffer_t * buf)116 int hb_picture_fill(uint8_t *data[], int stride[], hb_buffer_t *buf)
117 {
118 int ret, ii;
119
120 for (ii = 0; ii <= buf->f.max_plane; ii++)
121 stride[ii] = buf->plane[ii].stride;
122 for (; ii < 4; ii++)
123 stride[ii] = stride[ii - 1];
124
125 ret = av_image_fill_pointers(data, buf->f.fmt,
126 buf->plane[0].height_stride,
127 buf->data, stride);
128 if (ret != buf->size)
129 {
130 hb_error("Internal error hb_picture_fill expected %d, got %d",
131 buf->size, ret);
132 }
133 return ret;
134 }
135
hb_picture_crop(uint8_t * data[],int stride[],hb_buffer_t * buf,int top,int left)136 int hb_picture_crop(uint8_t *data[], int stride[], hb_buffer_t *buf,
137 int top, int left)
138 {
139 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(buf->f.fmt);
140 int x_shift, y_shift;
141
142 if (desc == NULL)
143 return -1;
144
145 x_shift = desc->log2_chroma_w;
146 y_shift = desc->log2_chroma_h;
147
148 data[0] = buf->plane[0].data + top * buf->plane[0].stride + left;
149 data[1] = buf->plane[1].data + (top >> y_shift) * buf->plane[1].stride +
150 (left >> x_shift);
151 data[2] = buf->plane[2].data + (top >> y_shift) * buf->plane[2].stride +
152 (left >> x_shift);
153 data[3] = NULL;
154
155 stride[0] = buf->plane[0].stride;
156 stride[1] = buf->plane[1].stride;
157 stride[2] = buf->plane[2].stride;
158 stride[3] = 0;
159
160 return 0;
161 }
162
163 /**
164 * Registers work objects, by adding the work object to a liked list.
165 * @param w Handle to hb_work_object_t to register.
166 */
hb_register(hb_work_object_t * w)167 void hb_register( hb_work_object_t * w )
168 {
169 w->next = hb_objects;
170 hb_objects = w;
171 }
172
173 void (*hb_log_callback)(const char* message);
174 static void redirect_thread_func(void *);
175
176 #if defined( SYS_MINGW )
177 #define pipe(phandles) _pipe (phandles, 4096, _O_BINARY)
178 #endif
179
180 /**
181 * Registers the given function as a logger. All logs will be passed to it.
182 * @param log_cb The function to register as a logger.
183 */
hb_register_logger(void (* log_cb)(const char * message))184 void hb_register_logger( void (*log_cb)(const char* message) )
185 {
186 hb_log_callback = log_cb;
187 hb_thread_init("ioredirect", redirect_thread_func, NULL, HB_NORMAL_PRIORITY);
188 }
189
hb_log_level_set(hb_handle_t * h,int level)190 void hb_log_level_set(hb_handle_t *h, int level)
191 {
192 global_verbosity_level = level;
193 }
194
195 /**
196 * libhb initialization routine.
197 * @param verbose HB_DEBUG_NONE or HB_DEBUG_ALL.
198 * @return Handle to hb_handle_t for use on all subsequent calls to libhb.
199 */
hb_init(int verbose)200 hb_handle_t * hb_init( int verbose )
201 {
202 hb_handle_t * h = calloc( sizeof( hb_handle_t ), 1 );
203
204 /* See hb_deep_log() and hb_log() in common.c */
205 hb_log_level_set(h, verbose);
206
207 h->id = hb_instance_counter++;
208
209 /* Initialize opaque for PowerManagement purposes */
210 h->system_sleep_opaque = hb_system_sleep_opaque_init();
211
212 h->title_set.list_title = hb_list_init();
213 h->jobs = hb_list_init();
214
215 h->state_lock = hb_lock_init();
216 h->state.state = HB_STATE_IDLE;
217
218 h->pause_lock = hb_lock_init();
219 h->pause_date = -1;
220
221 h->interjob = calloc( sizeof( hb_interjob_t ), 1 );
222
223 /* Start library thread */
224 hb_log( "hb_init: starting libhb thread" );
225 h->die = 0;
226 h->main_thread = hb_thread_init( "libhb", thread_func, h,
227 HB_NORMAL_PRIORITY );
228
229 return h;
230 }
231
232 // Make sure these strings at least exist in the executable even though
233 // they may not all be visible in the frontend.
234 static const char* hb_title = HB_PROJECT_TITLE;
235 static const char* hb_name = HB_PROJECT_NAME;
236 static const char* hb_website = HB_PROJECT_URL_WEBSITE;
237 static const char* hb_community = HB_PROJECT_URL_COMMUNITY;
238 static const char* hb_irc = HB_PROJECT_URL_IRC;
239 static const char* hb_version = HB_PROJECT_VERSION;
240 static const int hb_build = HB_PROJECT_BUILD;
241 static const char* hb_repo_url = HB_PROJECT_REPO_URL;
242 static const char* hb_repo_tag = HB_PROJECT_REPO_TAG;
243 static const int hb_repo_rev = HB_PROJECT_REPO_REV;
244 static const char* hb_repo_hash = HB_PROJECT_REPO_HASH;
245 static const char* hb_repo_branch = HB_PROJECT_REPO_BRANCH;
246 static const char* hb_repo_remote = HB_PROJECT_REPO_REMOTE;
247 static const char* hb_repo_type = HB_PROJECT_REPO_TYPE;
248
hb_get_full_description()249 const char * hb_get_full_description()
250 {
251 static char * desc = NULL;
252 if (desc == NULL)
253 {
254 desc = hb_strdup_printf("%s\n"
255 "\tWebsite: %s\n"
256 "\tForum: %s\n"
257 "\tIRC: %s\n"
258 "\tBuild Type: %s\n"
259 "\tRepository: %s\n"
260 "\tRelease Tag: %s\n"
261 "\tRevision: %d\n"
262 "\tCommit Hash: %s\n"
263 "\tBranch: %s\n"
264 "\tRemote: %s",
265 hb_title, hb_website, hb_community, hb_irc,
266 hb_repo_type, hb_repo_url, hb_repo_tag, hb_repo_rev,
267 hb_repo_hash, hb_repo_branch, hb_repo_remote);
268 }
269 return desc;
270 }
271
272 /**
273 * Returns current version of libhb.
274 * @param h Handle to hb_handle_t.
275 * @return character array of version number.
276 */
hb_get_version(hb_handle_t * h)277 const char * hb_get_version( hb_handle_t * h )
278 {
279 // Silence compiler warnings for unused variables
280 ((void)(hb_title));
281 ((void)(hb_name));
282 ((void)(hb_website));
283 ((void)(hb_community));
284 ((void)(hb_irc));
285 ((void)(hb_version));
286 ((void)(hb_repo_url));
287 ((void)(hb_repo_tag));
288 ((void)(hb_repo_rev));
289 ((void)(hb_repo_hash));
290 ((void)(hb_repo_branch));
291 ((void)(hb_repo_remote));
292 ((void)(hb_repo_type));
293 return hb_version;
294 }
295
296 /**
297 * Returns current build of libhb.
298 * @param h Handle to hb_handle_t.
299 * @return character array of build number.
300 */
hb_get_build(hb_handle_t * h)301 int hb_get_build( hb_handle_t * h )
302 {
303 return hb_build;
304 }
305
306 /**
307 * Deletes current previews associated with titles
308 * @param h Handle to hb_handle_t
309 */
hb_remove_previews(hb_handle_t * h)310 void hb_remove_previews( hb_handle_t * h )
311 {
312 char * filename;
313 char * dirname;
314 hb_title_t * title;
315 int i, count, len;
316 DIR * dir;
317 struct dirent * entry;
318
319 dirname = hb_get_temporary_directory();
320 dir = opendir( dirname );
321 if (dir == NULL)
322 {
323 free(dirname);
324 return;
325 }
326
327 count = hb_list_count( h->title_set.list_title );
328 while( ( entry = readdir( dir ) ) )
329 {
330 if( entry->d_name[0] == '.' )
331 {
332 continue;
333 }
334 for( i = 0; i < count; i++ )
335 {
336 title = hb_list_item( h->title_set.list_title, i );
337 filename = hb_strdup_printf("%d_%d", h->id, title->index);
338 len = snprintf( filename, 1024, "%d_%d", h->id, title->index );
339 if (strncmp(entry->d_name, filename, len) == 0)
340 {
341 free(filename);
342 filename = hb_strdup_printf("%s/%s", dirname, entry->d_name);
343 int ulerr = unlink( filename );
344 if (ulerr < 0) {
345 hb_log("Unable to remove preview: %i - %s", ulerr, filename);
346 }
347 free(filename);
348 break;
349 }
350 free(filename);
351 }
352 }
353 free(dirname);
354 closedir( dir );
355 }
356
357 /**
358 * Initializes a scan of the by calling hb_scan_init
359 * @param h Handle to hb_handle_t
360 * @param path location of VIDEO_TS folder.
361 * @param title_index Desired title to scan. 0 for all titles.
362 * @param preview_count Number of preview images to generate.
363 * @param store_previews Whether or not to write previews to disk.
364 */
hb_scan(hb_handle_t * h,const char * path,int title_index,int preview_count,int store_previews,uint64_t min_duration)365 void hb_scan( hb_handle_t * h, const char * path, int title_index,
366 int preview_count, int store_previews, uint64_t min_duration )
367 {
368 hb_title_t * title;
369
370 // Check if scanning is necessary.
371 if (h->title_set.path != NULL && !strcmp(h->title_set.path, path))
372 {
373 // Current title_set path matches requested path.
374 // Check if the requested title has already been scanned.
375 int ii;
376 for (ii = 0; ii < hb_list_count(h->title_set.list_title); ii++)
377 {
378 title = hb_list_item(h->title_set.list_title, ii);
379 if (title->index == title_index)
380 {
381 // In some cases, we don't care what the preview count is.
382 // E.g. when rescanning at the start of a job. In these
383 // cases, the caller can set preview_count to -1 to tell
384 // us to use the same count as the previous scan, if known.
385 if (preview_count < 0)
386 {
387 preview_count = title->preview_count;
388 }
389 if (preview_count == title->preview_count)
390 {
391 // Title has already been scanned.
392 hb_lock( h->state_lock );
393 h->state.state = HB_STATE_SCANDONE;
394 hb_unlock( h->state_lock );
395 return;
396 }
397 }
398 }
399 }
400 if (preview_count < 0)
401 {
402 preview_count = 10;
403 }
404
405 h->scan_die = 0;
406
407 /* Clean up from previous scan */
408 hb_remove_previews( h );
409 while( ( title = hb_list_item( h->title_set.list_title, 0 ) ) )
410 {
411 hb_list_rem( h->title_set.list_title, title );
412 hb_title_close( &title );
413 }
414 free((char*)h->title_set.path);
415 h->title_set.path = NULL;
416
417 /* Print CPU info here so that it's in all scan and encode logs */
418 const char *cpu_name = hb_get_cpu_name();
419 const char *cpu_type = hb_get_cpu_platform_name();
420 hb_log("CPU: %s", cpu_name != NULL ? cpu_name : "");
421 if (cpu_type != NULL)
422 {
423 hb_log(" - %s", cpu_type);
424 }
425 hb_log(" - logical processor count: %d", hb_get_cpu_count());
426
427 #if HB_PROJECT_FEATURE_QSV
428 if (!is_hardware_disabled())
429 {
430 /* Print QSV info here so that it's in all scan and encode logs */
431 hb_qsv_info_print();
432 }
433 #endif
434
435 hb_log( "hb_scan: path=%s, title_index=%d", path, title_index );
436 h->scan_thread = hb_scan_init( h, &h->scan_die, path, title_index,
437 &h->title_set, preview_count,
438 store_previews, min_duration );
439 }
440
hb_force_rescan(hb_handle_t * h)441 void hb_force_rescan( hb_handle_t * h )
442 {
443 free((char*)h->title_set.path);
444 h->title_set.path = NULL;
445 }
446
447 /**
448 * Returns the list of titles found.
449 * @param h Handle to hb_handle_t
450 * @return Handle to hb_list_t of the title list.
451 */
hb_get_titles(hb_handle_t * h)452 hb_list_t * hb_get_titles( hb_handle_t * h )
453 {
454 return h->title_set.list_title;
455 }
456
hb_get_title_set(hb_handle_t * h)457 hb_title_set_t * hb_get_title_set( hb_handle_t * h )
458 {
459 return &h->title_set;
460 }
461
hb_save_preview(hb_handle_t * h,int title,int preview,hb_buffer_t * buf,int format)462 int hb_save_preview( hb_handle_t * h, int title, int preview, hb_buffer_t *buf, int format )
463 {
464 FILE * file;
465 char * filename;
466 char reason[80];
467 const int planes_max = 3;
468 const int format_chars = 4;
469 char format_string[format_chars];
470
471 switch (format)
472 {
473 case HB_PREVIEW_FORMAT_YUV:
474 strncpy(format_string, "yuv", format_chars);
475 break;
476 case HB_PREVIEW_FORMAT_JPG:
477 strncpy(format_string, "jpg", format_chars);
478 break;
479 default:
480 hb_error("hb_save_preview: Unsupported preview format %d", format);
481 return -1;
482 }
483
484 filename = hb_get_temporary_filename("%d_%d_%d.%s", hb_get_instance_id(h),
485 title, preview, format_string);
486
487 file = hb_fopen(filename, "wb");
488 if (file == NULL)
489 {
490 if (strerror_r(errno, reason, 79) != 0)
491 {
492 strcpy(reason, "unknown -- strerror_r() failed");
493 }
494 hb_error("hb_save_preview: Failed to open %s (reason: %s)",
495 filename, reason);
496 free(filename);
497 return -1;
498 }
499
500 if (format == HB_PREVIEW_FORMAT_YUV)
501 {
502 int pp, hh;
503 for(pp = 0; pp < planes_max; pp++)
504 {
505 const uint8_t * data = buf->plane[pp].data;
506 const int stride = buf->plane[pp].stride;
507 const int w = buf->plane[pp].width;
508 const int h = buf->plane[pp].height;
509
510 for(hh = 0; hh < h; hh++)
511 {
512 if (fwrite(data, w, 1, file) < w)
513 {
514 if (ferror(file))
515 {
516 if (strerror_r(errno, reason, 79) != 0)
517 {
518 strcpy(reason, "unknown -- strerror_r() failed");
519 }
520 hb_error("hb_save_preview: Failed to write line %d to %s "
521 "(reason: %s). Preview will be incomplete.",
522 hh, filename, reason);
523 goto done;
524 }
525 }
526 data += stride;
527 }
528 }
529 }
530 else if (format == HB_PREVIEW_FORMAT_JPG)
531 {
532 tjhandle jpeg_compressor = tjInitCompress();
533 const int jpeg_quality = 90;
534 unsigned long jpeg_size = 0;
535 unsigned char * jpeg_data = NULL;
536 int planes_stride[planes_max];
537 uint8_t * planes_data[planes_max];
538 int pp, compressor_result;
539 for (pp = 0; pp < planes_max; pp++)
540 {
541 planes_stride[pp] = buf->plane[pp].stride;
542 planes_data[pp] = buf->plane[pp].data;
543 }
544
545 compressor_result = tjCompressFromYUVPlanes(jpeg_compressor,
546 (const unsigned char **)planes_data,
547 buf->plane[0].width,
548 planes_stride,
549 buf->plane[0].height,
550 TJSAMP_420,
551 &jpeg_data,
552 &jpeg_size,
553 jpeg_quality,
554 TJFLAG_FASTDCT);
555 if (compressor_result == 0)
556 {
557 const size_t ret = fwrite(jpeg_data, jpeg_size, 1, file);
558 if ((ret < jpeg_size) && (ferror(file)))
559 {
560 if (strerror_r(errno, reason, 79) != 0)
561 {
562 strcpy(reason, "unknown -- strerror_r() failed");
563 }
564 hb_error("hb_save_preview: Failed to write to %s "
565 "(reason: %s).", filename, reason);
566 }
567 }
568 else
569 {
570 hb_error("hb_save_preview: JPEG compression failed for "
571 "preview image %s", filename);
572 }
573
574 tjDestroy(jpeg_compressor);
575 tjFree(jpeg_data);
576 }
577
578 done:
579 free(filename);
580 fclose(file);
581
582 return 0;
583 }
584
hb_read_preview(hb_handle_t * h,hb_title_t * title,int preview,int format)585 hb_buffer_t * hb_read_preview(hb_handle_t * h, hb_title_t *title, int preview, int format)
586 {
587 FILE * file = NULL;
588 char * filename = NULL;
589 char reason[80];
590 const int planes_max = 3;
591 const int format_chars = 4;
592 char format_string[format_chars];
593
594 hb_buffer_t * buf;
595 buf = hb_frame_buffer_init(AV_PIX_FMT_YUV420P,
596 title->geometry.width, title->geometry.height);
597 buf->f.color_prim = title->color_prim;
598 buf->f.color_transfer = title->color_transfer;
599 buf->f.color_matrix = title->color_matrix;
600 buf->f.color_range = AVCOL_RANGE_MPEG;
601
602 if (!buf)
603 {
604 hb_error("hb_read_preview: hb_frame_buffer_init failed");
605 goto done;
606 }
607
608 switch (format)
609 {
610 case HB_PREVIEW_FORMAT_YUV:
611 strncpy(format_string, "yuv", format_chars);
612 break;
613 case HB_PREVIEW_FORMAT_JPG:
614 strncpy(format_string, "jpg", format_chars);
615 break;
616 default:
617 hb_error("hb_read_preview: Unsupported preview format %d", format);
618 return buf;
619 }
620
621 filename = hb_get_temporary_filename("%d_%d_%d.%s", hb_get_instance_id(h),
622 title->index, preview, format_string);
623
624 file = hb_fopen(filename, "rb");
625 if (file == NULL)
626 {
627 if (strerror_r(errno, reason, 79) != 0)
628 {
629 strcpy(reason, "unknown -- strerror_r() failed");
630 }
631 hb_error("hb_read_preview: Failed to open %s (reason: %s)",
632 filename, reason);
633 free(filename);
634 return NULL;
635 }
636
637 if (format == HB_PREVIEW_FORMAT_YUV)
638 {
639 int pp, hh;
640 for (pp = 0; pp < planes_max; pp++)
641 {
642 uint8_t * data = buf->plane[pp].data;
643 const int stride = buf->plane[pp].stride;
644 const int w = buf->plane[pp].width;
645 const int h = buf->plane[pp].height;
646
647 for (hh = 0; hh < h; hh++)
648 {
649 if (fread(data, w, 1, file) < w)
650 {
651 if (ferror(file))
652 {
653 if (strerror_r(errno, reason, 79) != 0)
654 {
655 strcpy(reason, "unknown -- strerror_r() failed");
656 }
657 hb_error("hb_read_preview: Failed to read line %d from %s "
658 "(reason: %s). Preview will be incomplete.",
659 hh, filename, reason );
660 goto done;
661 }
662 }
663 data += stride;
664 }
665 }
666 }
667 else if (format == HB_PREVIEW_FORMAT_JPG)
668 {
669 fseek(file, 0, SEEK_END);
670 unsigned long jpeg_size = ftell(file);
671 fseek(file, 0, SEEK_SET);
672 unsigned char * jpeg_data = tjAlloc(jpeg_size + 1);
673 jpeg_data[jpeg_size] = 0;
674
675 const size_t ret = fread(jpeg_data, jpeg_size, 1, file);
676 {
677 if ((ret < jpeg_size) && (ferror(file)))
678 {
679 if (strerror_r(errno, reason, 79) != 0)
680 {
681 strcpy(reason, "unknown -- strerror_r() failed");
682 }
683 hb_error("hb_read_preview: Failed to read from %s "
684 "(reason: %s).", filename, reason);
685 tjFree(jpeg_data);
686 goto done;
687 }
688 }
689
690 tjhandle jpeg_decompressor = tjInitDecompress();
691 int planes_stride[planes_max];
692 uint8_t * planes_data[planes_max];
693 int pp, decompressor_result;
694 for (pp = 0; pp < planes_max; pp++)
695 {
696 planes_stride[pp] = buf->plane[pp].stride;
697 planes_data[pp] = buf->plane[pp].data;
698 }
699
700 decompressor_result = tjDecompressToYUVPlanes(jpeg_decompressor,
701 jpeg_data,
702 jpeg_size,
703 (unsigned char **)planes_data,
704 buf->plane[0].width,
705 planes_stride,
706 buf->plane[0].height,
707 TJFLAG_FASTDCT);
708 if (decompressor_result != 0)
709 {
710 hb_error("hb_read_preview: JPEG decompression failed for "
711 "preview image %s", filename);
712 }
713
714 tjDestroy(jpeg_decompressor);
715 tjFree(jpeg_data);
716 }
717
718 done:
719 free(filename);
720 fclose(file);
721
722 return buf;
723 }
724
hb_get_preview2(hb_handle_t * h,int title_idx,int picture,hb_geometry_settings_t * geo,int deinterlace)725 hb_image_t* hb_get_preview2(hb_handle_t * h, int title_idx, int picture,
726 hb_geometry_settings_t *geo, int deinterlace)
727 {
728 char filename[1024];
729 hb_buffer_t * in_buf = NULL, * deint_buf = NULL;
730 hb_buffer_t * preview_buf = NULL;
731 uint32_t swsflags;
732 uint8_t * preview_data[4], * crop_data[4];
733 int preview_stride[4], crop_stride[4];
734 struct SwsContext * context;
735
736 int width = geo->geometry.width *
737 geo->geometry.par.num / geo->geometry.par.den;
738 int height = geo->geometry.height;
739
740 // Set min/max dimensions to prevent failure to initialize
741 // sws context and absurd sizes.
742 //
743 // This means output image size may not match requested image size!
744 int ww = width, hh = height;
745 width = MIN(MAX(width, HB_MIN_WIDTH), HB_MAX_WIDTH);
746 height = MIN(MAX(height * width / ww, HB_MIN_HEIGHT), HB_MAX_HEIGHT);
747 width = MIN(MAX(width * height / hh, HB_MIN_WIDTH), HB_MAX_WIDTH);
748
749 swsflags = SWS_LANCZOS | SWS_ACCURATE_RND;
750
751 preview_buf = hb_frame_buffer_init(AV_PIX_FMT_RGB32, width, height);
752 // fill in AVPicture
753 hb_picture_fill( preview_data, preview_stride, preview_buf );
754
755
756 memset( filename, 0, 1024 );
757
758 hb_title_t * title;
759 title = hb_find_title_by_index(h, title_idx);
760 if (title == NULL)
761 {
762 hb_error( "hb_get_preview2: invalid title (%d)", title_idx );
763 goto fail;
764 }
765
766 in_buf = hb_read_preview( h, title, picture, HB_PREVIEW_FORMAT_JPG );
767 if ( in_buf == NULL )
768 {
769 goto fail;
770 }
771
772 if (deinterlace)
773 {
774 // Deinterlace and crop
775 deint_buf = hb_frame_buffer_init( AV_PIX_FMT_YUV420P,
776 title->geometry.width, title->geometry.height );
777 hb_deinterlace(deint_buf, in_buf);
778 hb_picture_crop(crop_data, crop_stride, deint_buf,
779 geo->crop[0], geo->crop[2] );
780 }
781 else
782 {
783 // Crop
784 hb_picture_crop(crop_data, crop_stride, in_buf,
785 geo->crop[0], geo->crop[2] );
786 }
787
788 int colorspace = hb_sws_get_colorspace(title->color_matrix);
789
790 // Get scaling context
791 context = hb_sws_get_context(
792 title->geometry.width - (geo->crop[2] + geo->crop[3]),
793 title->geometry.height - (geo->crop[0] + geo->crop[1]),
794 AV_PIX_FMT_YUV420P, AVCOL_RANGE_MPEG,
795 width, height, AV_PIX_FMT_RGB32, AVCOL_RANGE_MPEG,
796 swsflags, colorspace);
797
798 if (context == NULL)
799 {
800 // if by chance hb_sws_get_context fails, don't crash in sws_scale
801 goto fail;
802 }
803
804 // Scale
805 sws_scale(context,
806 (const uint8_t * const *)crop_data, crop_stride,
807 0, title->geometry.height - (geo->crop[0] + geo->crop[1]),
808 preview_data, preview_stride);
809
810 // Free context
811 sws_freeContext( context );
812
813 hb_image_t *image = hb_buffer_to_image(preview_buf);
814
815 // Clean up
816 hb_buffer_close( &in_buf );
817 hb_buffer_close( &deint_buf );
818 hb_buffer_close( &preview_buf );
819
820 return image;
821
822 fail:
823
824 hb_buffer_close( &in_buf );
825 hb_buffer_close( &deint_buf );
826 hb_buffer_close( &preview_buf );
827
828 image = hb_image_init(AV_PIX_FMT_RGB32, width, height);
829 return image;
830 }
831
process_filter(hb_filter_object_t * filter)832 static void process_filter(hb_filter_object_t * filter)
833 {
834 hb_buffer_t * in, * out;
835
836 while (filter->status != HB_FILTER_DONE)
837 {
838 in = hb_fifo_get_wait(filter->fifo_in);
839 if (in == NULL)
840 continue;
841
842 out = NULL;
843 filter->status = filter->work(filter, &in, &out);
844 if (in != NULL)
845 {
846 hb_buffer_close(&in);
847 }
848 if (out != NULL)
849 {
850 hb_fifo_push(filter->fifo_out, out);
851 }
852 }
853 }
854
855 // Get preview and apply applicable filters
hb_get_preview3(hb_handle_t * h,int picture,hb_dict_t * job_dict)856 hb_image_t * hb_get_preview3(hb_handle_t * h, int picture,
857 hb_dict_t * job_dict)
858 {
859 hb_job_t * job;
860 hb_title_t * title = NULL;
861 hb_buffer_t * in = NULL, * out;
862
863 job = hb_dict_to_job(h, job_dict);
864 if (job == NULL)
865 {
866 hb_error("hb_get_preview3: failed to unpack job");
867 goto fail;
868 }
869 title = job->title;
870
871 in = hb_read_preview( h, title, picture, HB_PREVIEW_FORMAT_JPG );
872 if (in == NULL)
873 {
874 goto fail;
875 }
876
877 // Initialize supported filters
878 hb_list_t * list_filter = job->list_filter;
879 hb_filter_init_t init;
880 int ii;
881
882 memset(&init, 0, sizeof(init));
883 init.time_base.num = 1;
884 init.time_base.den = 90000;
885 init.job = job;
886 init.pix_fmt = AV_PIX_FMT_YUV420P;
887 init.color_range = AVCOL_RANGE_MPEG;
888
889 init.color_prim = title->color_prim;
890 init.color_transfer = title->color_transfer;
891 init.color_matrix = title->color_matrix;
892 init.geometry = title->geometry;
893 memset(init.crop, 0, sizeof(int[4]));
894 init.vrate = job->vrate;
895 init.cfr = 0;
896 init.grayscale = 0;
897
898 hb_filter_object_t * filter;
899
900 for (ii = 0; ii < hb_list_count(list_filter); )
901 {
902 filter = hb_list_item(list_filter, ii);
903 switch (filter->id)
904 {
905 case HB_FILTER_AVFILTER:
906 case HB_FILTER_CROP_SCALE:
907 case HB_FILTER_PAD:
908 case HB_FILTER_ROTATE:
909 case HB_FILTER_COLORSPACE:
910 case HB_FILTER_DECOMB:
911 case HB_FILTER_DETELECINE:
912 case HB_FILTER_DEINTERLACE:
913 case HB_FILTER_GRAYSCALE:
914 break;
915
916 case HB_FILTER_VFR:
917 case HB_FILTER_RENDER_SUB:
918 case HB_FILTER_QSV:
919 case HB_FILTER_NLMEANS:
920 case HB_FILTER_CHROMA_SMOOTH:
921 case HB_FILTER_LAPSHARP:
922 case HB_FILTER_UNSHARP:
923 case HB_FILTER_DEBLOCK:
924 case HB_FILTER_COMB_DETECT:
925 case HB_FILTER_HQDN3D:
926 // Not implemented, N/A, or requires multiple frame input
927 hb_list_rem(list_filter, filter);
928 hb_filter_close(&filter);
929 continue;
930 default:
931 hb_log("hb_get_preview3: Unrecognized filter (%d)",
932 filter->id);
933 hb_list_rem(list_filter, filter);
934 hb_filter_close(&filter);
935 continue;
936 }
937 if (filter->init != NULL && filter->init(filter, &init))
938 {
939 hb_error("hb_get_preview3: Failure to initialize filter '%s'",
940 filter->name);
941 hb_list_rem(list_filter, filter);
942 hb_filter_close(&filter);
943 continue;
944 }
945 ii++;
946 }
947
948 job->output_pix_fmt = init.pix_fmt;
949 job->color_prim = init.color_prim;
950 job->color_transfer = init.color_transfer;
951 job->color_matrix = init.color_matrix;
952 job->width = init.geometry.width;
953 job->height = init.geometry.height;
954 // job->par is supplied by the frontend.
955 //
956 // The filter chain does not know what the final desired PAR is.
957 // job->par = init.geometry.par;
958 memcpy(job->crop, init.crop, sizeof(int[4]));
959 job->vrate = init.vrate;
960 job->cfr = init.cfr;
961 job->grayscale = init.grayscale;
962
963 // Add "cropscale"
964 // Adjusts for pixel aspect, performs any requested
965 // post-scaling and sets required pix_fmt AV_PIX_FMT_RGB32
966 //
967 // This will scale the result at the end of the pipeline.
968 // I.e. padding will be scaled
969 hb_rational_t par = job->par;
970
971 int scaled_width = init.geometry.width;
972 int scaled_height = init.geometry.height;
973
974 filter = hb_filter_init(HB_FILTER_CROP_SCALE);
975 filter->settings = hb_dict_init();
976 if (par.num >= par.den)
977 {
978 scaled_width = scaled_width * par.num / par.den;
979 }
980 else
981 {
982 scaled_height = scaled_height * par.den / par.num;
983 }
984 hb_dict_set_int(filter->settings, "width", scaled_width);
985 hb_dict_set_int(filter->settings, "height", scaled_height);
986 hb_dict_set_string(filter->settings, "out_pix_fmt", av_get_pix_fmt_name(AV_PIX_FMT_RGB32));
987 hb_list_add(job->list_filter, filter);
988 if (filter->init != NULL && filter->init(filter, &init))
989 {
990 hb_error("hb_get_preview3: Failure to initialize filter '%s'",
991 filter->name);
992 hb_list_rem(list_filter, filter);
993 hb_filter_close(&filter);
994 }
995
996 hb_avfilter_combine(list_filter);
997
998 for( ii = 0; ii < hb_list_count( list_filter ); )
999 {
1000 filter = hb_list_item( list_filter, ii );
1001 filter->done = &job->done;
1002 if (filter->post_init != NULL && filter->post_init(filter, job))
1003 {
1004 hb_log( "hb_get_preview3: Failure to initialise filter '%s'",
1005 filter->name );
1006 hb_list_rem(list_filter, filter);
1007 hb_filter_close(&filter);
1008 continue;
1009 }
1010 ii++;
1011 }
1012
1013 // Set up filter fifos
1014 hb_fifo_t *fifo_in, * fifo_first, * fifo_last;
1015
1016 fifo_last = fifo_in = fifo_first = hb_fifo_init(2, 2);
1017 for( ii = 0; ii < hb_list_count( list_filter ); ii++)
1018 {
1019 filter = hb_list_item(list_filter, ii);
1020 if (!filter->skip)
1021 {
1022 filter->fifo_in = fifo_in;
1023 filter->fifo_out = hb_fifo_init(2, 2);
1024 fifo_last = fifo_in = filter->fifo_out;
1025 }
1026 }
1027
1028 // Feed preview frame to filter chain
1029 hb_fifo_push(fifo_first, in);
1030 hb_fifo_push(fifo_first, hb_buffer_eof_init());
1031
1032 // Process the preview frame through all filters
1033 for( ii = 0; ii < hb_list_count( list_filter ); ii++)
1034 {
1035 filter = hb_list_item(list_filter, ii);
1036 if (!filter->skip)
1037 {
1038 process_filter(filter);
1039 }
1040 }
1041 // Retrieve the filtered preview frame
1042 out = hb_fifo_get(fifo_last);
1043
1044 // Close filters
1045 for (ii = 0; ii < hb_list_count(list_filter); ii++)
1046 {
1047 filter = hb_list_item(list_filter, ii);
1048 filter->close(filter);
1049 }
1050
1051 // Close fifos
1052 hb_fifo_close(&fifo_first);
1053 for( ii = 0; ii < hb_list_count( list_filter ); ii++)
1054 {
1055 filter = hb_list_item(list_filter, ii);
1056 hb_fifo_close(&filter->fifo_out);
1057 }
1058
1059 if (out == NULL)
1060 {
1061 hb_error("hb_get_preview3: Failed to filter preview");
1062 goto fail;
1063 }
1064
1065 hb_image_t *image = hb_buffer_to_image(out);
1066 hb_buffer_close(&out);
1067 if (image->width < 16 || image->height < 16)
1068 {
1069 // Guard against broken filter generating degenerate images
1070 hb_error("hb_get_preview3: bad preview image output by filters");
1071 hb_image_close(&image);
1072 goto fail;
1073 }
1074
1075 // Clean up
1076 hb_job_close(&job);
1077
1078 return image;
1079
1080 fail:
1081
1082 {
1083 int width = 854, height = 480;
1084
1085 if (title != NULL)
1086 {
1087 hb_geometry_t * geo = &title->geometry;
1088
1089 width = geo->width * geo->par.num / geo->par.den;
1090 height = geo->height;
1091 }
1092
1093 image = hb_image_init(AV_PIX_FMT_RGB32, width, height);
1094 }
1095 hb_job_close(&job);
1096
1097 return image;
1098 }
1099
1100 /**
1101 * Analyzes a frame to detect interlacing artifacts
1102 * and returns true if interlacing (combing) is found.
1103 *
1104 * Code taken from Thomas Oestreich's 32detect filter
1105 * in the Transcode project, with minor formatting changes.
1106 *
1107 * @param buf An hb_buffer structure holding valid frame data
1108 * @param width The frame's width in pixels
1109 * @param height The frame's height in pixels
1110 * @param color_equal Sensitivity for detecting similar colors
1111 * @param color_diff Sensitivity for detecting different colors
1112 * @param threshold Sensitivity for flagging planes as combed
1113 * @param prog_equal Sensitivity for detecting similar colors on progressive frames
1114 * @param prog_diff Sensitivity for detecting different colors on progressive frames
1115 * @param prog_threshold Sensitivity for flagging progressive frames as combed
1116 */
hb_detect_comb(hb_buffer_t * buf,int color_equal,int color_diff,int threshold,int prog_equal,int prog_diff,int prog_threshold)1117 int hb_detect_comb( hb_buffer_t * buf, int color_equal, int color_diff, int threshold, int prog_equal, int prog_diff, int prog_threshold )
1118 {
1119 int j, k, n, off, cc_1, cc_2, cc[3];
1120 // int flag[3] ; // debugging flag
1121 uint16_t s1, s2, s3, s4;
1122 cc_1 = 0; cc_2 = 0;
1123
1124 if ( buf->s.flags & 16 )
1125 {
1126 /* Frame is progressive, be more discerning. */
1127 color_diff = prog_diff;
1128 color_equal = prog_equal;
1129 threshold = prog_threshold;
1130 }
1131
1132 /* One pas for Y, one pass for Cb, one pass for Cr */
1133 for( k = 0; k <= buf->f.max_plane; k++ )
1134 {
1135 uint8_t * data = buf->plane[k].data;
1136 int width = buf->plane[k].width;
1137 int stride = buf->plane[k].stride;
1138 int height = buf->plane[k].height;
1139
1140 for( j = 0; j < width; ++j )
1141 {
1142 off = 0;
1143
1144 for( n = 0; n < ( height - 4 ); n = n + 2 )
1145 {
1146 /* Look at groups of 4 sequential horizontal lines */
1147 s1 = ( ( data )[ off + j ] & 0xff );
1148 s2 = ( ( data )[ off + j + stride ] & 0xff );
1149 s3 = ( ( data )[ off + j + 2 * stride ] & 0xff );
1150 s4 = ( ( data )[ off + j + 3 * stride ] & 0xff );
1151
1152 /* Note if the 1st and 2nd lines are more different in
1153 color than the 1st and 3rd lines are similar in color.*/
1154 if ( ( abs( s1 - s3 ) < color_equal ) &&
1155 ( abs( s1 - s2 ) > color_diff ) )
1156 ++cc_1;
1157
1158 /* Note if the 2nd and 3rd lines are more different in
1159 color than the 2nd and 4th lines are similar in color.*/
1160 if ( ( abs( s2 - s4 ) < color_equal ) &&
1161 ( abs( s2 - s3 ) > color_diff) )
1162 ++cc_2;
1163
1164 /* Now move down 2 horizontal lines before starting over.*/
1165 off += 2 * stride;
1166 }
1167 }
1168
1169 // compare results
1170 /* The final cc score for a plane is the percentage of combed pixels it contains.
1171 Because sensitivity goes down to hundredths of a percent, multiply by 1000
1172 so it will be easy to compare against the threshold value which is an integer. */
1173 cc[k] = (int)( ( cc_1 + cc_2 ) * 1000.0 / ( width * height ) );
1174 }
1175
1176
1177 /* HandBrake is all yuv420, so weight the average percentage of all 3 planes accordingly.*/
1178 int average_cc = ( 2 * cc[0] + ( cc[1] / 2 ) + ( cc[2] / 2 ) ) / 3;
1179
1180 /* Now see if that average percentage of combed pixels surpasses the threshold percentage given by the user.*/
1181 if( average_cc > threshold )
1182 {
1183 #if 0
1184 hb_log("Average %i combed (Threshold %i) %i/%i/%i | PTS: %"PRId64" (%fs) %s", average_cc, threshold, cc[0], cc[1], cc[2], buf->start, (float)buf->start / 90000, (buf->flags & 16) ? "Film" : "Video" );
1185 #endif
1186 return 1;
1187 }
1188
1189 #if 0
1190 hb_log("SKIPPED Average %i combed (Threshold %i) %i/%i/%i | PTS: %"PRId64" (%fs) %s", average_cc, threshold, cc[0], cc[1], cc[2], buf->start, (float)buf->start / 90000, (buf->flags & 16) ? "Film" : "Video" );
1191 #endif
1192
1193 /* Reaching this point means no combing detected. */
1194 return 0;
1195
1196 }
1197
hflip_crop_pad(int * dst,int * src,int hflip)1198 static void hflip_crop_pad(int * dst, int * src, int hflip)
1199 {
1200 if (hflip)
1201 {
1202 dst[2] = src[3];
1203 dst[3] = src[2];
1204 }
1205 }
1206
rotate_crop_pad(int * dst,int * src,int angle)1207 static void rotate_crop_pad(int * dst, int * src, int angle)
1208 {
1209 if (angle == 90)
1210 {
1211 dst[3] = src[0];
1212 dst[1] = src[3];
1213 dst[2] = src[1];
1214 dst[0] = src[2];
1215 }
1216 else if (angle == 180)
1217 {
1218 dst[0] = src[1];
1219 dst[1] = src[0];
1220 dst[2] = src[3];
1221 dst[3] = src[2];
1222 }
1223 else if (angle == 270)
1224 {
1225 dst[2] = src[0];
1226 dst[1] = src[2];
1227 dst[3] = src[1];
1228 dst[0] = src[3];
1229 }
1230 }
1231
hb_rotate_geometry(hb_geometry_crop_t * geo,hb_geometry_crop_t * result,int angle,int hflip)1232 void hb_rotate_geometry( hb_geometry_crop_t * geo, hb_geometry_crop_t * result,
1233 int angle, int hflip)
1234 {
1235 hb_geometry_crop_t in = *geo; // Make a copy in case geo aliases result
1236 *result = in;
1237
1238 // re-orient result if needed
1239 hflip_crop_pad(result->crop, in.crop, hflip);
1240 hflip_crop_pad(result->pad, in.pad, hflip);
1241 if (angle == 90 || angle == 270)
1242 {
1243 result->geometry.width = in.geometry.height;
1244 result->geometry.height = in.geometry.width;
1245 result->geometry.par.num = in.geometry.par.den;
1246 result->geometry.par.den = in.geometry.par.num;
1247 }
1248 in = *result;
1249 rotate_crop_pad(result->crop, in.crop, angle);
1250 rotate_crop_pad(result->pad, in.pad, angle);
1251 }
1252
1253 /**
1254 * Calculates destination width and height for anamorphic content
1255 *
1256 * Returns calculated geometry
1257 * @param source_geometry - Pointer to source geometry info
1258 * @param geometry - Pointer to requested destination parameters
1259 */
hb_set_anamorphic_size2(hb_geometry_t * src_geo,hb_geometry_settings_t * geo,hb_geometry_t * result)1260 void hb_set_anamorphic_size2(hb_geometry_t * src_geo,
1261 hb_geometry_settings_t * geo,
1262 hb_geometry_t * result)
1263 {
1264 hb_rational_t in_par, src_par, orig_par;
1265 int keep_display_aspect = !!(geo->keep & HB_KEEP_DISPLAY_ASPECT);
1266 int keep_display_width = !!(geo->keep & HB_KEEP_DISPLAY_WIDTH);
1267 int keep_height = !!(geo->keep & HB_KEEP_HEIGHT);
1268 int keep_width = !!(geo->keep & HB_KEEP_WIDTH);
1269 int keep_pad = !!(geo->keep & HB_KEEP_PAD);
1270 int upscale = !!(geo->flags & HB_GEO_SCALE_UP);
1271 int best = !!(geo->flags & HB_GEO_SCALE_BEST);
1272
1273 /* Set up some variables to make the math easier to follow. */
1274 int cropped_width = src_geo->width - geo->crop[2] - geo->crop[3];
1275 int cropped_height = src_geo->height - geo->crop[0] - geo->crop[1];
1276 double cropped_sar = (double)cropped_width / cropped_height;
1277 int mod = (geo->modulus > 0) ? EVEN(geo->modulus) : 2;
1278 int pad_width = geo->pad[2] + geo->pad[3];
1279 int pad_height = geo->pad[0] + geo->pad[1];
1280 double displayWidth, displayHeight;
1281
1282 // Sanitize PAR
1283 if (geo->geometry.par.num == 0 || geo->geometry.par.den == 0)
1284 {
1285 geo->geometry.par.num = geo->geometry.par.den = 1;
1286 }
1287 if (src_geo->par.num == 0 || src_geo->par.den == 0)
1288 {
1289 src_geo->par.num = src_geo->par.den = 1;
1290 }
1291
1292 in_par = geo->geometry.par;
1293 src_par = src_geo->par;
1294
1295 if (!keep_width && !keep_display_width)
1296 {
1297 orig_par.num = geo->displayWidth;
1298 orig_par.den = geo->geometry.width + pad_width;
1299 }
1300 else
1301 {
1302 orig_par = in_par;
1303 }
1304
1305 /* If a source was really NTSC or PAL and the user specified ITU PAR
1306 values, replace the standard PAR values with the ITU broadcast ones. */
1307 if (src_geo->width == 720 && geo->itu_par)
1308 {
1309 // convert aspect to a scaled integer so we can test for 16:9 & 4:3
1310 // aspect ratios ignoring insignificant differences in the LSBs of
1311 // the floating point representation.
1312 int iaspect = src_geo->width * src_par.num * 9. /
1313 (src_geo->height * src_par.den);
1314
1315 /* Handle ITU PARs */
1316 if (src_geo->height == 480)
1317 {
1318 /* It's NTSC */
1319 if (iaspect == 16)
1320 {
1321 /* It's widescreen */
1322 in_par.num = 40;
1323 in_par.den = 33;
1324 }
1325 else if (iaspect == 12)
1326 {
1327 /* It's 4:3 */
1328 in_par.num = 10;
1329 in_par.den = 11;
1330 }
1331 }
1332 else if (src_geo->height == 576)
1333 {
1334 /* It's PAL */
1335 if (iaspect == 16)
1336 {
1337 /* It's widescreen */
1338 in_par.num = 16;
1339 in_par.den = 11;
1340 }
1341 else if (iaspect == 12)
1342 {
1343 /* It's 4:3 */
1344 in_par.num = 12;
1345 in_par.den = 11;
1346 }
1347 }
1348 }
1349
1350
1351 // Remove pad from DAR, simplifies latter calculations
1352 displayWidth = geo->displayWidth -
1353 (double)pad_width * orig_par.den / orig_par.num;
1354 displayHeight = geo->displayHeight - pad_height;
1355 if (!keep_pad)
1356 {
1357
1358 pad_width = 0;
1359 pad_height = 0;
1360 }
1361
1362 int width, height;
1363 int maxWidth, maxHeight;
1364
1365 if (geo->maxWidth > 0)
1366 {
1367 maxWidth = MIN(MAX(MULTIPLE_MOD_DOWN(geo->maxWidth, mod),
1368 HB_MIN_WIDTH), HB_MAX_WIDTH);
1369 }
1370 else
1371 {
1372 maxWidth = HB_MAX_WIDTH;
1373 }
1374 if (geo->maxHeight > 0)
1375 {
1376 maxHeight = MIN(MAX(MULTIPLE_MOD_DOWN(geo->maxHeight, mod),
1377 HB_MIN_HEIGHT), HB_MAX_HEIGHT);
1378 }
1379 else
1380 {
1381 maxHeight = HB_MAX_HEIGHT;
1382 }
1383 if (!upscale)
1384 {
1385 // Limit resolution to source resolution + pad
1386 if (maxWidth > cropped_width + pad_width)
1387 {
1388 maxWidth = MULTIPLE_MOD_DOWN(cropped_width + pad_width, mod);
1389 }
1390 if (maxHeight > cropped_height + pad_height)
1391 {
1392 maxHeight = MULTIPLE_MOD_DOWN(cropped_height + pad_height, mod);
1393 }
1394 }
1395
1396 width = geo->geometry.width;
1397 height = geo->geometry.height;
1398
1399 if (best && !keep_display_width)
1400 {
1401 // Select "best" resolution based on upscale settings and
1402 // source resolution.
1403 width = cropped_width;
1404 height = cropped_height;
1405 if (upscale && maxWidth > 0)
1406 {
1407 width = maxWidth - pad_width;
1408 }
1409 if (upscale && maxHeight > 0)
1410 {
1411 height = maxHeight - pad_height;
1412 }
1413 }
1414 switch (geo->mode)
1415 {
1416 case HB_ANAMORPHIC_STRICT:
1417 /* "Strict" anamorphic: MOD 2, source PAR, and source dimensions */
1418 mod = 2;
1419 in_par = src_par;
1420 width = cropped_width;
1421 height = cropped_height;
1422 break;
1423
1424 case HB_ANAMORPHIC_LOOSE:
1425 in_par = src_par;
1426 break;
1427
1428 case HB_ANAMORPHIC_NONE:
1429 /* "None" anamorphic, a.k.a. 1:1. */
1430 in_par.num = 1;
1431 in_par.den = 1;
1432 break;
1433
1434 case HB_ANAMORPHIC_CUSTOM:
1435 /* "Custom" anamorphic: Set a specific PAR */
1436 default:
1437 break;
1438 }
1439
1440 // Use 64 bits to avoid overflow till the final hb_reduce() call
1441 int64_t dst_par_num;
1442 int64_t dst_par_den;
1443
1444 hb_reduce64(&dst_par_num, &dst_par_den, in_par.num, in_par.den);
1445
1446 switch (geo->mode)
1447 {
1448 case HB_ANAMORPHIC_STRICT:
1449 case HB_ANAMORPHIC_LOOSE:
1450 case HB_ANAMORPHIC_NONE:
1451 case HB_ANAMORPHIC_CUSTOM:
1452 {
1453 double dar;
1454
1455 if (keep_display_aspect)
1456 {
1457 // Recompute width or height to maintain the source DAR
1458 double par;
1459
1460 par = (double)src_par.num / src_par.den;
1461 dar = par * cropped_sar;
1462
1463 if (!keep_height)
1464 {
1465 width = MULTIPLE_MOD_UP(width, mod);
1466 height = MULTIPLE_MOD(
1467 width * dst_par_num / dst_par_den / dar, mod);
1468 }
1469 else
1470 {
1471 height = MULTIPLE_MOD_UP(height, mod);
1472 width = MULTIPLE_MOD_UP(
1473 dar * height * dst_par_den / dst_par_num, mod);
1474 }
1475 }
1476 else if (keep_display_width)
1477 {
1478 // Recompute width if we are modifying display size
1479 // in these anamorphic modes. These modes all have a fixed
1480 // user specified PAR.
1481 //
1482 // It is assumed displayHeight == height in this scenario.
1483 double dwidth;
1484 dar = (double)displayWidth / displayHeight;
1485
1486 // We need to determine if we should round up or down.
1487 // If a wider display aspect is requested, then the computed
1488 // 'double' storage aspect will be larger than the current
1489 // storage aspect, else it will be smaller.
1490 dwidth = displayWidth * dst_par_den / dst_par_num;
1491 if (dwidth > geo->geometry.width)
1492 {
1493 width = MULTIPLE_MOD_UP((int)dwidth, mod);
1494 }
1495 else
1496 {
1497 width = MULTIPLE_MOD_DOWN((int)dwidth, mod);
1498 }
1499 height = MULTIPLE_MOD_UP(height, mod);
1500 }
1501 else
1502 {
1503 // Recompute width or height to maintain the current DAR
1504 dar = (double)displayWidth / displayHeight;
1505 if (!keep_height)
1506 {
1507 width = MULTIPLE_MOD_UP(width, mod);
1508 height = MULTIPLE_MOD(
1509 width * dst_par_num / dst_par_den / dar, mod);
1510 }
1511 else
1512 {
1513 height = MULTIPLE_MOD_UP(height, mod);
1514 width = MULTIPLE_MOD(
1515 dar * height * dst_par_den / dst_par_num, mod);
1516 }
1517 }
1518
1519 // Limit to min/max dimensions
1520 if (width + pad_width > maxWidth)
1521 {
1522 width = maxWidth - pad_width;
1523 if (keep_display_aspect)
1524 {
1525 height = MULTIPLE_MOD(
1526 width * dst_par_num / dst_par_den / dar, mod);
1527 }
1528 }
1529 if (height + pad_height > maxHeight)
1530 {
1531 height = maxHeight - pad_height;
1532 if (keep_display_aspect)
1533 {
1534 width = MULTIPLE_MOD_UP(
1535 dar * height * dst_par_den / dst_par_num, mod);
1536 }
1537 }
1538 if (width < HB_MIN_WIDTH)
1539 {
1540 width = HB_MIN_WIDTH;
1541 if (keep_display_aspect)
1542 {
1543 height = MULTIPLE_MOD(
1544 width * dst_par_num / dst_par_den / dar, mod);
1545 }
1546 }
1547 if (height < HB_MIN_HEIGHT)
1548 {
1549 height = HB_MIN_HEIGHT;
1550 if (keep_display_aspect)
1551 {
1552 width = MULTIPLE_MOD_UP(
1553 dar * height * dst_par_den / dst_par_num, mod);
1554 }
1555 }
1556
1557 if (geo->mode != HB_ANAMORPHIC_CUSTOM &&
1558 geo->mode != HB_ANAMORPHIC_NONE && keep_display_aspect)
1559 {
1560 // Rounding errors in width/height calculations may
1561 // throw off final display aspect.
1562 //
1563 // Recompute PAR to fix display aspect, unless user set
1564 // a specific PAR.
1565 dst_par_num = (int64_t)height * cropped_width * src_par.num;
1566 dst_par_den = (int64_t)width * cropped_height * src_par.den;
1567 }
1568 } break;
1569
1570 default:
1571 case HB_ANAMORPHIC_AUTO:
1572 {
1573 /* "Automatic" anamorphic.
1574 * - Uses mod-compliant dimensions, set by user
1575 * - Allows users to set the either width *or* height
1576 * - Does *not* maintain original source PAR if one
1577 * or both dimensions is limited by maxWidth/maxHeight.
1578 */
1579
1580 if (!keep_display_aspect && keep_display_width)
1581 {
1582 // Recompute PAR if we are modifying display size
1583 // in auto anamorphic mode (stretching the display aspect).
1584 //
1585 // Not that (keep_display_aspect && geo->displayWidth < 0)
1586 // is not handled. It is not a valid use case in the
1587 // frontends, so it is unnecessary to complicate this further
1588 // with support for it.
1589 width = geo->geometry.width;
1590 height = geo->geometry.height;
1591 dst_par_num = displayWidth;
1592 dst_par_den = width;
1593 break;
1594 }
1595
1596 /* Time to get picture dimensions that divide cleanly.*/
1597 width = MULTIPLE_MOD_UP(width, mod);
1598 height = MULTIPLE_MOD_UP(height, mod);
1599
1600 // Limit to min/max dimensions
1601 if (width + pad_width > maxWidth)
1602 {
1603 width = maxWidth - pad_width;
1604 }
1605 if (height + pad_height > maxHeight)
1606 {
1607 height = maxHeight - pad_height;
1608 }
1609 if (width < HB_MIN_WIDTH)
1610 {
1611 width = HB_MIN_WIDTH;
1612 }
1613 if (height < HB_MIN_HEIGHT)
1614 {
1615 height = HB_MIN_HEIGHT;
1616 }
1617
1618 /* Adjust the output PAR for new width/height */
1619 if (keep_display_aspect)
1620 {
1621 dst_par_num = (int64_t)height * cropped_width * src_par.num;
1622 dst_par_den = (int64_t)width * cropped_height * src_par.den;
1623 }
1624 else
1625 {
1626 dst_par_num = displayWidth;
1627 dst_par_den = width;
1628 }
1629 } break;
1630 }
1631
1632 /* Pass the results back to the caller */
1633 result->width = width;
1634 result->height = height;
1635
1636 // If the user is directly updating PAR, don't override PAR values.
1637 // I.e. don't even reduce the values.
1638 if (geo->mode == HB_ANAMORPHIC_CUSTOM ||
1639 geo->mode == HB_ANAMORPHIC_NONE)
1640 {
1641 // In these 2 anamorphic modes, the result PAR should be exactly
1642 // what the user set PAR to.
1643 result->par = in_par;
1644 }
1645 else
1646 {
1647 /* While x264 is smart enough to reduce fractions on its own, libavcodec
1648 * needs some help with the math, so lose superfluous factors. */
1649 hb_limit_rational64(&dst_par_num, &dst_par_den,
1650 dst_par_num, dst_par_den, 65535);
1651
1652 hb_reduce(&result->par.num, &result->par.den, dst_par_num, dst_par_den);
1653 }
1654 }
1655
1656 /**
1657 * Add a filter to a jobs filter list
1658 *
1659 * @param job Handle to hb_job_t
1660 * @param settings to give the filter
1661 */
hb_add_filter2(hb_value_array_t * list,hb_dict_t * filter_dict)1662 void hb_add_filter2( hb_value_array_t * list, hb_dict_t * filter_dict )
1663 {
1664 int new_id = hb_dict_get_int(filter_dict, "ID");
1665
1666 hb_filter_object_t * filter = hb_filter_get(new_id);
1667 if (filter == NULL)
1668 {
1669 hb_error("hb_add_filter2: Invalid filter ID %d", new_id);
1670 hb_value_free(&filter_dict);
1671 return;
1672 }
1673 if (filter->enforce_order)
1674 {
1675 // Find the position in the filter chain this filter belongs in
1676 int ii, len;
1677
1678 len = hb_value_array_len(list);
1679 for( ii = 0; ii < len; ii++ )
1680 {
1681 hb_value_t * f = hb_value_array_get(list, ii);
1682 int id = hb_dict_get_int(f, "ID");
1683 if (id > new_id)
1684 {
1685 hb_value_array_insert(list, ii, filter_dict);
1686 return;
1687 }
1688 else if ( id == new_id )
1689 {
1690 // Updating this filter with new settings
1691 hb_value_array_set(list, ii, filter_dict);
1692 return;
1693 }
1694 }
1695 }
1696 // No position found or order not enforced for this filter
1697 hb_value_array_append(list, filter_dict);
1698 }
1699
1700 /**
1701 * Add a filter to a jobs filter list
1702 *
1703 * @param job Handle to hb_job_t
1704 * @param settings to give the filter
1705 */
hb_add_filter_dict(hb_job_t * job,hb_filter_object_t * filter,const hb_dict_t * settings_in)1706 void hb_add_filter_dict( hb_job_t * job, hb_filter_object_t * filter,
1707 const hb_dict_t * settings_in )
1708 {
1709 hb_dict_t * settings;
1710
1711 // Always set filter->settings to a valid hb_dict_t
1712 if (settings_in == NULL)
1713 {
1714 settings = hb_dict_init();
1715 }
1716 else
1717 {
1718 settings = hb_value_dup(settings_in);
1719 }
1720 filter->settings = settings;
1721 if (filter->sub_filter)
1722 {
1723 filter->sub_filter->settings = hb_value_dup(settings);
1724 }
1725 if( filter->enforce_order )
1726 {
1727 // Find the position in the filter chain this filter belongs in
1728 int i;
1729 for( i = 0; i < hb_list_count( job->list_filter ); i++ )
1730 {
1731 hb_filter_object_t * f = hb_list_item( job->list_filter, i );
1732 if( f->id > filter->id )
1733 {
1734 hb_list_insert( job->list_filter, i, filter );
1735 return;
1736 }
1737 else if( f->id == filter->id )
1738 {
1739 // Don't allow the same filter to be added twice
1740 hb_filter_close( &filter );
1741 return;
1742 }
1743 }
1744 }
1745 // No position found or order not enforced for this filter
1746 hb_list_add( job->list_filter, filter );
1747 }
1748
1749 /**
1750 * Add a filter to a jobs filter list
1751 *
1752 * @param job Handle to hb_job_t
1753 * @param settings to give the filter
1754 */
hb_add_filter(hb_job_t * job,hb_filter_object_t * filter,const char * settings_in)1755 void hb_add_filter( hb_job_t * job, hb_filter_object_t * filter,
1756 const char * settings_in )
1757 {
1758 hb_dict_t * settings = hb_parse_filter_settings(settings_in);
1759 if (settings_in != NULL && settings == NULL)
1760 {
1761 hb_log("hb_add_filter: failed to parse filter settings!");
1762 return;
1763 }
1764 hb_add_filter_dict(job, filter, settings);
1765 hb_value_free(&settings);
1766 }
1767
1768 /**
1769 * Returns the number of jobs in the queue.
1770 * @param h Handle to hb_handle_t.
1771 * @return Number of jobs.
1772 */
hb_count(hb_handle_t * h)1773 int hb_count( hb_handle_t * h )
1774 {
1775 return hb_list_count( h->jobs );
1776 }
1777
1778 /**
1779 * Returns handle to job at index i within the job list.
1780 * @param h Handle to hb_handle_t.
1781 * @param i Index of job.
1782 * @returns Handle to hb_job_t of desired job.
1783 */
hb_job(hb_handle_t * h,int i)1784 hb_job_t * hb_job( hb_handle_t * h, int i )
1785 {
1786 return hb_list_item( h->jobs, i );
1787 }
1788
hb_current_job(hb_handle_t * h)1789 hb_job_t * hb_current_job( hb_handle_t * h )
1790 {
1791 return( h->current_job );
1792 }
1793
1794 /**
1795 * Adds a job to the job list.
1796 * @param h Handle to hb_handle_t.
1797 * @param job Handle to hb_job_t.
1798 */
hb_add_internal(hb_handle_t * h,hb_job_t * job,hb_list_t * list_pass)1799 static void hb_add_internal( hb_handle_t * h, hb_job_t * job, hb_list_t *list_pass )
1800 {
1801 hb_job_t * job_copy;
1802 hb_audio_t * audio;
1803 hb_subtitle_t * subtitle;
1804 int i;
1805 char audio_lang[4];
1806
1807 /* Copy the job */
1808 job_copy = calloc( sizeof( hb_job_t ), 1 );
1809 memcpy(job_copy, job, sizeof(hb_job_t));
1810 job_copy->json = NULL;
1811 job_copy->encoder_preset = NULL;
1812 job_copy->encoder_tune = NULL;
1813 job_copy->encoder_profile = NULL;
1814 job_copy->encoder_level = NULL;
1815 job_copy->encoder_options = NULL;
1816 job_copy->file = NULL;
1817 job_copy->list_chapter = NULL;
1818 job_copy->list_audio = NULL;
1819 job_copy->list_subtitle = NULL;
1820 job_copy->list_filter = NULL;
1821 job_copy->list_attachment = NULL;
1822 job_copy->metadata = NULL;
1823
1824 /* If we're doing Foreign Audio Search, copy all subtitles matching the
1825 * first audio track language we find in the audio list.
1826 *
1827 * Otherwise, copy all subtitles found in the input job (which can be
1828 * manually selected by the user, or added after the Foreign Audio
1829 * Search pass). */
1830 memset( audio_lang, 0, sizeof( audio_lang ) );
1831
1832 if( job->indepth_scan )
1833 {
1834
1835 /* Find the first audio language that is being encoded, then add all the
1836 * matching subtitles for that language. */
1837 for( i = 0; i < hb_list_count( job->list_audio ); i++ )
1838 {
1839 if( ( audio = hb_list_item( job->list_audio, i ) ) )
1840 {
1841 strncpy( audio_lang, audio->config.lang.iso639_2, sizeof( audio_lang ) );
1842 break;
1843 }
1844 }
1845
1846 /*
1847 * If doing a subtitle scan then add all the matching subtitles for this
1848 * language.
1849 */
1850 job_copy->list_subtitle = hb_list_init();
1851
1852 for( i = 0; i < hb_list_count( job->title->list_subtitle ); i++ )
1853 {
1854 subtitle = hb_list_item( job->title->list_subtitle, i );
1855 if( strcmp( subtitle->iso639_2, audio_lang ) == 0 &&
1856 hb_subtitle_can_force( subtitle->source ) )
1857 {
1858 /* Matched subtitle language with audio language, so add this to
1859 * our list to scan.
1860 *
1861 * We will update the subtitle list on the next pass later, after
1862 * the subtitle scan pass has completed. */
1863 hb_list_add( job_copy->list_subtitle,
1864 hb_subtitle_copy( subtitle ) );
1865 }
1866 }
1867 int count = hb_list_count(job_copy->list_subtitle);
1868 if (count == 0 ||
1869 (count == 1 && !job_copy->select_subtitle_config.force))
1870 {
1871 hb_log("Skipping subtitle scan. No suitable subtitle tracks.");
1872 hb_job_close(&job_copy);
1873 return;
1874 }
1875 }
1876 else
1877 {
1878 /* Copy all subtitles from the input job to title_copy/job_copy. */
1879 job_copy->list_subtitle = hb_subtitle_list_copy( job->list_subtitle );
1880 }
1881
1882 job_copy->list_chapter = hb_chapter_list_copy( job->list_chapter );
1883 job_copy->list_audio = hb_audio_list_copy( job->list_audio );
1884 job_copy->list_attachment = hb_attachment_list_copy( job->list_attachment );
1885 job_copy->metadata = hb_metadata_copy( job->metadata );
1886
1887 if (job->encoder_preset != NULL)
1888 job_copy->encoder_preset = strdup(job->encoder_preset);
1889 if (job->encoder_tune != NULL)
1890 job_copy->encoder_tune = strdup(job->encoder_tune);
1891 if (job->encoder_options != NULL)
1892 job_copy->encoder_options = strdup(job->encoder_options);
1893 if (job->encoder_profile != NULL)
1894 job_copy->encoder_profile = strdup(job->encoder_profile);
1895 if (job->encoder_level != NULL)
1896 job_copy->encoder_level = strdup(job->encoder_level);
1897 if (job->file != NULL)
1898 job_copy->file = strdup(job->file);
1899
1900 job_copy->h = h;
1901
1902 /* Copy the job filter list */
1903 job_copy->list_filter = hb_filter_list_copy( job->list_filter );
1904
1905 /* Add the job to the list */
1906 hb_list_add( list_pass, job_copy );
1907 }
1908
hb_job_copy(hb_job_t * job)1909 hb_job_t* hb_job_copy(hb_job_t * job)
1910 {
1911 hb_job_t * job_copy;
1912
1913 /* Copy the job */
1914 job_copy = calloc( sizeof( hb_job_t ), 1 );
1915 if (job_copy == NULL)
1916 return NULL;
1917
1918 if (job->json != NULL)
1919 {
1920 // JSON jobs should only have the json string set.
1921 job_copy->json = strdup(job->json);
1922 return job_copy;
1923 }
1924 memcpy( job_copy, job, sizeof( hb_job_t ) );
1925
1926 job_copy->list_subtitle = hb_subtitle_list_copy( job->list_subtitle );
1927 job_copy->list_chapter = hb_chapter_list_copy( job->list_chapter );
1928 job_copy->list_audio = hb_audio_list_copy( job->list_audio );
1929 job_copy->list_attachment = hb_attachment_list_copy( job->list_attachment );
1930 job_copy->metadata = hb_metadata_copy( job->metadata );
1931
1932 if (job->encoder_preset != NULL)
1933 job_copy->encoder_preset = strdup(job->encoder_preset);
1934 if (job->encoder_tune != NULL)
1935 job_copy->encoder_tune = strdup(job->encoder_tune);
1936 if (job->encoder_options != NULL)
1937 job_copy->encoder_options = strdup(job->encoder_options);
1938 if (job->encoder_profile != NULL)
1939 job_copy->encoder_profile = strdup(job->encoder_profile);
1940 if (job->encoder_level != NULL)
1941 job_copy->encoder_level = strdup(job->encoder_level);
1942 if (job->file != NULL)
1943 job_copy->file = strdup(job->file);
1944
1945 job_copy->list_filter = hb_filter_list_copy( job->list_filter );
1946
1947 return job_copy;
1948 }
1949
hb_add(hb_handle_t * h,hb_job_t * job)1950 int hb_add( hb_handle_t * h, hb_job_t * job )
1951 {
1952 hb_job_t *job_copy = hb_job_copy(job);
1953 job_copy->h = h;
1954 job_copy->sequence_id = ++h->sequence_id;
1955 hb_list_add(h->jobs, job_copy);
1956
1957 return job_copy->sequence_id;
1958 }
1959
hb_job_setup_passes(hb_handle_t * h,hb_job_t * job,hb_list_t * list_pass)1960 void hb_job_setup_passes(hb_handle_t * h, hb_job_t * job, hb_list_t * list_pass)
1961 {
1962 if (job->vquality > HB_INVALID_VIDEO_QUALITY)
1963 {
1964 job->twopass = 0;
1965 }
1966 if (job->indepth_scan)
1967 {
1968 hb_deep_log(2, "Adding subtitle scan pass");
1969 job->pass_id = HB_PASS_SUBTITLE;
1970 hb_add_internal(h, job, list_pass);
1971 job->indepth_scan = 0;
1972 }
1973 if (job->twopass)
1974 {
1975 hb_deep_log(2, "Adding two-pass encode");
1976 job->pass_id = HB_PASS_ENCODE_1ST;
1977 hb_add_internal(h, job, list_pass);
1978 job->pass_id = HB_PASS_ENCODE_2ND;
1979 hb_add_internal(h, job, list_pass);
1980 }
1981 else
1982 {
1983 job->pass_id = HB_PASS_ENCODE;
1984 hb_add_internal(h, job, list_pass);
1985 }
1986 }
1987
1988 /**
1989 * Removes a job from the job list.
1990 * @param h Handle to hb_handle_t.
1991 * @param job Handle to hb_job_t.
1992 */
hb_rem(hb_handle_t * h,hb_job_t * job)1993 void hb_rem( hb_handle_t * h, hb_job_t * job )
1994 {
1995 hb_list_rem( h->jobs, job );
1996 }
1997
1998 /**
1999 * Starts the conversion process.
2000 * Sets state to HB_STATE_WORKING.
2001 * calls hb_work_init, to launch work thread. Stores handle to work thread.
2002 * @param h Handle to hb_handle_t.
2003 */
hb_start(hb_handle_t * h)2004 void hb_start( hb_handle_t * h )
2005 {
2006 hb_lock( h->state_lock );
2007 h->state.state = HB_STATE_WORKING;
2008 h->state.sequence_id = 0;
2009 #define p h->state.param.working
2010 p.pass = -1;
2011 p.pass_count = -1;
2012 p.progress = 0.0;
2013 p.rate_cur = 0.0;
2014 p.rate_avg = 0.0;
2015 p.eta_seconds = 0;
2016 p.hours = -1;
2017 p.minutes = -1;
2018 p.seconds = -1;
2019 p.paused = 0;
2020 #undef p
2021 hb_unlock( h->state_lock );
2022
2023 h->paused = 0;
2024 h->pause_date = -1;
2025 h->pause_duration = 0;
2026 h->work_die = 0;
2027 h->work_error = HB_ERROR_NONE;
2028 h->work_thread = hb_work_init( h->jobs, &h->work_die, &h->work_error, &h->current_job );
2029 }
2030
2031 /**
2032 * Pauses the conversion process.
2033 * @param h Handle to hb_handle_t.
2034 */
hb_pause(hb_handle_t * h)2035 void hb_pause( hb_handle_t * h )
2036 {
2037 if( !h->paused )
2038 {
2039 hb_lock( h->pause_lock );
2040 h->paused = 1;
2041
2042 h->pause_date = hb_get_date();
2043
2044 hb_lock( h->state_lock );
2045 h->state.state = HB_STATE_PAUSED;
2046 hb_unlock( h->state_lock );
2047 }
2048 }
2049
2050 /**
2051 * Resumes the conversion process.
2052 * @param h Handle to hb_handle_t.
2053 */
hb_resume(hb_handle_t * h)2054 void hb_resume( hb_handle_t * h )
2055 {
2056 if( h->paused )
2057 {
2058 if (h->pause_date != -1)
2059 {
2060 // Calculate paused time for current job sequence
2061 h->pause_duration += hb_get_date() - h->pause_date;
2062
2063 // Calculate paused time for current job pass
2064 // Required to calculate accurate ETA for pass
2065 h->current_job->st_paused += hb_get_date() - h->pause_date;
2066 h->pause_date = -1;
2067 h->state.param.working.paused = h->pause_duration;
2068 }
2069
2070 hb_unlock( h->pause_lock );
2071 h->paused = 0;
2072 }
2073 }
2074
2075 /**
2076 * Stops the conversion process.
2077 * @param h Handle to hb_handle_t.
2078 */
hb_stop(hb_handle_t * h)2079 void hb_stop( hb_handle_t * h )
2080 {
2081 h->work_error = HB_ERROR_CANCELED;
2082 h->work_die = 1;
2083 hb_resume( h );
2084 }
2085
2086 /**
2087 * Stops the conversion process.
2088 * @param h Handle to hb_handle_t.
2089 */
hb_scan_stop(hb_handle_t * h)2090 void hb_scan_stop( hb_handle_t * h )
2091 {
2092 h->scan_die = 1;
2093 hb_resume( h );
2094 }
2095
2096 /**
2097 * Returns the state of the conversion process.
2098 * @param h Handle to hb_handle_t.
2099 * @param s Handle to hb_state_t which to copy the state data.
2100 */
hb_get_state(hb_handle_t * h,hb_state_t * s)2101 void hb_get_state( hb_handle_t * h, hb_state_t * s )
2102 {
2103 hb_lock( h->state_lock );
2104
2105 memcpy( s, &h->state, sizeof( hb_state_t ) );
2106 if ( h->state.state == HB_STATE_SCANDONE || h->state.state == HB_STATE_WORKDONE )
2107 h->state.state = HB_STATE_IDLE;
2108
2109 hb_unlock( h->state_lock );
2110 }
2111
hb_get_state2(hb_handle_t * h,hb_state_t * s)2112 void hb_get_state2( hb_handle_t * h, hb_state_t * s )
2113 {
2114 hb_lock( h->state_lock );
2115
2116 memcpy( s, &h->state, sizeof( hb_state_t ) );
2117
2118 hb_unlock( h->state_lock );
2119 }
2120
2121 /**
2122 * Closes access to libhb by freeing the hb_handle_t handle contained in hb_init.
2123 * @param _h Pointer to handle to hb_handle_t.
2124 */
hb_close(hb_handle_t ** _h)2125 void hb_close( hb_handle_t ** _h )
2126 {
2127 hb_handle_t * h = *_h;
2128 hb_title_t * title;
2129
2130 h->die = 1;
2131
2132 hb_thread_close( &h->main_thread );
2133
2134 while( ( title = hb_list_item( h->title_set.list_title, 0 ) ) )
2135 {
2136 hb_list_rem( h->title_set.list_title, title );
2137 hb_title_close( &title );
2138 }
2139 hb_list_close( &h->title_set.list_title );
2140 free((char*)h->title_set.path);
2141 h->title_set.path = NULL;
2142
2143 hb_list_close( &h->jobs );
2144 hb_lock_close( &h->state_lock );
2145 hb_lock_close( &h->pause_lock );
2146
2147 hb_system_sleep_opaque_close(&h->system_sleep_opaque);
2148
2149 free( h->interjob );
2150
2151 free( h );
2152 *_h = NULL;
2153 }
2154
hb_global_init_no_hardware()2155 int hb_global_init_no_hardware()
2156 {
2157 disable_hardware = 1;
2158 hb_log( "Init: Hardware encoders are disabled." );
2159 return hb_global_init();
2160 }
2161
hb_global_init()2162 int hb_global_init()
2163 {
2164 /* Print hardening status on global init */
2165 #if HB_PROJECT_SECURITY_HARDEN
2166 hb_log( "Compile-time hardening features are enabled" );
2167 #endif
2168
2169 int result = 0;
2170
2171 result = hb_platform_init();
2172 if (result < 0)
2173 {
2174 hb_error("Platform specific initialization failed!");
2175 return -1;
2176 }
2177
2178 #if HB_PROJECT_FEATURE_QSV
2179 if (!disable_hardware)
2180 {
2181 if (hb_qsv_available() < 0)
2182 {
2183 hb_error("hb_qsv_available failed!");
2184 return -1;
2185 }
2186 hb_param_configure_qsv();
2187 }
2188 #endif
2189
2190 /* libavcodec */
2191 hb_avcodec_init();
2192
2193 /* HB work objects */
2194 hb_register(&hb_muxer);
2195 hb_register(&hb_reader);
2196 hb_register(&hb_sync_video);
2197 hb_register(&hb_sync_audio);
2198 hb_register(&hb_sync_subtitle);
2199 hb_register(&hb_decavcodecv);
2200 hb_register(&hb_decavcodeca);
2201 hb_register(&hb_declpcm);
2202 hb_register(&hb_decavsub);
2203 hb_register(&hb_decsrtsub);
2204 hb_register(&hb_decssasub);
2205 hb_register(&hb_dectx3gsub);
2206 hb_register(&hb_encavcodec);
2207 hb_register(&hb_encavcodeca);
2208 #ifdef __APPLE__
2209 hb_register(&hb_encca_aac);
2210 hb_register(&hb_encca_haac);
2211 #endif
2212 hb_register(&hb_enctheora);
2213 hb_register(&hb_encvorbis);
2214 hb_register(&hb_encx264);
2215 #if HB_PROJECT_FEATURE_X265
2216 hb_register(&hb_encx265);
2217 #endif
2218 #if HB_PROJECT_FEATURE_QSV
2219 if (!disable_hardware)
2220 {
2221 hb_register(&hb_encqsv);
2222 }
2223 #endif
2224
2225 hb_x264_global_init();
2226 hb_common_global_init(disable_hardware);
2227
2228 /*
2229 * Initialise buffer pool
2230 */
2231 hb_buffer_pool_init();
2232
2233 // Initialize the builtin presets hb_dict_t
2234 hb_presets_builtin_init();
2235
2236 return result;
2237 }
2238
2239 /**
2240 * Cleans up libhb at a process level. Call before the app closes. Removes preview directory.
2241 */
hb_global_close()2242 void hb_global_close()
2243 {
2244 char * dirname;
2245 DIR * dir;
2246 struct dirent * entry;
2247
2248 hb_presets_free();
2249
2250 /* Find and remove temp folder */
2251 dirname = hb_get_temporary_directory();
2252
2253 dir = opendir( dirname );
2254 if (dir)
2255 {
2256 while( ( entry = readdir( dir ) ) )
2257 {
2258 char * filename;
2259 if( entry->d_name[0] == '.' )
2260 {
2261 continue;
2262 }
2263 filename = hb_strdup_printf("%s/%s", dirname, entry->d_name);
2264 unlink( filename );
2265 free(filename);
2266 }
2267 closedir( dir );
2268 rmdir( dirname );
2269 }
2270 free(dirname);
2271 }
2272
2273 /**
2274 * Monitors the state of the update, scan, and work threads.
2275 * Sets scan done state when scan thread exits.
2276 * Sets work done state when work thread exits.
2277 * @param _h Handle to hb_handle_t
2278 */
thread_func(void * _h)2279 static void thread_func( void * _h )
2280 {
2281 hb_handle_t * h = (hb_handle_t *) _h;
2282 char * dirname;
2283
2284 h->pid = getpid();
2285
2286 /* Create folder for temporary files */
2287 dirname = hb_get_temporary_directory();
2288
2289 hb_mkdir( dirname );
2290 free(dirname);
2291
2292 while( !h->die )
2293 {
2294 /* Check if the scan thread is done */
2295 if( h->scan_thread &&
2296 hb_thread_has_exited( h->scan_thread ) )
2297 {
2298 hb_thread_close( &h->scan_thread );
2299
2300 if ( h->scan_die )
2301 {
2302 hb_title_t * title;
2303
2304 hb_remove_previews( h );
2305 while( ( title = hb_list_item( h->title_set.list_title, 0 ) ) )
2306 {
2307 hb_list_rem( h->title_set.list_title, title );
2308 hb_title_close( &title );
2309 }
2310
2311 hb_log( "hb_scan: canceled" );
2312 }
2313 else
2314 {
2315 hb_log( "libhb: scan thread found %d valid title(s)",
2316 hb_list_count( h->title_set.list_title ) );
2317 }
2318 hb_lock( h->state_lock );
2319 h->state.state = HB_STATE_SCANDONE;
2320 hb_unlock( h->state_lock );
2321 }
2322
2323 /* Check if the work thread is done */
2324 if( h->work_thread &&
2325 hb_thread_has_exited( h->work_thread ) )
2326 {
2327 hb_thread_close( &h->work_thread );
2328
2329 hb_log( "libhb: work result = %d", h->work_error );
2330 hb_lock( h->state_lock );
2331 h->state.state = HB_STATE_WORKDONE;
2332 h->state.param.working.error = h->work_error;
2333
2334 hb_unlock( h->state_lock );
2335 }
2336
2337 if (h->paused)
2338 {
2339 h->state.param.working.paused = h->pause_duration +
2340 hb_get_date() - h->pause_date;
2341 }
2342 hb_snooze( 50 );
2343 }
2344
2345 if( h->scan_thread )
2346 {
2347 hb_scan_stop( h );
2348 hb_thread_close( &h->scan_thread );
2349 }
2350 if( h->work_thread )
2351 {
2352 hb_stop( h );
2353 hb_thread_close( &h->work_thread );
2354 }
2355 hb_remove_previews( h );
2356 }
2357
2358 /**
2359 * Redirects stderr to the registered callback
2360 * function.
2361 * @param _data Unused.
2362 */
redirect_thread_func(void * _data)2363 static void redirect_thread_func(void * _data)
2364 {
2365 int pfd[2];
2366 if (pipe(pfd))
2367 return;
2368 #if defined( SYS_MINGW )
2369 // dup2 doesn't work on windows for some stupid reason
2370 stderr->_file = pfd[1];
2371 #else
2372 dup2(pfd[1], /*stderr*/ 2);
2373 #endif
2374 FILE * log_f = fdopen(pfd[0], "rb");
2375
2376 char line_buffer[500];
2377 while(fgets(line_buffer, 500, log_f) != NULL)
2378 {
2379 hb_log_callback(line_buffer);
2380 }
2381 }
2382
2383 /**
2384 * Returns the PID.
2385 * @param h Handle to hb_handle_t
2386 */
hb_get_pid(hb_handle_t * h)2387 int hb_get_pid( hb_handle_t * h )
2388 {
2389 return h->pid;
2390 }
2391
2392 /**
2393 * Returns the id for the given instance.
2394 * @param h Handle to hb_handle_t
2395 * @returns The ID for the given instance
2396 */
hb_get_instance_id(hb_handle_t * h)2397 int hb_get_instance_id( hb_handle_t * h )
2398 {
2399 return h->id;
2400 }
2401
2402 /**
2403 * Sets the current state.
2404 * @param h Handle to hb_handle_t
2405 * @param s Handle to new hb_state_t
2406 */
hb_set_state(hb_handle_t * h,hb_state_t * s)2407 void hb_set_state( hb_handle_t * h, hb_state_t * s )
2408 {
2409 hb_lock( h->pause_lock );
2410 hb_lock( h->state_lock );
2411 memcpy( &h->state, s, sizeof( hb_state_t ) );
2412 if( h->state.state == HB_STATE_WORKING ||
2413 h->state.state == HB_STATE_SEARCHING )
2414 {
2415 // Set which job is being worked on
2416 if (h->current_job)
2417 h->state.sequence_id = h->current_job->sequence_id;
2418 }
2419 hb_unlock( h->state_lock );
2420 hb_unlock( h->pause_lock );
2421 }
2422
hb_set_work_error(hb_handle_t * h,hb_error_code err)2423 void hb_set_work_error( hb_handle_t * h, hb_error_code err )
2424 {
2425 h->work_error = err;
2426 }
2427
hb_system_sleep_allow(hb_handle_t * h)2428 void hb_system_sleep_allow(hb_handle_t *h)
2429 {
2430 hb_system_sleep_private_enable(h->system_sleep_opaque);
2431 }
2432
hb_system_sleep_prevent(hb_handle_t * h)2433 void hb_system_sleep_prevent(hb_handle_t *h)
2434 {
2435 hb_system_sleep_private_disable(h->system_sleep_opaque);
2436 }
2437
2438 /* Passes a pointer to persistent data */
hb_interjob_get(hb_handle_t * h)2439 hb_interjob_t * hb_interjob_get( hb_handle_t * h )
2440 {
2441 return h->interjob;
2442 }
2443
is_hardware_disabled(void)2444 int is_hardware_disabled(void){
2445 return disable_hardware;
2446 }
2447