delay.c 5.64 KB
Newer Older
1 2 3
/*****************************************************************************
 * delay.c: delay a stream
 *****************************************************************************
4
 * Copyright © 2009-2011 VLC authors and VideoLAN
5 6 7 8
 * $Id$
 *
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
 *
9 10
 * 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
11
 * the Free Software Foundation; either version 2.1 of the License, or
12 13 14 15
 * (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
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Lesser General Public License for more details.
18
 *
19 20 21
 * 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.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_sout.h>
#include <vlc_block.h>

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
39
#define ID_TEXT N_("Elementary Stream ID")
40 41 42
#define ID_LONGTEXT N_( \
    "Specify an identifier integer for this elementary stream" )

43
#define DELAY_TEXT N_("Delay of the ES (ms)")
44
#define DELAY_LONGTEXT N_( \
45 46
    "Specify a delay (in ms) for this elementary stream. " \
    "Positive means delay and negative means advance." )
47 48 49 50 51 52 53

static int  Open    ( vlc_object_t * );
static void Close   ( vlc_object_t * );

#define SOUT_CFG_PREFIX "sout-delay-"

vlc_module_begin()
54 55
    set_shortname( N_("Delay"))
    set_description( N_("Delay a stream"))
56 57
    set_capability( "sout stream", 50 )
    add_shortcut( "delay" )
58 59
    set_category( CAT_SOUT )
    set_subcategory( SUBCAT_SOUT_STREAM )
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
    set_callbacks( Open, Close )
    add_integer( SOUT_CFG_PREFIX "id", 0, ID_TEXT, ID_LONGTEXT,
                 false )
    add_integer( SOUT_CFG_PREFIX "delay", 0, DELAY_TEXT, DELAY_LONGTEXT,
                 false )
vlc_module_end()


/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static const char *ppsz_sout_options[] = {
    "id", "delay", NULL
};

75
static sout_stream_id_sys_t *Add( sout_stream_t *, const es_format_t * );
76
static void              Del   ( sout_stream_t *, sout_stream_id_sys_t * );
77
static int               Send  ( sout_stream_t *, sout_stream_id_sys_t *, block_t * );
78 79 80

struct sout_stream_sys_t
{
81
    sout_stream_id_sys_t *id;
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
    int i_id;
    mtime_t i_delay;
};

/*****************************************************************************
 * Open:
 *****************************************************************************/
static int Open( vlc_object_t *p_this )
{
    sout_stream_t     *p_stream = (sout_stream_t*)p_this;
    sout_stream_sys_t *p_sys;

    if( !p_stream->p_next )
    {
        msg_Err( p_stream, "cannot create chain" );
        return VLC_EGENERIC;
    }

Rémi Duraffort's avatar
Rémi Duraffort committed
100 101 102 103 104
    p_sys = calloc( 1, sizeof( sout_stream_sys_t ) );
    if( !p_sys )
        return VLC_ENOMEM;


105 106 107
    config_ChainParse( p_stream, SOUT_CFG_PREFIX, ppsz_sout_options,
                   p_stream->p_cfg );

Rémi Duraffort's avatar
Rémi Duraffort committed
108 109
    p_sys->i_id = var_GetInteger( p_stream, SOUT_CFG_PREFIX "id" );
    p_sys->i_delay = 1000 * var_GetInteger( p_stream, SOUT_CFG_PREFIX "delay" );
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130

    p_stream->pf_add    = Add;
    p_stream->pf_del    = Del;
    p_stream->pf_send   = Send;

    p_stream->p_sys     = p_sys;

    return VLC_SUCCESS;
}

/*****************************************************************************
 * Close:
 *****************************************************************************/
static void Close( vlc_object_t * p_this )
{
    sout_stream_t     *p_stream = (sout_stream_t*)p_this;
    sout_stream_sys_t *p_sys = (sout_stream_sys_t *)p_stream->p_sys;

    free( p_sys );
}

131
static sout_stream_id_sys_t * Add( sout_stream_t *p_stream, const es_format_t *p_fmt )
132 133 134 135 136 137 138
{
    sout_stream_sys_t *p_sys = (sout_stream_sys_t *)p_stream->p_sys;

    if ( p_fmt->i_id == p_sys->i_id )
    {
        msg_Dbg( p_stream, "delaying ID %d by %"PRId64,
                 p_sys->i_id, p_sys->i_delay );
139
        p_sys->id = p_stream->p_next->pf_add( p_stream->p_next, p_fmt );
140 141 142
        return p_sys->id;
    }

143
    return p_stream->p_next->pf_add( p_stream->p_next, p_fmt );
144 145
}

146
static void Del( sout_stream_t *p_stream, sout_stream_id_sys_t *id )
147 148 149 150 151 152
{
    sout_stream_sys_t *p_sys = (sout_stream_sys_t *)p_stream->p_sys;

    if ( id == p_sys->id )
        p_sys->id = NULL;

153
    p_stream->p_next->pf_del( p_stream->p_next, id );
154 155
}

156
static int Send( sout_stream_t *p_stream, sout_stream_id_sys_t *id,
157 158 159 160 161 162 163 164 165
                 block_t *p_buffer )
{
    sout_stream_sys_t *p_sys = (sout_stream_sys_t *)p_stream->p_sys;

    if ( id == p_sys->id )
    {
        block_t *p_block = p_buffer;
        while ( p_block != NULL )
        {
166
            if ( p_block->i_pts != VLC_TS_INVALID )
167
                p_block->i_pts += p_sys->i_delay;
168
            if ( p_block->i_dts != VLC_TS_INVALID )
169 170 171 172 173
                p_block->i_dts += p_sys->i_delay;
            p_block = p_block->p_next;
        }
    }

174
    return p_stream->p_next->pf_send( p_stream->p_next, id, p_buffer );
175
}