OSDN Git Service

Adds a very crude, CLI-only rotation filter to flip pixels vertically (mode 1), horiz...
authorjbrjake <jbrjake@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Sat, 19 Dec 2009 15:19:12 +0000 (15:19 +0000)
committerjbrjake <jbrjake@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Sat, 19 Dec 2009 15:19:12 +0000 (15:19 +0000)
git-svn-id: svn://localhost/HandBrake/trunk@3036 b64f7644-9d1e-0410-96f1-a4d463321fa5

libhb/common.h
libhb/internal.h
libhb/rotate.c [new file with mode: 0644]
test/test.c

index d760222..57447b0 100644 (file)
@@ -732,6 +732,7 @@ extern hb_filter_object_t hb_filter_deinterlace;
 extern hb_filter_object_t hb_filter_deblock;
 extern hb_filter_object_t hb_filter_denoise;
 extern hb_filter_object_t hb_filter_decomb;
+extern hb_filter_object_t hb_filter_rotate;
 
 typedef void hb_error_handler_t( const char *errmsg );
 
index efe18fa..ada06b6 100644 (file)
@@ -307,7 +307,8 @@ enum
     FILTER_DEBLOCK,
     FILTER_DENOISE,
     FILTER_DETELECINE,
-    FILTER_DECOMB
+    FILTER_DECOMB,
+    FILTER_ROTATE
 };
 
 extern hb_work_object_t * hb_objects;
diff --git a/libhb/rotate.c b/libhb/rotate.c
new file mode 100644 (file)
index 0000000..efa825a
--- /dev/null
@@ -0,0 +1,387 @@
+
+#include "hb.h"
+#include "hbffmpeg.h"
+//#include "mpeg2dec/mpeg2.h"
+
+#define MODE_DEFAULT     3
+// Mode 1: Flip vertically (y0 becomes yN and yN becomes y0)
+// Mode 2: Flip horizontally (x0 becomes xN and xN becomes x0)
+// Mode 3: Flip both horizontally and vertically (modes 1 and 2 combined)
+
+typedef struct rotate_arguments_s {
+    uint8_t **dst;
+    int stop;
+} rotate_arguments_t;
+
+struct hb_filter_private_s
+{
+    int              pix_fmt;
+    int              width[3];
+    int              height[3];
+
+    int              mode;
+
+    int              ref_stride[3];
+
+    int              cpu_count;
+
+    hb_thread_t    ** rotate_threads;        // Threads for Rotate - one per CPU
+    hb_lock_t      ** rotate_begin_lock;     // Thread has work
+    hb_lock_t      ** rotate_complete_lock;  // Thread has completed work
+    rotate_arguments_t *rotate_arguments;     // Arguments to thread for work
+
+    AVPicture        pic_in;
+    AVPicture        pic_out;
+    hb_buffer_t *    buf_out;
+    hb_buffer_t *    buf_settings;
+};
+
+hb_filter_private_t * hb_rotate_init( int pix_fmt,
+                                           int width,
+                                           int height,
+                                           char * settings );
+
+int hb_rotate_work( hb_buffer_t * buf_in,
+                         hb_buffer_t ** buf_out,
+                         int pix_fmt,
+                         int width,
+                         int height,
+                         hb_filter_private_t * pv );
+
+void hb_rotate_close( hb_filter_private_t * pv );
+
+hb_filter_object_t hb_filter_rotate =
+{
+    FILTER_ROTATE,
+    "Rotate (flips image axes)",
+    NULL,
+    hb_rotate_init,
+    hb_rotate_work,
+    hb_rotate_close,
+};
+
+
+static void rotate_filter_line( uint8_t *dst,
+                               uint8_t *cur,
+                               int plane,
+                               hb_filter_private_t * pv )
+{
+
+    int w = pv->width[plane];
+
+    int x;
+    for( x = 0; x < w; x++)
+    {
+        if( pv->mode & 2 )
+        {
+            dst[x] = cur[w-x-1];
+        }
+        else
+        {
+            dst[x] = cur[x];
+        }
+    }
+}
+
+typedef struct rotate_thread_arg_s {
+    hb_filter_private_t *pv;
+    int segment;
+} rotate_thread_arg_t;
+
+/*
+ * rotate this segment of all three planes in a single thread.
+ */
+void rotate_filter_thread( void *thread_args_v )
+{
+    rotate_arguments_t *rotate_work = NULL;
+    hb_filter_private_t * pv;
+    int run = 1;
+    int plane;
+    int segment, segment_start, segment_stop;
+    rotate_thread_arg_t *thread_args = thread_args_v;
+    uint8_t **dst;
+    int y, w, h, ref_stride;
+
+
+    pv = thread_args->pv;
+    segment = thread_args->segment;
+
+    hb_log("Rotate thread started for segment %d", segment);
+
+    while( run )
+    {
+        /*
+         * Wait here until there is work to do. hb_lock() blocks until
+         * render releases it to say that there is more work to do.
+         */
+        hb_lock( pv->rotate_begin_lock[segment] );
+
+        rotate_work = &pv->rotate_arguments[segment];
+
+        if( rotate_work->stop )
+        {
+            /*
+             * No more work to do, exit this thread.
+             */
+            run = 0;
+            continue;
+        } 
+
+        if( rotate_work->dst == NULL )
+        {
+            hb_error( "Thread started when no work available" );
+            hb_snooze(500);
+            continue;
+        }
+        
+        /*
+         * Process all three planes, but only this segment of it.
+         */
+        for( plane = 0; plane < 3; plane++)
+        {
+
+            dst = rotate_work->dst;
+            w = pv->width[plane];
+            h = pv->height[plane];
+            ref_stride = pv->ref_stride[plane];
+            segment_start = ( h / pv->cpu_count ) * segment;
+            if( segment == pv->cpu_count - 1 )
+            {
+                /*
+                 * Final segment
+                 */
+                segment_stop = h;
+            } else {
+                segment_stop = ( h / pv->cpu_count ) * ( segment + 1 );
+            }
+
+            for( y = segment_start; y < segment_stop; y++ )
+            {
+                uint8_t * cur;
+                
+                if( pv->mode & 1 )
+                {
+                    cur  = &pv->pic_in.data[plane][(h-y-1)*pv->pic_in.linesize[plane]];
+                }
+                else
+                {
+                    cur  = &pv->pic_in.data[plane][(y)*pv->pic_in.linesize[plane]];
+                }
+                uint8_t *dst2 = &dst[plane][y*w];
+
+                rotate_filter_line( dst2, 
+                                   cur, 
+                                   plane, 
+                                   pv );
+            }
+        }
+        /*
+         * Finished this segment, let everyone know.
+         */
+        hb_unlock( pv->rotate_complete_lock[segment] );
+    }
+    free( thread_args_v );
+}
+
+
+/*
+ * threaded rotate - each thread rptates a single segment of all
+ * three planes. Where a segment is defined as the frame divided by
+ * the number of CPUs.
+ *
+ * This function blocks until the frame is rotated.
+ */
+static void rotate_filter( uint8_t ** dst,
+                          hb_filter_private_t * pv )
+{
+
+    int segment;
+    
+    for( segment = 0; segment < pv->cpu_count; segment++ )
+    {  
+        /*
+         * Setup the work for this plane.
+         */
+        pv->rotate_arguments[segment].dst = dst;
+
+        /*
+         * Let the thread for this plane know that we've setup work 
+         * for it by releasing the begin lock (ensuring that the
+         * complete lock is already locked so that we block when
+         * we try to lock it again below).
+         */
+        hb_lock( pv->rotate_complete_lock[segment] );
+        hb_unlock( pv->rotate_begin_lock[segment] );
+    }
+
+    /*
+     * Wait until all three threads have completed by trying to get
+     * the complete lock that we locked earlier for each thread, which
+     * will block until that thread has completed the work on that
+     * plane.
+     */
+    for( segment = 0; segment < pv->cpu_count; segment++ )
+    {
+        hb_lock( pv->rotate_complete_lock[segment] );
+        hb_unlock( pv->rotate_complete_lock[segment] );
+    }
+
+    /*
+     * Entire frame is now rotated.
+     */
+}
+
+
+hb_filter_private_t * hb_rotate_init( int pix_fmt,
+                                           int width,
+                                           int height,
+                                           char * settings )
+{
+    if( pix_fmt != PIX_FMT_YUV420P )
+    {
+        return 0;
+    }
+
+    hb_filter_private_t * pv = calloc( 1, sizeof(struct hb_filter_private_s) );
+
+    pv->pix_fmt = pix_fmt;
+
+    pv->width[0]  = width;
+    pv->height[0] = height;
+    pv->width[1]  = pv->width[2]  = width >> 1;
+    pv->height[1] = pv->height[2] = height >> 1;
+
+    pv->buf_out = hb_video_buffer_init( width, height );
+    pv->buf_settings = hb_buffer_init( 0 );
+
+    pv->mode     = MODE_DEFAULT;
+
+    pv->ref_stride[0] = pv->width[0];
+    pv->ref_stride[1] = pv->width[1];
+    pv->ref_stride[2] = pv->width[2];
+    
+    if( settings )
+    {
+        sscanf( settings, "%d",
+                &pv->mode );
+    }
+
+    pv->cpu_count = hb_get_cpu_count();
+
+
+    /*
+     * Create threads and locks.
+     */
+    pv->rotate_threads = malloc( sizeof( hb_thread_t* ) * pv->cpu_count );
+    pv->rotate_begin_lock = malloc( sizeof( hb_lock_t * ) * pv->cpu_count );
+    pv->rotate_complete_lock = malloc( sizeof( hb_lock_t * ) * pv->cpu_count );
+    pv->rotate_arguments = malloc( sizeof( rotate_arguments_t ) * pv->cpu_count );
+
+    int i;
+    for( i = 0; i < pv->cpu_count; i++ )
+    {
+        rotate_thread_arg_t *thread_args;
+    
+        thread_args = malloc( sizeof( rotate_thread_arg_t ) );
+    
+        if( thread_args ) {
+            thread_args->pv = pv;
+            thread_args->segment = i;
+    
+            pv->rotate_begin_lock[i] = hb_lock_init();
+            pv->rotate_complete_lock[i] = hb_lock_init();
+    
+            /*
+             * Important to start off with the threads locked waiting
+             * on input.
+             */
+            hb_lock( pv->rotate_begin_lock[i] );
+    
+            pv->rotate_arguments[i].stop = 0;
+            pv->rotate_arguments[i].dst = NULL;
+            
+            pv->rotate_threads[i] = hb_thread_init( "rotate_filter_segment",
+                                                   rotate_filter_thread,
+                                                   thread_args,
+                                                   HB_NORMAL_PRIORITY );
+        } else {
+            hb_error( "rotate could not create threads" );
+        }
+    }
+
+    return pv;
+}
+
+void hb_rotate_close( hb_filter_private_t * pv )
+{
+    if( !pv )
+    {
+        return;
+    }
+
+    /* Cleanup frame buffers */
+    if( pv->buf_out )
+    {
+        hb_buffer_close( &pv->buf_out );
+    }
+    if (pv->buf_settings )
+    {
+        hb_buffer_close( &pv->buf_settings );
+    }
+
+    int i;
+    for( i = 0; i < pv->cpu_count; i++)
+    {
+        /*
+         * Tell each rotate thread to stop, and then cleanup.
+         */
+        pv->rotate_arguments[i].stop = 1;
+        hb_unlock(  pv->rotate_begin_lock[i] );
+    
+        hb_thread_close( &pv->rotate_threads[i] );
+        hb_lock_close( &pv->rotate_begin_lock[i] );
+        hb_lock_close( &pv->rotate_complete_lock[i] );
+    }
+    
+    /*
+     * free memory for rotate structs
+     */
+    free( pv->rotate_threads );
+    free( pv->rotate_begin_lock );
+    free( pv->rotate_complete_lock );
+    free( pv->rotate_arguments );
+
+    free( pv );
+}
+
+int hb_rotate_work( hb_buffer_t * buf_in,
+                         hb_buffer_t ** buf_out,
+                         int pix_fmt,
+                         int width,
+                         int height,
+                         hb_filter_private_t * pv )
+{
+    if( !pv ||
+        pix_fmt != pv->pix_fmt ||
+        width   != pv->width[0] ||
+        height  != pv->height[0] )
+    {
+        return FILTER_FAILED;
+    }
+
+    avpicture_fill( &pv->pic_in, buf_in->data,
+                    pix_fmt, width, height );
+
+    avpicture_fill( &pv->pic_out, pv->buf_out->data,
+                        pix_fmt, width, height );
+
+    //do stuff here
+    rotate_filter( pv->pic_out.data, pv );
+    hb_buffer_copy_settings( pv->buf_out, buf_in );
+    
+    *buf_out = pv->buf_out;
+    
+    return FILTER_OK;
+}
+
+
index 3d5e960..cc76297 100644 (file)
@@ -51,6 +51,8 @@ static int    detelecine            = 0;
 static char * detelecine_opt        = 0;
 static int    decomb                = 0;
 static char * decomb_opt            = 0;
+static int    rotate                = 0;
+static char * rotate_opt            = 0;
 static int    grayscale   = 0;
 static int    vcodec      = HB_VCODEC_FFMPEG;
 static int    h264_13     = 0;
@@ -1070,6 +1072,12 @@ static int HandleEvents( hb_handle_t * h )
             
             /* Add selected filters */
             job->filters = hb_list_init();
+            
+            if( rotate )
+            {
+                hb_filter_rotate.settings = rotate_opt;
+                hb_list_add( job->filters, &hb_filter_rotate);
+            }
             if( detelecine )
             {
                 hb_filter_detelecine.settings = detelecine_opt;
@@ -2326,6 +2334,8 @@ static void ShowHelp()
      "          <weak/medium/strong>\n"
      "    -7, --deblock           Deblock video with pp7 filter\n"
      "          <QP:M>            (default 5:2)\n"
+     "        --rotate            Flips images axes\n"
+     "          <M>               (default 3)\n"
     "    -g, --grayscale         Grayscale encoding\n"
     "\n"
 
@@ -2498,6 +2508,7 @@ static int ParseOptions( int argc, char ** argv )
     #define SRT_OFFSET          271
     #define SRT_LANG            272
     #define SRT_DEFAULT         273
+    #define ROTATE_FILTER       274
     
     for( ;; )
     {
@@ -2544,6 +2555,7 @@ static int ParseOptions( int argc, char ** argv )
             { "detelecine",  optional_argument, NULL,    '9' },
             { "decomb",      optional_argument, NULL,    '5' },
             { "grayscale",   no_argument,       NULL,    'g' },
+            { "rotate",      optional_argument, NULL,   ROTATE_FILTER },
             { "strict-anamorphic",  no_argument, &anamorphic_mode, 1 },
             { "loose-anamorphic", no_argument, &anamorphic_mode, 2 },
             { "custom-anamorphic", no_argument, &anamorphic_mode, 3 },
@@ -2844,6 +2856,13 @@ static int ParseOptions( int argc, char ** argv )
             case 'g':
                 grayscale = 1;
                 break;
+            case ROTATE_FILTER:
+                if( optarg != NULL )
+                {
+                    rotate_opt = strdup( optarg );
+                }
+                rotate = 1;
+                break;
             case DISPLAY_WIDTH:
                 if( optarg != NULL )
                 {