X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fvideo_output%2Fsnapshot.c;h=0d53e274b6d9f796e8cfd27d58c88b59a1460e90;hb=12ade3e3bc975d5426ba4af155b7372c31093b31;hp=35b6d6f3ed66b35d544cedd8798ebdb9916a71dd;hpb=b9751c6b4bf933fa5abe92a82b9855ccbf79529e;p=vlc diff --git a/modules/video_output/snapshot.c b/modules/video_output/snapshot.c index 35b6d6f3ed..0d53e274b6 100644 --- a/modules/video_output/snapshot.c +++ b/modules/video_output/snapshot.c @@ -26,10 +26,10 @@ * keep a cache of low-res snapshots. * The snapshot structure is defined in include/snapshot.h * In order to access the current snapshot cache, object variables are used: - * snapshot-list-pointer : the pointer on the first element in the list - * snapshot-datasize : size of a snapshot + * vout-snapshot-list-pointer : the pointer on the first element in the list + * vout-snapshot-datasize : size of a snapshot * (also available in snapshot_t->i_datasize) - * snapshot-cache-size : size of the cache list + * vout-snapshot-cache-size : size of the cache list * * It is used for the moment by the CORBA module and a specialized * python-vlc binding. @@ -45,361 +45,297 @@ #include #include -#include -#include +#include +#include #include -/***************************************************************************** - * Local prototypes - *****************************************************************************/ -static int Create ( vlc_object_t * ); -static void Destroy ( vlc_object_t * ); - -static int Init ( vout_thread_t * ); -static void End ( vout_thread_t * ); -static void Display ( vout_thread_t *, picture_t * ); - /***************************************************************************** * Module descriptor *****************************************************************************/ -#define WIDTH_TEXT N_( "Snapshot width" ) -#define WIDTH_LONGTEXT N_( "Width of the snapshot image." ) +#define WIDTH_TEXT N_("Snapshot width") +#define WIDTH_LONGTEXT N_("Width of the snapshot image.") -#define HEIGHT_TEXT N_( "Snapshot height" ) -#define HEIGHT_LONGTEXT N_( "Height of the snapshot image." ) +#define HEIGHT_TEXT N_("Snapshot height") +#define HEIGHT_LONGTEXT N_("Height of the snapshot image.") -#define CHROMA_TEXT N_( "Chroma" ) -#define CHROMA_LONGTEXT N_( "Output chroma for the snapshot image " \ - "(a 4 character string, like \"RV32\")." ) +#define CHROMA_TEXT N_("Chroma") +#define CHROMA_LONGTEXT N_("Output chroma for the snapshot image " \ + "(a 4 character string, like \"RV32\").") -#define CACHE_TEXT N_( "Cache size (number of images)" ) -#define CACHE_LONGTEXT N_( "Snapshot cache size (number of images to keep)." ) +#define CACHE_TEXT N_("Cache size (number of images)") +#define CACHE_LONGTEXT N_("Snapshot cache size (number of images to keep).") +static int Open (vlc_object_t *); +static void Close(vlc_object_t *); vlc_module_begin () - set_description( N_( "Snapshot module" ) ) - set_shortname( N_("Snapshot") ) + set_description(N_("Snapshot output")) + set_shortname(N_("Snapshot")) - set_category( CAT_VIDEO ) - set_subcategory( SUBCAT_VIDEO_VOUT ) - set_capability( "video output", 1 ) + set_category(CAT_VIDEO) + set_subcategory(SUBCAT_VIDEO_VOUT) + set_capability("vout display", 0) - add_integer( "snapshot-width", 320, NULL, WIDTH_TEXT, WIDTH_LONGTEXT, false ) - add_integer( "snapshot-height", 200, NULL, HEIGHT_TEXT, HEIGHT_LONGTEXT, false ) - add_string( "snapshot-chroma", "RV32", NULL, CHROMA_TEXT, CHROMA_LONGTEXT, true ) - add_integer( "snapshot-cache-size", 50, NULL, CACHE_TEXT, CACHE_LONGTEXT, true ) + add_integer("vout-snapshot-width", 320, NULL, WIDTH_TEXT, WIDTH_LONGTEXT, false) + add_integer("vout-snapshot-height", 200, NULL, HEIGHT_TEXT, HEIGHT_LONGTEXT, false) + add_string("vout-snapshot-chroma", "RV32", NULL, CHROMA_TEXT, CHROMA_LONGTEXT, true) + add_deprecated_alias("snapshot-chroma") + add_integer("vout-snapshot-cache-size", 50, NULL, CACHE_TEXT, CACHE_LONGTEXT, true) + add_deprecated_alias("snapshot-cache-size") - set_callbacks( Create, Destroy ) + set_callbacks(Open, Close) vlc_module_end () + /***************************************************************************** - * vout_sys_t: video output descriptor + * Local prototypes *****************************************************************************/ -struct vout_sys_t -{ - snapshot_t **p_list; /* List of available snapshots */ - int i_index; /* Index of the next available list member */ - int i_size; /* Size of the cache */ - int i_datasize; /* Size of an image */ - input_thread_t *p_input; /* The input thread */ +static picture_pool_t *Pool (vout_display_t *, unsigned); +static void Display(vout_display_t *, picture_t *); +static int Control(vout_display_t *, int, va_list); +static void Manage (vout_display_t *); + +typedef struct { + mtime_t date; /* Presentation time */ + int width; /* In pixels */ + int height; /* In pixels */ + int data_size; /* In bytes */ + uint8_t *data; /* Data area */ +} snapshot_t; + +struct vout_display_sys_t { + int count; /* Size of the cache */ + snapshot_t **snapshot; /* List of available snapshots */ + int index; /* Index of the next available list member */ + int data_size; /* Size of an image */ + picture_pool_t *pool; + + input_thread_t *input; /* The input thread */ }; -/***************************************************************************** - * Create: allocates video thread - ***************************************************************************** - * This function allocates and initializes a vout method. - *****************************************************************************/ -static int Create( vlc_object_t *p_this ) +/* */ +static int Open(vlc_object_t *object) { - vout_thread_t *p_vout = ( vout_thread_t * )p_this; + vout_display_t *vd = (vout_display_t *)object; + vout_display_sys_t *sys; /* Allocate instance and initialize some members */ - p_vout->p_sys = malloc( sizeof( vout_sys_t ) ); - if( ! p_vout->p_sys ) + vd->sys = sys = malloc(sizeof(*sys)); + if (!sys) return VLC_ENOMEM; - var_Create( p_vout, "snapshot-width", VLC_VAR_INTEGER ); - var_Create( p_vout, "snapshot-height", VLC_VAR_INTEGER ); - var_Create( p_vout, "snapshot-datasize", VLC_VAR_INTEGER ); - var_Create( p_vout, "snapshot-cache-size", VLC_VAR_INTEGER ); - var_Create( p_vout, "snapshot-list-pointer", VLC_VAR_ADDRESS ); - - p_vout->pf_init = Init; - p_vout->pf_end = End; - p_vout->pf_manage = NULL; - p_vout->pf_render = NULL; - p_vout->pf_display = Display; + char *chroma_fmt = var_InheritString(vd, "vout-snapshot-chroma"); + const vlc_fourcc_t chroma = vlc_fourcc_GetCodecFromString(VIDEO_ES, chroma_fmt); + free(chroma_fmt); - return VLC_SUCCESS; -} - -/***************************************************************************** - * Init: initialize video thread - *****************************************************************************/ -static int Init( vout_thread_t *p_vout ) -{ - int i_index; - picture_t *p_pic; - vlc_value_t val; - char* psz_chroma; - int i_chroma; - int i_width; - int i_height; - int i_datasize; - - i_width = config_GetInt( p_vout, "snapshot-width" ); - i_height = config_GetInt( p_vout, "snapshot-height" ); - - psz_chroma = config_GetPsz( p_vout, "snapshot-chroma" ); - if( psz_chroma ) - { - if( strlen( psz_chroma ) < 4 ) - { - msg_Err( p_vout, "snapshot-chroma should be 4 characters long" ); - return VLC_EGENERIC; - } - i_chroma = VLC_FOURCC( psz_chroma[0], psz_chroma[1], - psz_chroma[2], psz_chroma[3] ); - free( psz_chroma ); - } - else - { - msg_Err( p_vout, "Cannot find chroma information." ); + if (!chroma) { + msg_Err(vd, "snapshot-chroma should be 4 characters long"); + free(sys); return VLC_EGENERIC; } - I_OUTPUTPICTURES = 0; - - /* Initialize the output structure */ - p_vout->output.i_chroma = i_chroma; - p_vout->output.pf_setpalette = NULL; - p_vout->output.i_width = i_width; - p_vout->output.i_height = i_height; - p_vout->output.i_aspect = p_vout->output.i_width - * VOUT_ASPECT_FACTOR / p_vout->output.i_height; - - - /* Define the bitmasks */ - switch( i_chroma ) - { - case VLC_FOURCC( 'R','V','1','5' ): - p_vout->output.i_rmask = 0x001f; - p_vout->output.i_gmask = 0x03e0; - p_vout->output.i_bmask = 0x7c00; - break; - - case VLC_FOURCC( 'R','V','1','6' ): - p_vout->output.i_rmask = 0x001f; - p_vout->output.i_gmask = 0x07e0; - p_vout->output.i_bmask = 0xf800; - break; - - case VLC_FOURCC( 'R','V','2','4' ): - p_vout->output.i_rmask = 0xff0000; - p_vout->output.i_gmask = 0x00ff00; - p_vout->output.i_bmask = 0x0000ff; - break; - - case VLC_FOURCC( 'R','V','3','2' ): - p_vout->output.i_rmask = 0xff0000; - p_vout->output.i_gmask = 0x00ff00; - p_vout->output.i_bmask = 0x0000ff; - break; - } - - /* Try to initialize 1 direct buffer */ - p_pic = NULL; - - /* Find an empty picture slot */ - for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ ) - { - if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) - { - p_pic = p_vout->p_picture + i_index; - break; - } + const int width = var_InheritInteger(vd, "vout-snapshot-width"); + const int height = var_InheritInteger(vd, "vout-snapshot-height"); + if (width <= 0 || height <= 0) { + msg_Err(vd, "snapshot-width/height are invalid"); + free(sys); + return VLC_EGENERIC; } - /* Allocate the picture */ - if( p_pic == NULL ) - { - return VLC_SUCCESS; + /* */ + video_format_t fmt = vd->fmt; + fmt.i_chroma = chroma; + fmt.i_width = width; + fmt.i_height = height; + fmt.i_rmask = 0; + fmt.i_gmask = 0; + fmt.i_bmask = 0; + video_format_FixRgb(&fmt); + + picture_t *picture = picture_NewFromFormat(&fmt); + if (!picture) { + free(sys); + return VLC_EGENERIC; } - - vout_AllocatePicture( VLC_OBJECT(p_vout), p_pic, p_vout->output.i_chroma, - p_vout->output.i_width, p_vout->output.i_height, - p_vout->output.i_aspect ); - - if( p_pic->i_planes == 0 ) - { + sys->pool = picture_pool_New(1, &picture); + if (!sys->pool) { + picture_Release(picture); + free(sys); return VLC_EGENERIC; } + sys->data_size = 0; + for (int i = 0; i < picture->i_planes; i++) { + const plane_t *plane = &picture->p[i]; + sys->data_size += plane->i_visible_pitch * + plane->i_visible_lines * + plane->i_pixel_pitch; + } - p_pic->i_status = DESTROYED_PICTURE; - p_pic->i_type = DIRECT_PICTURE; - - PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; - - I_OUTPUTPICTURES++; - - - /* Get datasize and set variables */ - i_datasize = i_width * i_height * p_pic->p->i_pixel_pitch; + sys->index = 0; + sys->count = var_InheritInteger(vd, "vout-snapshot-cache-size"); - p_vout->p_sys->i_datasize = i_datasize; - p_vout->p_sys->i_index = 0; - p_vout->p_sys->i_size = config_GetInt( p_vout, "snapshot-cache-size" ); + /* FIXME following code leaks in case of error */ - if( p_vout->p_sys->i_size < 2 ) - { - msg_Err( p_vout, "snapshot-cache-size must be at least 1." ); + if (sys->count < 2) { + msg_Err(vd, "vout-snapshot-cache-size must be at least 1."); return VLC_EGENERIC; } - p_vout->p_sys->p_list = malloc( p_vout->p_sys->i_size * sizeof( snapshot_t * ) ); + sys->snapshot = calloc(sys->count, sizeof(*sys->snapshot)); - if( p_vout->p_sys->p_list == NULL ) + if (!sys->snapshot) return VLC_ENOMEM; /* Initialize the structures for the circular buffer */ - for( i_index = 0; i_index < p_vout->p_sys->i_size; i_index++ ) - { - snapshot_t *p_snapshot = malloc( sizeof( snapshot_t ) ); + for (int index = 0; index < sys->count; index++) { + snapshot_t *snapshot = malloc(sizeof(*snapshot)); - if( p_snapshot == NULL ) + if (!snapshot) return VLC_ENOMEM; - p_snapshot->i_width = i_width; - p_snapshot->i_height = i_height; - p_snapshot->i_datasize = i_datasize; - p_snapshot->date = 0; - p_snapshot->p_data = ( char* ) malloc( i_datasize ); - if( p_snapshot->p_data == NULL ) - { - free( p_snapshot ); + snapshot->date = VLC_TS_INVALID; + snapshot->width = fmt.i_width; + snapshot->height = fmt.i_height; + snapshot->data_size = sys->data_size; + snapshot->data = malloc(sys->data_size); + if (!snapshot->data) { + free(snapshot); return VLC_ENOMEM; } - p_vout->p_sys->p_list[i_index] = p_snapshot; + sys->snapshot[index] = snapshot; } - val.i_int = i_width; - var_Set( p_vout, "snapshot-width", val ); - val.i_int = i_height; - var_Set( p_vout, "snapshot-height", val ); - val.i_int = i_datasize; - var_Set( p_vout, "snapshot-datasize", val ); + /* */ + var_Create(vd, "vout-snapshot-width", VLC_VAR_INTEGER); + var_Create(vd, "vout-snapshot-height", VLC_VAR_INTEGER); + var_Create(vd, "vout-snapshot-datasize", VLC_VAR_INTEGER); + var_Create(vd, "vout-snapshot-cache-size", VLC_VAR_INTEGER); + var_Create(vd, "vout-snapshot-list-pointer", VLC_VAR_ADDRESS); - val.i_int = p_vout->p_sys->i_size; - var_Set( p_vout, "snapshot-cache-size", val ); - - val.p_address = p_vout->p_sys->p_list; - var_Set( p_vout, "snapshot-list-pointer", val ); + var_SetInteger(vd, "vout-snapshot-width", fmt.i_width); + var_SetInteger(vd, "vout-snapshot-height", fmt.i_height); + var_SetInteger(vd, "vout-snapshot-datasize", sys->data_size); + var_SetInteger(vd, "vout-snapshot-cache-size", sys->count); + var_SetAddress(vd, "vout-snapshot-list-pointer", sys->snapshot); /* Get the p_input pointer (to access video times) */ - p_vout->p_sys->p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT, - FIND_PARENT ); - - if( !p_vout->p_sys->p_input ) + sys->input = vlc_object_find(vd, VLC_OBJECT_INPUT, FIND_PARENT); + if (!sys->input) return VLC_ENOOBJ; - if( var_Create( p_vout->p_sys->p_input, "snapshot-id", VLC_VAR_INTEGER ) ) - { - msg_Err( p_vout, "Cannot create snapshot-id variable in p_input(%p).", - p_vout->p_sys->p_input ); + if (var_Create(sys->input, "vout-snapshot-id", VLC_VAR_ADDRESS)) { + msg_Err(vd, "Cannot create vout-snapshot-id variable in p_input(%p).", + sys->input); return VLC_EGENERIC; } /* Register the snapshot vout module at the input level */ - val.p_address = p_vout; - - if( var_Set( p_vout->p_sys->p_input, "snapshot-id", val ) ) - { - msg_Err( p_vout, "Cannot register snapshot-id in p_input(%p).", - p_vout->p_sys->p_input ); + if (var_SetAddress(sys->input, "vout-snapshot-id", vd)) { + msg_Err(vd, "Cannot register vout-snapshot-id in p_input(%p).", + sys->input); return VLC_EGENERIC; } + /* */ + vout_display_info_t info = vd->info; + info.has_hide_mouse = true; + + /* */ + vd->fmt = fmt; + vd->info = info; + vd->pool = Pool; + vd->prepare = NULL; + vd->display = Display; + vd->control = Control; + vd->manage = Manage; + + /* */ + vout_display_SendEventFullscreen(vd, false); return VLC_SUCCESS; } -/***************************************************************************** - * End: terminate video thread output method - *****************************************************************************/ -static void End( vout_thread_t *p_vout ) -{ - (void)p_vout; -} - -/***************************************************************************** - * Destroy: destroy video thread - ***************************************************************************** - * Terminate an output method created by Create - *****************************************************************************/ -static void Destroy( vlc_object_t *p_this ) +/* */ +static void Close(vlc_object_t *object) { - vout_thread_t *p_vout = ( vout_thread_t * )p_this; - int i_index; + vout_display_t *vd = (vout_display_t *)object; + vout_display_sys_t *sys = vd->sys; - var_Destroy( p_vout->p_sys->p_input, "snapshot-id" ); + var_Destroy(sys->input, "vout-snapshot-id"); - vlc_object_release( p_vout->p_sys->p_input ); - var_Destroy( p_this, "snapshot-width" ); - var_Destroy( p_this, "snapshot-height" ); - var_Destroy( p_this, "snapshot-datasize" ); + vlc_object_release(sys->input); + var_Destroy(vd, "vout-snapshot-width"); + var_Destroy(vd, "vout-snapshot-height"); + var_Destroy(vd, "vout-snapshot-datasize"); - for( i_index = 0 ; i_index < p_vout->p_sys->i_size ; i_index++ ) - { - free( p_vout->p_sys->p_list[ i_index ]->p_data ); + for (int index = 0 ; index < sys->count; index++) { + free(sys->snapshot[index]->data); + free(sys->snapshot[index]); } - free( p_vout->p_sys->p_list ); - /* Destroy structure */ - free( p_vout->p_sys ); -} + free(sys->snapshot); -/* Return the position in ms from the start of the movie */ -static mtime_t snapshot_GetMovietime( vout_thread_t *p_vout ) -{ - input_thread_t* p_input; - vlc_value_t val; - mtime_t i_result; + picture_pool_Delete(sys->pool); - p_input = p_vout->p_sys->p_input; - if( !p_input ) - return 0; - - var_Get( p_input, "time", &val ); - - i_result = val.i_time - p_input->i_pts_delay; - - return( i_result / 1000 ); + free(sys); } /***************************************************************************** - * Display: displays previously rendered output - ***************************************************************************** - * This function copies the rendered picture into our circular buffer. + * *****************************************************************************/ -static void Display( vout_thread_t *p_vout, picture_t *p_pic ) +static picture_pool_t *Pool(vout_display_t *vd, unsigned count) { - int i_index; - mtime_t i_date; - - i_index = p_vout->p_sys->i_index; + VLC_UNUSED(count); + return vd->sys->pool; +} - vlc_memcpy( p_vout->p_sys->p_list[i_index]->p_data, p_pic->p->p_pixels, - p_vout->p_sys->i_datasize ); +/* Return the position in ms from the start of the movie */ +static mtime_t snapshot_GetMovietime(vout_display_t *vd) +{ + vout_display_sys_t *sys = vd->sys; - i_date = snapshot_GetMovietime( p_vout ); + if (!sys->input) + return VLC_TS_INVALID; + return var_GetTime(sys->input, "time") / 1000; +} - p_vout->p_sys->p_list[i_index]->date = i_date; +static void Display(vout_display_t *vd, picture_t *picture) +{ + vout_display_sys_t *sys = vd->sys; + + const int index = sys->index; + + /* FIXME a lock or an event of some sort would be needed to protect + * the content of sys->snapshot vs external users */ + uint8_t *p_dst = sys->snapshot[index]->data; + for (int i = 0; i < picture->i_planes; i++) { + const plane_t *plane = &picture->p[i]; + for( int y = 0; y < plane->i_visible_lines; y++) { + vlc_memcpy(p_dst, &plane->p_pixels[y*plane->i_pitch], + plane->i_visible_pitch); + p_dst += plane->i_visible_pitch; + } + } + sys->snapshot[index]->date = snapshot_GetMovietime(vd); - i_index++; + sys->index = (index + 1) % sys->count; +} - if( i_index >= p_vout->p_sys->i_size ) - { - i_index = 0; +static int Control(vout_display_t *vd, int query, va_list args) +{ + VLC_UNUSED(vd); + switch (query) { + case VOUT_DISPLAY_CHANGE_FULLSCREEN: { + const vout_display_cfg_t *cfg = va_arg(args, const vout_display_cfg_t *); + if (cfg->is_fullscreen) + return VLC_EGENERIC; + return VLC_SUCCESS; } + default: + return VLC_EGENERIC; + } +} - p_vout->p_sys->i_index = i_index; +static void Manage (vout_display_t *vd) +{ + VLC_UNUSED(vd); }