Exemple #1
0
/**
 * This function will handle a snapshot request
 */
static void VoutSaveSnapshot( vout_thread_t *p_vout )
{
    char *psz_path = var_GetNonEmptyString( p_vout, "snapshot-path" );
    char *psz_format = var_GetNonEmptyString( p_vout, "snapshot-format" );
    char *psz_prefix = var_GetNonEmptyString( p_vout, "snapshot-prefix" );

    /* */
    picture_t *p_picture;
    block_t *p_image;
    video_format_t fmt;

    /* 500ms timeout
     * XXX it will cause trouble with low fps video (< 2fps) */
    if( vout_GetSnapshot( p_vout, &p_image, &p_picture, &fmt, psz_format, 500*1000 ) )
    {
        p_picture = NULL;
        p_image = NULL;
        goto exit;
    }

    if( !psz_path )
    {
        psz_path = VoutSnapshotGetDefaultDirectory();
        if( !psz_path )
        {
            msg_Err( p_vout, "no path specified for snapshots" );
            goto exit;
        }
    }

    char *psz_filename;
    if( VoutWriteSnapshot( p_vout, &psz_filename,
                           p_image,
                           psz_path, psz_format, psz_prefix ) )
        goto exit;

    VoutOsdSnapshot( p_vout, p_picture, psz_filename );

    /* Generate a media player event  - Right now just trigger a global libvlc var
        CHECK: Could not find a more local object. The goal is to communicate
        vout_thread with libvlc_media_player or its input_thread */
    var_SetString( p_vout->p_libvlc, "vout-snapshottaken", psz_filename );
    free( psz_filename );

exit:
    if( p_image )
        block_Release( p_image );
    if( p_picture )
        picture_Release( p_picture );
    free( psz_prefix );
    free( psz_format );
    free( psz_path );
}
Exemple #2
0
int vout_Snapshot( vout_thread_t *p_vout, picture_t *p_pic )
{
    image_handler_t *p_image = image_HandlerCreate( p_vout );
    video_format_t fmt_in, fmt_out;
    char *psz_filename = NULL;
    vlc_value_t val, format;
    DIR *path;
    int i_ret;
    bool b_embedded_snapshot;
    int i_id = 0;

    /* */
    val.psz_string = var_GetNonEmptyString( p_vout, "snapshot-path" );

    /* Embedded snapshot : if snapshot-path == object:id */
    if( val.psz_string && sscanf( val.psz_string, "object:%d", &i_id ) > 0 )
        b_embedded_snapshot = true;
    else
        b_embedded_snapshot = false;

    /* */
    memset( &fmt_in, 0, sizeof(video_format_t) );
    fmt_in = p_vout->fmt_in;
    if( fmt_in.i_sar_num <= 0 || fmt_in.i_sar_den <= 0 )
    {
        fmt_in.i_sar_num =
        fmt_in.i_sar_den = 1;
    }

    /* */
    memset( &fmt_out, 0, sizeof(video_format_t) );
    fmt_out.i_sar_num =
    fmt_out.i_sar_den = 1;
    fmt_out.i_chroma = b_embedded_snapshot ? VLC_FOURCC('p','n','g',' ') : 0;
    fmt_out.i_width = var_GetInteger( p_vout, "snapshot-width" );
    fmt_out.i_height = var_GetInteger( p_vout, "snapshot-height" );

    if( b_embedded_snapshot &&
        fmt_out.i_width == 0 && fmt_out.i_height == 0 )
    {
        /* If snapshot-width and/or snapshot height were not specified,
           use a default snapshot width of 320 */
        fmt_out.i_width = 320;
    }

    if( fmt_out.i_height == 0 && fmt_out.i_width > 0 )
    {
        fmt_out.i_height = fmt_in.i_height * fmt_out.i_width / fmt_in.i_width;
        const int i_height = fmt_out.i_height * fmt_in.i_sar_den / fmt_in.i_sar_num;
        if( i_height > 0 )
            fmt_out.i_height = i_height;
    }
    else
    {
        if( fmt_out.i_width == 0 && fmt_out.i_height > 0 )
        {
            fmt_out.i_width = fmt_in.i_width * fmt_out.i_height / fmt_in.i_height;
        }
        else
        {
            fmt_out.i_width = fmt_in.i_width;
            fmt_out.i_height = fmt_in.i_height;
        }
        const int i_width = fmt_out.i_width * fmt_in.i_sar_num / fmt_in.i_sar_den;
        if( i_width > 0 )
            fmt_out.i_width = i_width;
    }

    /* Embedded snapshot
       create a snapshot_t* and store it in
       object(object-id)->p_private, then unlock and signal the
       waiting object.
     */
    if( b_embedded_snapshot )
    {
        vlc_object_t* p_dest;
        block_t *p_block;
        snapshot_t *p_snapshot;
        size_t i_size;

        /* Destination object-id is following object: */
        p_dest = ( vlc_object_t* )vlc_object_get( i_id );
        if( !p_dest )
        {
            msg_Err( p_vout, "Cannot find calling object" );
            image_HandlerDelete( p_image );
            return VLC_EGENERIC;
        }
        /* Object must be locked. We will unlock it once we get the
           snapshot and written it to p_private */
        p_dest->p_private = NULL;

        /* Save the snapshot to a memory zone */
        p_block = image_Write( p_image, p_pic, &fmt_in, &fmt_out );
        if( !p_block )
        {
            msg_Err( p_vout, "Could not get snapshot" );
            image_HandlerDelete( p_image );
            vlc_object_signal( p_dest );
            vlc_object_release( p_dest );
            return VLC_EGENERIC;
        }

        /* Copy the p_block data to a snapshot structure */
        /* FIXME: get the timestamp */
        p_snapshot = malloc( sizeof( snapshot_t ) );
        if( !p_snapshot )
        {
            block_Release( p_block );
            image_HandlerDelete( p_image );
            vlc_object_signal( p_dest );
            vlc_object_release( p_dest );
            return VLC_ENOMEM;
        }

        i_size = p_block->i_buffer;

        p_snapshot->i_width = fmt_out.i_width;
        p_snapshot->i_height = fmt_out.i_height;
        p_snapshot->i_datasize = i_size;
        p_snapshot->date = p_block->i_pts; /* FIXME ?? */
        p_snapshot->p_data = malloc( i_size );
        if( !p_snapshot->p_data )
        {
            block_Release( p_block );
            free( p_snapshot );
            image_HandlerDelete( p_image );
            vlc_object_signal( p_dest );
            vlc_object_release( p_dest );
            return VLC_ENOMEM;
        }
        memcpy( p_snapshot->p_data, p_block->p_buffer, p_block->i_buffer );

        p_dest->p_private = p_snapshot;

        block_Release( p_block );

        /* Unlock the object */
        vlc_object_signal( p_dest );
        vlc_object_release( p_dest );

        image_HandlerDelete( p_image );
        return VLC_SUCCESS;
    }

    /* Get default directory if none provided */
    if( !val.psz_string )
        val.psz_string = VoutSnapshotGetDefaultDirectory( p_vout );
    if( !val.psz_string )
    {
        msg_Err( p_vout, "no path specified for snapshots" );
        image_HandlerDelete( p_image );
        return VLC_EGENERIC;
    }

    /* Get snapshot format, default being "png" */
    format.psz_string = var_GetNonEmptyString( p_vout, "snapshot-format" );
    if( !format.psz_string )
        format.psz_string = strdup( "png" );
    if( !format.psz_string )
    {
        free( val.psz_string );
        image_HandlerDelete( p_image );
        return VLC_ENOMEM;
    }

    /*
     * Did the user specify a directory? If not, path = NULL.
     */
    path = utf8_opendir ( (const char *)val.psz_string  );
    if( path != NULL )
    {
        char *psz_prefix = var_GetNonEmptyString( p_vout, "snapshot-prefix" );
        if( psz_prefix == NULL )
            psz_prefix = strdup( "vlcsnap-" );
        else
        {
            char *psz_tmp = str_format( p_vout, psz_prefix );
            filename_sanitize( psz_tmp );
            free( psz_prefix );
            psz_prefix = psz_tmp;
        }

        closedir( path );
        if( var_GetBool( p_vout, "snapshot-sequential" ) == true )
        {
            int i_num = var_GetInteger( p_vout, "snapshot-num" );
            struct stat st;

            do
            {
                free( psz_filename );
                if( asprintf( &psz_filename, "%s" DIR_SEP "%s%05d.%s",
                              val.psz_string, psz_prefix, i_num++,
                              format.psz_string ) == -1 )
                {
                    msg_Err( p_vout, "could not create snapshot" );
                    image_HandlerDelete( p_image );
                    return VLC_EGENERIC;
                }
            }
            while( utf8_stat( psz_filename, &st ) == 0 );

            var_SetInteger( p_vout, "snapshot-num", i_num );
        }
        else
        {
            if( asprintf( &psz_filename, "%s" DIR_SEP "%s%u.%s",
                          val.psz_string, psz_prefix,
                          (unsigned int)(p_pic->date / 100000) & 0xFFFFFF,
                          format.psz_string ) == -1 )
            {
                msg_Err( p_vout, "could not create snapshot" );
                image_HandlerDelete( p_image );
                return VLC_EGENERIC;
            }
        }

        free( psz_prefix );
    }
    else // The user specified a full path name (including file name)
    {
        psz_filename = str_format( p_vout, val.psz_string );
        path_sanitize( psz_filename );
    }

    free( val.psz_string );
    free( format.psz_string );

    /* Save the snapshot */
    i_ret = image_WriteUrl( p_image, p_pic, &fmt_in, &fmt_out, psz_filename );
    if( i_ret != VLC_SUCCESS )
    {
        msg_Err( p_vout, "could not create snapshot %s", psz_filename );
        free( psz_filename );
        image_HandlerDelete( p_image );
        return VLC_EGENERIC;
    }

    /* */
    msg_Dbg( p_vout, "snapshot taken (%s)", psz_filename );
    vout_OSDMessage( VLC_OBJECT( p_vout ), DEFAULT_CHAN,
                     "%s", psz_filename );
    free( psz_filename );

    /* */
    if( var_GetBool( p_vout, "snapshot-preview" ) )
    {
        if( VoutSnapshotPip( p_vout, p_image, p_pic, &fmt_in ) )
            msg_Warn( p_vout, "Failed to display snapshot" );
    }
    image_HandlerDelete( p_image );

    return VLC_SUCCESS;
}