/*****************************************************************************
- * motiondetec.c : Second version of a motion detection plugin.
+ * motiondetect.c : Second version of a motion detection plugin.
*****************************************************************************
- * Copyright (C) 2000-2008 the VideoLAN team
+ * Copyright (C) 2000-2008 VLC authors and VideoLAN
* $Id$
*
* Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_sout.h>
-#include <vlc_vout.h>
-#include "vlc_filter.h"
+#include <vlc_filter.h>
#include "filter_picture.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static picture_t *Filter( filter_t *, picture_t * );
-static picture_t *FilterPacked( filter_t *, picture_t * );
static void GaussianConvolution( uint32_t *, uint32_t *, int, int, int );
static int FindShapes( uint32_t *, uint32_t *, int, int, int,
int *, int *, int *, int *, int *);
struct filter_sys_t
{
+ bool is_yuv_planar;
bool b_old;
picture_t *p_old;
uint32_t *p_buf;
filter_t *p_filter = (filter_t *)p_this;
const video_format_t *p_fmt = &p_filter->fmt_in.video;
filter_sys_t *p_sys;
+ bool is_yuv_planar;
switch( p_fmt->i_chroma )
{
CASE_PLANAR_YUV
- p_filter->pf_video_filter = Filter;
+ is_yuv_planar = true;
break;
CASE_PACKED_YUV_422
- p_filter->pf_video_filter = FilterPacked;
+ is_yuv_planar = false;
break;
default:
- msg_Err( p_filter, "Unsupported input chroma (%4s)",
+ msg_Err( p_filter, "Unsupported input chroma (%4.4s)",
(char*)&(p_fmt->i_chroma) );
return VLC_EGENERIC;
}
+ p_filter->pf_video_filter = Filter;
/* Allocate structure */
p_filter->p_sys = p_sys = malloc( sizeof( filter_sys_t ) );
if( p_filter->p_sys == NULL )
return VLC_ENOMEM;
+ p_sys->is_yuv_planar = is_yuv_planar;
p_sys->b_old = false;
- p_sys->p_old = picture_New( p_fmt->i_chroma,
- p_fmt->i_width, p_fmt->i_height, 0 );
+ p_sys->p_old = picture_NewFromFormat( p_fmt );
p_sys->p_buf = calloc( p_fmt->i_width * p_fmt->i_height, sizeof(*p_sys->p_buf) );
p_sys->p_buf2 = calloc( p_fmt->i_width * p_fmt->i_height, sizeof(*p_sys->p_buf) );
/*****************************************************************************
- * Filter YUV Planar
+ * Filter YUV Planar/Packed
*****************************************************************************/
-static picture_t *Filter( filter_t *p_filter, picture_t *p_inpic )
+static void PreparePlanar( filter_t *p_filter, picture_t *p_inpic )
{
filter_sys_t *p_sys = p_filter->p_sys;
const video_format_t *p_fmt = &p_filter->fmt_in.video;
- picture_t *p_outpic;
-
uint8_t *p_oldpix = p_sys->p_old->p[Y_PLANE].p_pixels;
const int i_old_pitch = p_sys->p_old->p[Y_PLANE].i_pitch;
- uint32_t *p_buf = p_sys->p_buf;
- uint32_t *p_buf2= p_sys->p_buf2;
-
- unsigned x, y;
-
- if( !p_inpic )
- return NULL;
const uint8_t *p_inpix = p_inpic->p[Y_PLANE].p_pixels;
const int i_src_pitch = p_inpic->p[Y_PLANE].i_pitch;
- if( !p_sys->b_old )
- {
- picture_Copy( p_sys->p_old, p_inpic );
- p_sys->b_old = true;
- return p_inpic;
- }
-
- p_outpic = filter_NewPicture( p_filter );
- if( !p_outpic )
- {
- picture_Release( p_inpic );
- return NULL;
- }
- picture_Copy( p_outpic, p_inpic );
-
/**
* Substract Y planes
*/
- for( y = 0; y < p_fmt->i_height; y++ )
+ for( unsigned y = 0; y < p_fmt->i_height; y++ )
{
- for( x = 0; x < p_fmt->i_width; x++ )
- p_buf2[y*p_fmt->i_width+x] = abs( p_inpix[y*i_src_pitch+x] - p_oldpix[y*i_old_pitch+x] );
+ for( unsigned x = 0; x < p_fmt->i_width; x++ )
+ p_sys->p_buf2[y*p_fmt->i_width+x] = abs( p_inpix[y*i_src_pitch+x] - p_oldpix[y*i_old_pitch+x] );
}
int i_chroma_dx;
default:
msg_Warn( p_filter, "Not taking chroma into account" );
- i_chroma_dx = 0;
- i_chroma_dy = 0;
- break;
+ return;
}
- if( i_chroma_dx != 0 && i_chroma_dy != 0 )
- {
- const uint8_t *p_inpix_u = p_inpic->p[U_PLANE].p_pixels;
- const uint8_t *p_inpix_v = p_inpic->p[V_PLANE].p_pixels;
- const int i_src_pitch_u = p_inpic->p[U_PLANE].i_pitch;
- const int i_src_pitch_v = p_inpic->p[V_PLANE].i_pitch;
+ const uint8_t *p_inpix_u = p_inpic->p[U_PLANE].p_pixels;
+ const uint8_t *p_inpix_v = p_inpic->p[V_PLANE].p_pixels;
+ const int i_src_pitch_u = p_inpic->p[U_PLANE].i_pitch;
+ const int i_src_pitch_v = p_inpic->p[V_PLANE].i_pitch;
- const uint8_t *p_oldpix_u = p_sys->p_old->p[U_PLANE].p_pixels;
- const uint8_t *p_oldpix_v = p_sys->p_old->p[V_PLANE].p_pixels;
- const int i_old_pitch_u = p_sys->p_old->p[U_PLANE].i_pitch;
- const int i_old_pitch_v = p_sys->p_old->p[V_PLANE].i_pitch;
+ const uint8_t *p_oldpix_u = p_sys->p_old->p[U_PLANE].p_pixels;
+ const uint8_t *p_oldpix_v = p_sys->p_old->p[V_PLANE].p_pixels;
+ const int i_old_pitch_u = p_sys->p_old->p[U_PLANE].i_pitch;
+ const int i_old_pitch_v = p_sys->p_old->p[V_PLANE].i_pitch;
- for( y = 0; y < p_fmt->i_height/i_chroma_dy; y++ )
+ for( unsigned y = 0; y < p_fmt->i_height/i_chroma_dy; y++ )
+ {
+ for( unsigned x = 0; x < p_fmt->i_width/i_chroma_dx; x ++ )
{
- for( x = 0; x < p_fmt->i_width/i_chroma_dx; x ++ )
- {
- const int d = abs( p_inpix_u[y*i_src_pitch_u+x] - p_oldpix_u[y*i_old_pitch_u+x] ) +
- abs( p_inpix_v[y*i_src_pitch_v+x] - p_oldpix_v[y*i_old_pitch_v+x] );
- int i, j;
+ const int d = abs( p_inpix_u[y*i_src_pitch_u+x] - p_oldpix_u[y*i_old_pitch_u+x] ) +
+ abs( p_inpix_v[y*i_src_pitch_v+x] - p_oldpix_v[y*i_old_pitch_v+x] );
+ int i, j;
- for( j = 0; j < i_chroma_dy; j++ )
- {
- for( i = 0; i < i_chroma_dx; i++ )
- p_buf2[i_chroma_dy*p_fmt->i_width*j + i_chroma_dx*i] = d;
- }
+ for( j = 0; j < i_chroma_dy; j++ )
+ {
+ for( i = 0; i < i_chroma_dx; i++ )
+ p_sys->p_buf2[i_chroma_dy*p_fmt->i_width*j + i_chroma_dx*i] = d;
}
}
}
-
- /**
- * Get the areas where movement was detected
- */
- p_sys->i_colors = FindShapes( p_buf2, p_buf, p_fmt->i_width, p_fmt->i_width, p_fmt->i_height,
- p_sys->colors, p_sys->color_x_min, p_sys->color_x_max, p_sys->color_y_min, p_sys->color_y_max );
-
- /**
- * Count final number of shapes
- * Draw rectangles (there can be more than 1 moving shape in 1 rectangle)
- */
- Draw( p_filter, p_outpic->p[Y_PLANE].p_pixels, p_outpic->p[Y_PLANE].i_pitch, 1 );
-
- /**
- * We're done. Lets keep a copy of the picture
- * TODO we may just picture_Release with a latency of 1 if the filters/vout
- * handle it correctly */
- picture_Copy( p_sys->p_old, p_inpic );
-
- picture_Release( p_inpic );
- return p_outpic;
}
-/*****************************************************************************
- * Filter YUV Packed
- *****************************************************************************/
-static picture_t *FilterPacked( filter_t *p_filter, picture_t *p_inpic )
+static int PreparePacked( filter_t *p_filter, picture_t *p_inpic, int *pi_pix_offset )
{
filter_sys_t *p_sys = p_filter->p_sys;
const video_format_t *p_fmt = &p_filter->fmt_in.video;
- picture_t *p_outpic;
-
- const uint8_t *p_inpix = p_inpic->p[Y_PLANE].p_pixels;
- const int i_src_pitch = p_inpic->p[Y_PLANE].i_pitch;
-
- uint8_t *p_oldpix = p_sys->p_old->p[Y_PLANE].p_pixels;
- const int i_old_pitch = p_sys->p_old->p[Y_PLANE].i_pitch;
- uint32_t *p_buf = p_sys->p_buf;
- uint32_t *p_buf2= p_sys->p_buf2;
int i_y_offset, i_u_offset, i_v_offset;
-
- unsigned x, y;
-
if( GetPackedYuvOffsets( p_fmt->i_chroma,
&i_y_offset, &i_u_offset, &i_v_offset ) )
{
- msg_Warn( p_filter, "Unsupported input chroma (%4s)",
+ msg_Warn( p_filter, "Unsupported input chroma (%4.4s)",
(char*)&p_fmt->i_chroma );
- return p_inpic;
+ return VLC_EGENERIC;
}
+ *pi_pix_offset = i_y_offset;
- if( !p_sys->b_old )
+ /* Substract all planes at once */
+ uint8_t *p_oldpix = p_sys->p_old->p[Y_PLANE].p_pixels;
+ const int i_old_pitch = p_sys->p_old->p[Y_PLANE].i_pitch;
+
+ const uint8_t *p_inpix = p_inpic->p[Y_PLANE].p_pixels;
+ const int i_src_pitch = p_inpic->p[Y_PLANE].i_pitch;
+
+ for( unsigned y = 0; y < p_fmt->i_height; y++ )
{
- picture_Copy( p_sys->p_old, p_inpic );
- p_sys->b_old = true;
- return p_inpic;
+ for( unsigned x = 0; x < p_fmt->i_width; x+=2 )
+ {
+ int d;
+ d = abs( p_inpix[y*i_src_pitch+2*x+i_u_offset] - p_oldpix[y*i_old_pitch+2*x+i_u_offset] ) +
+ abs( p_inpix[y*i_src_pitch+2*x+i_v_offset] - p_oldpix[y*i_old_pitch+2*x+i_v_offset] );
+
+ for( int i = 0; i < 2; i++ )
+ p_sys->p_buf2[y*p_fmt->i_width+x+i] =
+ abs( p_inpix[y*i_src_pitch+2*(x+i)+i_y_offset] - p_oldpix[y*i_old_pitch+2*(x+i)+i_y_offset] ) + d;
+ }
}
+ return VLC_SUCCESS;
+}
- p_outpic = filter_NewPicture( p_filter );
+static picture_t *Filter( filter_t *p_filter, picture_t *p_inpic )
+{
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ if( !p_inpic )
+ return NULL;
+
+ picture_t *p_outpic = filter_NewPicture( p_filter );
if( !p_outpic )
{
picture_Release( p_inpic );
}
picture_Copy( p_outpic, p_inpic );
- /* Substract all planes at once */
-
- for( y = 0; y < p_fmt->i_height; y++ )
+ if( !p_sys->b_old )
{
- for( x = 0; x < p_fmt->i_width; x+=2 )
- {
- int i;
- int d;
-
- d = abs( p_inpix[y*i_src_pitch+2*x+i_u_offset] - p_oldpix[y*i_old_pitch+2*x+i_u_offset] ) +
- abs( p_inpix[y*i_src_pitch+2*x+i_v_offset] - p_oldpix[y*i_old_pitch+2*x+i_v_offset] );
+ picture_Copy( p_sys->p_old, p_inpic );
+ p_sys->b_old = true;
+ goto exit;
+ }
- for( i = 0; i < 2; i++ )
- p_buf2[y*p_fmt->i_width+x+i] =
- abs( p_inpix[y*i_src_pitch+2*(x+i)+i_y_offset] - p_oldpix[y*i_old_pitch+2*(x+i)+i_y_offset] ) + d;
- }
+ int i_pix_offset;
+ int i_pix_size;
+ if( p_sys->is_yuv_planar )
+ {
+ PreparePlanar( p_filter, p_inpic );
+ i_pix_offset = 0;
+ i_pix_size = 1;
+ }
+ else
+ {
+ if( PreparePacked( p_filter, p_inpic, &i_pix_offset ) )
+ goto exit;
+ i_pix_size = 2;
}
/**
* Get the areas where movement was detected
*/
- p_sys->i_colors = FindShapes( p_buf2, p_buf, p_fmt->i_width, p_fmt->i_width, p_fmt->i_height,
+ const video_format_t *p_fmt = &p_filter->fmt_in.video;
+ p_sys->i_colors = FindShapes( p_sys->p_buf2, p_sys->p_buf, p_fmt->i_width, p_fmt->i_width, p_fmt->i_height,
p_sys->colors, p_sys->color_x_min, p_sys->color_x_max, p_sys->color_y_min, p_sys->color_y_max );
/**
* Count final number of shapes
* Draw rectangles (there can be more than 1 moving shape in 1 rectangle)
*/
- Draw( p_filter, &p_outpic->p[Y_PLANE].p_pixels[i_y_offset], p_outpic->p[Y_PLANE].i_pitch, 2 );
+ Draw( p_filter, &p_outpic->p[Y_PLANE].p_pixels[i_pix_offset], p_outpic->p[Y_PLANE].i_pitch, i_pix_size );
/**
* We're done. Lets keep a copy of the picture
* handle it correctly */
picture_Copy( p_sys->p_old, p_inpic );
+exit:
picture_Release( p_inpic );
return p_outpic;
}
-
/*****************************************************************************
* Gaussian Convolution
*****************************************************************************