1 /*****************************************************************************
2 * crop.c: crop video filter
3 *****************************************************************************
4 * Copyright (C) 2010-2014 x264 project
5 *
6 * Authors: Steven Walters <kemuri9@gmail.com>
7 * James Darnley <james.darnley@gmail.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
22 *
23 * This program is also available under a commercial proprietary license.
24 * For more information, contact us at licensing@x264.com.
25 *****************************************************************************/
26
27 #include "video.h"
28 #define NAME "crop"
29
30 #define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, NAME, __VA_ARGS__ )
31
32 cli_vid_filter_t crop_filter;
33
34 typedef struct
35 {
36 hnd_t prev_hnd;
37 cli_vid_filter_t prev_filter;
38
39 int dims[4]; /* left, top, width, height */
40 const x264_cli_csp_t *csp;
41 } crop_hnd_t;
42
help(int longhelp)43 static void help( int longhelp )
44 {
45 printf( " "NAME":left,top,right,bottom\n" );
46 if( !longhelp )
47 return;
48 printf( " removes pixels from the edges of the frame\n" );
49 }
50
init(hnd_t * handle,cli_vid_filter_t * filter,video_info_t * info,x264_param_t * param,char * opt_string)51 static int init( hnd_t *handle, cli_vid_filter_t *filter, video_info_t *info, x264_param_t *param, char *opt_string )
52 {
53 crop_hnd_t *h;
54 static const char *optlist[] = { "left", "top", "right", "bottom", NULL };
55 char **opts;
56 int i;
57
58 FAIL_IF_ERROR( x264_cli_csp_is_invalid( info->csp ), "invalid csp %d\n", info->csp )
59
60 h = calloc( 1, sizeof(crop_hnd_t) );
61 if( !h )
62 return -1;
63
64 h->csp = x264_cli_get_csp( info->csp );
65 opts = x264_split_options( opt_string, optlist );
66 if( !opts )
67 return -1;
68 for( i = 0; i < 4; i++ )
69 {
70 char *opt = x264_get_option( optlist[i], opts );
71 int dim_mod;
72
73 FAIL_IF_ERROR( !opt, "%s crop value not specified\n", optlist[i] )
74
75 h->dims[i] = x264_otoi( opt, -1 );
76 FAIL_IF_ERROR( h->dims[i] < 0, "%s crop value `%s' is less than 0\n", optlist[i], opt )
77 dim_mod = i&1 ? (h->csp->mod_height << info->interlaced) : h->csp->mod_width;
78 FAIL_IF_ERROR( h->dims[i] % dim_mod, "%s crop value `%s' is not a multiple of %d\n", optlist[i], opt, dim_mod )
79 }
80 x264_free_string_array( opts );
81 h->dims[2] = info->width - h->dims[0] - h->dims[2];
82 h->dims[3] = info->height - h->dims[1] - h->dims[3];
83 FAIL_IF_ERROR( h->dims[2] <= 0 || h->dims[3] <= 0, "invalid output resolution %dx%d\n", h->dims[2], h->dims[3] )
84
85 if( info->width != h->dims[2] || info->height != h->dims[3] )
86 x264_cli_log( NAME, X264_LOG_INFO, "cropping to %dx%d\n", h->dims[2], h->dims[3] );
87 else
88 {
89 /* do nothing as the user supplied 0s for all the values */
90 free( h );
91 return 0;
92 }
93 /* done initializing, overwrite values */
94 info->width = h->dims[2];
95 info->height = h->dims[3];
96
97 h->prev_filter = *filter;
98 h->prev_hnd = *handle;
99 *handle = h;
100 *filter = crop_filter;
101
102 return 0;
103 }
104
get_frame(hnd_t handle,cli_pic_t * output,int frame)105 static int get_frame( hnd_t handle, cli_pic_t *output, int frame )
106 {
107 crop_hnd_t *h = handle;
108 int i;
109
110 if( h->prev_filter.get_frame( h->prev_hnd, output, frame ) )
111 return -1;
112 output->img.width = h->dims[2];
113 output->img.height = h->dims[3];
114 /* shift the plane pointers down 'top' rows and right 'left' columns. */
115 for( i = 0; i < output->img.planes; i++ )
116 {
117 intptr_t offset = output->img.stride[i] * h->dims[1] * h->csp->height[i];
118 offset += h->dims[0] * h->csp->width[i] * x264_cli_csp_depth_factor( output->img.csp );
119 output->img.plane[i] += offset;
120 }
121 return 0;
122 }
123
release_frame(hnd_t handle,cli_pic_t * pic,int frame)124 static int release_frame( hnd_t handle, cli_pic_t *pic, int frame )
125 {
126 crop_hnd_t *h = handle;
127 /* NO filter should ever have a dependent release based on the plane pointers,
128 * so avoid unnecessary unshifting */
129 return h->prev_filter.release_frame( h->prev_hnd, pic, frame );
130 }
131
free_filter(hnd_t handle)132 static void free_filter( hnd_t handle )
133 {
134 crop_hnd_t *h = handle;
135 h->prev_filter.free( h->prev_hnd );
136 free( h );
137 }
138
139 cli_vid_filter_t crop_filter = { NAME, help, init, get_frame, release_frame, free_filter, NULL };
140