preparser.c 6.43 KB
Newer Older
1
/*****************************************************************************
Filip Roséen's avatar
Filip Roséen committed
2
 * preparser.c
3
 *****************************************************************************
Filip Roséen's avatar
Filip Roséen committed
4
 * Copyright © 2017-2017 VLC authors and VideoLAN
5
6
 * $Id$
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
7
8
9
 * 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
10
11
12
13
 * (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
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
14
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
16
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
17
18
19
 * 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.
20
 *****************************************************************************/
Filip Roséen's avatar
Filip Roséen committed
21

22
23
24
25
26
27
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>

Filip Roséen's avatar
Filip Roséen committed
28
#include "misc/background_worker.h"
29
#include "input/input_interface.h"
Filip Roséen's avatar
Filip Roséen committed
30
31
32
#include "input/input_internal.h"
#include "preparser.h"
#include "fetcher.h"
33

34
struct input_preparser_t
35
{
Filip Roséen's avatar
Filip Roséen committed
36
    vlc_object_t* owner;
37
    input_fetcher_t* fetcher;
Filip Roséen's avatar
Filip Roséen committed
38
    struct background_worker* worker;
39
40
    atomic_int  state;
    atomic_bool ended;
41
    atomic_bool deactivated;
42
43
};

44
45
static void InputEvent( input_thread_t *input, void *preparser_,
                        const struct vlc_input_event *event )
46
{
47
48
    VLC_UNUSED( input );
    input_preparser_t *preparser = preparser_;
49

50
51
52
53
54
55
56
57
58
59
60
61
    switch( event->type )
    {
        case INPUT_EVENT_STATE:
            atomic_store( &preparser->state, event->state );
            break;
        case INPUT_EVENT_DEAD:
            atomic_store( &preparser->ended, true );
            background_worker_RequestProbe( preparser->worker );
            break;
        default:
            break;
    }
62
63
}

Filip Roséen's avatar
Filip Roséen committed
64
static int PreparserOpenInput( void* preparser_, void* item_, void** out )
65
{
66
    input_preparser_t* preparser = preparser_;
67

68
69
70
71
    atomic_store( &preparser->state, INIT_S );
    atomic_store( &preparser->ended, false );
    input_thread_t* input = input_CreatePreparser( preparser->owner, InputEvent,
                                                   preparser, item_ );
Filip Roséen's avatar
Filip Roséen committed
72
    if( !input )
73
    {
Filip Roséen's avatar
Filip Roséen committed
74
75
        input_item_SignalPreparseEnded( item_, ITEM_PREPARSE_FAILED );
        return VLC_EGENERIC;
76
77
    }

Filip Roséen's avatar
Filip Roséen committed
78
    if( input_Start( input ) )
79
    {
80
        input_Close( input );
Filip Roséen's avatar
Filip Roséen committed
81
82
        input_item_SignalPreparseEnded( item_, ITEM_PREPARSE_FAILED );
        return VLC_EGENERIC;
83
    }
Filip Roséen's avatar
Filip Roséen committed
84
85
86

    *out = input;
    return VLC_SUCCESS;
87
88
}

Filip Roséen's avatar
Filip Roséen committed
89
static int PreparserProbeInput( void* preparser_, void* input_ )
90
{
91
92
93
    input_preparser_t* preparser = preparser_;
    return atomic_load( &preparser->ended );
    VLC_UNUSED( input_ );
Filip Roséen's avatar
Filip Roséen committed
94
}
95

Filip Roséen's avatar
Filip Roséen committed
96
97
static void PreparserCloseInput( void* preparser_, void* input_ )
{
98
    input_preparser_t* preparser = preparser_;
Filip Roséen's avatar
Filip Roséen committed
99
100
    input_thread_t* input = input_;
    input_item_t* item = input_priv(input)->p_item;
101

102
    int status;
103
    switch( atomic_load( &preparser->state ) )
104
105
106
107
108
109
110
111
112
113
    {
        case END_S:
            status = ITEM_PREPARSE_DONE;
            break;
        case ERROR_S:
            status = ITEM_PREPARSE_FAILED;
            break;
        default:
            status = ITEM_PREPARSE_TIMEOUT;
    }
114

Filip Roséen's avatar
Filip Roséen committed
115
116
117
118
    input_Stop( input );
    input_Close( input );

    if( preparser->fetcher )
119
    {
120
        if( !input_fetcher_Push( preparser->fetcher, item, 0, status ) )
121
122
            return;
    }
Filip Roséen's avatar
Filip Roséen committed
123
124
125

    input_item_SetPreparsed( item, true );
    input_item_SignalPreparseEnded( item, status );
126
127
}

Filip Roséen's avatar
Filip Roséen committed
128
129
static void InputItemRelease( void* item ) { input_item_Release( item ); }
static void InputItemHold( void* item ) { input_item_Hold( item ); }
130

131
input_preparser_t* input_preparser_New( vlc_object_t *parent )
132
{
133
    input_preparser_t* preparser = malloc( sizeof *preparser );
134

Filip Roséen's avatar
Filip Roséen committed
135
136
137
138
139
140
141
    struct background_worker_config conf = {
        .default_timeout = var_InheritInteger( parent, "preparse-timeout" ),
        .pf_start = PreparserOpenInput,
        .pf_probe = PreparserProbeInput,
        .pf_stop = PreparserCloseInput,
        .pf_release = InputItemRelease,
        .pf_hold = InputItemHold };
Thomas Guillem's avatar
Thomas Guillem committed
142
143


Filip Roséen's avatar
Filip Roséen committed
144
145
146
147
148
149
150
    if( likely( preparser ) )
        preparser->worker = background_worker_New( preparser, &conf );

    if( unlikely( !preparser || !preparser->worker ) )
    {
        free( preparser );
        return NULL;
151
    }
152

Filip Roséen's avatar
Filip Roséen committed
153
    preparser->owner = parent;
154
    preparser->fetcher = input_fetcher_New( parent );
155
    atomic_init( &preparser->state, INIT_S );
156
    atomic_init( &preparser->deactivated, false );
157
    atomic_init( &preparser->ended, false );
Filip Roséen's avatar
Filip Roséen committed
158
159
160
161
162

    if( unlikely( !preparser->fetcher ) )
        msg_Warn( parent, "unable to create art fetcher" );

    return preparser;
163
164
}

165
void input_preparser_Push( input_preparser_t *preparser,
Filip Roséen's avatar
Filip Roséen committed
166
167
    input_item_t *item, input_item_meta_request_option_t i_options,
    int timeout, void *id )
168
{
169
170
171
    if( atomic_load( &preparser->deactivated ) )
        return;

Filip Roséen's avatar
Filip Roséen committed
172
    vlc_mutex_lock( &item->lock );
173
    enum input_item_type_e i_type = item->i_type;
Filip Roséen's avatar
Filip Roséen committed
174
175
    int b_net = item->b_net;
    vlc_mutex_unlock( &item->lock );
176

Filip Roséen's avatar
Filip Roséen committed
177
    switch( i_type )
178
    {
Filip Roséen's avatar
Filip Roséen committed
179
180
181
182
183
184
        case ITEM_TYPE_NODE:
        case ITEM_TYPE_FILE:
        case ITEM_TYPE_DIRECTORY:
        case ITEM_TYPE_PLAYLIST:
            if( !b_net || i_options & META_REQUEST_OPTION_SCOPE_NETWORK )
                break;
Steve Lhomme's avatar
Steve Lhomme committed
185
            /* fallthrough */
Filip Roséen's avatar
Filip Roséen committed
186
187
        default:
            input_item_SignalPreparseEnded( item, ITEM_PREPARSE_SKIPPED );
188
            return;
189
    }
Filip Roséen's avatar
Filip Roséen committed
190
191
192

    if( background_worker_Push( preparser->worker, item, id, timeout ) )
        input_item_SignalPreparseEnded( item, ITEM_PREPARSE_FAILED );
193
194
}

195
void input_preparser_fetcher_Push( input_preparser_t *preparser,
Filip Roséen's avatar
Filip Roséen committed
196
    input_item_t *item, input_item_meta_request_option_t options )
197
{
Filip Roséen's avatar
Filip Roséen committed
198
    if( preparser->fetcher )
199
        input_fetcher_Push( preparser->fetcher, item, options, -1 );
Filip Roséen's avatar
Filip Roséen committed
200
}
201

202
void input_preparser_Cancel( input_preparser_t *preparser, void *id )
Filip Roséen's avatar
Filip Roséen committed
203
204
{
    background_worker_Cancel( preparser->worker, id );
205
206
}

207
void input_preparser_Deactivate( input_preparser_t* preparser )
208
209
210
211
212
{
    atomic_store( &preparser->deactivated, true );
    background_worker_Cancel( preparser->worker, NULL );
}

213
void input_preparser_Delete( input_preparser_t *preparser )
214
{
Filip Roséen's avatar
Filip Roséen committed
215
    background_worker_Delete( preparser->worker );
216

Filip Roséen's avatar
Filip Roséen committed
217
    if( preparser->fetcher )
218
        input_fetcher_Delete( preparser->fetcher );
219

Filip Roséen's avatar
Filip Roséen committed
220
221
    free( preparser );
}