picture_t *picture_NewFromResource( const video_format_t *p_fmt, const picture_resource_t *p_resource ) { video_format_t fmt = *p_fmt; /* It is needed to be sure all information are filled */ video_format_Setup( &fmt, p_fmt->i_chroma, p_fmt->i_width, p_fmt->i_height, p_fmt->i_sar_num, p_fmt->i_sar_den ); if( p_fmt->i_x_offset < p_fmt->i_width && p_fmt->i_y_offset < p_fmt->i_height && p_fmt->i_visible_width > 0 && p_fmt->i_x_offset + p_fmt->i_visible_width <= p_fmt->i_width && p_fmt->i_visible_height > 0 && p_fmt->i_y_offset + p_fmt->i_visible_height <= p_fmt->i_height ) video_format_CopyCrop( &fmt, p_fmt ); /* */ picture_t *p_picture = calloc( 1, sizeof(*p_picture) ); if( !p_picture ) return NULL; if( p_resource ) { if( picture_Setup( p_picture, fmt.i_chroma, fmt.i_width, fmt.i_height, fmt.i_sar_num, fmt.i_sar_den ) ) { free( p_picture ); return NULL; } p_picture->p_sys = p_resource->p_sys; for( int i = 0; i < p_picture->i_planes; i++ ) { p_picture->p[i].p_pixels = p_resource->p[i].p_pixels; p_picture->p[i].i_lines = p_resource->p[i].i_lines; p_picture->p[i].i_pitch = p_resource->p[i].i_pitch; } } else { if( vout_AllocatePicture( p_picture, fmt.i_chroma, fmt.i_width, fmt.i_height, fmt.i_sar_num, fmt.i_sar_den ) ) { free( p_picture ); return NULL; } } /* */ p_picture->format = fmt; p_picture->i_refcount = 1; p_picture->pf_release = PictureReleaseCallback; return p_picture; }
/***************************************************************************** * Init: initialize video thread *****************************************************************************/ static int Init( vout_thread_t *p_vout ) { int i_index; picture_t *p_pic; /* Initialize the output structure */ p_vout->output.i_chroma = p_vout->render.i_chroma; p_vout->output.pf_setpalette = NULL; p_vout->output.i_width = p_vout->render.i_width; p_vout->output.i_height = p_vout->render.i_height; p_vout->output.i_aspect = p_vout->output.i_width * VOUT_ASPECT_FACTOR / p_vout->output.i_height; p_vout->output.i_rmask = 0xff0000; p_vout->output.i_gmask = 0x00ff00; p_vout->output.i_bmask = 0x0000ff; /* 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; } } /* Allocate the picture */ if( p_pic == NULL ) { 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 ) { return VLC_EGENERIC; } p_pic->i_status = DESTROYED_PICTURE; p_pic->i_type = DIRECT_PICTURE; PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; I_OUTPUTPICTURES++; return VLC_SUCCESS; }
/***************************************************************************** * LoadPNG: loads the PNG logo into memory *****************************************************************************/ static picture_t *LoadPNG( vlc_object_t *p_this ) { picture_t *p_pic; char *psz_filename; vlc_value_t val; FILE *file; int i, j, i_trans; vlc_bool_t b_alpha = VLC_TRUE; png_uint_32 i_width, i_height; int i_color_type, i_interlace_type, i_compression_type, i_filter_type; int i_bit_depth; png_bytep *p_row_pointers; png_structp p_png; png_infop p_info, p_end_info; var_Create( p_this, "logo-file", VLC_VAR_STRING | VLC_VAR_DOINHERIT ); var_Get( p_this, "logo-file", &val ); psz_filename = val.psz_string; if( !psz_filename || !*psz_filename ) { msg_Err( p_this, "logo file not specified" ); return 0; } if( !(file = fopen( psz_filename , "rb" )) ) { msg_Err( p_this, "logo file (%s) not found", psz_filename ); free( psz_filename ); return 0; } free( psz_filename ); p_png = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); p_info = png_create_info_struct( p_png ); p_end_info = png_create_info_struct( p_png ); png_init_io( p_png, file ); png_read_info( p_png, p_info ); png_get_IHDR( p_png, p_info, &i_width, &i_height, &i_bit_depth, &i_color_type, &i_interlace_type, &i_compression_type, &i_filter_type); if( i_color_type == PNG_COLOR_TYPE_PALETTE ) png_set_palette_to_rgb( p_png ); if( i_color_type == PNG_COLOR_TYPE_GRAY || i_color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb( p_png ); if( png_get_valid( p_png, p_info, PNG_INFO_tRNS ) ) { png_set_tRNS_to_alpha( p_png ); } else if( !(i_color_type & PNG_COLOR_MASK_ALPHA) ) { b_alpha = VLC_FALSE; } p_row_pointers = malloc( sizeof(png_bytep) * i_height ); for( i = 0; i < (int)i_height; i++ ) p_row_pointers[i] = malloc( 4 * ( i_bit_depth + 7 ) / 8 * i_width ); png_read_image( p_png, p_row_pointers ); png_read_end( p_png, p_end_info ); fclose( file ); png_destroy_read_struct( &p_png, &p_info, &p_end_info ); /* Convert to YUVA */ p_pic = malloc( sizeof(picture_t) ); if( vout_AllocatePicture( p_this, p_pic, VLC_FOURCC('Y','U','V','A'), i_width, i_height, VOUT_ASPECT_FACTOR ) != VLC_SUCCESS ) { for( i = 0; i < (int)i_height; i++ ) free( p_row_pointers[i] ); free( p_row_pointers ); return 0; } var_Create(p_this, "logo-transparency", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT); var_Get( p_this, "logo-transparency", &val ); i_trans = __MAX( __MIN( val.i_int, 255 ), 0 ); for( j = 0; j < (int)i_height ; j++ ) { uint8_t *p = (uint8_t *)p_row_pointers[j]; for( i = 0; i < (int)i_width ; i++ ) { int i_offset = i + j * p_pic->p[Y_PLANE].i_pitch; p_pic->p[Y_PLANE].p_pixels[i_offset] = (p[0] * 257L + p[1] * 504 + p[2] * 98)/1000 + 16; p_pic->p[U_PLANE].p_pixels[i_offset] = (p[2] * 439L - p[0] * 148 - p[1] * 291)/1000 + 128; p_pic->p[V_PLANE].p_pixels[i_offset] = (p[0] * 439L - p[1] * 368 - p[2] * 71)/1000 + 128; p_pic->p[A_PLANE].p_pixels[i_offset] = b_alpha ? (p[3] * i_trans) / 255 : i_trans; p += (b_alpha ? 4 : 3); } } for( i = 0; i < (int)i_height; i++ ) free( p_row_pointers[i] ); free( p_row_pointers ); return p_pic; }
/***************************************************************************** * 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." ); 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; } } /* Allocate the picture */ if( p_pic == NULL ) { return VLC_SUCCESS; } 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 ) { return VLC_EGENERIC; } 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; 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" ); if( p_vout->p_sys->i_size < 2 ) { msg_Err( p_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 * ) ); if( p_vout->p_sys->p_list == NULL ) 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 ) ); if( p_snapshot == NULL ) 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 ) return VLC_ENOMEM; p_vout->p_sys->p_list[i_index] = p_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 ); 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 ); /* 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 ) 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 (%d).", p_vout->p_sys->p_input->i_object_id ); return VLC_EGENERIC; } /* Register the snapshot vout module at the input level */ val.i_int = p_vout->i_object_id; if( var_Set( p_vout->p_sys->p_input, "snapshot-id", val ) ) { msg_Err( p_vout, "Cannot register snapshot-id in p_input (%d).", p_vout->p_sys->p_input->i_object_id ); return VLC_EGENERIC; } return VLC_SUCCESS; }
/***************************************************************************** * Init: initialize dummy video thread output method *****************************************************************************/ static int Init( vout_thread_t *p_vout ) { int i_index, i_chroma; char *psz_chroma; picture_t *p_pic; vlc_bool_t b_chroma = 0; psz_chroma = config_GetPsz( p_vout, "dummy-chroma" ); if( psz_chroma ) { if( strlen( psz_chroma ) >= 4 ) { i_chroma = VLC_FOURCC( psz_chroma[0], psz_chroma[1], psz_chroma[2], psz_chroma[3] ); b_chroma = 1; } free( psz_chroma ); } I_OUTPUTPICTURES = 0; /* Initialize the output structure */ if( b_chroma ) { msg_Dbg( p_vout, "forcing chroma 0x%.8x (%4.4s)", i_chroma, (char*)&i_chroma ); p_vout->output.i_chroma = i_chroma; if ( i_chroma == VLC_FOURCC( 'R', 'G', 'B', '2' ) ) { p_vout->output.pf_setpalette = SetPalette; } p_vout->output.i_width = p_vout->render.i_width; p_vout->output.i_height = p_vout->render.i_height; p_vout->output.i_aspect = p_vout->render.i_aspect; } else { /* Use same chroma as input */ p_vout->output.i_chroma = p_vout->render.i_chroma; p_vout->output.i_rmask = p_vout->render.i_rmask; p_vout->output.i_gmask = p_vout->render.i_gmask; p_vout->output.i_bmask = p_vout->render.i_bmask; p_vout->output.i_width = p_vout->render.i_width; p_vout->output.i_height = p_vout->render.i_height; p_vout->output.i_aspect = p_vout->render.i_aspect; } /* Try to initialize DUMMY_MAX_DIRECTBUFFERS direct buffers */ while( I_OUTPUTPICTURES < DUMMY_MAX_DIRECTBUFFERS ) { 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; } } /* Allocate the picture */ if( p_pic == NULL ) { break; } 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 ) { break; } p_pic->i_status = DESTROYED_PICTURE; p_pic->i_type = DIRECT_PICTURE; PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; I_OUTPUTPICTURES++; } return( 0 ); }