]> git.sesse.net Git - x264/blob - filters/video/crop.c
Add video filtering system to x264cli
[x264] / filters / video / crop.c
1 /*****************************************************************************
2  * crop.c: x264 crop video filter
3  *****************************************************************************
4  * Copyright (C) 2010 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
24 #include "video.h"
25 #define NAME "crop"
26 #define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, NAME, __VA_ARGS__ )
27
28 cli_vid_filter_t crop_filter;
29
30 typedef struct
31 {
32     hnd_t prev_hnd;
33     cli_vid_filter_t prev_filter;
34
35     int dims[4]; /* left, top, width, height */
36     const x264_cli_csp_t *csp;
37 } crop_hnd_t;
38
39 static void help( int longhelp )
40 {
41     printf( "      "NAME":left,top,right,bottom\n" );
42     if( !longhelp )
43         return;
44     printf( "            removes pixels from the edges of the frame\n" );
45 }
46
47 static int init( hnd_t *handle, cli_vid_filter_t *filter, video_info_t *info, x264_param_t *param, char *opt_string )
48 {
49     FAIL_IF_ERROR( x264_cli_csp_is_invalid( info->csp ), "invalid csp %d\n", info->csp )
50     crop_hnd_t *h = calloc( 1, sizeof(crop_hnd_t) );
51     if( !h )
52         return -1;
53
54     h->csp = x264_cli_get_csp( info->csp );
55     static const char *optlist[] = { "left", "top", "right", "bottom", NULL };
56     char **opts = x264_split_options( opt_string, optlist );
57     if( !opts )
58         return -1;
59
60     for( int i = 0; i < 4; i++ )
61     {
62         char *opt = x264_get_option( optlist[i], opts );
63         FAIL_IF_ERROR( !opt, "%s crop value not specified\n", optlist[i] )
64         h->dims[i] = x264_otoi( opt, -1 );
65         FAIL_IF_ERROR( h->dims[i] < 0, "%s crop value `%s' is less than 0\n", optlist[i], opt )
66         int dim_mod = i&1 ? (h->csp->mod_height << info->interlaced) : h->csp->mod_width;
67         FAIL_IF_ERROR( h->dims[i] % dim_mod, "%s crop value `%s' is not a multiple of %d\n", optlist[i], opt, dim_mod )
68     }
69     x264_free_string_array( opts );
70     h->dims[2] = info->width  - h->dims[0] - h->dims[2];
71     h->dims[3] = info->height - h->dims[1] - h->dims[3];
72     FAIL_IF_ERROR( h->dims[2] <= 0 || h->dims[3] <= 0, "invalid output resolution %dx%d\n", h->dims[2], h->dims[3] )
73
74     if( info->width != h->dims[2] || info->height != h->dims[3] )
75         x264_cli_log( NAME, X264_LOG_INFO, "cropping to %dx%d\n", h->dims[2], h->dims[3] );
76     else
77     {
78         /* do nothing as the user supplied 0s for all the values */
79         free( h );
80         return 0;
81     }
82     /* done initializing, overwrite values */
83     info->width  = h->dims[2];
84     info->height = h->dims[3];
85
86     h->prev_filter = *filter;
87     h->prev_hnd = *handle;
88     *handle = h;
89     *filter = crop_filter;
90
91     return 0;
92 }
93
94 static int get_frame( hnd_t handle, cli_pic_t *output, int frame )
95 {
96     crop_hnd_t *h = handle;
97     if( h->prev_filter.get_frame( h->prev_hnd, output, frame ) )
98         return -1;
99     output->img.width  = h->dims[2];
100     output->img.height = h->dims[3];
101     /* shift the plane pointers down 'top' rows and right 'left' columns. */
102     for( int i = 0; i < output->img.planes; i++ )
103         output->img.plane[i] += (int)(output->img.stride[i] * h->dims[1] * h->csp->height[i]
104                                     + h->dims[0] * h->csp->width[i]);
105     return 0;
106 }
107
108 static int release_frame( hnd_t handle, cli_pic_t *pic, int frame )
109 {
110     crop_hnd_t *h = handle;
111     /* NO filter should ever have a dependent release based on the plane pointers,
112      * so avoid unnecessary unshifting */
113     return h->prev_filter.release_frame( h->prev_hnd, pic, frame );
114 }
115
116 static void free_filter( hnd_t handle )
117 {
118     crop_hnd_t *h = handle;
119     h->prev_filter.free( h->prev_hnd );
120     free( h );
121 }
122
123 cli_vid_filter_t crop_filter = { NAME, help, init, get_frame, release_frame, free_filter, NULL };