Exemple #1
0
/**
 * Filter a picture
 */
picture_t *Filter( filter_t *p_filter, picture_t *p_pic_in ) {
    if( !p_pic_in || !p_filter) return NULL;

    const video_format_t  *p_fmt_in = &p_filter->fmt_in.video;
    filter_sys_t *p_sys = p_filter->p_sys;

    picture_t *p_pic_out = filter_NewPicture( p_filter );
    if( !p_pic_out ) {
        picture_Release( p_pic_in );
        return NULL;
    }

    int i_ret = 0;
    p_sys->b_bake_request = false;

    if ((p_sys->pi_order == NULL) || (p_sys->ps_desk_planes == NULL) || (p_sys->ps_pict_planes == NULL)  || (p_sys->ps_puzzle_array == NULL) || (p_sys->ps_pieces == NULL))
        p_sys->b_init = false;

    if ((p_sys->ps_pieces_shapes == NULL) && p_sys->s_current_param.b_advanced && (p_sys->s_current_param.i_shape_size != 0))
        p_sys->b_init = false;

    /* assert initialized & allocated data match with current frame characteristics */
    if ( p_sys->s_allocated.i_planes != p_pic_out->i_planes)
        p_sys->b_init = false;
    p_sys->s_current_param.i_planes = p_pic_out->i_planes;
    if (p_sys->ps_pict_planes != NULL) {
        for (uint8_t i_plane = 0; i_plane < p_sys->s_allocated.i_planes; i_plane++) {
            if ( (p_sys->ps_pict_planes[i_plane].i_lines != p_pic_in->p[i_plane].i_visible_lines)
                    || (p_sys->ps_pict_planes[i_plane].i_width != p_pic_in->p[i_plane].i_visible_pitch / p_pic_in->p[i_plane].i_pixel_pitch)
                    || (p_sys->ps_desk_planes[i_plane].i_lines != p_pic_out->p[i_plane].i_visible_lines)
                    || (p_sys->ps_desk_planes[i_plane].i_width != p_pic_out->p[i_plane].i_visible_pitch / p_pic_out->p[i_plane].i_pixel_pitch) )
                p_sys->b_init = false;
        }
    }

    p_sys->s_current_param.i_pict_width  = (int) p_pic_in->p[0].i_visible_pitch / p_pic_in->p[0].i_pixel_pitch;
    p_sys->s_current_param.i_pict_height = (int) p_pic_in->p[0].i_visible_lines;
    p_sys->s_current_param.i_desk_width  = (int) p_pic_out->p[0].i_visible_pitch / p_pic_out->p[0].i_pixel_pitch;
    p_sys->s_current_param.i_desk_height = (int) p_pic_out->p[0].i_visible_lines;

    /* assert no mismatch between sizes */
    if (    p_sys->s_current_param.i_pict_width  != p_sys->s_current_param.i_desk_width
         || p_sys->s_current_param.i_pict_height != p_sys->s_current_param.i_desk_height
         || p_sys->s_current_param.i_pict_width  != (int) p_fmt_in->i_width
         || p_sys->s_current_param.i_pict_height != (int) p_fmt_in->i_height )
        return NULL;

    vlc_mutex_lock( &p_sys->lock );

    /* check if we have to compute initial data */
    if ( p_sys->b_change_param || p_sys->b_bake_request || !p_sys->b_init ) {
        if ( p_sys->s_allocated.i_rows != p_sys->s_new_param.i_rows
                || p_sys->s_allocated.i_cols != p_sys->s_new_param.i_cols
                || p_sys->s_allocated.i_rotate != p_sys->s_new_param.i_rotate
                || p_sys->s_allocated.i_mode != p_sys->s_new_param.i_mode
                || p_sys->b_bake_request  || !p_sys->b_init )
        {
            p_sys->b_bake_request = true;
            p_sys->b_init = false;
            p_sys->b_shuffle_rqst = true;
            p_sys->b_shape_init = false;
        }

        if ( p_sys->s_current_param.i_border != p_sys->s_new_param.i_border
                || p_sys->s_current_param.i_shape_size != p_sys->s_new_param.i_shape_size )
        {
            p_sys->b_bake_request = true;
            p_sys->b_shape_init = false;
        }

        /* depending on the game selected, set associated internal flags */
        switch ( p_sys->s_new_param.i_mode )
        {
          case 0:  /* jigsaw puzzle */
            p_sys->s_new_param.b_advanced    = true;
            p_sys->s_new_param.b_blackslot   = false;
            p_sys->s_new_param.b_near        = false;
            break;
          case 1:  /* sliding puzzle */
            p_sys->s_new_param.b_advanced    = false;
            p_sys->s_new_param.b_blackslot   = true;
            p_sys->s_new_param.b_near        = true;
            break;
          case 2:  /* swap puzzle */
            p_sys->s_new_param.b_advanced    = false;
            p_sys->s_new_param.b_blackslot   = false;
            p_sys->s_new_param.b_near        = true;
            break;
          case 3:  /* exchange puzzle */
            p_sys->s_new_param.b_advanced    = false;
            p_sys->s_new_param.b_blackslot   = false;
            p_sys->s_new_param.b_near        = false;
            break;
        }
        p_sys->s_current_param.i_mode = p_sys->s_new_param.i_mode;

        if ( p_sys->s_current_param.b_blackslot != p_sys->s_new_param.b_blackslot
                && p_sys->i_selected == NO_PCE
                && p_sys->s_current_param.b_blackslot )
            p_sys->i_selected = 0;

        if ( p_sys->s_current_param.i_auto_shuffle_speed != p_sys->s_new_param.i_auto_shuffle_speed )
            p_sys->i_auto_shuffle_countdown_val = init_countdown(p_sys->s_new_param.i_auto_shuffle_speed);

        if ( p_sys->s_current_param.i_auto_solve_speed != p_sys->s_new_param.i_auto_solve_speed )
            p_sys->i_auto_solve_countdown_val = init_countdown(p_sys->s_current_param.i_auto_solve_speed);

        p_sys->s_current_param.i_rows       = p_sys->s_new_param.i_rows;
        p_sys->s_current_param.i_cols       = p_sys->s_new_param.i_cols;
        p_sys->s_current_param.i_pieces_nbr = p_sys->s_current_param.i_rows * p_sys->s_current_param.i_cols;
        p_sys->s_current_param.b_advanced   = p_sys->s_new_param.b_advanced;
        if (!p_sys->s_new_param.b_advanced) {
            p_sys->s_current_param.b_blackslot   = p_sys->s_new_param.b_blackslot;
            p_sys->s_current_param.b_near        = p_sys->s_new_param.b_near || p_sys->s_new_param.b_blackslot;
            p_sys->s_current_param.i_border      = 0;
            p_sys->s_current_param.b_preview     = false;
            p_sys->s_current_param.i_preview_size= 0;
            p_sys->s_current_param.i_shape_size  = 0;
            p_sys->s_current_param.i_auto_shuffle_speed  = 0;
            p_sys->s_current_param.i_auto_solve_speed    = 0;
            p_sys->s_current_param.i_rotate      = 0;
        }
        else
        {
            p_sys->s_current_param.b_blackslot = false;
            p_sys->s_current_param.b_near      = false;
            p_sys->s_current_param.i_border    = p_sys->s_new_param.i_border;
            p_sys->s_current_param.b_preview   = p_sys->s_new_param.b_preview;
            p_sys->s_current_param.i_preview_size        = p_sys->s_new_param.i_preview_size;
            p_sys->s_current_param.i_shape_size          = p_sys->s_new_param.i_shape_size;
            p_sys->s_current_param.i_auto_shuffle_speed  = p_sys->s_new_param.i_auto_shuffle_speed;
            p_sys->s_current_param.i_auto_solve_speed    = p_sys->s_new_param.i_auto_solve_speed;
            p_sys->s_current_param.i_rotate     = p_sys->s_new_param.i_rotate;
        }
        p_sys->b_change_param = false;
    }

    vlc_mutex_unlock( &p_sys->lock );

    /* generate initial puzzle data when needed */
    if ( p_sys->b_bake_request ) {
        if (!p_sys->b_shuffle_rqst) {
            /* here we have to keep the same position
             * we have to save locations before generating new data
             */
            save_game_t *ps_save_game = puzzle_save(p_filter);
            if (!ps_save_game)
                return CopyInfoAndRelease( p_pic_out, p_pic_in );
            i_ret = puzzle_bake( p_filter, p_pic_out, p_pic_in );
            if ( i_ret != VLC_SUCCESS )
            {
                free(ps_save_game->ps_pieces);
                free(ps_save_game);
                return CopyInfoAndRelease( p_pic_out, p_pic_in );
            }
            puzzle_load( p_filter, ps_save_game);
            free(ps_save_game->ps_pieces);
            free(ps_save_game);
        }
        else {
            i_ret = puzzle_bake( p_filter, p_pic_out, p_pic_in );
            if ( i_ret != VLC_SUCCESS )
                return CopyInfoAndRelease( p_pic_out, p_pic_in );
        }
    }

    /* shuffle the desk and generate pieces data  */
    if ( p_sys->b_shuffle_rqst && p_sys->b_init ) {
        i_ret = puzzle_bake_piece ( p_filter );
        if (i_ret != VLC_SUCCESS)
            return CopyInfoAndRelease( p_pic_out, p_pic_in );
    }

    /* preset output pic */
    if ( !p_sys->b_bake_request && !p_sys->b_shuffle_rqst && p_sys->b_init && !p_sys->b_finished )
        puzzle_preset_desk_background(p_pic_out, 0, 127, 127);
    else {
        /* copy src to dst during init & bake process */
        for( uint8_t i_plane = 0; i_plane < p_pic_out->i_planes; i_plane++ )
            memcpy( p_pic_out->p[i_plane].p_pixels, p_pic_in->p[i_plane].p_pixels,
                p_pic_in->p[i_plane].i_pitch * (int32_t) p_pic_in->p[i_plane].i_visible_lines );
    }

    vlc_mutex_lock( &p_sys->pce_lock );

    /* manage the game, adjust locations, groups and regenerate some corrupted data if any */
    for (uint32_t i = 0; i < __MAX( 4, p_sys->s_allocated.i_pieces_nbr / 4 )
                             && ( !p_sys->b_bake_request && !p_sys->b_mouse_drag
                             && p_sys->b_init && p_sys->s_current_param.b_advanced ); i++)
    {
        puzzle_solve_pces_accuracy( p_filter );
    }

    for (uint32_t i = 0; i < __MAX( 4, p_sys->s_allocated.i_pieces_nbr / 4 )
                             && ( !p_sys->b_bake_request && !p_sys->b_mouse_drag
                             && p_sys->b_init && p_sys->s_current_param.b_advanced ); i++)
    {
        puzzle_solve_pces_group( p_filter );
    }

    if ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init
            && p_sys->s_current_param.b_advanced )
        puzzle_count_pce_group( p_filter);
    if ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init
            && p_sys->s_current_param.b_advanced ) {
        i_ret = puzzle_sort_layers( p_filter);
        if (i_ret != VLC_SUCCESS)
        {
            vlc_mutex_unlock( &p_sys->pce_lock );
            return CopyInfoAndRelease( p_pic_out, p_pic_in );
        }
    }

    for (uint32_t i = 0; i < __MAX( 4, p_sys->s_allocated.i_pieces_nbr / 24 )
                            && ( !p_sys->b_bake_request && !p_sys->b_mouse_drag
                            && p_sys->b_init && p_sys->s_current_param.b_advanced ); i++)
    {
        p_sys->i_calc_corn_loop++;
        p_sys->i_calc_corn_loop %= p_sys->s_allocated.i_pieces_nbr;
        puzzle_calculate_corners( p_filter, p_sys->i_calc_corn_loop );
    }

    /* computer moves some piece depending on auto_solve and auto_shuffle param */
    if ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init
             && p_sys->ps_puzzle_array != NULL && p_sys->s_current_param.b_advanced )
    {
        puzzle_auto_shuffle( p_filter );
        puzzle_auto_solve( p_filter );
    }

    vlc_mutex_unlock( &p_sys->pce_lock );

    /* draw output pic */
    if ( !p_sys->b_bake_request && p_sys->b_init  && p_sys->ps_puzzle_array != NULL ) {

        puzzle_draw_borders(p_filter, p_pic_in, p_pic_out);

        p_sys->i_pointed_pce = NO_PCE;
        puzzle_draw_pieces(p_filter, p_pic_in, p_pic_out);

        /* when puzzle_draw_pieces() has not updated p_sys->i_pointed_pce,
         * use puzzle_find_piece to define the piece pointed by the mouse
         */
        if (p_sys->i_pointed_pce == NO_PCE)
            p_sys->i_mouse_drag_pce = puzzle_find_piece( p_filter, p_sys->i_mouse_x, p_sys->i_mouse_y, -1);
        else
            p_sys->i_mouse_drag_pce = p_sys->i_pointed_pce;

        if (p_sys->s_current_param.b_preview )
            puzzle_draw_preview(p_filter, p_pic_in, p_pic_out);

        /* highlight the selected piece when not playing jigsaw mode */
        if ( p_sys->i_selected != NO_PCE && !p_sys->s_current_param.b_blackslot
                && !p_sys->s_current_param.b_advanced )
        {
            int32_t c = (p_sys->i_selected % p_sys->s_allocated.i_cols);
            int32_t r = (p_sys->i_selected / p_sys->s_allocated.i_cols);

            puzzle_draw_rectangle(p_pic_out,
                p_sys->ps_puzzle_array[r][c][0].i_x,
                p_sys->ps_puzzle_array[r][c][0].i_y,
                p_sys->ps_puzzle_array[r][c][0].i_width,
                p_sys->ps_puzzle_array[r][c][0].i_lines,
                255, 127, 127);
        }

        /* draw the blackslot when playing sliding puzzle mode */
        if ( p_sys->i_selected != NO_PCE && p_sys->s_current_param.b_blackslot
                && !p_sys->s_current_param.b_advanced )
        {
            int32_t c = (p_sys->i_selected % p_sys->s_allocated.i_cols);
            int32_t r = (p_sys->i_selected / p_sys->s_allocated.i_cols);

            puzzle_fill_rectangle(p_pic_out,
                p_sys->ps_puzzle_array[r][c][0].i_x,
                p_sys->ps_puzzle_array[r][c][0].i_y,
                p_sys->ps_puzzle_array[r][c][0].i_width,
                p_sys->ps_puzzle_array[r][c][0].i_lines,
                0, 127, 127);
        }

        /* Draw the 'puzzle_shuffle' button if the puzzle is finished */
        if ( p_sys->b_finished )
            puzzle_draw_sign(p_pic_out, 0, 0, SHUFFLE_WIDTH, SHUFFLE_LINES, ppsz_shuffle_button, false);

        /* draw an arrow at mouse pointer to indicate current action (rotation...) */
        if ((p_sys->i_mouse_drag_pce != NO_PCE) && !p_sys->b_mouse_drag
                && !p_sys->b_finished && p_sys->s_current_param.b_advanced )
        {
            vlc_mutex_lock( &p_sys->pce_lock );

            int32_t i_delta_x;

            if (p_sys->s_current_param.i_rotate != 3)
                i_delta_x = 0;
            else if ( (p_sys->ps_pieces[p_sys->i_mouse_drag_pce].i_actual_angle & 1) == 0)
                i_delta_x = p_sys->ps_desk_planes[0].i_pce_max_width / 6;
            else
                i_delta_x = p_sys->ps_desk_planes[0].i_pce_max_lines / 6;

            if (p_sys->s_current_param.i_rotate == 0)
                p_sys->i_mouse_action = 0;
            else if (p_sys->s_current_param.i_rotate == 1)
                p_sys->i_mouse_action = 2;
            else if ( p_sys->i_mouse_x >= ( p_sys->ps_pieces[p_sys->i_mouse_drag_pce].i_center_x + i_delta_x) )
                p_sys->i_mouse_action = -1;  /* rotate counterclockwise */
            else if ( p_sys->i_mouse_x <= ( p_sys->ps_pieces[p_sys->i_mouse_drag_pce].i_center_x - i_delta_x) )
                p_sys->i_mouse_action = +1;
            else
                p_sys->i_mouse_action = 4;   /* center click: only mirror */

            if ( p_sys->i_mouse_action == +1 )
                puzzle_draw_sign(p_pic_out, p_sys->i_mouse_x - ARROW_WIDTH,
                                 p_sys->i_mouse_y, ARROW_WIDTH, ARROW_LINES, ppsz_rot_arrow_sign, false);
            else if ( p_sys->i_mouse_action == -1 )
                puzzle_draw_sign(p_pic_out, p_sys->i_mouse_x - ARROW_WIDTH,
                                 p_sys->i_mouse_y, ARROW_WIDTH, ARROW_LINES, ppsz_rot_arrow_sign, true);
            else if ( p_sys->i_mouse_action == 4 )
                puzzle_draw_sign(p_pic_out, p_sys->i_mouse_x - ARROW_WIDTH,
                                 p_sys->i_mouse_y, ARROW_WIDTH, ARROW_LINES, ppsz_mir_arrow_sign, false);

            vlc_mutex_unlock( &p_sys->pce_lock );
        }
    }

    return CopyInfoAndRelease( p_pic_out, p_pic_in );
}
Exemple #2
0
static int Open(vlc_object_t *obj)
{
    filter_t *filter = (filter_t *)obj;
    filter_sys_t *sys = NULL;
    HINSTANCE hdecoder_dll = NULL;
    HINSTANCE d3d9_dll = NULL;
    HRESULT hr;
    picture_t *dst = NULL;
    GUID *processorGUIDs = NULL;
    GUID *processorGUID = NULL;
    IDirectXVideoProcessorService *processor = NULL;

    if (filter->fmt_in.video.i_chroma != VLC_CODEC_D3D9_OPAQUE
     && filter->fmt_in.video.i_chroma != VLC_CODEC_D3D9_OPAQUE_10B)
        return VLC_EGENERIC;
    if (!video_format_IsSimilar(&filter->fmt_in.video, &filter->fmt_out.video))
        return VLC_EGENERIC;

    d3d9_dll = LoadLibrary(TEXT("D3D9.DLL"));
    if (!d3d9_dll)
        goto error;

    hdecoder_dll = LoadLibrary(TEXT("DXVA2.DLL"));
    if (!hdecoder_dll)
        goto error;

    dst = filter_NewPicture(filter);
    if (dst == NULL)
        goto error;

    if (!dst->p_sys)
    {
        msg_Dbg(filter, "D3D9 opaque without a texture");
        goto error;
    }

    sys = calloc(1, sizeof (*sys));
    if (unlikely(sys == NULL))
        goto error;

    HRESULT (WINAPI *CreateVideoService)(IDirect3DDevice9 *,
                                         REFIID riid,
                                         void **ppService);
    CreateVideoService =
      (void *)GetProcAddress(hdecoder_dll, "DXVA2CreateVideoService");
    if (CreateVideoService == NULL)
        goto error;

    hr = IDirect3DSurface9_GetDevice( dst->p_sys->surface, &sys->d3ddev );
    if (FAILED(hr))
        goto error;

    D3DSURFACE_DESC dstDesc;
    hr = IDirect3DSurface9_GetDesc( dst->p_sys->surface, &dstDesc );
    if (unlikely(FAILED(hr)))
        goto error;

    hr = CreateVideoService( sys->d3ddev, &IID_IDirectXVideoProcessorService,
                            (void**)&processor);
    if (FAILED(hr))
        goto error;

    DXVA2_VideoDesc dsc;
    ZeroMemory(&dsc, sizeof(dsc));
    dsc.SampleWidth     = dstDesc.Width;
    dsc.SampleHeight    = dstDesc.Height;
    dsc.Format          = dstDesc.Format;
    if (filter->fmt_in.video.i_frame_rate && filter->fmt_in.video.i_frame_rate_base) {
        dsc.InputSampleFreq.Numerator   = filter->fmt_in.video.i_frame_rate;
        dsc.InputSampleFreq.Denominator = filter->fmt_in.video.i_frame_rate_base;
    } else {
        dsc.InputSampleFreq.Numerator   = 0;
        dsc.InputSampleFreq.Denominator = 0;
    }
    dsc.OutputFrameFreq = dsc.InputSampleFreq;

    DXVA2_ExtendedFormat *pFormat = &dsc.SampleFormat;
    pFormat->SampleFormat = dst->b_top_field_first ?
                DXVA2_SampleFieldInterleavedEvenFirst :
                DXVA2_SampleFieldInterleavedOddFirst;

    UINT count = 0;
    hr = IDirectXVideoProcessorService_GetVideoProcessorDeviceGuids( processor,
                                                                &dsc,
                                                                &count,
                                                                &processorGUIDs);
    if (FAILED(hr))
        goto error;

    char *psz_mode = var_InheritString( filter, "deinterlace-mode" );
    const struct filter_mode_t *p_mode = GetFilterMode(psz_mode);
    if (p_mode == NULL)
    {
        msg_Dbg(filter, "unknown mode %s, trying blend", psz_mode);
        p_mode = GetFilterMode("blend");
    }
    if (strcmp(p_mode->psz_mode, psz_mode))
        msg_Dbg(filter, "using %s deinterlacing mode", p_mode->psz_mode);

    DXVA2_VideoProcessorCaps caps, best_caps;
    unsigned best_score = 0;
    for (UINT i=0; i<count; ++i) {
        hr = IDirectXVideoProcessorService_GetVideoProcessorCaps( processor,
                                                                  processorGUIDs+i,
                                                                  &dsc,
                                                                  dsc.Format,
                                                                  &caps);
        if ( FAILED(hr) || !caps.DeinterlaceTechnology )
            continue;

        unsigned score = (caps.DeinterlaceTechnology & p_mode->i_mode) ? 10 : 1;
        if (best_score < score) {
            best_score = score;
            best_caps = caps;
            processorGUID = processorGUIDs + i;
        }
    }

    if (processorGUID == NULL)
    {
        msg_Dbg(filter, "Could not find a filter to output the required format");
        goto error;
    }

    hr = IDirectXVideoProcessorService_CreateVideoProcessor( processor,
                                                             processorGUID,
                                                             &dsc,
                                                             dsc.Format,
                                                             1,
                                                             &sys->processor );
    if (FAILED(hr))
        goto error;

    hr = IDirectXVideoProcessorService_CreateSurface( processor,
                                                      dstDesc.Width,
                                                      dstDesc.Height,
                                                      0,
                                                      dstDesc.Format,
                                                      D3DPOOL_DEFAULT,
                                                      0,
                                                      DXVA2_VideoProcessorRenderTarget,
                                                      &sys->hw_surface,
                                                      NULL);
    if (FAILED(hr))
        goto error;

    sys->hdecoder_dll = hdecoder_dll;
    sys->d3d9_dll     = d3d9_dll;
    sys->decoder_caps = best_caps;

    InitDeinterlacingContext( &sys->context );

    sys->context.settings = p_mode->settings;
    sys->context.settings.b_use_frame_history = best_caps.NumBackwardRefSamples != 0 ||
                                       best_caps.NumForwardRefSamples  != 0;
    if (sys->context.settings.b_use_frame_history != p_mode->settings.b_use_frame_history)
        msg_Dbg( filter, "deinterlacing not using frame history as requested");
    if (sys->context.settings.b_double_rate)
        sys->context.pf_render_ordered = RenderPic;
    else
        sys->context.pf_render_single_pic = RenderSinglePic;

    video_format_t out_fmt;
    GetDeinterlacingOutput( &sys->context, &out_fmt, &filter->fmt_in.video );
    if( !filter->b_allow_fmt_out_change &&
         out_fmt.i_height != filter->fmt_in.video.i_height )
    {
       goto error;
    }

    CoTaskMemFree(processorGUIDs);
    IDirectXVideoProcessorService_Release(processor);
    picture_Release(dst);

    sys->buffer_new = filter->owner.video.buffer_new;
    filter->owner.video.buffer_new = NewOutputPicture;
    filter->fmt_out.video   = out_fmt;
    filter->pf_video_filter = Deinterlace;
    filter->pf_flush        = Flush;
    filter->p_sys = sys;

    return VLC_SUCCESS;
error:
    CoTaskMemFree(processorGUIDs);
    if (sys && sys->processor)
        IDirectXVideoProcessor_Release( sys->processor );
    if (processor)
        IDirectXVideoProcessorService_Release(processor);
    if (sys && sys->d3ddev)
        IDirect3DDevice9_Release( sys->d3ddev );
    if (hdecoder_dll)
        FreeLibrary(hdecoder_dll);
    if (d3d9_dll)
        FreeLibrary(d3d9_dll);
    if (dst)
        picture_Release(dst);
    free(sys);

    return VLC_EGENERIC;
}
Exemple #3
0
static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
{
    picture_t *p_outpic;
    filter_sys_t *p_sys = p_filter->p_sys;
    const int i_dim = p_sys->i_dim;
    type_t *pt_buffer;
    type_t *pt_scale;
    const type_t *pt_distribution = p_sys->pt_distribution;

    if( !p_pic ) return NULL;

    p_outpic = filter_NewPicture( p_filter );
    if( !p_outpic )
    {
        picture_Release( p_pic );
        return NULL;
    }
    if( !p_sys->pt_buffer )
    {
        p_sys->pt_buffer = realloc_or_free( p_sys->pt_buffer,
                                            p_pic->p[Y_PLANE].i_visible_lines *
                                            p_pic->p[Y_PLANE].i_pitch * sizeof( type_t ) );
    }

    pt_buffer = p_sys->pt_buffer;
    if( !p_sys->pt_scale )
    {
        const int i_visible_lines = p_pic->p[Y_PLANE].i_visible_lines;
        const int i_visible_pitch = p_pic->p[Y_PLANE].i_visible_pitch;
        const int i_pitch = p_pic->p[Y_PLANE].i_pitch;

        p_sys->pt_scale = xmalloc( i_visible_lines * i_pitch * sizeof( type_t ) );
        pt_scale = p_sys->pt_scale;

        for( int i_line = 0 ; i_line < i_visible_lines ; i_line++ )
        {
            for( int i_col = 0; i_col < i_visible_pitch ; i_col++ )
            {
                type_t t_value = 0;

                for( int y = __MAX( -i_dim, -i_line );
                        y <= __MIN( i_dim, i_visible_lines - i_line - 1 );
                        y++ )
                {
                    for( int x = __MAX( -i_dim, -i_col );
                            x <= __MIN( i_dim, i_visible_pitch - i_col + 1 );
                            x++ )
                    {
                        t_value += pt_distribution[y+i_dim] *
                                   pt_distribution[x+i_dim];
                    }
                }
                pt_scale[i_line*i_pitch+i_col] = t_value;
            }
        }
    }

    pt_scale = p_sys->pt_scale;
    for( int i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
    {

        uint8_t *p_in = p_pic->p[i_plane].p_pixels;
        uint8_t *p_out = p_outpic->p[i_plane].p_pixels;

        const int i_visible_lines = p_pic->p[i_plane].i_visible_lines;
        const int i_visible_pitch = p_pic->p[i_plane].i_visible_pitch;
        const int i_in_pitch = p_pic->p[i_plane].i_pitch;

        int i_line, i_col;
        const int x_factor = p_pic->p[Y_PLANE].i_visible_pitch/i_visible_pitch-1;
        const int y_factor = p_pic->p[Y_PLANE].i_visible_lines/i_visible_lines-1;

        for( i_line = 0 ; i_line < i_visible_lines ; i_line++ )
        {
            for( i_col = 0; i_col < i_visible_pitch ; i_col++ )
            {
                type_t t_value = 0;
                int x;
                const int c = i_line*i_in_pitch+i_col;
                for( x = __MAX( -i_dim, -i_col*(x_factor+1) );
                        x <= __MIN( i_dim, (i_visible_pitch - i_col)*(x_factor+1) + 1 );
                        x++ )
                {
                    t_value += pt_distribution[x+i_dim] *
                               p_in[c+(x>>x_factor)];
                }
                pt_buffer[c] = t_value;
            }
        }
        for( i_line = 0 ; i_line < i_visible_lines ; i_line++ )
        {
            for( i_col = 0; i_col < i_visible_pitch ; i_col++ )
            {
                type_t t_value = 0;
                int y;
                const int c = i_line*i_in_pitch+i_col;
                for( y = __MAX( -i_dim, (-i_line)*(y_factor+1) );
                        y <= __MIN( i_dim, (i_visible_lines - i_line)*(y_factor+1) - 1 );
                        y++ )
                {
                    t_value += pt_distribution[y+i_dim] *
                               pt_buffer[c+(y>>y_factor)*i_in_pitch];
                }

                const type_t t_scale = pt_scale[(i_line<<y_factor)*(i_in_pitch<<x_factor)+(i_col<<x_factor)];
                p_out[i_line * p_outpic->p[i_plane].i_pitch + i_col] = (uint8_t)(t_value / t_scale); // FIXME wouldn't it be better to round instead of trunc ?
            }
        }
    }

    return CopyInfoAndRelease( p_outpic, p_pic );
}
Exemple #4
0
Fichier : canvas.c Projet : paa/vlc
static picture_t *video_new( filter_t *p_filter )
{
    return filter_NewPicture( (filter_t*)p_filter->p_owner );
}
Exemple #5
0
/****************************************************************************
 * Filter: the whole thing
 ****************************************************************************/
static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
{
    filter_sys_t *p_sys = p_filter->p_sys;
    picture_t *p_outpic;
    int i_plane;
    int i_width, i_height, i_xcrop, i_ycrop,
        i_outwidth, i_outheight, i_xpadd, i_ypadd;

    const int p_padd_color[] = { 0x00, 0x80, 0x80, 0xff };

    if( !p_pic ) return NULL;

    /* Request output picture */
    p_outpic = filter_NewPicture( p_filter );
    if( !p_outpic )
    {
        picture_Release( p_pic );
        return NULL;
    }

    for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ )
    /* p_pic and p_outpic have the same chroma/number of planes but that's
     * about it. */
    {
        plane_t *p_plane = p_pic->p+i_plane;
        plane_t *p_outplane = p_outpic->p+i_plane;
        uint8_t *p_in = p_plane->p_pixels;
        uint8_t *p_out = p_outplane->p_pixels;
        int i_pixel_pitch = p_plane->i_pixel_pitch;
        int i_padd_color = i_plane > 3 ? p_padd_color[0]
                                       : p_padd_color[i_plane];

        /* These assignments assume that the first plane always has
         * a width and height equal to the picture's */
        i_width =     ( ( p_filter->fmt_in.video.i_visible_width
                          - p_sys->i_cropleft - p_sys->i_cropright )
                        * p_plane->i_visible_pitch )
                      / p_pic->p->i_visible_pitch;
        i_height =    ( ( p_filter->fmt_in.video.i_visible_height
                          - p_sys->i_croptop - p_sys->i_cropbottom )
                        * p_plane->i_visible_lines )
                      / p_pic->p->i_visible_lines;
        i_xcrop =     ( p_sys->i_cropleft * p_plane->i_visible_pitch)
                      / p_pic->p->i_visible_pitch;
        i_ycrop =     ( p_sys->i_croptop * p_plane->i_visible_lines)
                      / p_pic->p->i_visible_lines;
        i_outwidth =  ( p_filter->fmt_out.video.i_visible_width
                        * p_outplane->i_visible_pitch )
                      / p_outpic->p->i_visible_pitch;
        i_outheight = ( p_filter->fmt_out.video.i_visible_height
                        * p_outplane->i_visible_lines )
                      / p_outpic->p->i_visible_lines;
        i_xpadd =     ( p_sys->i_paddleft * p_outplane->i_visible_pitch )
                      / p_outpic->p->i_visible_pitch;
        i_ypadd =     ( p_sys->i_paddtop * p_outplane->i_visible_lines )
                       / p_outpic->p->i_visible_lines;

        /* Crop the top */
        p_in += i_ycrop * p_plane->i_pitch;

        /* Padd on the top */
        vlc_memset( p_out, i_padd_color, i_ypadd * p_outplane->i_pitch );
        p_out += i_ypadd * p_outplane->i_pitch;

        int i_line;
        for( i_line = 0; i_line < i_height; i_line++ )
        {
            uint8_t *p_in_next = p_in + p_plane->i_pitch;
            uint8_t *p_out_next = p_out + p_outplane->i_pitch;

            /* Crop on the left */
            p_in += i_xcrop * i_pixel_pitch;

            /* Padd on the left */
            vlc_memset( p_out, i_padd_color, i_xpadd * i_pixel_pitch );
            p_out += i_xpadd * i_pixel_pitch;

            /* Copy the image and crop on the right */
            vlc_memcpy( p_out, p_in, i_width * i_pixel_pitch );
            p_out += i_width * i_pixel_pitch;
            p_in += i_width * i_pixel_pitch;

            /* Padd on the right */
            vlc_memset( p_out, i_padd_color,
                        ( i_outwidth - i_xpadd - i_width ) * i_pixel_pitch );

            /* Got to begining of the next line */
            p_in = p_in_next;
            p_out = p_out_next;
        }

        /* Padd on the bottom */
        vlc_memset( p_out, i_padd_color,
                 ( i_outheight - i_ypadd - i_height ) * p_outplane->i_pitch );
    }

    return CopyInfoAndRelease( p_outpic, p_pic );
}
Exemple #6
0
static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
{
    picture_t *p_outpic;
    filter_sys_t *p_sys = p_filter->p_sys;
    int i_sin, i_cos;

    if( !p_pic ) return NULL;

    p_outpic = filter_NewPicture( p_filter );
    if( !p_outpic )
    {
        picture_Release( p_pic );
        return NULL;
    }

    vlc_spin_lock( &p_sys->lock );
    i_sin = p_sys->i_sin;
    i_cos = p_sys->i_cos;
    vlc_spin_unlock( &p_sys->lock );

    for( int i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
    {
        const int i_visible_lines = p_pic->p[i_plane].i_visible_lines;
        const int i_visible_pitch = p_pic->p[i_plane].i_visible_pitch;
        const int i_pitch         = p_pic->p[i_plane].i_pitch;
        const int i_hidden_pitch  = i_pitch - i_visible_pitch;

        const int i_aspect = ( i_visible_lines * p_pic->p[Y_PLANE].i_visible_pitch ) / ( p_pic->p[Y_PLANE].i_visible_lines * i_visible_pitch );
        /* = 2 for U and V planes in YUV 4:2:2, = 1 otherwise */

        const int i_line_center = i_visible_lines>>1;
        const int i_col_center  = i_visible_pitch>>1;

        const uint8_t *p_in = p_pic->p[i_plane].p_pixels;
        uint8_t *p_out = p_outpic->p[i_plane].p_pixels;
        uint8_t *p_outendline = p_out + i_visible_pitch;
        const uint8_t *p_outend = p_out + i_visible_lines * i_pitch;

        const uint8_t black_pixel = ( i_plane == Y_PLANE ) ? 0x00 : 0x80;

        const int i_line_next =  i_cos / i_aspect -i_sin*i_visible_pitch;
        const int i_col_next  = -i_sin / i_aspect -i_cos*i_visible_pitch;
        int i_line_orig0 = ( - i_cos * i_line_center / i_aspect
                             - i_sin * i_col_center + (1<<11) );
        int i_col_orig0 =    i_sin * i_line_center / i_aspect
                           - i_cos * i_col_center + (1<<11);
        for( ; p_outendline < p_outend;
             p_out += i_hidden_pitch, p_outendline += i_pitch,
             i_line_orig0 += i_line_next, i_col_orig0 += i_col_next )
        {
            for( ; p_out < p_outendline;
                 p_out++, i_line_orig0 += i_sin, i_col_orig0 += i_cos )
            {
                const int i_line_orig = (i_line_orig0>>12)*i_aspect + i_line_center;
                const int i_col_orig  = (i_col_orig0>>12)  + i_col_center;
                const uint8_t* p_orig_offset = p_in + i_line_orig * i_pitch
                                                + i_col_orig;
                const uint8_t i_line_percent = (i_line_orig0>>4) & 255;
                const uint8_t i_col_percent  = (i_col_orig0 >>4) & 255;

                if(    -1 <= i_line_orig && i_line_orig < i_visible_lines
                    && -1 <= i_col_orig  && i_col_orig  < i_visible_pitch )
                {
                #define test 1
                #undef test
                #ifdef test
                    if( ( i_col_orig > i_visible_pitch/2 ) )
                #endif
                    {
                        uint8_t i_curpix = black_pixel;
                        uint8_t i_colpix = black_pixel;
                        uint8_t i_linpix = black_pixel;
                        uint8_t i_nexpix = black_pixel;
                        if( ( 0 <= i_line_orig ) && ( 0 <= i_col_orig ) )
                            i_curpix = *p_orig_offset;
                        p_orig_offset++;

                        if(  ( i_col_orig < i_visible_pitch - 1)
                             && ( i_line_orig >= 0 ) )
                            i_colpix = *p_orig_offset;

                        p_orig_offset+=i_pitch;
                        if( ( i_line_orig < i_visible_lines - 1)
                            && ( i_col_orig  < i_visible_pitch - 1) )
                            i_nexpix = *p_orig_offset;

                        p_orig_offset--;
                        if(  ( i_line_orig < i_visible_lines - 1)
                             && ( i_col_orig >= 0 ) )
                            i_linpix = *p_orig_offset;

                        unsigned int temp = 0;
                        temp+= i_curpix *
                            (256 - i_line_percent) * ( 256 - i_col_percent );
                        temp+= i_linpix *
                            i_line_percent * (256 - i_col_percent );
                        temp+= i_nexpix *
                            ( i_col_percent) * ( i_line_percent);
                        temp+= i_colpix *
                            i_col_percent * (256 - i_line_percent );
                        *p_out = temp >> 16;
                    }
                #ifdef test
                    else if (i_col_orig == i_visible_pitch/2 )
                    {   *p_out = black_pixel;
                    }
                    else
                        *p_out = *p_orig_offset;
                #endif
                #undef test
                }
                else
                {
                    *p_out = black_pixel;
                }
            }
Exemple #7
0
/* This is the filter function. See Open(). */
picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )
{
    filter_sys_t *p_sys = p_filter->p_sys;
    picture_t *p_dst[DEINTERLACE_DST_SIZE];

    /* Request output picture */
    p_dst[0] = filter_NewPicture( p_filter );
    if( p_dst[0] == NULL )
    {
        picture_Release( p_pic );
        return NULL;
    }
    picture_CopyProperties( p_dst[0], p_pic );

    /* Any unused p_dst pointers must be NULL, because they are used to
       check how many output frames we have. */
    for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )
        p_dst[i] = NULL;

    /* Update the input frame history, if the currently active algorithm
       needs it. */
    if( p_sys->b_use_frame_history )
    {
        /* Duplicate the picture
         * TODO when the vout rework is finished, picture_Hold() might be enough
         * but becarefull, the pitches must match */
        picture_t *p_dup = picture_NewFromFormat( &p_pic->format );
        if( p_dup )
            picture_Copy( p_dup, p_pic );

        /* Slide the history */
        if( p_sys->pp_history[0] )
            picture_Release( p_sys->pp_history[0] );
        for( int i = 1; i < HISTORY_SIZE; i++ )
            p_sys->pp_history[i-1] = p_sys->pp_history[i];
        p_sys->pp_history[HISTORY_SIZE-1] = p_dup;
    }

    /* Slide the metadata history. */
    for( int i = 1; i < METADATA_SIZE; i++ )
    {
        p_sys->meta.pi_date[i-1]            = p_sys->meta.pi_date[i];
        p_sys->meta.pi_nb_fields[i-1]       = p_sys->meta.pi_nb_fields[i];
        p_sys->meta.pb_top_field_first[i-1] = p_sys->meta.pb_top_field_first[i];
    }
    /* The last element corresponds to the current input frame. */
    p_sys->meta.pi_date[METADATA_SIZE-1]            = p_pic->date;
    p_sys->meta.pi_nb_fields[METADATA_SIZE-1]       = p_pic->i_nb_fields;
    p_sys->meta.pb_top_field_first[METADATA_SIZE-1] = p_pic->b_top_field_first;

    /* Remember the frame offset that we should use for this frame.
       The value in p_sys will be updated to reflect the correct value
       for the *next* frame when we call the renderer. */
    int i_frame_offset = p_sys->i_frame_offset;
    int i_meta_idx     = (METADATA_SIZE-1) - i_frame_offset;

    /* These correspond to the current *outgoing* frame. */
    bool b_top_field_first;
    int i_nb_fields;
    if( i_frame_offset != CUSTOM_PTS )
    {
        /* Pick the correct values from the history. */
        b_top_field_first = p_sys->meta.pb_top_field_first[i_meta_idx];
        i_nb_fields       = p_sys->meta.pi_nb_fields[i_meta_idx];
    }
    else
    {
        /* Framerate doublers must not request CUSTOM_PTS, as they need the
           original field timings, and need Deinterlace() to allocate the
           correct number of output frames. */
        assert( !p_sys->b_double_rate );

        /* NOTE: i_nb_fields is only used for framerate doublers, so it is
                 unused in this case. b_top_field_first is only passed to the
                 algorithm. We assume that algorithms that request CUSTOM_PTS
                 will, if necessary, extract the TFF/BFF information themselves.
        */
        b_top_field_first = p_pic->b_top_field_first; /* this is not guaranteed
                                                         to be meaningful */
        i_nb_fields       = p_pic->i_nb_fields;       /* unused */
    }

    /* For framerate doublers, determine field duration and allocate
       output frames. */
    mtime_t i_field_dur = 0;
    int i_double_rate_alloc_end = 0; /* One past last for allocated output
                                        frames in p_dst[]. Used only for
                                        framerate doublers. Will be inited
                                        below. Declared here because the
                                        PTS logic needs the result. */
    if( p_sys->b_double_rate )
    {
        /* Calculate one field duration. */
        int i = 0;
        int iend = METADATA_SIZE-1;
        /* Find oldest valid logged date.
           The current input frame doesn't count. */
        for( ; i < iend; i++ )
            if( p_sys->meta.pi_date[i] > VLC_TS_INVALID )
                break;
        if( i < iend )
        {
            /* Count how many fields the valid history entries
               (except the new frame) represent. */
            int i_fields_total = 0;
            for( int j = i ; j < iend; j++ )
                i_fields_total += p_sys->meta.pi_nb_fields[j];
            /* One field took this long. */
            i_field_dur = (p_pic->date - p_sys->meta.pi_date[i]) / i_fields_total;
        }
        /* Note that we default to field duration 0 if it could not be
           determined. This behaves the same as the old code - leaving the
           extra output frame dates the same as p_pic->date if the last cached
           date was not valid.
        */

        i_double_rate_alloc_end = i_nb_fields;
        if( i_nb_fields > DEINTERLACE_DST_SIZE )
        {
            /* Note that the effective buffer size depends also on the constant
               private_picture in vout_wrapper.c, since that determines the
               maximum number of output pictures filter_NewPicture() will
               successfully allocate for one input frame.
            */
            msg_Err( p_filter, "Framerate doubler: output buffer too small; "\
                               "fields = %d, buffer size = %d. Dropping the "\
                               "remaining fields.",
                               i_nb_fields, DEINTERLACE_DST_SIZE );
            i_double_rate_alloc_end = DEINTERLACE_DST_SIZE;
        }

        /* Allocate output frames. */
        for( int i = 1; i < i_double_rate_alloc_end ; ++i )
        {
            p_dst[i-1]->p_next =
            p_dst[i]           = filter_NewPicture( p_filter );
            if( p_dst[i] )
            {
                picture_CopyProperties( p_dst[i], p_pic );
            }
            else
            {
                msg_Err( p_filter, "Framerate doubler: could not allocate "\
                                   "output frame %d", i+1 );
                i_double_rate_alloc_end = i; /* Inform the PTS logic about the
                                                correct end position. */
                break; /* If this happens, the rest of the allocations
                          aren't likely to work, either... */
            }
        }
        /* Now we have allocated *up to* the correct number of frames;
           normally, exactly the correct number. Upon alloc failure,
           we may have succeeded in allocating *some* output frames,
           but fewer than were desired. In such a case, as many will
           be rendered as were successfully allocated.

           Note that now p_dst[i] != NULL
           for 0 <= i < i_double_rate_alloc_end. */
    }
    assert( p_sys->b_double_rate  ||  p_dst[1] == NULL );
    assert( i_nb_fields > 2  ||  p_dst[2] == NULL );

    /* Render */
    switch( p_sys->i_mode )
    {
        case DEINTERLACE_DISCARD:
            RenderDiscard( p_dst[0], p_pic, 0 );
            break;

        case DEINTERLACE_BOB:
            RenderBob( p_dst[0], p_pic, !b_top_field_first );
            if( p_dst[1] )
                RenderBob( p_dst[1], p_pic, b_top_field_first );
            if( p_dst[2] )
                RenderBob( p_dst[2], p_pic, !b_top_field_first );
            break;;

        case DEINTERLACE_LINEAR:
            RenderLinear( p_filter, p_dst[0], p_pic, !b_top_field_first );
            if( p_dst[1] )
                RenderLinear( p_filter, p_dst[1], p_pic, b_top_field_first );
            if( p_dst[2] )
                RenderLinear( p_filter, p_dst[2], p_pic, !b_top_field_first );
            break;

        case DEINTERLACE_MEAN:
            RenderMean( p_filter, p_dst[0], p_pic );
            break;

        case DEINTERLACE_BLEND:
            RenderBlend( p_filter, p_dst[0], p_pic );
            break;

        case DEINTERLACE_X:
            RenderX( p_dst[0], p_pic );
            break;

        case DEINTERLACE_YADIF:
            if( RenderYadif( p_filter, p_dst[0], p_pic, 0, 0 ) )
                goto drop;
            break;

        case DEINTERLACE_YADIF2X:
            if( RenderYadif( p_filter, p_dst[0], p_pic, 0, !b_top_field_first ) )
                goto drop;
            if( p_dst[1] )
                RenderYadif( p_filter, p_dst[1], p_pic, 1, b_top_field_first );
            if( p_dst[2] )
                RenderYadif( p_filter, p_dst[2], p_pic, 2, !b_top_field_first );
            break;

        case DEINTERLACE_PHOSPHOR:
            if( RenderPhosphor( p_filter, p_dst[0], 0,
                                !b_top_field_first ) )
                goto drop;
            if( p_dst[1] )
                RenderPhosphor( p_filter, p_dst[1], 1,
                                b_top_field_first );
            if( p_dst[2] )
                RenderPhosphor( p_filter, p_dst[2], 2,
                                !b_top_field_first );
            break;

        case DEINTERLACE_IVTC:
            /* Note: RenderIVTC will automatically drop the duplicate frames
                     produced by IVTC. This is part of normal operation. */
            if( RenderIVTC( p_filter, p_dst[0] ) )
                goto drop;
            break;
    }

    /* Set output timestamps, if the algorithm didn't request CUSTOM_PTS
       for this frame. */
    assert( i_frame_offset <= METADATA_SIZE  ||  i_frame_offset == CUSTOM_PTS );
    if( i_frame_offset != CUSTOM_PTS )
    {
        mtime_t i_base_pts = p_sys->meta.pi_date[i_meta_idx];

        /* Note: in the usual case (i_frame_offset = 0  and
                 b_double_rate = false), this effectively does nothing.
                 This is needed to correct the timestamp
                 when i_frame_offset > 0. */
        p_dst[0]->date = i_base_pts;

        if( p_sys->b_double_rate )
        {
            /* Processing all actually allocated output frames. */
            for( int i = 1; i < i_double_rate_alloc_end; ++i )
            {
                /* XXX it's not really good especially for the first picture, but
                 * I don't think that delaying by one frame is worth it */
                if( i_base_pts > VLC_TS_INVALID )
                    p_dst[i]->date = i_base_pts + i * i_field_dur;
                else
                    p_dst[i]->date = VLC_TS_INVALID;
            }
        }
    }

    for( int i = 0; i < DEINTERLACE_DST_SIZE; ++i )
    {
        if( p_dst[i] )
        {
            p_dst[i]->b_progressive = true;
            p_dst[i]->i_nb_fields = 2;
        }
    }

    picture_Release( p_pic );
    return p_dst[0];

drop:
    picture_Release( p_dst[0] );
    for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i )
    {
        if( p_dst[i] )
            picture_Release( p_dst[i] );
    }
    picture_Release( p_pic );
    return NULL;
}
Exemple #8
0
/*****************************************************************************
 * Buffer management
 *****************************************************************************/
static picture_t *BufferNew( filter_t *p_filter )
{
    filter_t *p_parent = (filter_t*)p_filter->p_owner;

    return filter_NewPicture( p_parent );
}
Exemple #9
0
/*****************************************************************************
 * Render: displays previously rendered output
 *****************************************************************************
 * This function send the currently rendered image to Distort image, waits
 * until it is displayed and switch the two rendering buffers, preparing next
 * frame.
 *****************************************************************************/
static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
{
    picture_t *p_outpic;

    unsigned int w, h;
    int x,y;
    uint8_t u,v;

    picture_t *p_converted;
    video_format_t fmt_out;
    memset( &fmt_out, 0, sizeof(video_format_t) );
    fmt_out.p_palette = NULL;

    if( !p_pic ) return NULL;

    p_outpic = filter_NewPicture( p_filter );
    if( !p_outpic )
    {
        picture_Release( p_pic );
        return NULL;
    }

    if( !p_filter->p_sys->p_image )
        p_filter->p_sys->p_image = image_HandlerCreate( p_filter );

    /* chrominance */
    u = p_filter->p_sys->u;
    v = p_filter->p_sys->v;
    for( y = 0; y<p_outpic->p[U_PLANE].i_lines; y++)
    {
        vlc_memset(
                p_outpic->p[U_PLANE].p_pixels+y*p_outpic->p[U_PLANE].i_pitch,
                u, p_outpic->p[U_PLANE].i_pitch );
        vlc_memset(
                p_outpic->p[V_PLANE].p_pixels+y*p_outpic->p[V_PLANE].i_pitch,
                v, p_outpic->p[V_PLANE].i_pitch );
        if( v == 0 && u != 0 )
            u --;
        else if( u == 0xff )
            v --;
        else if( v == 0xff )
            u ++;
        else if( u == 0 )
            v ++;
    }

    /* luminance */
    plane_CopyPixels( &p_outpic->p[Y_PLANE], &p_pic->p[Y_PLANE] );

    /* image visualization */
    fmt_out = p_filter->fmt_out.video;
    fmt_out.i_width = p_filter->fmt_out.video.i_width*p_filter->p_sys->scale/150;
    fmt_out.i_height = p_filter->fmt_out.video.i_height*p_filter->p_sys->scale/150;
    p_converted = image_Convert( p_filter->p_sys->p_image, p_pic,
                                 &(p_pic->format), &fmt_out );

    if( p_converted )
    {
#define copyimage( plane, b ) \
        for( y=0; y<p_converted->p[plane].i_visible_lines; y++) { \
        for( x=0; x<p_converted->p[plane].i_visible_pitch; x++) { \
            int nx, ny; \
            if( p_filter->p_sys->yinc == 1 ) \
                ny= y; \
            else \
                ny = p_converted->p[plane].i_visible_lines-y; \
            if( p_filter->p_sys->xinc == 1 ) \
                nx = x; \
            else \
                nx = p_converted->p[plane].i_visible_pitch-x; \
            p_outpic->p[plane].p_pixels[(p_filter->p_sys->x*b+nx)+(ny+p_filter->p_sys->y*b)*p_outpic->p[plane].i_pitch ] = p_converted->p[plane].p_pixels[y*p_converted->p[plane].i_pitch+x]; \
        } }
        copyimage( Y_PLANE, 2 );
        copyimage( U_PLANE, 1 );
        copyimage( V_PLANE, 1 );
#undef copyimage

        picture_Release( p_converted );
    }
    else
    {
        msg_Err( p_filter, "Image scaling failed miserably." );
    }

    p_filter->p_sys->x += p_filter->p_sys->xinc;
    p_filter->p_sys->y += p_filter->p_sys->yinc;

    p_filter->p_sys->scale += p_filter->p_sys->scaleinc;
    if( p_filter->p_sys->scale >= 50 ) p_filter->p_sys->scaleinc = -1;
    if( p_filter->p_sys->scale <= 1 ) p_filter->p_sys->scaleinc = 1;

    w = p_filter->fmt_out.video.i_width*p_filter->p_sys->scale/150;
    h = p_filter->fmt_out.video.i_height*p_filter->p_sys->scale/150;
    if( p_filter->p_sys->x*2 + w >= p_filter->fmt_out.video.i_width )
        p_filter->p_sys->xinc = -1;
    if( p_filter->p_sys->x <= 0 )
        p_filter->p_sys->xinc = 1;

    if( p_filter->p_sys->x*2 + w >= p_filter->fmt_out.video.i_width )
        p_filter->p_sys->x = (p_filter->fmt_out.video.i_width-w)/2;
    if( p_filter->p_sys->y*2 + h >= p_filter->fmt_out.video.i_height )
        p_filter->p_sys->y = (p_filter->fmt_out.video.i_height-h)/2;

    if( p_filter->p_sys->y*2 + h >= p_filter->fmt_out.video.i_height )
        p_filter->p_sys->yinc = -1;
    if( p_filter->p_sys->y <= 0 )
        p_filter->p_sys->yinc = 1;

    for( y = 0; y< 16; y++ )
    {
        if( p_filter->p_sys->v == 0 && p_filter->p_sys->u != 0 )
            p_filter->p_sys->u -= 1;
        else if( p_filter->p_sys->u == 0xff )
            p_filter->p_sys->v -= 1;
        else if( p_filter->p_sys->v == 0xff )
            p_filter->p_sys->u += 1;
        else if( p_filter->p_sys->u == 0 )
            p_filter->p_sys->v += 1;
    }

    return CopyInfoAndRelease( p_outpic, p_pic );
}
Exemple #10
0
/**
 * Filter a picture
 */
static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
{
    filter_sys_t *p_sys = p_filter->p_sys;

    picture_t *p_outpic = filter_NewPicture( p_filter );
    if( !p_outpic )
    {
        picture_Release( p_pic );
        return NULL;
    }

    /* */
    vlc_mutex_lock( &p_sys->lock );
    if( p_sys->b_change )
    {
        p_sys->i_rows      = p_sys->change.i_rows;
        p_sys->i_cols      = p_sys->change.i_cols;
        p_sys->b_blackslot = p_sys->change.b_blackslot;
        p_sys->b_change = false;

        Shuffle( p_sys );
    }
    vlc_mutex_unlock( &p_sys->lock );

    /* */
    const int i_rows = p_sys->i_rows;
    const int i_cols = p_sys->i_cols;

    /* */
    for( int i_plane = 0; i_plane < p_outpic->i_planes; i_plane++ )
    {
        const plane_t *p_in = &p_pic->p[i_plane];
        const int i_pitch = p_in->i_pitch;
        plane_t *p_out = &p_outpic->p[i_plane];

        for( int i = 0; i < i_cols * i_rows; i++ )
        {
            int i_col = i % i_cols;
            int i_row = i / i_cols;
            int i_ocol = p_sys->pi_order[i] % i_cols;
            int i_orow = p_sys->pi_order[i] / i_cols;
            int i_last_row = i_row + 1;
            i_orow *= p_in->i_lines / i_rows;
            i_row *= p_in->i_lines / i_rows;
            i_last_row *= p_in->i_lines / i_rows;

            if( p_sys->b_blackslot && p_sys->b_finished && i == p_sys->i_selected )
            {
                uint8_t color = ( i_plane == Y_PLANE ? 0x0 : 0x80 );
                for( ; i_row < i_last_row; i_row++, i_orow++ )
                {
                    memset( p_out->p_pixels + i_row * i_pitch + i_col * i_pitch / i_cols,
                            color, i_pitch / i_cols );
                }
            }
            else
            {
                for( ; i_row < i_last_row; i_row++, i_orow++ )
                {
                    memcpy( p_out->p_pixels + i_row * i_pitch + i_col * i_pitch / i_cols,
                            p_in->p_pixels + i_orow * i_pitch + i_ocol * i_pitch / i_cols,
                            i_pitch / i_cols );
                }
            }
        }
    }

    if( p_sys->i_selected != -1 && !p_sys->b_blackslot )
    {
        const plane_t *p_in = &p_pic->p[Y_PLANE];
        const int i_pitch = p_in->i_pitch;
        plane_t *p_out = &p_outpic->p[Y_PLANE];

        int i_col = p_sys->i_selected % i_cols;
        int i_row = p_sys->i_selected / i_cols;
        int i_last_row = i_row + 1;
        i_row *= p_in->i_lines / i_rows;
        i_last_row *= p_in->i_lines / i_rows;
        memset( p_out->p_pixels + i_row * i_pitch + i_col * i_pitch / i_cols,
                0xff, i_pitch / i_cols );
        for( ; i_row < i_last_row; i_row++ )
        {
            p_out->p_pixels[   i_row * i_pitch
                             + i_col * i_pitch / i_cols ] = 0xff;
            p_out->p_pixels[ i_row * i_pitch
                             + (i_col+1) * i_pitch / i_cols - 1 ] = 0xff;
        }
        i_row--;
        memset( p_out->p_pixels + i_row * i_pitch + i_col * i_pitch / i_cols,
                0xff, i_pitch / i_cols );
    }

    if( p_sys->b_finished )
    {
        plane_t *p_out = &p_outpic->p[Y_PLANE];
        for( int i = 0; i < SHUFFLE_HEIGHT; i++ )
        {
            for( int j = 0; j < SHUFFLE_WIDTH; j++ )
            {
                if( shuffle_button[i][j] == '.' )
                   p_out->p_pixels[ i * p_out->i_pitch + j ] = 0xff;
            }
        }
    }

    return CopyInfoAndRelease( p_outpic, p_pic );
}
static picture_t *FilterPacked( filter_t *p_filter, picture_t *p_pic )
{
    picture_t *p_outpic;
    filter_sys_t *p_sys = p_filter->p_sys;

    vlc_mutex_lock( &p_sys->lock );
    int i_simthres = p_sys->i_simthres;
    int i_satthres = p_sys->i_satthres;
    int i_color = p_sys->i_color;
    vlc_mutex_unlock( &p_sys->lock );

    if( !p_pic ) return NULL;

    p_outpic = filter_NewPicture( p_filter );
    if( !p_outpic )
    {
        picture_Release( p_pic );
        return NULL;
    }

    int i_y_offset, i_u_offset, i_v_offset;
    int i_ret = GetPackedYuvOffsets( p_filter->fmt_in.video.i_chroma,
                                     &i_y_offset, &i_u_offset, &i_v_offset );
    if( i_ret == VLC_EGENERIC )
    {
        picture_Release( p_pic );
        return NULL;
    }

    /*
     * Copy Y and do the U and V planes
     */
    int refu, refv, reflength;
    GetReference( &refu, &refv, &reflength, i_color );

    for( int y = 0; y < p_pic->p->i_visible_lines; y++ )
    {
        uint8_t *p_src = &p_pic->p->p_pixels[y * p_pic->p->i_pitch];
        uint8_t *p_dst = &p_outpic->p->p_pixels[y * p_outpic->p->i_pitch];

        for( int x = 0; x < p_pic->p->i_visible_pitch / 4; x++ )
        {
            p_dst[i_y_offset + 0] = p_src[i_y_offset + 0];
            p_dst[i_y_offset + 2] = p_src[i_y_offset + 2];

            if( IsSimilar( p_src[i_u_offset] - 0x80, p_src[i_v_offset] - 0x80,
                           refu, refv, reflength,
                           i_satthres, i_simthres ) )
            {
                p_dst[i_u_offset] = p_src[i_u_offset];
                p_dst[i_v_offset] = p_src[i_v_offset];
            }
            else
            {
                p_dst[i_u_offset] = 0x80;
                p_dst[i_v_offset] = 0x80;
            }

            p_dst += 4;
            p_src += 4;
        }
    }

    return CopyInfoAndRelease( p_outpic, p_pic );
}
Exemple #12
0
/**
 * Video filter
 */
static picture_t *FilterVideo( filter_t *p_filter, picture_t *p_src )
{
    filter_sys_t *p_sys = p_filter->p_sys;
    logo_list_t *p_list = &p_sys->list;

    picture_t *p_dst = filter_NewPicture( p_filter );
    if( !p_dst )
        goto exit;

    picture_Copy( p_dst, p_src );

    /* */
    vlc_mutex_lock( &p_sys->lock );

    logo_t *p_logo;
    if( p_list->i_next_pic < p_src->date )
        p_logo = LogoListNext( p_list, p_src->date );
    else
        p_logo = LogoListCurrent( p_list );

    /* */
    const picture_t *p_pic = p_logo->p_pic;
    if( p_pic )
    {
        const video_format_t *p_fmt = &p_pic->format;
        const int i_dst_w = p_filter->fmt_out.video.i_visible_width;
        const int i_dst_h = p_filter->fmt_out.video.i_visible_height;

        if( p_sys->i_pos )
        {
            if( p_sys->i_pos & SUBPICTURE_ALIGN_BOTTOM )
            {
                p_sys->i_pos_y = i_dst_h - p_fmt->i_visible_height;
            }
            else if ( !(p_sys->i_pos & SUBPICTURE_ALIGN_TOP) )
            {
                p_sys->i_pos_y = ( i_dst_h - p_fmt->i_visible_height ) / 2;
            }
            else
            {
                p_sys->i_pos_y = 0;
            }

            if( p_sys->i_pos & SUBPICTURE_ALIGN_RIGHT )
            {
                p_sys->i_pos_x = i_dst_w - p_fmt->i_visible_width;
            }
            else if ( !(p_sys->i_pos & SUBPICTURE_ALIGN_LEFT) )
            {
                p_sys->i_pos_x = ( i_dst_w - p_fmt->i_visible_width ) / 2;
            }
            else
            {
                p_sys->i_pos_x = 0;
            }
        }

        /* */
        const int i_alpha = p_logo->i_alpha != -1 ? p_logo->i_alpha : p_list->i_alpha;
        if( filter_ConfigureBlend( p_sys->p_blend, i_dst_w, i_dst_h, p_fmt ) ||
            filter_Blend( p_sys->p_blend, p_dst, p_sys->i_pos_x, p_sys->i_pos_y,
                          p_pic, i_alpha ) )
        {
            msg_Err( p_filter, "failed to blend a picture" );
        }
    }
    vlc_mutex_unlock( &p_sys->lock );

exit:
    picture_Release( p_src );
    return p_dst;
}
Exemple #13
0
Fichier : wave.c Projet : Kafay/vlc
/*****************************************************************************
 * Render: displays previously rendered output
 *****************************************************************************
 * This function send the currently rendered image to Distort image, waits
 * until it is displayed and switch the two rendering buffers, preparing next
 * frame.
 *****************************************************************************/
static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
{
    picture_t *p_outpic;
    int i_index;
    double f_angle;
    mtime_t new_date = mdate();

    if( !p_pic ) return NULL;

    p_outpic = filter_NewPicture( p_filter );
    if( !p_outpic )
    {
        picture_Release( p_pic );
        return NULL;
    }

    p_filter->p_sys->f_angle += (new_date - p_filter->p_sys->last_date) / 200000.0;
    p_filter->p_sys->last_date = new_date;
    f_angle = p_filter->p_sys->f_angle;

    for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
    {
        int i_line, i_num_lines, i_visible_pitch, i_pixel_pitch, i_offset,
            i_visible_pixels;
        uint8_t black_pixel;
        uint8_t *p_in, *p_out;

        p_in = p_pic->p[i_index].p_pixels;
        p_out = p_outpic->p[i_index].p_pixels;

        i_num_lines = p_pic->p[i_index].i_visible_lines;
        i_visible_pitch = p_pic->p[i_index].i_visible_pitch;
        i_pixel_pitch = p_pic->p[i_index].i_pixel_pitch;
        i_visible_pixels = i_visible_pitch/i_pixel_pitch;

        black_pixel = ( p_pic->i_planes > 1 && i_index == Y_PLANE ) ? 0x00
                                                                    : 0x80;

        /* Ok, we do 3 times the sin() calculation for each line. So what ? */
        for( i_line = 0 ; i_line < i_num_lines ; i_line++ )
        {
            /* Calculate today's offset, don't go above 1/20th of the screen */
            i_offset = (int)( (double)(i_visible_pixels)
                         * sin( f_angle + 10.0 * (double)i_line
                                               / (double)i_num_lines )
                         / 20.0 )*i_pixel_pitch;

            if( i_offset )
            {
                if( i_offset < 0 )
                {
                    vlc_memcpy( p_out, p_in - i_offset,
                                i_visible_pitch + i_offset );
                    p_in += p_pic->p[i_index].i_pitch;
                    p_out += p_outpic->p[i_index].i_pitch;
                    vlc_memset( p_out + i_offset, black_pixel, -i_offset );
                }
                else
                {
                    vlc_memcpy( p_out + i_offset, p_in,
                                i_visible_pitch - i_offset );
                    vlc_memset( p_out, black_pixel, i_offset );
                    p_in += p_pic->p[i_index].i_pitch;
                    p_out += p_outpic->p[i_index].i_pitch;
                }
            }
            else
            {
                vlc_memcpy( p_out, p_in, i_visible_pitch );
                p_in += p_pic->p[i_index].i_pitch;
                p_out += p_outpic->p[i_index].i_pitch;
            }

        }
    }

    return CopyInfoAndRelease( p_outpic, p_pic );
}