preparser.c 6.56 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
    atomic_bool deactivated;
40
41
};

42
43
44
45
46
47
48
49
50
51
typedef struct input_preparser_task_t
{
    input_preparser_t* preparser;
    input_thread_t* input;
    atomic_int state;
    atomic_bool done;

} input_preparser_task_t;

static void InputEvent( input_thread_t *input, void *task_,
52
                        const struct vlc_input_event *event )
53
{
54
    VLC_UNUSED( input );
55
    input_preparser_task_t* task = task_;
56

57
58
59
    switch( event->type )
    {
        case INPUT_EVENT_STATE:
60
            atomic_store( &task->state, event->state );
61
            break;
62

63
        case INPUT_EVENT_DEAD:
64
65
            atomic_store( &task->done, true );
            background_worker_RequestProbe( task->preparser->worker );
66
            break;
67
        default: ;
68
    }
69
70
}

Filip Roséen's avatar
Filip Roséen committed
71
static int PreparserOpenInput( void* preparser_, void* item_, void** out )
72
{
73
    input_preparser_t* preparser = preparser_;
74
    input_preparser_task_t* task = malloc( sizeof *task );
75

76
77
    if( unlikely( !task ) )
        goto error;
78

79
80
81
82
83
84
85
86
87
88
    atomic_init( &task->state, INIT_S );
    atomic_init( &task->done, false );

    task->preparser = preparser_;
    task->input = input_CreatePreparser( preparser->owner, InputEvent,
                                         task, item_ );
    if( !task->input )
        goto error;

    if( input_Start( task->input ) )
89
    {
90
91
        input_Close( task->input );
        goto error;
92
    }
Filip Roséen's avatar
Filip Roséen committed
93

94
95
    *out = task;

Filip Roséen's avatar
Filip Roséen committed
96
    return VLC_SUCCESS;
97
98
99
100
101

error:
    free( task );
    input_item_SignalPreparseEnded( item_, ITEM_PREPARSE_FAILED );
    return VLC_EGENERIC;
102
103
}

104
static int PreparserProbeInput( void* preparser_, void* task_ )
105
{
106
107
108
    input_preparser_task_t* task = task_;
    return atomic_load( &task->done );
    VLC_UNUSED( preparser_ );
Filip Roséen's avatar
Filip Roséen committed
109
}
110

111
static void PreparserCloseInput( void* preparser_, void* task_ )
Filip Roséen's avatar
Filip Roséen committed
112
{
113
114
    input_preparser_task_t* task = task_;

115
    input_preparser_t* preparser = preparser_;
116
117
    input_thread_t* input = task->input;
    input_item_t* item = input_priv(task->input)->p_item;
118

119
    int status;
120
    switch( atomic_load( &task->state ) )
121
122
123
124
125
126
127
128
129
130
    {
        case END_S:
            status = ITEM_PREPARSE_DONE;
            break;
        case ERROR_S:
            status = ITEM_PREPARSE_FAILED;
            break;
        default:
            status = ITEM_PREPARSE_TIMEOUT;
    }
131

Filip Roséen's avatar
Filip Roséen committed
132
133
134
    input_Stop( input );
    input_Close( input );

135
136
    free( task );

Filip Roséen's avatar
Filip Roséen committed
137
    if( preparser->fetcher )
138
    {
139
        if( !input_fetcher_Push( preparser->fetcher, item, 0, status ) )
140
141
            return;
    }
Filip Roséen's avatar
Filip Roséen committed
142
143
144

    input_item_SetPreparsed( item, true );
    input_item_SignalPreparseEnded( item, status );
145
146
}

Filip Roséen's avatar
Filip Roséen committed
147
148
static void InputItemRelease( void* item ) { input_item_Release( item ); }
static void InputItemHold( void* item ) { input_item_Hold( item ); }
149

150
input_preparser_t* input_preparser_New( vlc_object_t *parent )
151
{
152
    input_preparser_t* preparser = malloc( sizeof *preparser );
153

Filip Roséen's avatar
Filip Roséen committed
154
155
156
157
158
159
160
    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
161
162


Filip Roséen's avatar
Filip Roséen committed
163
164
165
166
167
168
169
    if( likely( preparser ) )
        preparser->worker = background_worker_New( preparser, &conf );

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

Filip Roséen's avatar
Filip Roséen committed
172
    preparser->owner = parent;
173
    preparser->fetcher = input_fetcher_New( parent );
174
    atomic_init( &preparser->deactivated, false );
Filip Roséen's avatar
Filip Roséen committed
175
176
177
178
179

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

    return preparser;
180
181
}

182
void input_preparser_Push( input_preparser_t *preparser,
Filip Roséen's avatar
Filip Roséen committed
183
184
    input_item_t *item, input_item_meta_request_option_t i_options,
    int timeout, void *id )
185
{
186
187
188
    if( atomic_load( &preparser->deactivated ) )
        return;

Filip Roséen's avatar
Filip Roséen committed
189
    vlc_mutex_lock( &item->lock );
190
    enum input_item_type_e i_type = item->i_type;
Filip Roséen's avatar
Filip Roséen committed
191
192
    int b_net = item->b_net;
    vlc_mutex_unlock( &item->lock );
193

Filip Roséen's avatar
Filip Roséen committed
194
    switch( i_type )
195
    {
Filip Roséen's avatar
Filip Roséen committed
196
197
198
199
200
201
        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
202
            /* fallthrough */
Filip Roséen's avatar
Filip Roséen committed
203
204
        default:
            input_item_SignalPreparseEnded( item, ITEM_PREPARSE_SKIPPED );
205
            return;
206
    }
Filip Roséen's avatar
Filip Roséen committed
207
208
209

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

212
void input_preparser_fetcher_Push( input_preparser_t *preparser,
Filip Roséen's avatar
Filip Roséen committed
213
    input_item_t *item, input_item_meta_request_option_t options )
214
{
Filip Roséen's avatar
Filip Roséen committed
215
    if( preparser->fetcher )
216
        input_fetcher_Push( preparser->fetcher, item, options, -1 );
Filip Roséen's avatar
Filip Roséen committed
217
}
218

219
void input_preparser_Cancel( input_preparser_t *preparser, void *id )
Filip Roséen's avatar
Filip Roséen committed
220
221
{
    background_worker_Cancel( preparser->worker, id );
222
223
}

224
void input_preparser_Deactivate( input_preparser_t* preparser )
225
226
227
228
229
{
    atomic_store( &preparser->deactivated, true );
    background_worker_Cancel( preparser->worker, NULL );
}

230
void input_preparser_Delete( input_preparser_t *preparser )
231
{
Filip Roséen's avatar
Filip Roséen committed
232
    background_worker_Delete( preparser->worker );
233

Filip Roséen's avatar
Filip Roséen committed
234
    if( preparser->fetcher )
235
        input_fetcher_Delete( preparser->fetcher );
236

Filip Roséen's avatar
Filip Roséen committed
237
238
    free( preparser );
}