annotate concat.c @ 5771:e8c8f5a002ff libavformat

Fix concat seek result. Patch by Wolfram Gloger wmglo AT-SIGN dent.med.uni-muenchen DOT de.
author stefano
date Mon, 08 Mar 2010 00:22:03 +0000
parents b280788e1936
children d3d45b140065
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
5634
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
1 /*
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
2 * Concat URL protocol
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
3 * Copyright (c) 2006 Steve Lhomme
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
4 * Copyright (c) 2007 Wolfram Gloger
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
5 * Copyright (c) 2010 Michele OrrĂ¹
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
6 *
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
7 * This file is part of FFmpeg.
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
8 *
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
9 * FFmpeg is free software; you can redistribute it and/or
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
10 * modify it under the terms of the GNU Lesser General Public
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
11 * License as published by the Free Software Foundation; either
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
12 * version 2.1 of the License, or (at your option) any later version.
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
13 *
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
14 * FFmpeg is distributed in the hope that it will be useful,
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
17 * Lesser General Public License for more details.
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
18 *
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
19 * You should have received a copy of the GNU Lesser General Public
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
20 * License along with FFmpeg; if not, write to the Free Software
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
22 */
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
23
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
24 #include "avformat.h"
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
25 #include "libavutil/avstring.h"
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
26 #include "libavutil/mem.h"
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
27
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
28 #define AV_CAT_SEPARATOR "|"
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
29
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
30 struct concat_nodes {
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
31 URLContext *uc; ///< node's URLContext
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
32 int64_t size; ///< url filesize
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
33 };
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
34
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
35 struct concat_data {
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
36 struct concat_nodes *nodes; ///< list of nodes to concat
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
37 size_t length; ///< number of cat'ed nodes
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
38 size_t current; ///< index of currently read node
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
39 };
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
40
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
41 static av_cold int concat_close(URLContext *h)
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
42 {
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
43 int err = 0;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
44 size_t i;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
45 struct concat_data *data = h->priv_data;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
46 struct concat_nodes *nodes = data->nodes;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
47
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
48 for (i = 0; i != data->length; i++)
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
49 err |= url_close(nodes[i].uc);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
50
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
51 av_freep(&data->nodes);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
52 av_freep(&h->priv_data);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
53
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
54 return err < 0 ? -1 : 0;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
55 }
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
56
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
57 static av_cold int concat_open(URLContext *h, const char *uri, int flags)
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
58 {
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
59 char *node_uri = NULL, *tmp_uri;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
60 int err = 0;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
61 int64_t size;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
62 size_t len, i;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
63 URLContext *uc;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
64 struct concat_data *data;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
65 struct concat_nodes *nodes;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
66
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
67 av_strstart(uri, "concat:", &uri);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
68
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
69 /* creating data */
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
70 if (!(data = av_mallocz(sizeof(*data))))
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
71 return AVERROR(ENOMEM);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
72 h->priv_data = data;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
73
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
74 for (i = 0, len = 1; uri[i]; i++)
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
75 if (uri[i] == *AV_CAT_SEPARATOR)
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
76 /* integer overflow */
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
77 if (++len == UINT_MAX / sizeof(*nodes)) {
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
78 av_freep(&h->priv_data);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
79 return AVERROR(ENAMETOOLONG);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
80 }
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
81
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
82 if (!(nodes = av_malloc(sizeof(*nodes) * len))) {
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
83 av_freep(&h->priv_data);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
84 return AVERROR(ENOMEM);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
85 } else
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
86 data->nodes = nodes;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
87
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
88 /* handle input */
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
89 if (!*uri)
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
90 err = AVERROR(ENOENT);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
91 for (i = 0; *uri; i++) {
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
92 /* parsing uri */
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
93 len = strcspn(uri, AV_CAT_SEPARATOR);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
94 if (!(tmp_uri = av_realloc(node_uri, len+1))) {
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
95 err = AVERROR(ENOMEM);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
96 break;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
97 } else
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
98 node_uri = tmp_uri;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
99 av_strlcpy(node_uri, uri, len+1);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
100 uri += len + strspn(uri+len, AV_CAT_SEPARATOR);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
101
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
102 /* creating URLContext */
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
103 if ((err = url_open(&uc, node_uri, flags)) < 0)
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
104 break;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
105
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
106 /* creating size */
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
107 if ((size = url_filesize(uc)) < 0) {
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
108 url_close(uc);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
109 err = AVERROR(ENOSYS);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
110 break;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
111 }
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
112
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
113 /* assembling */
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
114 nodes[i].uc = uc;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
115 nodes[i].size = size;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
116 }
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
117 av_free(node_uri);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
118 data->length = i;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
119
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
120 if (err < 0)
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
121 concat_close(h);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
122 else if (!(nodes = av_realloc(nodes, data->length * sizeof(*nodes)))) {
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
123 concat_close(h);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
124 err = AVERROR(ENOMEM);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
125 } else
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
126 data->nodes = nodes;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
127 return err;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
128 }
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
129
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
130 static int concat_read(URLContext *h, unsigned char *buf, int size)
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
131 {
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
132 int result, total = 0;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
133 struct concat_data *data = h->priv_data;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
134 struct concat_nodes *nodes = data->nodes;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
135 size_t i = data->current;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
136
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
137 while (size > 0) {
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
138 result = url_read(nodes[i].uc, buf, size);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
139 if (result < 0)
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
140 return total ? total : result;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
141 if (!result)
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
142 if (i + 1 == data->length ||
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
143 url_seek(nodes[++i].uc, 0, SEEK_SET) < 0)
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
144 break;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
145 total += result;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
146 buf += result;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
147 size -= result;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
148 }
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
149 data->current = i;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
150 return total;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
151 }
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
152
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
153 static int64_t concat_seek(URLContext *h, int64_t pos, int whence)
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
154 {
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
155 int64_t result;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
156 struct concat_data *data = h->priv_data;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
157 struct concat_nodes *nodes = data->nodes;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
158 size_t i;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
159
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
160 switch (whence) {
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
161 case SEEK_END:
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
162 for (i = data->length - 1;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
163 i && pos < -nodes[i-1].size;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
164 i--)
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
165 pos += nodes[i-1].size;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
166 break;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
167 case SEEK_CUR:
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
168 /* get the absolute position */
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
169 for (i = 0; i != data->current; i++)
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
170 pos += nodes[i].size;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
171 pos += url_seek(nodes[i].uc, 0, SEEK_CUR);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
172 whence = SEEK_SET;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
173 /* fall through with the absolute position */
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
174 case SEEK_SET:
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
175 for (i = 0; i != data->length - 1 && pos >= nodes[i].size; i++)
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
176 pos -= nodes[i].size;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
177 break;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
178 default:
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
179 return AVERROR(EINVAL);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
180 }
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
181
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
182 result = url_seek(nodes[i].uc, pos, whence);
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
183 if (result >= 0) {
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
184 data->current = i;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
185 while (i)
5771
e8c8f5a002ff Fix concat seek result.
stefano
parents: 5634
diff changeset
186 result += nodes[--i].size;
5634
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
187 }
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
188 return result;
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
189 }
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
190
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
191 URLProtocol concat_protocol = {
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
192 "concat",
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
193 concat_open,
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
194 concat_read,
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
195 NULL,
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
196 concat_seek,
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
197 concat_close,
b280788e1936 Implement a physical concatenation protocol.
stefano
parents:
diff changeset
198 };