Exemple #1
0
static void transcode_video_filter_init( sout_stream_t *p_stream,
                                         sout_stream_id_t *id )
{

    id->p_f_chain = filter_chain_New( p_stream, "video filter2",
                                     false,
                                     transcode_video_filter_allocation_init,
                                     transcode_video_filter_allocation_clear,
                                     p_stream->p_sys );
    /* Deinterlace */
    if( p_stream->p_sys->b_deinterlace )
    {
       filter_chain_AppendFilter( id->p_f_chain,
                                  p_stream->p_sys->psz_deinterlace,
                                  p_stream->p_sys->p_deinterlace_cfg,
                                  &id->p_decoder->fmt_out,
                                  &id->p_decoder->fmt_out );
    }

    /* Take care of the scaling and chroma conversions */
    if( ( id->p_decoder->fmt_out.video.i_chroma !=
          id->p_encoder->fmt_in.video.i_chroma ) ||
        ( id->p_decoder->fmt_out.video.i_width !=
          id->p_encoder->fmt_in.video.i_width ) ||
        ( id->p_decoder->fmt_out.video.i_height !=
          id->p_encoder->fmt_in.video.i_height ) )
    {
       filter_chain_AppendFilter( id->p_f_chain,
                                  NULL, NULL,
                                  &id->p_decoder->fmt_out,
                                  &id->p_encoder->fmt_in );
    }

    if( p_stream->p_sys->psz_vf2 )
    {
        const es_format_t *p_fmt_out;
        id->p_uf_chain = filter_chain_New( p_stream, "video filter2",
                                          true,
                           transcode_video_filter_allocation_init,
                           transcode_video_filter_allocation_clear,
                           p_stream->p_sys );
        filter_chain_Reset( id->p_uf_chain, &id->p_encoder->fmt_in,
                            &id->p_encoder->fmt_in );
        filter_chain_AppendFromString( id->p_uf_chain, p_stream->p_sys->psz_vf2 );
        p_fmt_out = filter_chain_GetFmtOut( id->p_uf_chain );
        es_format_Copy( &id->p_encoder->fmt_in, p_fmt_out );
        id->p_encoder->fmt_out.video.i_width =
            id->p_encoder->fmt_in.video.i_width;
        id->p_encoder->fmt_out.video.i_height =
            id->p_encoder->fmt_in.video.i_height;
        id->p_encoder->fmt_out.video.i_sar_num =
            id->p_encoder->fmt_in.video.i_sar_num;
        id->p_encoder->fmt_out.video.i_sar_den =
            id->p_encoder->fmt_in.video.i_sar_den;
    }

}
static int CreateChain( filter_chain_t *p_chain, es_format_t *p_fmt_mid, config_chain_t *p_cfg )
{
    filter_t *p_filter1;
    if( !( p_filter1 =
           filter_chain_AppendFilter( p_chain, NULL, p_cfg, NULL, p_fmt_mid )) )
        return VLC_EGENERIC;
    if( !filter_chain_AppendFilter( p_chain, NULL, p_cfg, p_fmt_mid, NULL ) )
    {
        filter_chain_DeleteFilter( p_chain, p_filter1 );
        return VLC_EGENERIC;
    }
    return VLC_SUCCESS;
}
Exemple #3
0
static int BuildFilterChain( filter_t *p_filter )
{
    es_format_t fmt_mid;
    int i_ret = VLC_EGENERIC;

    filter_sys_t *p_sys = p_filter->p_sys;

    /* Now try chroma format list */
    const vlc_fourcc_t *pi_allowed_chromas = get_allowed_chromas( p_filter );
    for( int i = 0; pi_allowed_chromas[i]; i++ )
    {
        filter_chain_Reset( p_sys->p_chain, &p_filter->fmt_in, &p_filter->fmt_out );

        const vlc_fourcc_t i_chroma = pi_allowed_chromas[i];
        if( i_chroma == p_filter->fmt_in.i_codec ||
            i_chroma == p_filter->fmt_out.i_codec )
            continue;

        msg_Dbg( p_filter, "Trying to use chroma %4.4s as middle man",
                 (char*)&i_chroma );

        es_format_Copy( &fmt_mid, &p_filter->fmt_in );
        fmt_mid.i_codec        =
        fmt_mid.video.i_chroma = i_chroma;
        fmt_mid.video.i_rmask  = 0;
        fmt_mid.video.i_gmask  = 0;
        fmt_mid.video.i_bmask  = 0;
        video_format_FixRgb(&fmt_mid.video);

        if( filter_chain_AppendConverter( p_sys->p_chain,
                                          NULL, &fmt_mid ) == VLC_SUCCESS )
        {
            p_sys->p_video_filter =
                filter_chain_AppendFilter( p_sys->p_chain,
                                           p_filter->psz_name, p_filter->p_cfg,
                                           &fmt_mid, &fmt_mid );
            if( p_sys->p_video_filter )
            {
                filter_AddProxyCallbacks( p_filter,
                                          p_sys->p_video_filter,
                                          RestartFilterCallback );
                if (p_sys->p_video_filter->pf_video_mouse != NULL)
                    p_filter->pf_video_mouse = ChainMouse;
                es_format_Clean( &fmt_mid );
                i_ret = VLC_SUCCESS;
                break;
            }
        }
        es_format_Clean( &fmt_mid );
    }
    if( i_ret != VLC_SUCCESS )
        filter_chain_Reset( p_sys->p_chain, &p_filter->fmt_in, &p_filter->fmt_out );

    return i_ret;
}
Exemple #4
0
static void transcode_video_filter_init( sout_stream_t *p_stream,
                                         sout_stream_id_t *id )
{
    es_format_t *p_fmt_out = &id->p_decoder->fmt_out;
    id->p_encoder->fmt_in.video.i_chroma = id->p_encoder->fmt_in.i_codec;

    id->p_f_chain = filter_chain_New( p_stream, "video filter2",
                                      false,
                                      transcode_video_filter_allocation_init,
                                      transcode_video_filter_allocation_clear,
                                      p_stream->p_sys );
    filter_chain_Reset( id->p_f_chain, p_fmt_out, p_fmt_out );

    /* Deinterlace */
    if( p_stream->p_sys->b_deinterlace )
    {
        filter_chain_AppendFilter( id->p_f_chain,
                                   p_stream->p_sys->psz_deinterlace,
                                   p_stream->p_sys->p_deinterlace_cfg,
                                   &id->p_decoder->fmt_out,
                                   &id->p_decoder->fmt_out );

        p_fmt_out = filter_chain_GetFmtOut( id->p_f_chain );
    }

    /* Check that we have visible_width/height*/
    if( !p_fmt_out->video.i_visible_height )
        p_fmt_out->video.i_visible_height = p_fmt_out->video.i_height;
    if( !p_fmt_out->video.i_visible_width )
        p_fmt_out->video.i_visible_width = p_fmt_out->video.i_width;

    if( p_stream->p_sys->psz_vf2 )
    {
        id->p_uf_chain = filter_chain_New( p_stream, "video filter2",
                                          true,
                           transcode_video_filter_allocation_init,
                           transcode_video_filter_allocation_clear,
                           p_stream->p_sys );
        filter_chain_Reset( id->p_uf_chain, p_fmt_out,
                            &id->p_encoder->fmt_in );
        filter_chain_AppendFromString( id->p_uf_chain, p_stream->p_sys->psz_vf2 );
        p_fmt_out = filter_chain_GetFmtOut( id->p_uf_chain );
        es_format_Copy( &id->p_encoder->fmt_in, p_fmt_out );
        id->p_encoder->fmt_out.video.i_width =
            id->p_encoder->fmt_in.video.i_width;
        id->p_encoder->fmt_out.video.i_height =
            id->p_encoder->fmt_in.video.i_height;
        id->p_encoder->fmt_out.video.i_sar_num =
            id->p_encoder->fmt_in.video.i_sar_num;
        id->p_encoder->fmt_out.video.i_sar_den =
            id->p_encoder->fmt_in.video.i_sar_den;
    }

}
Exemple #5
0
static int CreateChain( filter_t *p_parent, es_format_t *p_fmt_mid, config_chain_t *p_cfg )
{
    filter_chain_Reset( p_parent->p_sys->p_chain, &p_parent->fmt_in, &p_parent->fmt_out );

    filter_t *p_filter;

    if( p_parent->fmt_in.video.orientation != p_fmt_mid->video.orientation)
    {
        p_filter = AppendTransform( p_parent->p_sys->p_chain, &p_parent->fmt_in, p_fmt_mid );
    }
    else
    {
        p_filter = filter_chain_AppendFilter( p_parent->p_sys->p_chain, NULL, p_cfg, NULL, p_fmt_mid );
    }

    if( !p_filter )
        return VLC_EGENERIC;

    //Check if first filter was enough (transform filter most likely):
    if( es_format_IsSimilar(&p_filter->fmt_out, &p_parent->fmt_out ))
        return VLC_SUCCESS;

    if( p_fmt_mid->video.orientation != p_parent->fmt_out.video.orientation)
    {
        p_filter = AppendTransform( p_parent->p_sys->p_chain, p_fmt_mid, &p_parent->fmt_out );
    }
    else
    {
        p_filter = filter_chain_AppendFilter( p_parent->p_sys->p_chain, NULL, p_cfg, p_fmt_mid, NULL );
    }

    if( !p_filter )
    {
        //Clean up.
        filter_chain_Reset( p_parent->p_sys->p_chain, NULL, NULL );
        return VLC_EGENERIC;
    }

    return VLC_SUCCESS;
}
Exemple #6
0
static filter_t * AppendTransform( filter_chain_t *p_chain, const es_format_t *p_fmt1,
                                   const es_format_t *p_fmt2 )
{
    video_transform_t transform = video_format_GetTransform(p_fmt1->video.orientation, p_fmt2->video.orientation);

    const char *type;

    switch ( transform ) {

        case TRANSFORM_R90:
            type = "90";
            break;
        case TRANSFORM_R180:
            type = "180";
            break;
        case TRANSFORM_R270:
            type = "270";
            break;
        case TRANSFORM_HFLIP:
            type = "hflip";
            break;
        case TRANSFORM_VFLIP:
            type = "vflip";
            break;
        case TRANSFORM_TRANSPOSE:
            type = "transpose";
            break;
        case TRANSFORM_ANTI_TRANSPOSE:
            type = "antitranspose";
            break;
        default:
            type = NULL;
            break;
    }

    if( !type )
        return NULL;

    config_chain_t *cfg;
    char *name;
    char config[100];
    snprintf( config, 100, "transform{type=%s}", type );
    char *next = config_ChainCreate( &name, &cfg, config );

    filter_t *p_filter = filter_chain_AppendFilter( p_chain, name, cfg, p_fmt1, p_fmt2 );

    config_ChainDestroy(cfg);
    free(name);
    free(next);

    return p_filter;
}
Exemple #7
0
/* Take care of the scaling and chroma conversions.
 *
 * XXX: Shouldn't this really be after p_uf_chain, not p_f_chain,
 * in case p_uf_chain changes the format?
 */
static void conversion_video_filter_append( sout_stream_id_t *id )
{
    const es_format_t *p_fmt_out = &id->p_decoder->fmt_out;
    if( id->p_f_chain )
        p_fmt_out = filter_chain_GetFmtOut( id->p_f_chain );

    if( ( p_fmt_out->video.i_chroma != id->p_encoder->fmt_in.video.i_chroma ) ||
        ( p_fmt_out->video.i_width != id->p_encoder->fmt_in.video.i_width ) ||
        ( p_fmt_out->video.i_height != id->p_encoder->fmt_in.video.i_height ) )
    {
        filter_chain_AppendFilter( id->p_f_chain,
                                   NULL, NULL,
                                   p_fmt_out,
                                   &id->p_encoder->fmt_in );
    }
}
Exemple #8
0
static int transcode_audio_filter_chain_build( sout_stream_t *p_stream, filter_chain_t *p_chain,
                                               const es_format_t *p_dst, const es_format_t *p_src )
{
    if( !transcode_audio_filter_needed( p_dst, p_src ) )
        return VLC_SUCCESS;

    es_format_t current = *p_src;

    msg_Dbg( p_stream, "Looking for filter "
             "(%4.4s->%4.4s, channels %d->%d, rate %d->%d)",
         (const char *)&p_src->i_codec,
         (const char *)&p_dst->i_codec,
         p_src->audio.i_channels,
         p_dst->audio.i_channels,
         p_src->audio.i_rate,
         p_dst->audio.i_rate );

    /* If any filter is needed, convert to fl32 */
    if( current.i_codec != VLC_CODEC_FL32 )
    {
        /* First step, convert to fl32 */
        current.i_codec =
        current.audio.i_format = VLC_CODEC_FL32;
        aout_FormatPrepare( &current.audio );

        if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, &current ) )
        {
            msg_Err( p_stream, "Failed to find conversion filter to fl32" );
            return VLC_EGENERIC;
        }
        current = *filter_chain_GetFmtOut( p_chain );
    }

    /* Fix sample rate */
    if( current.audio.i_rate != p_dst->audio.i_rate )
    {
        current.audio.i_rate = p_dst->audio.i_rate;
        aout_FormatPrepare( &current.audio );
        if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, &current ) )
        {
            msg_Err( p_stream, "Failed to find conversion filter for resampling" );
            return VLC_EGENERIC;
        }
        current = *filter_chain_GetFmtOut( p_chain );
    }

    /* Fix channels */
    if( current.audio.i_channels != p_dst->audio.i_channels )
    {
        current.audio.i_channels = p_dst->audio.i_channels;
        current.audio.i_physical_channels = p_dst->audio.i_physical_channels;
        current.audio.i_original_channels = p_dst->audio.i_original_channels;

        if( ( !current.audio.i_physical_channels || !current.audio.i_original_channels ) &&
            current.audio.i_channels < 6 )
            current.audio.i_physical_channels =
            current.audio.i_original_channels = pi_channels_maps[current.audio.i_channels];

        aout_FormatPrepare( &current.audio );
        if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, &current ) )
        {
            msg_Err( p_stream, "Failed to find conversion filter for channel mixing" );
            return VLC_EGENERIC;
        }
        current = *filter_chain_GetFmtOut( p_chain );
    }
    /* And last step, convert to the requested codec */
    if( current.i_codec != p_dst->i_codec )
    {
        current.i_codec = p_dst->i_codec;
        aout_FormatPrepare( &current.audio );
        if( !filter_chain_AppendFilter( p_chain, NULL, NULL, NULL, &current ) )
        {
            msg_Err( p_stream, "Failed to find conversion filter to %4.4s",
                     (const char*)&p_dst->i_codec);
            return VLC_EGENERIC;
        }
        current = *filter_chain_GetFmtOut( p_chain );
    }

    if( transcode_audio_filter_needed( p_dst, &current ) )
    {
        /* Weird case, a filter has side effects, doomed */
        msg_Err( p_stream, "Failed to create a valid audio filter chain" );
        return VLC_EGENERIC;
    }

    msg_Dbg( p_stream, "Got complete audio filter chain" );
    return VLC_SUCCESS;
}
Exemple #9
0
static int Activate( vlc_object_t *p_this )
{
    filter_t *p_filter = (filter_t *)p_this;
    unsigned i_canvas_width; /* width of output canvas */
    unsigned i_canvas_height; /* height of output canvas */
    unsigned i_canvas_aspect; /* canvas PictureAspectRatio */
    es_format_t fmt; /* target format after up/down conversion */
    char psz_croppadd[100];
    int i_padd,i_offset;
    char *psz_aspect, *psz_parser;
    bool b_padd;
    unsigned i_fmt_in_aspect;

    if( !p_filter->b_allow_fmt_out_change )
    {
        msg_Err( p_filter, "Picture format change isn't allowed" );
        return VLC_EGENERIC;
    }

    if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
    {
        msg_Err( p_filter, "Input and output chromas don't match" );
        return VLC_EGENERIC;
    }

    config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
                       p_filter->p_cfg );

    i_canvas_width = var_CreateGetInteger( p_filter, CFG_PREFIX "width" );
    i_canvas_height = var_CreateGetInteger( p_filter, CFG_PREFIX "height" );

    if( i_canvas_width == 0 || i_canvas_height == 0 )
    {
        msg_Err( p_filter, "Width and height options must be set" );
        return VLC_EGENERIC;
    }

    if( i_canvas_width & 1 || i_canvas_height & 1 )
    {
        /* If this restriction were ever relaxed, it is very important to
         * get the field polatiry correct */
        msg_Err( p_filter, "Width and height options must be even integers" );
        return VLC_EGENERIC;
    }

    i_fmt_in_aspect = (int64_t)p_filter->fmt_in.video.i_sar_num *
                      p_filter->fmt_in.video.i_width *
                      VOUT_ASPECT_FACTOR /
                      p_filter->fmt_in.video.i_sar_den /
                      p_filter->fmt_in.video.i_height;
    psz_aspect = var_CreateGetNonEmptyString( p_filter, CFG_PREFIX "aspect" );
    if( psz_aspect )
    {
        psz_parser = strchr( psz_aspect, ':' );
        int numerator = atoi( psz_aspect );
        int denominator = psz_parser ? atoi( psz_parser+1 ) : 0;
        denominator = denominator == 0 ? 1 : denominator;
        i_canvas_aspect = numerator * VOUT_ASPECT_FACTOR / denominator;
        free( psz_aspect );

        if( numerator <= 0 || denominator < 0 )
        {
            msg_Err( p_filter, "Aspect ratio must be strictly positive" );
            return VLC_EGENERIC;
        }
    }
    else
    {
        /* if there is no user supplied aspect ratio, assume the canvas
         * has the same sample aspect ratio as the subpicture */
        /* aspect = subpic_sar * canvas_width / canvas_height
         *  where subpic_sar = subpic_ph * subpic_par / subpic_pw */
        i_canvas_aspect = (uint64_t) p_filter->fmt_in.video.i_height
                        * i_fmt_in_aspect
                        * i_canvas_width
                        / (i_canvas_height * p_filter->fmt_in.video.i_width);
    }

    b_padd = var_CreateGetBool( p_filter, CFG_PREFIX "padd" );

    filter_sys_t *p_sys = (filter_sys_t *)malloc( sizeof( filter_sys_t ) );
    if( !p_sys )
        return VLC_ENOMEM;
    p_filter->p_sys = p_sys;

    p_sys->p_chain = filter_chain_New( p_filter, "video filter2", true,
                                       alloc_init, NULL, p_filter );
    if( !p_sys->p_chain )
    {
        msg_Err( p_filter, "Could not allocate filter chain" );
        free( p_sys );
        return VLC_EGENERIC;
    }

    es_format_Copy( &fmt, &p_filter->fmt_in );

    /* one dimension will end up with one of the following: */
    fmt.video.i_width = i_canvas_width;
    fmt.video.i_height = i_canvas_height;

    if( b_padd )
    {
        /* Padd */
        if( i_canvas_aspect > i_fmt_in_aspect )
        {
            /* The canvas has a wider aspect than the subpicture:
             *  ie, pillarbox the [scaled] subpicture */
            /* The following is derived form:
             * width = upconverted_subpic_height * subpic_par / canvas_sar
             *  where canvas_sar = canvas_width / (canvas_height * canvas_par)
             * then simplify */
            fmt.video.i_width = i_canvas_width
                              * i_fmt_in_aspect
                              / i_canvas_aspect;
            if( fmt.video.i_width & 1 ) fmt.video.i_width -= 1;

            i_padd = (i_canvas_width - fmt.video.i_width) / 2;
            i_offset = (i_padd & 1);
            _snprintf( psz_croppadd, 100, "croppadd{paddleft=%d,paddright=%d}",
                      i_padd - i_offset, i_padd + i_offset );			// sunqueen modify
        }
        else
        {
            /* The canvas has a taller aspect than the subpicture:
             *  ie, letterbox the [scaled] subpicture */
            fmt.video.i_height = i_canvas_height
                               * i_canvas_aspect
                               / i_fmt_in_aspect;
            if( fmt.video.i_height & 1 ) fmt.video.i_height -= 1;

            i_padd = (i_canvas_height - fmt.video.i_height ) / 2;
            i_offset = (i_padd & 1);
            _snprintf( psz_croppadd, 100, "croppadd{paddtop=%d,paddbottom=%d}",
                      i_padd - i_offset, i_padd + i_offset );			// sunqueen modify
        }
    }
    else
    {
        /* Crop */
        if( i_canvas_aspect < i_fmt_in_aspect )
        {
            /* The canvas has a narrower aspect than the subpicture:
             *  ie, crop the [scaled] subpicture horizontally */
            fmt.video.i_width = i_canvas_width
                              * i_fmt_in_aspect
                              / i_canvas_aspect;
            if( fmt.video.i_width & 1 ) fmt.video.i_width -= 1;

            i_padd = (fmt.video.i_width - i_canvas_width) / 2;
            i_offset = (i_padd & 1);
            _snprintf( psz_croppadd, 100, "croppadd{cropleft=%d,cropright=%d}",
                      i_padd - i_offset, i_padd + i_offset );			// sunqueen modify
        }
        else
        {
            /* The canvas has a shorter aspect than the subpicture:
             *  ie, crop the [scaled] subpicture vertically */
            fmt.video.i_height = i_canvas_height
                               * i_canvas_aspect
                               / i_fmt_in_aspect;
            if( fmt.video.i_height & 1 ) fmt.video.i_height -= 1;

            i_padd = (fmt.video.i_height - i_canvas_height) / 2;
            i_offset = (i_padd & 1);
            _snprintf( psz_croppadd, 100, "croppadd{croptop=%d,cropbottom=%d}",
                      i_padd - i_offset, i_padd + i_offset );			// sunqueen modify
        }
    }

    /* xxx, should the clean area include the letter-boxing?
     *  probably not, as some codecs can make use of that information
     *  and it should be a scaled version of the input clean area
     *   -- davidf */
    fmt.video.i_visible_width = fmt.video.i_width;
    fmt.video.i_visible_height = fmt.video.i_height;

    filter_chain_Reset( p_sys->p_chain, &p_filter->fmt_in, &fmt );
    /* Append scaling module */
    filter_chain_AppendFilter( p_sys->p_chain, NULL, NULL, NULL, NULL );
    /* Append padding module */
    filter_chain_AppendFromString( p_sys->p_chain, psz_croppadd );

    fmt = *filter_chain_GetFmtOut( p_sys->p_chain );
    es_format_Copy( &p_filter->fmt_out, &fmt );

    p_filter->fmt_out.video.i_sar_num =
        i_canvas_aspect    * p_filter->fmt_out.video.i_height;
    p_filter->fmt_out.video.i_sar_den =
        VOUT_ASPECT_FACTOR * p_filter->fmt_out.video.i_width;

    if( p_filter->fmt_out.video.i_width != i_canvas_width
     || p_filter->fmt_out.video.i_height != i_canvas_height )
    {
        msg_Warn( p_filter, "Looks like something went wrong. "
                  "Output size is %dx%d while we asked for %dx%d",
                  p_filter->fmt_out.video.i_width,
                  p_filter->fmt_out.video.i_height,
                  i_canvas_width, i_canvas_height );
    }

    p_filter->pf_video_filter = Filter;

    return VLC_SUCCESS;
}