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