OSDN Git Service

Remove the set cpu count option as it doesn't do anything now
[handbrake-jp/handbrake-jp-git.git] / libhb / rotate.c
1
2 #include "hb.h"
3 #include "hbffmpeg.h"
4 //#include "mpeg2dec/mpeg2.h"
5
6 #define MODE_DEFAULT     3
7 // Mode 1: Flip vertically (y0 becomes yN and yN becomes y0)
8 // Mode 2: Flip horizontally (x0 becomes xN and xN becomes x0)
9 // Mode 3: Flip both horizontally and vertically (modes 1 and 2 combined)
10
11 typedef struct rotate_arguments_s {
12     uint8_t **dst;
13     int stop;
14 } rotate_arguments_t;
15
16 struct hb_filter_private_s
17 {
18     int              pix_fmt;
19     int              width[3];
20     int              height[3];
21
22     int              mode;
23
24     int              ref_stride[3];
25
26     int              cpu_count;
27
28     hb_thread_t    ** rotate_threads;        // Threads for Rotate - one per CPU
29     hb_lock_t      ** rotate_begin_lock;     // Thread has work
30     hb_lock_t      ** rotate_complete_lock;  // Thread has completed work
31     rotate_arguments_t *rotate_arguments;     // Arguments to thread for work
32
33     AVPicture        pic_in;
34     AVPicture        pic_out;
35     hb_buffer_t *    buf_out;
36     hb_buffer_t *    buf_settings;
37 };
38
39 hb_filter_private_t * hb_rotate_init( int pix_fmt,
40                                            int width,
41                                            int height,
42                                            char * settings );
43
44 int hb_rotate_work( hb_buffer_t * buf_in,
45                          hb_buffer_t ** buf_out,
46                          int pix_fmt,
47                          int width,
48                          int height,
49                          hb_filter_private_t * pv );
50
51 void hb_rotate_close( hb_filter_private_t * pv );
52
53 hb_filter_object_t hb_filter_rotate =
54 {
55     FILTER_ROTATE,
56     "Rotate (flips image axes)",
57     NULL,
58     hb_rotate_init,
59     hb_rotate_work,
60     hb_rotate_close,
61 };
62
63
64 static void rotate_filter_line( uint8_t *dst,
65                                uint8_t *cur,
66                                int plane,
67                                hb_filter_private_t * pv )
68 {
69
70     int w = pv->width[plane];
71
72     int x;
73     for( x = 0; x < w; x++)
74     {
75         if( pv->mode & 2 )
76         {
77             dst[x] = cur[w-x-1];
78         }
79         else
80         {
81             dst[x] = cur[x];
82         }
83     }
84 }
85
86 typedef struct rotate_thread_arg_s {
87     hb_filter_private_t *pv;
88     int segment;
89 } rotate_thread_arg_t;
90
91 /*
92  * rotate this segment of all three planes in a single thread.
93  */
94 void rotate_filter_thread( void *thread_args_v )
95 {
96     rotate_arguments_t *rotate_work = NULL;
97     hb_filter_private_t * pv;
98     int run = 1;
99     int plane;
100     int segment, segment_start, segment_stop;
101     rotate_thread_arg_t *thread_args = thread_args_v;
102     uint8_t **dst;
103     int y, w, h, ref_stride;
104
105
106     pv = thread_args->pv;
107     segment = thread_args->segment;
108
109     hb_log("Rotate thread started for segment %d", segment);
110
111     while( run )
112     {
113         /*
114          * Wait here until there is work to do. hb_lock() blocks until
115          * render releases it to say that there is more work to do.
116          */
117         hb_lock( pv->rotate_begin_lock[segment] );
118
119         rotate_work = &pv->rotate_arguments[segment];
120
121         if( rotate_work->stop )
122         {
123             /*
124              * No more work to do, exit this thread.
125              */
126             run = 0;
127             continue;
128         } 
129
130         if( rotate_work->dst == NULL )
131         {
132             hb_error( "Thread started when no work available" );
133             hb_snooze(500);
134             continue;
135         }
136         
137         /*
138          * Process all three planes, but only this segment of it.
139          */
140         for( plane = 0; plane < 3; plane++)
141         {
142
143             dst = rotate_work->dst;
144             w = pv->width[plane];
145             h = pv->height[plane];
146             ref_stride = pv->ref_stride[plane];
147             segment_start = ( h / pv->cpu_count ) * segment;
148             if( segment == pv->cpu_count - 1 )
149             {
150                 /*
151                  * Final segment
152                  */
153                 segment_stop = h;
154             } else {
155                 segment_stop = ( h / pv->cpu_count ) * ( segment + 1 );
156             }
157
158             for( y = segment_start; y < segment_stop; y++ )
159             {
160                 uint8_t * cur;
161                 
162                 if( pv->mode & 1 )
163                 {
164                     cur  = &pv->pic_in.data[plane][(h-y-1)*pv->pic_in.linesize[plane]];
165                 }
166                 else
167                 {
168                     cur  = &pv->pic_in.data[plane][(y)*pv->pic_in.linesize[plane]];
169                 }
170                 uint8_t *dst2 = &dst[plane][y*w];
171
172                 rotate_filter_line( dst2, 
173                                    cur, 
174                                    plane, 
175                                    pv );
176             }
177         }
178         /*
179          * Finished this segment, let everyone know.
180          */
181         hb_unlock( pv->rotate_complete_lock[segment] );
182     }
183     free( thread_args_v );
184 }
185
186
187 /*
188  * threaded rotate - each thread rptates a single segment of all
189  * three planes. Where a segment is defined as the frame divided by
190  * the number of CPUs.
191  *
192  * This function blocks until the frame is rotated.
193  */
194 static void rotate_filter( uint8_t ** dst,
195                           hb_filter_private_t * pv )
196 {
197
198     int segment;
199     
200     for( segment = 0; segment < pv->cpu_count; segment++ )
201     {  
202         /*
203          * Setup the work for this plane.
204          */
205         pv->rotate_arguments[segment].dst = dst;
206
207         /*
208          * Let the thread for this plane know that we've setup work 
209          * for it by releasing the begin lock (ensuring that the
210          * complete lock is already locked so that we block when
211          * we try to lock it again below).
212          */
213         hb_lock( pv->rotate_complete_lock[segment] );
214         hb_unlock( pv->rotate_begin_lock[segment] );
215     }
216
217     /*
218      * Wait until all three threads have completed by trying to get
219      * the complete lock that we locked earlier for each thread, which
220      * will block until that thread has completed the work on that
221      * plane.
222      */
223     for( segment = 0; segment < pv->cpu_count; segment++ )
224     {
225         hb_lock( pv->rotate_complete_lock[segment] );
226         hb_unlock( pv->rotate_complete_lock[segment] );
227     }
228
229     /*
230      * Entire frame is now rotated.
231      */
232 }
233
234
235 hb_filter_private_t * hb_rotate_init( int pix_fmt,
236                                            int width,
237                                            int height,
238                                            char * settings )
239 {
240     if( pix_fmt != PIX_FMT_YUV420P )
241     {
242         return 0;
243     }
244
245     hb_filter_private_t * pv = calloc( 1, sizeof(struct hb_filter_private_s) );
246
247     pv->pix_fmt = pix_fmt;
248
249     pv->width[0]  = width;
250     pv->height[0] = height;
251     pv->width[1]  = pv->width[2]  = width >> 1;
252     pv->height[1] = pv->height[2] = height >> 1;
253
254     pv->buf_out = hb_video_buffer_init( width, height );
255     pv->buf_settings = hb_buffer_init( 0 );
256
257     pv->mode     = MODE_DEFAULT;
258
259     pv->ref_stride[0] = pv->width[0];
260     pv->ref_stride[1] = pv->width[1];
261     pv->ref_stride[2] = pv->width[2];
262     
263     if( settings )
264     {
265         sscanf( settings, "%d",
266                 &pv->mode );
267     }
268
269     pv->cpu_count = hb_get_cpu_count();
270
271
272     /*
273      * Create threads and locks.
274      */
275     pv->rotate_threads = malloc( sizeof( hb_thread_t* ) * pv->cpu_count );
276     pv->rotate_begin_lock = malloc( sizeof( hb_lock_t * ) * pv->cpu_count );
277     pv->rotate_complete_lock = malloc( sizeof( hb_lock_t * ) * pv->cpu_count );
278     pv->rotate_arguments = malloc( sizeof( rotate_arguments_t ) * pv->cpu_count );
279
280     int i;
281     for( i = 0; i < pv->cpu_count; i++ )
282     {
283         rotate_thread_arg_t *thread_args;
284     
285         thread_args = malloc( sizeof( rotate_thread_arg_t ) );
286     
287         if( thread_args ) {
288             thread_args->pv = pv;
289             thread_args->segment = i;
290     
291             pv->rotate_begin_lock[i] = hb_lock_init();
292             pv->rotate_complete_lock[i] = hb_lock_init();
293     
294             /*
295              * Important to start off with the threads locked waiting
296              * on input.
297              */
298             hb_lock( pv->rotate_begin_lock[i] );
299     
300             pv->rotate_arguments[i].stop = 0;
301             pv->rotate_arguments[i].dst = NULL;
302             
303             pv->rotate_threads[i] = hb_thread_init( "rotate_filter_segment",
304                                                    rotate_filter_thread,
305                                                    thread_args,
306                                                    HB_NORMAL_PRIORITY );
307         } else {
308             hb_error( "rotate could not create threads" );
309         }
310     }
311
312     return pv;
313 }
314
315 void hb_rotate_close( hb_filter_private_t * pv )
316 {
317     if( !pv )
318     {
319         return;
320     }
321
322     /* Cleanup frame buffers */
323     if( pv->buf_out )
324     {
325         hb_buffer_close( &pv->buf_out );
326     }
327     if (pv->buf_settings )
328     {
329         hb_buffer_close( &pv->buf_settings );
330     }
331
332     int i;
333     for( i = 0; i < pv->cpu_count; i++)
334     {
335         /*
336          * Tell each rotate thread to stop, and then cleanup.
337          */
338         pv->rotate_arguments[i].stop = 1;
339         hb_unlock(  pv->rotate_begin_lock[i] );
340     
341         hb_thread_close( &pv->rotate_threads[i] );
342         hb_lock_close( &pv->rotate_begin_lock[i] );
343         hb_lock_close( &pv->rotate_complete_lock[i] );
344     }
345     
346     /*
347      * free memory for rotate structs
348      */
349     free( pv->rotate_threads );
350     free( pv->rotate_begin_lock );
351     free( pv->rotate_complete_lock );
352     free( pv->rotate_arguments );
353
354     free( pv );
355 }
356
357 int hb_rotate_work( hb_buffer_t * buf_in,
358                          hb_buffer_t ** buf_out,
359                          int pix_fmt,
360                          int width,
361                          int height,
362                          hb_filter_private_t * pv )
363 {
364     if( !pv ||
365         pix_fmt != pv->pix_fmt ||
366         width   != pv->width[0] ||
367         height  != pv->height[0] )
368     {
369         return FILTER_FAILED;
370     }
371
372     avpicture_fill( &pv->pic_in, buf_in->data,
373                     pix_fmt, width, height );
374
375     avpicture_fill( &pv->pic_out, pv->buf_out->data,
376                         pix_fmt, width, height );
377
378     //do stuff here
379     rotate_filter( pv->pic_out.data, pv );
380     hb_buffer_copy_settings( pv->buf_out, buf_in );
381     
382     *buf_out = pv->buf_out;
383     
384     return FILTER_OK;
385 }
386
387