void subpicture_Update( subpicture_t *p_subpicture, const video_format_t *p_fmt_src, const video_format_t *p_fmt_dst, mtime_t i_ts ) { subpicture_updater_t *p_upd = &p_subpicture->updater; subpicture_private_t *p_private = p_subpicture->p_private; if( !p_upd->pf_validate ) return; if( !p_upd->pf_validate( p_subpicture, !video_format_IsSimilar( p_fmt_src, &p_private->src ), p_fmt_src, !video_format_IsSimilar( p_fmt_dst, &p_private->dst ), p_fmt_dst, i_ts ) ) return; subpicture_region_ChainDelete( p_subpicture->p_region ); p_subpicture->p_region = NULL; p_upd->pf_update( p_subpicture, p_fmt_src, p_fmt_dst, i_ts ); video_format_Clean( &p_private->src ); video_format_Clean( &p_private->dst ); video_format_Copy( &p_private->src, p_fmt_src ); video_format_Copy( &p_private->dst, p_fmt_dst ); }
static filter_t *CreateFilter( vlc_object_t *p_this, const es_format_t *p_fmt_in, const video_format_t *p_fmt_out ) { filter_t *p_filter; p_filter = vlc_custom_create( p_this, sizeof(filter_t), "filter" ); p_filter->owner.video.buffer_new = filter_new_picture; es_format_Copy( &p_filter->fmt_in, p_fmt_in ); es_format_Copy( &p_filter->fmt_out, p_fmt_in ); video_format_Copy( &p_filter->fmt_out.video, p_fmt_out ); /* whatever the input offset, write at offset 0 in the target image */ p_filter->fmt_out.video.i_x_offset = 0; p_filter->fmt_out.video.i_y_offset = 0; p_filter->fmt_out.i_codec = p_fmt_out->i_chroma; p_filter->p_module = module_need( p_filter, "video converter", NULL, false ); if( !p_filter->p_module ) { msg_Dbg( p_filter, "no video converter found" ); DeleteFilter( p_filter ); return NULL; } return p_filter; }
subpicture_region_private_t *subpicture_region_private_New( video_format_t *p_fmt ) { subpicture_region_private_t *p_private = malloc( sizeof(*p_private) ); if( !p_private ) return NULL; if ( video_format_Copy( &p_private->fmt, p_fmt ) != VLC_SUCCESS ) return NULL; p_private->p_picture = NULL; return p_private; }
subpicture_region_t *subpicture_region_New( const video_format_t *p_fmt ) { subpicture_region_t *p_region = calloc( 1, sizeof(*p_region ) ); if( !p_region ) return NULL; if ( p_fmt->i_chroma == VLC_CODEC_YUVP ) { video_format_Copy( &p_region->fmt, p_fmt ); /* YUVP should have a palette */ if( p_region->fmt.p_palette == NULL ) { p_region->fmt.p_palette = calloc( 1, sizeof(*p_region->fmt.p_palette) ); if( p_region->fmt.p_palette == NULL ) { free( p_region ); return NULL; } } } else { p_region->fmt = *p_fmt; p_region->fmt.p_palette = NULL; } p_region->i_alpha = 0xff; if( p_fmt->i_chroma == VLC_CODEC_TEXT ) return p_region; p_region->p_picture = picture_NewFromFormat( p_fmt ); if( !p_region->p_picture ) { video_format_Clean( &p_region->fmt ); free( p_region ); return NULL; } return p_region; }
video_splitter_t *video_splitter_New( vlc_object_t *p_this, const char *psz_name, const video_format_t *p_fmt ) { video_splitter_t *p_splitter = vlc_custom_create( p_this, sizeof(*p_splitter), VLC_OBJECT_GENERIC, "video splitter" ); if( !p_splitter ) return NULL; video_format_Copy( &p_splitter->fmt, p_fmt ); /* */ p_splitter->p_module = module_need( p_splitter, "video splitter", psz_name, true ); if( ! p_splitter->p_module ) { video_splitter_Delete( p_splitter ); return NULL; } return p_splitter; }
/** This function allocates and initialize the DirectX vout display. */ static int Open(vlc_object_t *object) { vout_display_t *vd = (vout_display_t *)object; vout_display_sys_t *sys; /* Allocate structure */ vd->sys = sys = calloc(1, sizeof(*sys)); if (!sys) return VLC_ENOMEM; /* Load direct draw DLL */ sys->hddraw_dll = LoadLibrary(_T("DDRAW.DLL")); if (!sys->hddraw_dll) { msg_Warn(vd, "DirectXInitDDraw failed loading ddraw.dll"); free(sys); return VLC_EGENERIC; } /* */ sys->use_wallpaper = var_CreateGetBool(vd, "video-wallpaper"); /* FIXME */ sys->use_overlay = false;//var_CreateGetBool(vd, "overlay"); /* FIXME */ sys->restore_overlay = false; var_Create(vd, "directx-device", VLC_VAR_STRING | VLC_VAR_DOINHERIT); /* Initialisation */ if (CommonInit(vd)) goto error; /* */ video_format_t fmt = vd->fmt; if (DirectXOpen(vd, &fmt)) goto error; /* */ vout_display_info_t info = vd->info; info.is_slow = true; info.has_double_click = true; info.has_hide_mouse = false; info.has_pictures_invalid = true; info.has_event_thread = true; /* Interaction TODO support starting with wallpaper mode */ vlc_mutex_init(&sys->lock); sys->ch_wallpaper = sys->use_wallpaper; sys->wallpaper_requested = sys->use_wallpaper; sys->use_wallpaper = false; vlc_value_t val; val.psz_string = _("Wallpaper"); var_Change(vd, "video-wallpaper", VLC_VAR_SETTEXT, &val, NULL); var_AddCallback(vd, "video-wallpaper", WallpaperCallback, NULL); /* Setup vout_display now that everything is fine */ video_format_Clean(&vd->fmt); video_format_Copy(&vd->fmt, &fmt); vd->info = info; vd->pool = Pool; vd->prepare = NULL; vd->display = Display; vd->control = Control; vd->manage = Manage; return VLC_SUCCESS; error: DirectXClose(vd); CommonClean(vd); if (sys->hddraw_dll) FreeLibrary(sys->hddraw_dll); free(sys); return VLC_EGENERIC; }
/***************************************************************************** * Open: allocates Wall video thread output method ***************************************************************************** * This function allocates and initializes a Wall vout method. *****************************************************************************/ static int Open( vlc_object_t *p_this ) { video_splitter_t *p_splitter = (video_splitter_t*)p_this; video_splitter_sys_t *p_sys; const panoramix_chroma_t *p_chroma; for( int i = 0; ; i++ ) { vlc_fourcc_t i_chroma = p_chroma_array[i].i_chroma; if( !i_chroma ) { msg_Err( p_splitter, "colorspace not supported by plug-in !" ); return VLC_EGENERIC; } if( i_chroma == p_splitter->fmt.i_chroma ) { p_chroma = &p_chroma_array[i]; break; } } /* Allocate structure */ p_splitter->p_sys = p_sys = malloc( sizeof( *p_sys ) ); if( !p_sys ) return VLC_ENOMEM; /* */ p_sys->p_chroma = p_chroma; /* */ config_ChainParse( p_splitter, CFG_PREFIX, ppsz_filter_options, p_splitter->p_cfg ); /* */ p_sys->i_col = var_InheritInteger( p_splitter, CFG_PREFIX "cols" ); p_sys->i_row = var_InheritInteger( p_splitter, CFG_PREFIX "rows" ); /* Autodetect number of displays */ if( p_sys->i_col < 0 || p_sys->i_row < 0 ) { #ifdef WIN32 const int i_monitor_count = GetSystemMetrics(SM_CMONITORS); if( i_monitor_count > 1 ) { p_sys->i_col = GetSystemMetrics( SM_CXVIRTUALSCREEN ) / GetSystemMetrics( SM_CXSCREEN ); p_sys->i_row = GetSystemMetrics( SM_CYVIRTUALSCREEN ) / GetSystemMetrics( SM_CYSCREEN ); if( p_sys->i_col * p_sys->i_row != i_monitor_count ) { p_sys->i_col = i_monitor_count; p_sys->i_row = 1; } } #else const unsigned i_monitors = CountMonitors( p_this ); if( i_monitors > 1 ) /* Find closest to square */ for( unsigned w = 1; (i_monitors / w) >= w ; w++ ) { if( i_monitors % w ) continue; p_sys->i_row = w; p_sys->i_col = i_monitors / w; } #endif /* By default do 2x1 */ if( p_sys->i_row < 0 ) p_sys->i_row = 1; if( p_sys->i_col < 0 ) p_sys->i_col = 2; var_SetInteger( p_splitter, CFG_PREFIX "cols", p_sys->i_col); var_SetInteger( p_splitter, CFG_PREFIX "rows", p_sys->i_row); } /* */ p_sys->b_attenuate = var_InheritBool( p_splitter, CFG_PREFIX "attenuate"); p_sys->bz_length = var_InheritInteger( p_splitter, CFG_PREFIX "bz-length" ); p_sys->bz_height = var_InheritInteger( p_splitter, CFG_PREFIX "bz-height" ); p_sys->bz_begin = var_InheritInteger( p_splitter, CFG_PREFIX "bz-begin" ); p_sys->bz_middle = var_InheritInteger( p_splitter, CFG_PREFIX "bz-middle" ); p_sys->bz_end = var_InheritInteger( p_splitter, CFG_PREFIX "bz-end" ); p_sys->bz_middle_pos = var_InheritInteger( p_splitter, CFG_PREFIX "bz-middle-pos" ); double d_p = 100.0 / p_sys->bz_middle_pos; p_sys->a_2 = d_p * p_sys->bz_begin - (double)(d_p * d_p / (d_p - 1)) * p_sys->bz_middle + (double)(d_p / (d_p - 1)) * p_sys->bz_end; p_sys->a_1 = -(d_p + 1) * p_sys->bz_begin + (double)(d_p * d_p / (d_p - 1)) * p_sys->bz_middle - (double)(1 / (d_p - 1)) * p_sys->bz_end; p_sys->a_0 = p_sys->bz_begin; /* */ p_sys->i_col = VLC_CLIP( COL_MAX, 1, p_sys->i_col ); p_sys->i_row = VLC_CLIP( ROW_MAX, 1, p_sys->i_row ); msg_Dbg( p_splitter, "opening a %i x %i wall", p_sys->i_col, p_sys->i_row ); if( p_sys->bz_length > 0 && ( p_sys->i_row > 1 || p_sys->i_col > 1 ) ) { const int i_overlap_w2_max = p_splitter->fmt.i_width / p_sys->i_col / 2; const int i_overlap_h2_max = p_splitter->fmt.i_height / p_sys->i_row / 2; const int i_overlap2_max = __MIN( i_overlap_w2_max, i_overlap_h2_max ); if( p_sys->i_col > 1 ) p_sys->i_overlap_w2 = i_overlap2_max * p_sys->bz_length / 100; else p_sys->i_overlap_w2 = 0; if( p_sys->i_row > 1 ) p_sys->i_overlap_h2 = i_overlap2_max * p_sys->bz_height / 100; else p_sys->i_overlap_h2 = 0; /* */ int i_div_max_w = 1; int i_div_max_h = 1; for( int i = 0; i < VOUT_MAX_PLANES; i++ ) { i_div_max_w = __MAX( i_div_max_w, p_chroma->pi_div_w[i] ); i_div_max_h = __MAX( i_div_max_h, p_chroma->pi_div_h[i] ); } p_sys->i_overlap_w2 = i_div_max_w * (p_sys->i_overlap_w2 / i_div_max_w); p_sys->i_overlap_h2 = i_div_max_h * (p_sys->i_overlap_h2 / i_div_max_h); } else { p_sys->i_overlap_w2 = 0; p_sys->i_overlap_h2 = 0; } /* Compute attenuate parameters */ if( p_sys->b_attenuate ) { panoramix_gamma_t p_gamma[VOUT_MAX_PLANES]; p_gamma[0].f_gamma = var_InheritFloat( p_splitter, CFG_PREFIX "bz-gamma-red" ); p_gamma[1].f_gamma = var_InheritFloat( p_splitter, CFG_PREFIX "bz-gamma-green" ); p_gamma[2].f_gamma = var_InheritFloat( p_splitter, CFG_PREFIX "bz-gamma-blue" ); p_gamma[0].f_black_crush = var_InheritInteger( p_splitter, CFG_PREFIX "bz-blackcrush-red" ) / 255.0; p_gamma[1].f_black_crush = var_InheritInteger( p_splitter, CFG_PREFIX "bz-blackcrush-green" ) / 255.0; p_gamma[2].f_black_crush = var_InheritInteger( p_splitter, CFG_PREFIX "bz-blackcrush-blue" ) / 255.0; p_gamma[0].f_white_crush = var_InheritInteger( p_splitter, CFG_PREFIX "bz-whitecrush-red" ) / 255.0; p_gamma[1].f_white_crush = var_InheritInteger( p_splitter, CFG_PREFIX "bz-whitecrush-green" ) / 255.0; p_gamma[2].f_white_crush = var_InheritInteger( p_splitter, CFG_PREFIX "bz-whitecrush-blue" ) / 255.0; p_gamma[0].f_black_level = var_InheritInteger( p_splitter, CFG_PREFIX "bz-blacklevel-red" ) / 255.0; p_gamma[1].f_black_level = var_InheritInteger( p_splitter, CFG_PREFIX "bz-blacklevel-green" ) / 255.0; p_gamma[2].f_black_level = var_InheritInteger( p_splitter, CFG_PREFIX "bz-blacklevel-blue" ) / 255.0; p_gamma[0].f_white_level = var_InheritInteger( p_splitter, CFG_PREFIX "bz-whitelevel-red" ) / 255.0; p_gamma[1].f_white_level = var_InheritInteger( p_splitter, CFG_PREFIX "bz-whitelevel-green" ) / 255.0; p_gamma[2].f_white_level = var_InheritInteger( p_splitter, CFG_PREFIX "bz-whitelevel-blue" ) / 255.0; for( int i = 3; i < VOUT_MAX_PLANES; i++ ) { /* Initialize unsupported planes */ p_gamma[i].f_gamma = 1.0; p_gamma[i].f_black_crush = 140.0/255.0; p_gamma[i].f_white_crush = 200.0/255.0; p_gamma[i].f_black_level = 150.0/255.0; p_gamma[i].f_white_level = 0.0/255.0; } if( p_chroma->i_chroma == VLC_CODEC_YV12 ) { /* Exchange U and V */ panoramix_gamma_t t = p_gamma[1]; p_gamma[1] = p_gamma[2]; p_gamma[2] = t; } for( int i_index = 0; i_index < 256; i_index++ ) { for( int i_index2 = 0; i_index2 <= ACCURACY; i_index2++ ) { for( int i_plane = 0; i_plane < VOUT_MAX_PLANES; i_plane++ ) { double f_factor = GammaFactor( &p_gamma[i_plane], (float)i_index / 255.0 ); float f_lut = clip_unit( 1.0 - ((ACCURACY - (float)i_index2) * f_factor / (ACCURACY - 1)) ); p_sys->p_lut[i_plane][i_index2][i_index] = f_lut * i_index + (int)( (1.0 - f_lut) * (float)p_chroma->pi_black[i_plane] ); } } } for( int i_plane = 0; i_plane < VOUT_MAX_PLANES; i_plane++ ) { if( !p_chroma->pi_div_w[i_plane] || !p_chroma->pi_div_h[i_plane] ) continue; const int i_length_w = (2 * p_sys->i_overlap_w2) / p_chroma->pi_div_w[i_plane]; const int i_length_h = (2 * p_sys->i_overlap_h2) / p_chroma->pi_div_h[i_plane]; for( int i_dir = 0; i_dir < 2; i_dir++ ) { const int i_length = i_dir == 0 ? i_length_w : i_length_h; const int i_den = i_length * i_length; const int a_2 = p_sys->a_2 * (ACCURACY / 100); const int a_1 = p_sys->a_1 * i_length * (ACCURACY / 100); const int a_0 = p_sys->a_0 * i_den * (ACCURACY / 100); for( int i_position = 0; i_position < 2; i_position++ ) { for( int i_index = 0; i_index < i_length; i_index++ ) { const int v = i_position == 1 ? i_index : (i_length - i_index); const int i_lambda = clip_accuracy( ACCURACY - (a_2 * v*v + a_1 * v + a_0) / i_den ); if( i_dir == 0 ) p_sys->lambdav[i_plane][i_position][i_index] = i_lambda; else p_sys->lambdah[i_plane][i_position][i_index] = i_lambda; } } } } } /* */ char *psz_state = var_InheritString( p_splitter, CFG_PREFIX "active" ); /* */ bool pb_active[COL_MAX*ROW_MAX]; for( int i = 0; i < COL_MAX*ROW_MAX; i++ ) pb_active[i] = psz_state == NULL; /* Parse active list if provided */ char *psz_tmp = psz_state; while( psz_tmp && *psz_tmp ) { char *psz_next = strchr( psz_tmp, ',' ); if( psz_next ) *psz_next++ = '\0'; const int i_index = atoi( psz_tmp ); if( i_index >= 0 && i_index < COL_MAX*ROW_MAX ) pb_active[i_index] = true; psz_tmp = psz_next; } free( psz_state ); /* */ p_splitter->i_output = Configuration( p_sys->pp_output, p_sys->i_col, p_sys->i_row, p_splitter->fmt.i_width, p_splitter->fmt.i_height, p_sys->i_overlap_w2, p_sys->i_overlap_h2, p_sys->b_attenuate, pb_active ); p_splitter->p_output = calloc( p_splitter->i_output, sizeof(*p_splitter->p_output) ); if( !p_splitter->p_output ) { free( p_sys ); return VLC_ENOMEM; } for( int y = 0; y < p_sys->i_row; y++ ) { for( int x = 0; x < p_sys->i_col; x++ ) { panoramix_output_t *p_output = &p_sys->pp_output[x][y]; if( !p_output->b_active ) continue; video_splitter_output_t *p_cfg = &p_splitter->p_output[p_output->i_output]; /* */ video_format_Copy( &p_cfg->fmt, &p_splitter->fmt ); p_cfg->fmt.i_visible_width = p_cfg->fmt.i_width = p_output->i_width; p_cfg->fmt.i_visible_height = p_cfg->fmt.i_height = p_output->i_height; p_cfg->window.i_x = p_output->i_x; p_cfg->window.i_y = p_output->i_y; p_cfg->window.i_align = p_output->i_align; p_cfg->psz_module = NULL; } } /* */ p_splitter->pf_filter = Filter; p_splitter->pf_mouse = Mouse; return VLC_SUCCESS; }
void es_format_InitFromVideo( es_format_t *p_es, const video_format_t *p_fmt ) { es_format_Init( p_es, VIDEO_ES, p_fmt->i_chroma ); video_format_Copy( &p_es->video, p_fmt ); }
static int SetOutputType(decoder_t *p_dec, DWORD stream_id, IMFMediaType **result) { decoder_sys_t *p_sys = p_dec->p_sys; HRESULT hr; *result = NULL; IMFMediaType *output_media_type = NULL; /* * Enumerate available output types. The list is ordered by * preference thus we will use the first one unless YV12/I420 is * available for video or float32 for audio. */ int output_type_index = 0; bool found = false; for (int i = 0; !found; ++i) { hr = IMFTransform_GetOutputAvailableType(p_sys->mft, stream_id, i, &output_media_type); if (hr == MF_E_NO_MORE_TYPES) break; else if (hr == MF_E_TRANSFORM_TYPE_NOT_SET) { /* The input type must be set before setting the output type for this MFT. */ return VLC_SUCCESS; } else if (FAILED(hr)) goto error; GUID subtype; hr = IMFMediaType_GetGUID(output_media_type, &MF_MT_SUBTYPE, &subtype); if (FAILED(hr)) goto error; if (p_dec->fmt_in.i_cat == VIDEO_ES) { if (IsEqualGUID(&subtype, &MFVideoFormat_YV12) || IsEqualGUID(&subtype, &MFVideoFormat_I420)) found = true; } else { UINT32 bits_per_sample; hr = IMFMediaType_GetUINT32(output_media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &bits_per_sample); if (FAILED(hr)) continue; if (bits_per_sample == 32 && IsEqualGUID(&subtype, &MFAudioFormat_Float)) found = true; } if (found) output_type_index = i; IMFMediaType_Release(output_media_type); output_media_type = NULL; } /* * It's not an error if we don't find the output type we were * looking for, in this case we use the first available type which * is the "preferred" output type for this MFT. */ hr = IMFTransform_GetOutputAvailableType(p_sys->mft, stream_id, output_type_index, &output_media_type); if (FAILED(hr)) goto error; hr = IMFTransform_SetOutputType(p_sys->mft, stream_id, output_media_type, 0); if (FAILED(hr)) goto error; GUID subtype; hr = IMFMediaType_GetGUID(output_media_type, &MF_MT_SUBTYPE, &subtype); if (FAILED(hr)) goto error; if (p_dec->fmt_in.i_cat == VIDEO_ES) { video_format_Copy( &p_dec->fmt_out.video, &p_dec->fmt_in.video ); p_dec->fmt_out.i_codec = vlc_fourcc_GetCodec(p_dec->fmt_in.i_cat, subtype.Data1); } else { p_dec->fmt_out.audio = p_dec->fmt_in.audio; UINT32 bitspersample = 0; hr = IMFMediaType_GetUINT32(output_media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &bitspersample); if (SUCCEEDED(hr) && bitspersample) p_dec->fmt_out.audio.i_bitspersample = bitspersample; UINT32 channels = 0; hr = IMFMediaType_GetUINT32(output_media_type, &MF_MT_AUDIO_NUM_CHANNELS, &channels); if (SUCCEEDED(hr) && channels) p_dec->fmt_out.audio.i_channels = channels; UINT32 rate = 0; hr = IMFMediaType_GetUINT32(output_media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &rate); if (SUCCEEDED(hr) && rate) p_dec->fmt_out.audio.i_rate = rate; vlc_fourcc_t fourcc; wf_tag_to_fourcc(subtype.Data1, &fourcc, NULL); p_dec->fmt_out.i_codec = vlc_fourcc_GetCodecAudio(fourcc, p_dec->fmt_out.audio.i_bitspersample); p_dec->fmt_out.audio.i_physical_channels = pi_channels_maps[p_dec->fmt_out.audio.i_channels]; } *result = output_media_type; return VLC_SUCCESS; error: msg_Err(p_dec, "Error in SetOutputType()"); if (output_media_type) IMFMediaType_Release(output_media_type); return VLC_EGENERIC; }
static picture_t *ImageRead( image_handler_t *p_image, block_t *p_block, const video_format_t *p_fmt_in, video_format_t *p_fmt_out ) { picture_t *p_pic = NULL; /* Check if we can reuse the current decoder */ if( p_image->p_dec && p_image->p_dec->fmt_in.i_codec != p_fmt_in->i_chroma ) { DeleteDecoder( p_image->p_dec ); p_image->p_dec = 0; } /* Start a decoder */ if( !p_image->p_dec ) { p_image->p_dec = CreateDecoder( p_image->p_parent, p_fmt_in ); if( !p_image->p_dec ) { block_Release(p_block); return NULL; } if( p_image->p_dec->fmt_out.i_cat != VIDEO_ES ) { DeleteDecoder( p_image->p_dec ); p_image->p_dec = NULL; block_Release(p_block); return NULL; } p_image->p_dec->pf_queue_video = ImageQueueVideo; p_image->p_dec->p_queue_ctx = p_image; } p_block->i_pts = p_block->i_dts = mdate(); int ret = p_image->p_dec->pf_decode( p_image->p_dec, p_block ); if( ret == VLCDEC_SUCCESS ) { /* Drain */ p_image->p_dec->pf_decode( p_image->p_dec, NULL ); p_pic = picture_fifo_Pop( p_image->outfifo ); unsigned lostcount = 0; picture_t *lostpic; while( ( lostpic = picture_fifo_Pop( p_image->outfifo ) ) != NULL ) { picture_Release( lostpic ); lostcount++; } if( lostcount > 0 ) msg_Warn( p_image->p_parent, "Image decoder output more than one " "picture (%d)", lostcount ); } if( p_pic == NULL ) { msg_Warn( p_image->p_parent, "no image decoded" ); return 0; } if( !p_fmt_out->i_chroma ) p_fmt_out->i_chroma = p_image->p_dec->fmt_out.video.i_chroma; if( !p_fmt_out->i_width && p_fmt_out->i_height ) p_fmt_out->i_width = (int64_t)p_image->p_dec->fmt_out.video.i_width * p_image->p_dec->fmt_out.video.i_sar_num * p_fmt_out->i_height / p_image->p_dec->fmt_out.video.i_height / p_image->p_dec->fmt_out.video.i_sar_den; if( !p_fmt_out->i_height && p_fmt_out->i_width ) p_fmt_out->i_height = (int64_t)p_image->p_dec->fmt_out.video.i_height * p_image->p_dec->fmt_out.video.i_sar_den * p_fmt_out->i_width / p_image->p_dec->fmt_out.video.i_width / p_image->p_dec->fmt_out.video.i_sar_num; if( !p_fmt_out->i_width ) p_fmt_out->i_width = p_image->p_dec->fmt_out.video.i_width; if( !p_fmt_out->i_height ) p_fmt_out->i_height = p_image->p_dec->fmt_out.video.i_height; if( !p_fmt_out->i_visible_width ) p_fmt_out->i_visible_width = p_fmt_out->i_width; if( !p_fmt_out->i_visible_height ) p_fmt_out->i_visible_height = p_fmt_out->i_height; /* Check if we need chroma conversion or resizing */ if( p_image->p_dec->fmt_out.video.i_chroma != p_fmt_out->i_chroma || p_image->p_dec->fmt_out.video.i_width != p_fmt_out->i_width || p_image->p_dec->fmt_out.video.i_height != p_fmt_out->i_height ) { if( p_image->p_filter ) if( p_image->p_filter->fmt_in.video.i_chroma != p_image->p_dec->fmt_out.video.i_chroma || p_image->p_filter->fmt_out.video.i_chroma != p_fmt_out->i_chroma ) { /* We need to restart a new filter */ DeleteFilter( p_image->p_filter ); p_image->p_filter = 0; } /* Start a filter */ if( !p_image->p_filter ) { p_image->p_filter = CreateFilter( p_image->p_parent, &p_image->p_dec->fmt_out, p_fmt_out ); if( !p_image->p_filter ) { picture_Release( p_pic ); return NULL; } } else { /* Filters should handle on-the-fly size changes */ p_image->p_filter->fmt_in = p_image->p_dec->fmt_out; p_image->p_filter->fmt_out = p_image->p_dec->fmt_out; p_image->p_filter->fmt_out.i_codec = p_fmt_out->i_chroma; p_image->p_filter->fmt_out.video = *p_fmt_out; } p_pic = p_image->p_filter->pf_video_filter( p_image->p_filter, p_pic ); video_format_Clean( p_fmt_out ); video_format_Copy( p_fmt_out, &p_image->p_filter->fmt_out.video ); } else { video_format_Clean( p_fmt_out ); video_format_Copy( p_fmt_out, &p_image->p_dec->fmt_out.video ); } return p_pic; }
/** * This function allocates and initializes a Clone splitter module */ static int Open( vlc_object_t *p_this ) { video_splitter_t *p_splitter = (video_splitter_t*)p_this; config_ChainParse( p_splitter, CFG_PREFIX, ppsz_filter_options, p_splitter->p_cfg ); char *psz_clonelist = var_CreateGetNonEmptyString( p_splitter, CFG_PREFIX "vout-list" ); if( psz_clonelist ) { /* Count the number of defined vout */ p_splitter->i_output = 1; for( int i = 0; psz_clonelist[i]; i++ ) { if( psz_clonelist[i] == VOUTSEPARATOR ) p_splitter->i_output++; } /* */ p_splitter->p_output = calloc( p_splitter->i_output, sizeof(*p_splitter->p_output) ); if( !p_splitter->p_output ) { free( psz_clonelist ); return VLC_EGENERIC; } /* Tokenize the list */ char *psz_tmp = psz_clonelist; for( int i = 0; psz_tmp && *psz_tmp; i++ ) { char *psz_new = strchr( psz_tmp, VOUTSEPARATOR ); if( psz_new ) *psz_new++ = '\0'; p_splitter->p_output[i].psz_module = strdup( psz_tmp ); psz_tmp = psz_new; } free( psz_clonelist ); } else { /* No list was specified. We will use the default vout, and get * the number of clones from clone-count */ p_splitter->i_output = var_CreateGetInteger( p_splitter, CFG_PREFIX "count" ); if( p_splitter->i_output <= 0 ) p_splitter->i_output = 1; p_splitter->p_output = calloc( p_splitter->i_output, sizeof(*p_splitter->p_output) ); if( !p_splitter->p_output ) return VLC_EGENERIC; for( int i = 0; i < p_splitter->i_output; i++ ) p_splitter->p_output[i].psz_module = NULL; } /* */ for( int i = 0; i < p_splitter->i_output; i++ ) { video_splitter_output_t *p_cfg = &p_splitter->p_output[i]; video_format_Copy( &p_cfg->fmt, &p_splitter->fmt ); p_cfg->window.i_x = 0; p_cfg->window.i_y = 0; p_cfg->window.i_align = 0; } /* */ p_splitter->pf_filter = Filter; p_splitter->pf_mouse = NULL; msg_Dbg( p_splitter, "spawning %i clone(s)", p_splitter->i_output ); return VLC_SUCCESS; }
/** * This function allocates and initializes a Wall splitter module. */ static int Open( vlc_object_t *p_this ) { video_splitter_t *p_splitter = (video_splitter_t*)p_this; video_splitter_sys_t *p_sys; p_splitter->p_sys = p_sys = malloc( sizeof(*p_sys) ); if( !p_sys ) return VLC_ENOMEM; config_ChainParse( p_splitter, CFG_PREFIX, ppsz_filter_options, p_splitter->p_cfg ); /* */ p_sys->i_col = var_CreateGetInteger( p_splitter, CFG_PREFIX "cols" ); p_sys->i_col = __MAX( 1, __MIN( COL_MAX, p_sys->i_col ) ); p_sys->i_row = var_CreateGetInteger( p_splitter, CFG_PREFIX "rows" ); p_sys->i_row = __MAX( 1, __MIN( ROW_MAX, p_sys->i_row ) ); msg_Dbg( p_splitter, "opening a %i x %i wall", p_sys->i_col, p_sys->i_row ); /* */ char *psz_state = var_CreateGetNonEmptyString( p_splitter, CFG_PREFIX "active" ); /* */ bool pb_active[COL_MAX*ROW_MAX]; for( int i = 0; i < COL_MAX*ROW_MAX; i++ ) pb_active[i] = psz_state == NULL; /* Parse active list if provided */ char *psz_tmp = psz_state; while( psz_tmp && *psz_tmp ) { char *psz_next = strchr( psz_tmp, ',' ); if( psz_next ) *psz_next++ = '\0'; const int i_index = atoi( psz_tmp ); if( i_index >= 0 && i_index < COL_MAX*ROW_MAX ) pb_active[i_index] = true; psz_tmp = psz_next; } free( psz_state ); /* Parse aspect ratio if provided */ int i_aspect = 0; char *psz_aspect = var_CreateGetNonEmptyString( p_splitter, CFG_PREFIX "element-aspect" ); if( psz_aspect ) { int i_ar_num, i_ar_den; if( sscanf( psz_aspect, "%d:%d", &i_ar_num, &i_ar_den ) == 2 && i_ar_num > 0 && i_ar_den > 0 ) { i_aspect = i_ar_num * VOUT_ASPECT_FACTOR / i_ar_den; } else { msg_Warn( p_splitter, "invalid aspect ratio specification" ); } free( psz_aspect ); } if( i_aspect <= 0 ) i_aspect = 4 * VOUT_ASPECT_FACTOR / 3; /* Compute placements/size of the windows */ const unsigned w1 = ( p_splitter->fmt.i_width / p_sys->i_col ) & ~1; const unsigned h1 = ( w1 * VOUT_ASPECT_FACTOR / i_aspect ) & ~1; const unsigned h2 = ( p_splitter->fmt.i_height / p_sys->i_row ) & ~1; const unsigned w2 = ( h2 * i_aspect / VOUT_ASPECT_FACTOR ) & ~1; unsigned i_target_width; unsigned i_target_height; unsigned i_hstart, i_hend; unsigned i_vstart, i_vend; bool b_vstart_rounded; bool b_hstart_rounded; if( h1 * p_sys->i_row < p_splitter->fmt.i_height ) { i_target_width = w2; i_target_height = h2; i_vstart = 0; b_vstart_rounded = false; i_vend = p_splitter->fmt.i_height; unsigned i_tmp = i_target_width * p_sys->i_col; while( i_tmp < p_splitter->fmt.i_width ) i_tmp += p_sys->i_col; i_hstart = (( i_tmp - p_splitter->fmt.i_width ) / 2)&~1; b_hstart_rounded = ( ( i_tmp - p_splitter->fmt.i_width ) % 2 ) || ( ( ( i_tmp - p_splitter->fmt.i_width ) / 2 ) & 1 ); i_hend = i_hstart + p_splitter->fmt.i_width; } else { i_target_height = h1; i_target_width = w1; i_hstart = 0; b_hstart_rounded = false; i_hend = p_splitter->fmt.i_width; unsigned i_tmp = i_target_height * p_sys->i_row; while( i_tmp < p_splitter->fmt.i_height ) i_tmp += p_sys->i_row; i_vstart = ( ( i_tmp - p_splitter->fmt.i_height ) / 2 ) & ~1; b_vstart_rounded = ( ( i_tmp - p_splitter->fmt.i_height ) % 2 ) || ( ( ( i_tmp - p_splitter->fmt.i_height ) / 2 ) & 1 ); i_vend = i_vstart + p_splitter->fmt.i_height; } msg_Dbg( p_splitter, "target resolution %dx%d", i_target_width, i_target_height ); msg_Dbg( p_splitter, "target window (%d,%d)-(%d,%d)", i_hstart,i_vstart,i_hend,i_vend ); int i_active = 0; for( int y = 0, i_top = 0; y < p_sys->i_row; y++ ) { /* */ int i_height = 0; int i_halign = 0; if( y * i_target_height >= i_vstart && ( y + 1 ) * i_target_height <= i_vend ) { i_height = i_target_height; } else if( ( y + 1 ) * i_target_height < i_vstart || ( y * i_target_height ) > i_vend ) { i_height = 0; } else { i_height = ( i_target_height - i_vstart%i_target_height ); if( y >= ( p_sys->i_row / 2 ) ) { i_halign = VOUT_ALIGN_TOP; i_height -= b_vstart_rounded ? 2: 0; } else { i_halign = VOUT_ALIGN_BOTTOM; } } /* */ for( int x = 0, i_left = 0; x < p_sys->i_col; x++ ) { wall_output_t *p_output = &p_sys->pp_output[x][y]; /* */ int i_width; int i_valign = 0; if( x*i_target_width >= i_hstart && (x+1)*i_target_width <= i_hend ) { i_width = i_target_width; } else if( ( x + 1 ) * i_target_width < i_hstart || ( x * i_target_width ) > i_hend ) { i_width = 0; } else { i_width = ( i_target_width - i_hstart % i_target_width ); if( x >= ( p_sys->i_col / 2 ) ) { i_valign = VOUT_ALIGN_LEFT; i_width -= b_hstart_rounded ? 2: 0; } else { i_valign = VOUT_ALIGN_RIGHT; } } /* */ p_output->b_active = pb_active[y * p_sys->i_col + x] && i_height > 0 && i_width > 0; p_output->i_output = -1; p_output->i_align = i_valign | i_halign; p_output->i_width = i_width; p_output->i_height = i_height; p_output->i_left = i_left; p_output->i_top = i_top; msg_Dbg( p_splitter, "window %dx%d at %d:%d size %dx%d", x, y, i_left, i_top, i_width, i_height ); if( p_output->b_active ) i_active++; i_left += i_width; } i_top += i_height; } if( i_active <= 0 ) { msg_Err( p_splitter, "No active video output" ); free( p_sys ); return VLC_EGENERIC; } /* Setup output configuration */ p_splitter->i_output = i_active; p_splitter->p_output = calloc( p_splitter->i_output, sizeof(*p_splitter->p_output) ); if( !p_splitter->p_output ) { free( p_sys ); return VLC_ENOMEM; } for( int y = 0, i_output = 0; y < p_sys->i_row; y++ ) { for( int x = 0; x < p_sys->i_col; x++ ) { wall_output_t *p_output = &p_sys->pp_output[x][y]; if( !p_output->b_active ) continue; p_output->i_output = i_output++; video_splitter_output_t *p_cfg = &p_splitter->p_output[p_output->i_output]; video_format_Copy( &p_cfg->fmt, &p_splitter->fmt ); p_cfg->fmt.i_visible_width = p_cfg->fmt.i_width = p_output->i_width; p_cfg->fmt.i_visible_height = p_cfg->fmt.i_height = p_output->i_height; p_cfg->fmt.i_sar_num = (int64_t)i_aspect * i_target_height; p_cfg->fmt.i_sar_den = VOUT_ASPECT_FACTOR * i_target_width; p_cfg->window.i_x = p_output->i_left; /* FIXME relative to video-x/y (TODO in wrapper.c) ? */ p_cfg->window.i_y = p_output->i_top; p_cfg->window.i_align = p_output->i_align; p_cfg->psz_module = NULL; } } /* */ p_splitter->pf_filter = Filter; p_splitter->pf_mouse = Mouse; return VLC_SUCCESS; }