3 Copyright (c) 2003-2015 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
14 #define MODE_DEFAULT 3
18 // degrees - Rotation angle, may be one of 90, 180, or 270
19 // mirror - Mirror image around x axis
22 // Mode 180:1 Mirror then rotate 180'
24 // Mode 180:0 Rotate 180'
25 // Mode 90:0 Rotate 90'
26 // Mode 270:0 Rotate 270'
28 // Legacy Mode Examples (also accepted):
29 // Mode 1: Flip vertically (y0 becomes yN and yN becomes y0) (aka 180:1)
30 // Mode 2: Flip horizontally (x0 becomes xN and xN becomes x0) (aka 0:1)
31 // Mode 3: Flip both horizontally and vertically (aka 180:0)
32 // Mode 4: Rotate 90' (aka 90:0)
33 // Mode 7: Flip horiz & vert plus Rotate 90' (aka 270:0)
35 typedef struct rotate_arguments_s
{
40 struct hb_filter_private_s
49 taskset_t rotate_taskset
; // Threads for Rotate - one per CPU
50 rotate_arguments_t
*rotate_arguments
; // Arguments to thread for work
53 static int hb_rotate_init( hb_filter_object_t
* filter
,
54 hb_filter_init_t
* init
);
56 static int hb_rotate_work( hb_filter_object_t
* filter
,
57 hb_buffer_t
** buf_in
,
58 hb_buffer_t
** buf_out
);
60 static void hb_rotate_close( hb_filter_object_t
* filter
);
62 static int hb_rotate_info( hb_filter_object_t
* filter
,
63 hb_filter_info_t
* info
);
65 hb_filter_object_t hb_filter_rotate
=
67 .id
= HB_FILTER_ROTATE
,
69 .name
= "Rotate (rotate & flip image axes)",
71 .init
= hb_rotate_init
,
72 .work
= hb_rotate_work
,
73 .close
= hb_rotate_close
,
74 .info
= hb_rotate_info
78 typedef struct rotate_thread_arg_s
{
79 hb_filter_private_t
*pv
;
81 } rotate_thread_arg_t
;
84 * rotate this segment of all three planes in a single thread.
86 void rotate_filter_thread( void *thread_args_v
)
88 rotate_arguments_t
*rotate_work
= NULL
;
89 hb_filter_private_t
* pv
;
92 int segment
, segment_start
, segment_stop
;
93 rotate_thread_arg_t
*thread_args
= thread_args_v
;
100 pv
= thread_args
->pv
;
101 segment
= thread_args
->segment
;
103 hb_log("Rotate thread started for segment %d", segment
);
108 * Wait here until there is work to do.
110 taskset_thread_wait4start( &pv
->rotate_taskset
, segment
);
112 if( taskset_thread_stop( &pv
->rotate_taskset
, segment
) )
115 * No more work to do, exit this thread.
118 goto report_completion
;
121 rotate_work
= &pv
->rotate_arguments
[segment
];
122 if( rotate_work
->dst
== NULL
)
124 hb_error( "Thread started when no work available" );
126 goto report_completion
;
130 * Process all three planes, but only this segment of it.
132 dst_buf
= rotate_work
->dst
;
133 src_buf
= rotate_work
->src
;
134 for( plane
= 0; plane
< 3; plane
++)
136 int dst_stride
, src_stride
;
138 dst
= dst_buf
->plane
[plane
].data
;
139 dst_stride
= dst_buf
->plane
[plane
].stride
;
140 src_stride
= src_buf
->plane
[plane
].stride
;
142 int h
= src_buf
->plane
[plane
].height
;
143 int w
= src_buf
->plane
[plane
].width
;
144 segment_start
= ( h
/ pv
->cpu_count
) * segment
;
145 if( segment
== pv
->cpu_count
- 1 )
152 segment_stop
= ( h
/ pv
->cpu_count
) * ( segment
+ 1 );
155 for( y
= segment_start
; y
< segment_stop
; y
++ )
160 cur
= &src_buf
->plane
[plane
].data
[y
* src_stride
];
161 for( x
= 0; x
< w
; x
++)
179 if( pv
->mode
& 4 ) // Rotate 90 clockwise
185 dst
[yo
*dst_stride
+ xo
] = cur
[x
];
192 * Finished this segment, let everyone know.
194 taskset_thread_complete( &pv
->rotate_taskset
, segment
);
200 * threaded rotate - each thread rotates a single segment of all
201 * three planes. Where a segment is defined as the frame divided by
202 * the number of CPUs.
204 * This function blocks until the frame is rotated.
206 static void rotate_filter(
207 hb_filter_private_t
* pv
,
214 for( segment
= 0; segment
< pv
->cpu_count
; segment
++ )
217 * Setup the work for this plane.
219 pv
->rotate_arguments
[segment
].dst
= out
;
220 pv
->rotate_arguments
[segment
].src
= in
;
224 * Allow the taskset threads to make one pass over the data.
226 taskset_cycle( &pv
->rotate_taskset
);
229 * Entire frame is now rotated.
234 static int hb_rotate_init( hb_filter_object_t
* filter
,
235 hb_filter_init_t
* init
)
237 filter
->private_data
= calloc( 1, sizeof(struct hb_filter_private_s
) );
238 hb_filter_private_t
* pv
= filter
->private_data
;
240 int degrees
= MODE_DEFAULT
, mirror
= 0, num_params
= 0;
242 if( filter
->settings
)
244 num_params
= sscanf(filter
->settings
, "%d:%d", °rees
, &mirror
);
263 // Unsupported rotation angle
264 hb_error("Unsupported rotate mode %d", degrees
);
266 // Legacy "mode" supplied in settings
267 pv
->mode
= degrees
& 7;
270 if (num_params
> 1 && mirror
)
273 pv
->cpu_count
= hb_get_cpu_count();
276 * Create rotate taskset.
278 pv
->rotate_arguments
= malloc( sizeof( rotate_arguments_t
) * pv
->cpu_count
);
279 if( pv
->rotate_arguments
== NULL
||
280 taskset_init( &pv
->rotate_taskset
, /*thread_count*/pv
->cpu_count
,
281 sizeof( rotate_thread_arg_t
) ) == 0 )
283 hb_error( "rotate could not initialize taskset" );
287 for( i
= 0; i
< pv
->cpu_count
; i
++ )
289 rotate_thread_arg_t
*thread_args
;
291 thread_args
= taskset_thread_args( &pv
->rotate_taskset
, i
);
293 thread_args
->pv
= pv
;
294 thread_args
->segment
= i
;
295 pv
->rotate_arguments
[i
].dst
= NULL
;
297 if( taskset_thread_spawn( &pv
->rotate_taskset
, i
,
298 "rotate_filter_segment",
299 rotate_filter_thread
,
300 HB_NORMAL_PRIORITY
) == 0 )
302 hb_error( "rotate could not spawn thread" );
305 // Set init width/height so the next stage in the pipline
306 // knows what it will be getting
309 // 90 degree rotation, exchange width and height
310 int tmp
= init
->geometry
.width
;
311 init
->geometry
.width
= init
->geometry
.height
;
312 init
->geometry
.height
= tmp
;
314 tmp
= init
->geometry
.par
.num
;
315 init
->geometry
.par
.num
= init
->geometry
.par
.den
;
316 init
->geometry
.par
.den
= tmp
;
318 pv
->width
= init
->geometry
.width
;
319 pv
->height
= init
->geometry
.height
;
320 pv
->par
= init
->geometry
.par
;
325 static int hb_rotate_info( hb_filter_object_t
* filter
,
326 hb_filter_info_t
* info
)
328 hb_filter_private_t
* pv
= filter
->private_data
;
332 memset( info
, 0, sizeof( hb_filter_info_t
) );
333 info
->out
.geometry
.width
= pv
->width
;
334 info
->out
.geometry
.height
= pv
->height
;
335 info
->out
.geometry
.par
= pv
->par
;
338 int mirror_x
= !!(pv
->mode
& 2);
339 int mirror_y
= !!(pv
->mode
& 1);
347 degrees
+= !!(pv
->mode
& 4) * 90;
351 sprintf(&info
->human_readable_desc
[pos
], "Rotate %d%s", degrees
,
352 mirror_x
? " / mirror image" : "");
356 sprintf(&info
->human_readable_desc
[pos
], "Mirror image");
360 sprintf(&info
->human_readable_desc
[pos
], "No rotation or mirror!");
365 static void hb_rotate_close( hb_filter_object_t
* filter
)
367 hb_filter_private_t
* pv
= filter
->private_data
;
374 taskset_fini( &pv
->rotate_taskset
);
377 * free memory for rotate structs
379 free( pv
->rotate_arguments
);
382 filter
->private_data
= NULL
;
385 static int hb_rotate_work( hb_filter_object_t
* filter
,
386 hb_buffer_t
** buf_in
,
387 hb_buffer_t
** buf_out
)
389 hb_filter_private_t
* pv
= filter
->private_data
;
390 hb_buffer_t
* in
= *buf_in
, * out
;
392 if (in
->s
.flags
& HB_BUF_FLAG_EOF
)
396 return HB_FILTER_DONE
;
400 // Short circuit case where filter does nothing
406 int width_out
, height_out
;
409 width_out
= in
->f
.height
;
410 height_out
= in
->f
.width
;
414 width_out
= in
->f
.width
;
415 height_out
= in
->f
.height
;
418 out
= hb_video_buffer_init( width_out
, height_out
);
421 rotate_filter( pv
, out
, in
);
423 hb_buffer_move_subs( out
, in
);