+ if (data->stream)
+ {
+ hb_stream_close(&data->stream);
+ }
+ if( data->batch )
+ {
+ hb_batch_close( &data->batch );
+ }
+ free( data->path );
+ free( data );
+ _data = NULL;
+}
+
+// -----------------------------------------------
+// stuff related to cropping
+
+#define DARK 32
+
+static inline int absdiff( int x, int y )
+{
+ return x < y ? y - x : x - y;
+}
+
+static inline int clampBlack( int x )
+{
+ // luma 'black' is 16 and anything less should be clamped at 16
+ return x < 16 ? 16 : x;
+}
+
+static int row_all_dark( hb_title_t *title, uint8_t* luma, int row )
+{
+ luma += title->width * row;
+
+ // compute the average luma value of the row
+ int i, avg = 0;
+ for ( i = 0; i < title->width; ++i )
+ {
+ avg += clampBlack( luma[i] );
+ }
+ avg /= title->width;
+ if ( avg >= DARK )
+ return 0;
+
+ // since we're trying to detect smooth borders, only take the row if
+ // all pixels are within +-16 of the average (this range is fairly coarse
+ // but there's a lot of quantization noise for luma values near black
+ // so anything less will fail to crop because of the noise).
+ for ( i = 0; i < title->width; ++i )
+ {
+ if ( absdiff( avg, clampBlack( luma[i] ) ) > 16 )
+ return 0;
+ }
+ return 1;
+}
+
+static int column_all_dark( hb_title_t *title, uint8_t* luma, int top, int bottom,
+ int col )
+{
+ int stride = title->width;
+ int height = title->height - top - bottom;
+ luma += stride * top + col;
+
+ // compute the average value of the column
+ int i = height, avg = 0, row = 0;
+ for ( ; --i >= 0; row += stride )
+ {
+ avg += clampBlack( luma[row] );
+ }
+ avg /= height;
+ if ( avg >= DARK )
+ return 0;
+
+ // since we're trying to detect smooth borders, only take the column if
+ // all pixels are within +-16 of the average.
+ i = height, row = 0;
+ for ( ; --i >= 0; row += stride )
+ {
+ if ( absdiff( avg, clampBlack( luma[row] ) ) > 16 )
+ return 0;
+ }
+ return 1;
+}
+#undef DARK
+
+typedef struct {
+ int n;
+ int t[HB_MAX_PREVIEWS];
+ int b[HB_MAX_PREVIEWS];
+ int l[HB_MAX_PREVIEWS];
+ int r[HB_MAX_PREVIEWS];
+} crop_record_t;
+
+static void record_crop( crop_record_t *crops, int t, int b, int l, int r )
+{
+ crops->t[crops->n] = t;
+ crops->b[crops->n] = b;
+ crops->l[crops->n] = l;
+ crops->r[crops->n] = r;
+ ++crops->n;
+}
+
+static int compare_int( const void *a, const void *b )
+{
+ return *(const int *)a - *(const int *)b;
+}
+
+static void sort_crops( crop_record_t *crops )
+{
+ qsort( crops->t, crops->n, sizeof(crops->t[0]), compare_int );
+ qsort( crops->b, crops->n, sizeof(crops->t[0]), compare_int );
+ qsort( crops->l, crops->n, sizeof(crops->t[0]), compare_int );
+ qsort( crops->r, crops->n, sizeof(crops->t[0]), compare_int );
+}
+
+// -----------------------------------------------
+// stuff related to title width/height/aspect info
+
+typedef struct {
+ int count; /* number of times we've seen this info entry */
+ hb_work_info_t info; /* copy of info entry */
+} info_list_t;
+
+static void remember_info( info_list_t *info_list, hb_work_info_t *info )
+{
+ for ( ; info_list->count; ++info_list )
+ {
+ if ( memcmp( &info_list->info, info, sizeof(*info) ) == 0 )
+ {
+ // we found a match - bump its count
+ ++info_list->count;
+ return;
+ }
+ }
+ // no match found - add new entry to list (info_list points to
+ // the first free slot). NB - we assume that info_list was allocated
+ // so that it's big enough even if there are no dups. I.e., 10 slots
+ // allocated if there are 10 previews.
+ info_list->count = 1;
+ info_list->info = *info;
+}
+
+static void most_common_info( info_list_t *info_list, hb_work_info_t *info )
+{
+ int i, biggest = 0;
+ for ( i = 1; info_list[i].count; ++i )
+ {
+ if ( info_list[i].count > info_list[biggest].count )
+ biggest = i;
+ }
+ *info = info_list[biggest].info;
+ free( info_list );