Statistics
| Branch: | Revision:

ffmpeg / libavformat / concat.c @ bc371aca

History | View | Annotate | Download (5.31 KB)

1
/*
2
 * Concat URL protocol
3
 * Copyright (c) 2006 Steve Lhomme
4
 * Copyright (c) 2007 Wolfram Gloger
5
 * Copyright (c) 2010 Michele OrrĂ¹
6
 *
7
 * This file is part of Libav.
8
 *
9
 * Libav is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public
11
 * License as published by the Free Software Foundation; either
12
 * version 2.1 of the License, or (at your option) any later version.
13
 *
14
 * Libav is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public
20
 * License along with Libav; if not, write to the Free Software
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22
 */
23

    
24
#include "avformat.h"
25
#include "libavutil/avstring.h"
26
#include "libavutil/mem.h"
27
#include "url.h"
28

    
29
#define AV_CAT_SEPARATOR "|"
30

    
31
struct concat_nodes {
32
    URLContext *uc;                ///< node's URLContext
33
    int64_t     size;              ///< url filesize
34
};
35

    
36
struct concat_data {
37
    struct concat_nodes *nodes;    ///< list of nodes to concat
38
    size_t               length;   ///< number of cat'ed nodes
39
    size_t               current;  ///< index of currently read node
40
};
41

    
42
static av_cold int concat_close(URLContext *h)
43
{
44
    int err = 0;
45
    size_t i;
46
    struct concat_data  *data  = h->priv_data;
47
    struct concat_nodes *nodes = data->nodes;
48

    
49
    for (i = 0; i != data->length; i++)
50
        err |= url_close(nodes[i].uc);
51

    
52
    av_freep(&data->nodes);
53
    av_freep(&h->priv_data);
54

    
55
    return err < 0 ? -1 : 0;
56
}
57

    
58
static av_cold int concat_open(URLContext *h, const char *uri, int flags)
59
{
60
    char *node_uri = NULL, *tmp_uri;
61
    int err = 0;
62
    int64_t size;
63
    size_t  len, i;
64
    URLContext *uc;
65
    struct concat_data  *data;
66
    struct concat_nodes *nodes;
67

    
68
    av_strstart(uri, "concat:", &uri);
69

    
70
    /* creating data */
71
    if (!(data = av_mallocz(sizeof(*data))))
72
        return AVERROR(ENOMEM);
73
    h->priv_data = data;
74

    
75
    for (i = 0, len = 1; uri[i]; i++)
76
        if (uri[i] == *AV_CAT_SEPARATOR)
77
            /* integer overflow */
78
            if (++len == UINT_MAX / sizeof(*nodes)) {
79
                av_freep(&h->priv_data);
80
                return AVERROR(ENAMETOOLONG);
81
            }
82

    
83
    if (!(nodes = av_malloc(sizeof(*nodes) * len))) {
84
        av_freep(&h->priv_data);
85
        return AVERROR(ENOMEM);
86
    } else
87
        data->nodes = nodes;
88

    
89
    /* handle input */
90
    if (!*uri)
91
        err = AVERROR(ENOENT);
92
    for (i = 0; *uri; i++) {
93
        /* parsing uri */
94
        len = strcspn(uri, AV_CAT_SEPARATOR);
95
        if (!(tmp_uri = av_realloc(node_uri, len+1))) {
96
            err = AVERROR(ENOMEM);
97
            break;
98
        } else
99
            node_uri = tmp_uri;
100
        av_strlcpy(node_uri, uri, len+1);
101
        uri += len + strspn(uri+len, AV_CAT_SEPARATOR);
102

    
103
        /* creating URLContext */
104
        if ((err = ffurl_open(&uc, node_uri, flags)) < 0)
105
            break;
106

    
107
        /* creating size */
108
        if ((size = url_filesize(uc)) < 0) {
109
            url_close(uc);
110
            err = AVERROR(ENOSYS);
111
            break;
112
        }
113

    
114
        /* assembling */
115
        nodes[i].uc   = uc;
116
        nodes[i].size = size;
117
    }
118
    av_free(node_uri);
119
    data->length = i;
120

    
121
    if (err < 0)
122
        concat_close(h);
123
    else if (!(nodes = av_realloc(nodes, data->length * sizeof(*nodes)))) {
124
        concat_close(h);
125
        err = AVERROR(ENOMEM);
126
    } else
127
        data->nodes = nodes;
128
    return err;
129
}
130

    
131
static int concat_read(URLContext *h, unsigned char *buf, int size)
132
{
133
    int result, total = 0;
134
    struct concat_data  *data  = h->priv_data;
135
    struct concat_nodes *nodes = data->nodes;
136
    size_t i = data->current;
137

    
138
    while (size > 0) {
139
        result = ffurl_read(nodes[i].uc, buf, size);
140
        if (result < 0)
141
            return total ? total : result;
142
        if (!result)
143
            if (i + 1 == data->length ||
144
                url_seek(nodes[++i].uc, 0, SEEK_SET) < 0)
145
                break;
146
        total += result;
147
        buf   += result;
148
        size  -= result;
149
    }
150
    data->current = i;
151
    return total;
152
}
153

    
154
static int64_t concat_seek(URLContext *h, int64_t pos, int whence)
155
{
156
    int64_t result;
157
    struct concat_data  *data  = h->priv_data;
158
    struct concat_nodes *nodes = data->nodes;
159
    size_t i;
160

    
161
    switch (whence) {
162
    case SEEK_END:
163
        for (i = data->length - 1;
164
             i && pos < -nodes[i].size;
165
             i--)
166
            pos += nodes[i].size;
167
        break;
168
    case SEEK_CUR:
169
        /* get the absolute position */
170
        for (i = 0; i != data->current; i++)
171
            pos += nodes[i].size;
172
        pos += url_seek(nodes[i].uc, 0, SEEK_CUR);
173
        whence = SEEK_SET;
174
        /* fall through with the absolute position */
175
    case SEEK_SET:
176
        for (i = 0; i != data->length - 1 && pos >= nodes[i].size; i++)
177
            pos -= nodes[i].size;
178
        break;
179
    default:
180
        return AVERROR(EINVAL);
181
    }
182

    
183
    result = url_seek(nodes[i].uc, pos, whence);
184
    if (result >= 0) {
185
        data->current = i;
186
        while (i)
187
            result += nodes[--i].size;
188
    }
189
    return result;
190
}
191

    
192
URLProtocol ff_concat_protocol = {
193
    "concat",
194
    concat_open,
195
    concat_read,
196
    NULL,
197
    concat_seek,
198
    concat_close,
199
};