Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  resource.c   Sprache: C

 

/*****************************************************************************
 * resource.c
 *****************************************************************************
 * Copyright (C) 2008 Laurent Aimar
 *
 * Authors: Laurent Aimar < fenrir _AT_ videolan _DOT_ org >
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


/*****************************************************************************
 * Preamble
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <assert.h>

#include <vlc_common.h>
#include <vlc_atomic.h>
#include <vlc_decoder.h>
#include <vlc_vout.h>
#include <vlc_spu.h>
#include <vlc_aout.h>
#include <vlc_sout.h>
#include "../libvlc.h"
#include "../stream_output/stream_output.h"
#include "../audio_output/aout_internal.h"
#include "../video_output/vout_internal.h"
#include "input_interface.h"
#include "event.h"
#include "resource.h"

struct vout_resource
{
    vout_thread_t *vout;
    enum vlc_vout_order order;
    bool started;
    char *psz_prev_title;

    struct vlc_list node;
};

struct input_resource_t
{
    vlc_atomic_rc_t rc;

    vlc_object_t   *p_parent;

    /* This lock is used to serialize request and protect
     * our variables */

    vlc_mutex_t    lock;

    /* */
    input_thread_t *p_input;

    sout_stream_t *p_sout;
    char *psz_sout;
    vout_thread_t   *p_vout_dummy;
    struct vout_resource *vout_rsc_free;

    /* This lock is used to protect vout resources access (for hold)
     * It is a special case because of embed video (possible deadlock
     * between vout window request and vout holds in some(qt) interface)
     */

    vlc_mutex_t    lock_hold;

    /* You need lock+lock_hold to write to the following variables and
     * only lock or lock_hold to read them */

    struct vlc_list vout_rscs;

    bool            b_aout_busy;
    audio_output_t *p_aout;
};

#define resource_GetFirstVoutRsc(resource) \
    vlc_list_first_entry_or_null(&resource->vout_rscs, struct vout_resource, node)

static inline struct vout_resource *
resource_GetVoutRsc(input_resource_t *resource, vout_thread_t *vout)
{
    struct vout_resource *vout_rsc;

    vlc_list_foreach(vout_rsc, &resource->vout_rscs, node)
        if (vout_rsc->vout == vout)
            return vout_rsc;

    vlc_assert_unreachable();
}

static inline struct vout_resource *
vout_resource_Create(vout_thread_t *vout)
{
    struct vout_resource *vout_rsc = malloc(sizeof(*vout_rsc));
    if (unlikely(vout_rsc == NULL))
        return NULL;

    vout_rsc->started = false;
    vout_rsc->vout = vout;
    vout_rsc->psz_prev_title = NULL;
    return vout_rsc;
}

static inline void
vout_resource_Add(struct vout_resource *vout_rsc, input_resource_t *resource)
{
    vlc_list_append(&vout_rsc->node, &resource->vout_rscs);
}

static inline vout_thread_t *
vout_resource_Remove(struct vout_resource *vout_rsc)
{
    vlc_list_remove(&vout_rsc->node);
    vout_thread_t *vout = vout_rsc->vout;
    free(vout_rsc->psz_prev_title);
    free(vout_rsc);

    assert(vout);
    return vout;
}

/* */
static void DestroySout( input_resource_t *p_resource )
{
    if( p_resource->p_sout )
    {
        msg_Dbg( p_resource->p_parent, "destroying stream output" );
        sout_StreamChainDelete( p_resource->p_sout, NULL );
        free(p_resource->psz_sout);
    }
    p_resource->p_sout = NULL;
}

/* */
static void DestroyVout( input_resource_t *p_resource )
{
    assert( vlc_list_is_empty( &p_resource->vout_rscs )
         || p_resource->vout_rsc_free == resource_GetFirstVoutRsc( p_resource ) );

    if( p_resource->vout_rsc_free )
    {
        vlc_mutex_lock(&p_resource->lock_hold);
        vout_thread_t *vout = vout_resource_Remove( p_resource->vout_rsc_free );
        vlc_mutex_unlock(&p_resource->lock_hold);

        vout_Close( vout );
        p_resource->vout_rsc_free = NULL;
    }
}

static void VoutSetAndDeduplicateTitle( vout_thread_t *p_vout,
                                        char **ppsz_title,
                                        char **ppsz_prev_title )
{
    if( !*ppsz_prev_title || strcmp( *ppsz_prev_title, *ppsz_title ) )
    {
        vout_DisplayTitle( p_vout, *ppsz_title );
        free( *ppsz_prev_title );
        *ppsz_prev_title = *ppsz_title;
        *ppsz_title = NULL;
    }
}

static void DisplayVoutTitle( input_resource_t *p_resource,
                              vout_thread_t *p_vout,
                              char ** ppsz_prev_title )
{
    if( p_resource->p_input == NULL )
        return;

    /* TODO display the title only one time for the same input ? */

    input_item_t *p_item = input_GetItem( p_resource->p_input );

    char *psz_nowplaying = input_item_GetNowPlayingFb( p_item );
    if( psz_nowplaying && *psz_nowplaying )
    {
        VoutSetAndDeduplicateTitle( p_vout, &psz_nowplaying, ppsz_prev_title );
    }
    else
    {
        char *psz_artist = input_item_GetArtist( p_item );
        char *psz_name = input_item_GetTitle( p_item );

        if( !psz_name || *psz_name == '\0' )
        {
            free( psz_name );
            psz_name = input_item_GetName( p_item );
        }
        if( psz_artist && *psz_artist )
        {
            char *psz_string = NULL;
            if( asprintf( &psz_string, "%s - %s", psz_name, psz_artist ) > 0 )
            {
                VoutSetAndDeduplicateTitle( p_vout, &psz_string, ppsz_prev_title );
                free( psz_string );
            }
        }
        else if( psz_name )
        {
            VoutSetAndDeduplicateTitle( p_vout, &psz_name, ppsz_prev_title );
        }
        free( psz_name );
        free( psz_artist );
    }
    free( psz_nowplaying );
}

/* Audio output */
audio_output_t *input_resource_GetAout( input_resource_t *p_resource )
{
    audio_output_t *p_aout;

    vlc_mutex_lock( &p_resource->lock_hold );
    p_aout = p_resource->p_aout;

    if( p_aout == NULL || p_resource->b_aout_busy )
    {
        msg_Dbg( p_resource->p_parent, "creating audio output" );
        vlc_mutex_unlock( &p_resource->lock_hold );

        p_aout = aout_New( p_resource->p_parent );
        if( p_aout == NULL )
            return NULL; /* failed */

        vlc_mutex_lock( &p_resource->lock_hold );
        if( p_resource->p_aout == NULL )
            p_resource->p_aout = p_aout;
    }
    else
        msg_Dbg( p_resource->p_parent, "reusing audio output" );

    if( p_resource->p_aout == p_aout )
    {
        assert( !p_resource->b_aout_busy );
        p_resource->b_aout_busy = true;
    }
    vlc_mutex_unlock( &p_resource->lock_hold );
    return p_aout;
}

void input_resource_PutAout( input_resource_t *p_resource,
                             audio_output_t *p_aout )
{
    assert( p_aout != NULL );

    vlc_mutex_lock( &p_resource->lock_hold );
    if( p_aout == p_resource->p_aout )
    {
        assert( p_resource->b_aout_busy );
        p_resource->b_aout_busy = false;
        msg_Dbg( p_resource->p_parent, "keeping audio output" );
        p_aout = NULL;
    }
    else
        msg_Dbg( p_resource->p_parent, "destroying extra audio output" );
    vlc_mutex_unlock( &p_resource->lock_hold );

    if( p_aout != NULL )
        aout_Release( p_aout );
}

audio_output_t *input_resource_HoldAout( input_resource_t *p_resource )
{
    audio_output_t *p_aout;

    vlc_mutex_lock( &p_resource->lock_hold );
    p_aout = p_resource->p_aout;
    if( p_aout != NULL )
        aout_Hold(p_aout);
    vlc_mutex_unlock( &p_resource->lock_hold );

    return p_aout;
}

void input_resource_ResetAout( input_resource_t *p_resource )
{
    audio_output_t *p_aout = NULL;

    vlc_mutex_lock( &p_resource->lock_hold );
    if( !p_resource->b_aout_busy )
        p_aout = p_resource->p_aout;

    p_resource->p_aout = NULL;
    p_resource->b_aout_busy = false;
    vlc_mutex_unlock( &p_resource->lock_hold );

    if( p_aout != NULL )
        aout_Release( p_aout );
}

/* Common */
input_resource_t *input_resource_New( vlc_object_t *p_parent )
{
    input_resource_t *p_resource = calloc( 1, sizeof(*p_resource) );
    if( !p_resource )
        return NULL;

    p_resource->p_vout_dummy = vout_CreateDummy(p_parent);
    if( !p_resource->p_vout_dummy )
    {
        free( p_resource );
        return NULL;
    }

    vlc_list_init( &p_resource->vout_rscs );

    vlc_atomic_rc_init( &p_resource->rc );
    p_resource->p_parent = p_parent;
    vlc_mutex_init( &p_resource->lock );
    vlc_mutex_init( &p_resource->lock_hold );
    return p_resource;
}

void input_resource_Release( input_resource_t *p_resource )
{
    if( !vlc_atomic_rc_dec( &p_resource->rc ) )
        return;

    DestroySout( p_resource );
    DestroyVout( p_resource );
    if( p_resource->p_aout != NULL )
        aout_Release( p_resource->p_aout );

    vout_Release( p_resource->p_vout_dummy );
    free( p_resource );
}

input_resource_t *input_resource_Hold( input_resource_t *p_resource )
{
    vlc_atomic_rc_inc( &p_resource->rc );
    return p_resource;
}

void input_resource_SetInput( input_resource_t *p_resource, input_thread_t *p_input )
{
    vlc_mutex_lock( &p_resource->lock );

    if( p_resource->p_input && !p_input )
        assert( vlc_list_is_empty( &p_resource->vout_rscs )
             || p_resource->vout_rsc_free == resource_GetFirstVoutRsc( p_resource ) );

    /* */
    p_resource->p_input = p_input;

    vlc_mutex_unlock( &p_resource->lock );
}

static void input_resource_PutVoutLocked(input_resource_t *p_resource,
                                         vout_thread_t *vout,
                                         enum input_resource_vout_state *vout_state)
{
    assert(vout != NULL);
    struct vout_resource *vout_rsc = resource_GetVoutRsc(p_resource, vout);
    assert(vout_rsc != NULL);

    if (vout_state != NULL)
        *vout_state = vout_rsc->started ? INPUT_RESOURCE_VOUT_STOPPED
                                        : INPUT_RESOURCE_VOUT_NOTCHANGED;

    if (vout_rsc->started)
    {
        vout_StopDisplay(vout_rsc->vout);
        vout_rsc->started = false;
    }

    if (vout_rsc == resource_GetFirstVoutRsc(p_resource))
    {
        assert(p_resource->vout_rsc_free == NULL || p_resource->vout_rsc_free == vout_rsc);

        msg_Dbg(p_resource->p_parent, "saving a free vout");
        p_resource->vout_rsc_free = vout_rsc;
    }
    else
    {
        msg_Dbg(p_resource->p_parent, "destroying vout (already one saved or active)");

        vlc_mutex_lock(&p_resource->lock_hold);
        vout_resource_Remove(vout_rsc);
        vlc_mutex_unlock(&p_resource->lock_hold);

        vout_Stop(vout);
        vout_Close(vout);
    }
}

void input_resource_PutVout(input_resource_t *p_resource,
                            vout_thread_t *vout,
                            enum input_resource_vout_state *vout_state)
{
    vlc_mutex_lock( &p_resource->lock );
    input_resource_PutVoutLocked( p_resource, vout, vout_state );
    vlc_mutex_unlock( &p_resource->lock );
}

static struct vout_resource *
RequestVoutRsc(input_resource_t *p_resource)
{
    struct vout_resource *vout_rsc = NULL;

    if( p_resource->vout_rsc_free != NULL )
    {
        /* The free vout is always the first one */
        msg_Dbg(p_resource->p_parent, "trying to reuse free vout");

        vout_rsc = p_resource->vout_rsc_free;
        p_resource->vout_rsc_free = NULL;
    }
    else
    {
        /* Use the dummy vout as the parent of the future main vout. This
         * will allow the future vout to inherit all parameters
         * pre-configured on this dummy vout. */

        vlc_object_t *parent = vlc_list_is_empty( &p_resource->vout_rscs ) ?
            VLC_OBJECT(p_resource->p_vout_dummy) : p_resource->p_parent;
        vout_thread_t *vout = vout_Create(parent);
        if (vout == NULL)
            return NULL;

        vout_rsc = vout_resource_Create(vout);
        if (vout_rsc == NULL)
        {
            vout_Close(vout);
            return NULL;
        }

        vout_rsc->order = vlc_list_is_empty( &p_resource->vout_rscs ) ?
            VLC_VOUT_ORDER_PRIMARY : VLC_VOUT_ORDER_SECONDARY;

        vlc_mutex_lock(&p_resource->lock_hold);
        vout_resource_Add(vout_rsc, p_resource);
        vlc_mutex_unlock(&p_resource->lock_hold);
    }

    return vout_rsc;
}

vout_thread_t *input_resource_RequestVout(input_resource_t *p_resource,
                                          vlc_video_context *vctx,
                                          const vout_configuration_t *cfg,
                                          enum vlc_vout_order *order,
                                          enum input_resource_vout_state *vout_state)
{
    vlc_mutex_lock( &p_resource->lock );
    struct vout_resource *vout_rsc = NULL;

    if (vout_state != NULL)
        *vout_state = INPUT_RESOURCE_VOUT_NOTCHANGED;

    vout_configuration_t dcfg = *cfg;
    if (dcfg.vout == NULL)
    {
        vout_rsc = RequestVoutRsc(p_resource);
        if (vout_rsc == NULL)
        {
            vlc_mutex_unlock( &p_resource->lock );
            return NULL;
        }
        dcfg.vout = vout_rsc->vout;
    }
    else
    {
        vout_rsc = resource_GetVoutRsc(p_resource, dcfg.vout);
        assert(vout_rsc != NULL);

        /* the caller is going to reuse the free vout, it's not free anymore */
        if (p_resource->vout_rsc_free == vout_rsc)
            p_resource->vout_rsc_free = NULL;
    }

    if (order != NULL)
        *order = vout_rsc->order;

    if (dcfg.fmt == NULL)
    {
        /* A NULL fmt means that only the vout creation is requested, do not
         * start it with vout_Request(). */

        vlc_mutex_unlock(&p_resource->lock);
        return dcfg.vout;
    }

    if (vout_Request(&dcfg, vctx, p_resource->p_input)) {
        if (vout_rsc->started && vout_state != NULL)
            *vout_state = INPUT_RESOURCE_VOUT_STOPPED;

        vout_rsc->started = false;
        input_resource_PutVoutLocked(p_resource, dcfg.vout, NULL);
        vlc_mutex_unlock(&p_resource->lock);
        return NULL;
    }

    if (!vout_rsc->started)
    {
        vout_rsc->started = true;
        if (vout_state != NULL)
            *vout_state = INPUT_RESOURCE_VOUT_STARTED;

        DisplayVoutTitle(p_resource, cfg->vout, &vout_rsc->psz_prev_title);

        /* Send original viewpoint to the input in order to update other ESes */
        if (p_resource->p_input != NULL)
        {
            input_control_param_t param = { .viewpoint = cfg->fmt->pose };
            input_ControlPush(p_resource->p_input, INPUT_CONTROL_SET_INITIAL_VIEWPOINT,
                              ¶m);
        }
    }
    vlc_mutex_unlock( &p_resource->lock );

    return dcfg.vout;
}

vout_thread_t *input_resource_HoldVout( input_resource_t *p_resource )
{
    vlc_mutex_lock( &p_resource->lock_hold );

    struct vout_resource *vout_rsc = resource_GetFirstVoutRsc( p_resource );
    vout_thread_t *p_vout = vout_rsc != NULL ? vout_rsc->vout : NULL;
    if( p_vout )
        vout_Hold(p_vout);

    vlc_mutex_unlock( &p_resource->lock_hold );

    return p_vout;
}

vout_thread_t *input_resource_HoldDummyVout( input_resource_t *p_resource )
{
    return vout_Hold(p_resource->p_vout_dummy);
}

void input_resource_HoldVouts( input_resource_t *p_resource, vout_thread_t ***ppp_vout,
                               size_t *pi_vout )
{
    vout_thread_t **pp_vout;

    *pi_vout = 0;
    *ppp_vout = NULL;

    vlc_mutex_lock( &p_resource->lock_hold );

    if( vlc_list_is_empty( &p_resource->vout_rscs ) )
        goto exit;

    size_t count = 0;
    struct vout_resource *vout_rsc;
    vlc_list_foreach( vout_rsc, &p_resource->vout_rscs, node )
        count ++;

    pp_vout = vlc_alloc( count, sizeof(*pp_vout) );
    if( !pp_vout )
        goto exit;

    *ppp_vout = pp_vout;
    *pi_vout = count;

    count = 0;
    vlc_list_foreach( vout_rsc, &p_resource->vout_rscs, node )
        pp_vout[count++] = vout_Hold( vout_rsc->vout );

exit:
    vlc_mutex_unlock( &p_resource->lock_hold );
}

void input_resource_StopFreeVout(input_resource_t *p_resource)
{
    vlc_mutex_lock(&p_resource->lock);
    if (p_resource->vout_rsc_free != NULL)
    {
        msg_Dbg(p_resource->vout_rsc_free->vout, "stop free vout");
        vout_Stop(p_resource->vout_rsc_free->vout);
    }
    vlc_mutex_unlock(&p_resource->lock);
}

/* */
sout_stream_t *input_resource_RequestSout( input_resource_t *p_resource, const char *psz_sout )
{
    sout_stream_t *sout;

    assert(psz_sout != NULL);
    vlc_mutex_lock( &p_resource->lock );
    /* Check the validity of the sout */
    if (p_resource->p_sout != NULL
     && strcmp(p_resource->psz_sout, psz_sout) != 0)
    {
        msg_Dbg(p_resource->p_parent, "destroying unusable sout");
        DestroySout(p_resource);
    }

    sout = p_resource->p_sout;

    if (sout != NULL)
    {
        /* Reuse it */
        msg_Dbg(p_resource->p_parent, "reusing sout");
        msg_Dbg(p_resource->p_parent, "you probably want to use gather stream_out");
        p_resource->p_sout = NULL;
    }
    else
    {
        /* Create a new one */
        p_resource->psz_sout = strdup(psz_sout);

        if (likely(p_resource->psz_sout != NULL)) {
            sout = sout_NewInstance(p_resource->p_parent, psz_sout);
            if (sout == NULL)
                free(p_resource->psz_sout);
        }
    }
    vlc_mutex_unlock( &p_resource->lock );
    return sout;
}

void input_resource_PutSout(input_resource_t *resource, sout_stream_t *sout)
{
    if (sout == NULL)
    {
        input_resource_TerminateSout(resource);
        return;
    }

    vlc_mutex_lock(&resource->lock);
    assert(resource->p_sout == NULL);
    resource->p_sout = sout;
    vlc_mutex_unlock(&resource->lock);
}

void input_resource_TerminateSout( input_resource_t *p_resource )
{
    vlc_mutex_lock( &p_resource->lock );
    DestroySout(p_resource);
    vlc_mutex_unlock( &p_resource->lock );
}

Messung
CHZG
849610093

¤ Dauer der Verarbeitung: 0.7 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104842
#Domains=499162