3 * Copyright (c) 2006 Steve Lhomme
4 * Copyright (c) 2007 Wolfram Gloger
5 * Copyright (c) 2010 Michele OrrĂ¹
7 * This file is part of Libav.
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.
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.
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
25 #include "libavutil/avstring.h"
26 #include "libavutil/mem.h"
29 #define AV_CAT_SEPARATOR "|"
32 URLContext
*uc
; ///< node's URLContext
33 int64_t size
; ///< url filesize
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
42 static av_cold
int concat_close(URLContext
*h
)
46 struct concat_data
*data
= h
->priv_data
;
47 struct concat_nodes
*nodes
= data
->nodes
;
49 for (i
= 0; i
!= data
->length
; i
++)
50 err
|= ffurl_close(nodes
[i
].uc
);
52 av_freep(&data
->nodes
);
54 return err
< 0 ? -1 : 0;
57 static av_cold
int concat_open(URLContext
*h
, const char *uri
, int flags
)
59 char *node_uri
= NULL
, *tmp_uri
;
64 struct concat_data
*data
= h
->priv_data
;
65 struct concat_nodes
*nodes
;
67 av_strstart(uri
, "concat:", &uri
);
69 for (i
= 0, len
= 1; uri
[i
]; i
++)
70 if (uri
[i
] == *AV_CAT_SEPARATOR
)
71 /* integer overflow */
72 if (++len
== UINT_MAX
/ sizeof(*nodes
)) {
73 av_freep(&h
->priv_data
);
74 return AVERROR(ENAMETOOLONG
);
77 if (!(nodes
= av_malloc(sizeof(*nodes
) * len
))) {
78 return AVERROR(ENOMEM
);
84 err
= AVERROR(ENOENT
);
85 for (i
= 0; *uri
; i
++) {
87 len
= strcspn(uri
, AV_CAT_SEPARATOR
);
88 if (!(tmp_uri
= av_realloc(node_uri
, len
+1))) {
89 err
= AVERROR(ENOMEM
);
93 av_strlcpy(node_uri
, uri
, len
+1);
94 uri
+= len
+ strspn(uri
+len
, AV_CAT_SEPARATOR
);
96 /* creating URLContext */
97 if ((err
= ffurl_open(&uc
, node_uri
, flags
,
98 &h
->interrupt_callback
, NULL
)) < 0)
102 if ((size
= ffurl_size(uc
)) < 0) {
104 err
= AVERROR(ENOSYS
);
110 nodes
[i
].size
= size
;
117 else if (!(nodes
= av_realloc(nodes
, data
->length
* sizeof(*nodes
)))) {
119 err
= AVERROR(ENOMEM
);
125 static int concat_read(URLContext
*h
, unsigned char *buf
, int size
)
127 int result
, total
= 0;
128 struct concat_data
*data
= h
->priv_data
;
129 struct concat_nodes
*nodes
= data
->nodes
;
130 size_t i
= data
->current
;
133 result
= ffurl_read(nodes
[i
].uc
, buf
, size
);
135 return total
? total
: result
;
137 if (i
+ 1 == data
->length
||
138 ffurl_seek(nodes
[++i
].uc
, 0, SEEK_SET
) < 0)
148 static int64_t concat_seek(URLContext
*h
, int64_t pos
, int whence
)
151 struct concat_data
*data
= h
->priv_data
;
152 struct concat_nodes
*nodes
= data
->nodes
;
157 for (i
= data
->length
- 1;
158 i
&& pos
< -nodes
[i
].size
;
160 pos
+= nodes
[i
].size
;
163 /* get the absolute position */
164 for (i
= 0; i
!= data
->current
; i
++)
165 pos
+= nodes
[i
].size
;
166 pos
+= ffurl_seek(nodes
[i
].uc
, 0, SEEK_CUR
);
168 /* fall through with the absolute position */
170 for (i
= 0; i
!= data
->length
- 1 && pos
>= nodes
[i
].size
; i
++)
171 pos
-= nodes
[i
].size
;
174 return AVERROR(EINVAL
);
177 result
= ffurl_seek(nodes
[i
].uc
, pos
, whence
);
181 result
+= nodes
[--i
].size
;
186 URLProtocol ff_concat_protocol
= {
188 .url_open
= concat_open
,
189 .url_read
= concat_read
,
190 .url_seek
= concat_seek
,
191 .url_close
= concat_close
,
192 .priv_data_size
= sizeof(struct concat_data
),