00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "avformat.h"
00025 #include "libavutil/avstring.h"
00026 #include "libavutil/mem.h"
00027
00028 #define AV_CAT_SEPARATOR "|"
00029
00030 struct concat_nodes {
00031 URLContext *uc;
00032 int64_t size;
00033 };
00034
00035 struct concat_data {
00036 struct concat_nodes *nodes;
00037 size_t length;
00038 size_t current;
00039 };
00040
00041 static av_cold int concat_close(URLContext *h)
00042 {
00043 int err = 0;
00044 size_t i;
00045 struct concat_data *data = h->priv_data;
00046 struct concat_nodes *nodes = data->nodes;
00047
00048 for (i = 0; i != data->length; i++)
00049 err |= url_close(nodes[i].uc);
00050
00051 av_freep(&data->nodes);
00052 av_freep(&h->priv_data);
00053
00054 return err < 0 ? -1 : 0;
00055 }
00056
00057 static av_cold int concat_open(URLContext *h, const char *uri, int flags)
00058 {
00059 char *node_uri = NULL, *tmp_uri;
00060 int err = 0;
00061 int64_t size;
00062 size_t len, i;
00063 URLContext *uc;
00064 struct concat_data *data;
00065 struct concat_nodes *nodes;
00066
00067 av_strstart(uri, "concat:", &uri);
00068
00069
00070 if (!(data = av_mallocz(sizeof(*data))))
00071 return AVERROR(ENOMEM);
00072 h->priv_data = data;
00073
00074 for (i = 0, len = 1; uri[i]; i++)
00075 if (uri[i] == *AV_CAT_SEPARATOR)
00076
00077 if (++len == UINT_MAX / sizeof(*nodes)) {
00078 av_freep(&h->priv_data);
00079 return AVERROR(ENAMETOOLONG);
00080 }
00081
00082 if (!(nodes = av_malloc(sizeof(*nodes) * len))) {
00083 av_freep(&h->priv_data);
00084 return AVERROR(ENOMEM);
00085 } else
00086 data->nodes = nodes;
00087
00088
00089 if (!*uri)
00090 err = AVERROR(ENOENT);
00091 for (i = 0; *uri; i++) {
00092
00093 len = strcspn(uri, AV_CAT_SEPARATOR);
00094 if (!(tmp_uri = av_realloc(node_uri, len+1))) {
00095 err = AVERROR(ENOMEM);
00096 break;
00097 } else
00098 node_uri = tmp_uri;
00099 av_strlcpy(node_uri, uri, len+1);
00100 uri += len + strspn(uri+len, AV_CAT_SEPARATOR);
00101
00102
00103 if ((err = url_open(&uc, node_uri, flags)) < 0)
00104 break;
00105
00106
00107 if ((size = url_filesize(uc)) < 0) {
00108 url_close(uc);
00109 err = AVERROR(ENOSYS);
00110 break;
00111 }
00112
00113
00114 nodes[i].uc = uc;
00115 nodes[i].size = size;
00116 }
00117 av_free(node_uri);
00118 data->length = i;
00119
00120 if (err < 0)
00121 concat_close(h);
00122 else if (!(nodes = av_realloc(nodes, data->length * sizeof(*nodes)))) {
00123 concat_close(h);
00124 err = AVERROR(ENOMEM);
00125 } else
00126 data->nodes = nodes;
00127 return err;
00128 }
00129
00130 static int concat_read(URLContext *h, unsigned char *buf, int size)
00131 {
00132 int result, total = 0;
00133 struct concat_data *data = h->priv_data;
00134 struct concat_nodes *nodes = data->nodes;
00135 size_t i = data->current;
00136
00137 while (size > 0) {
00138 result = url_read(nodes[i].uc, buf, size);
00139 if (result < 0)
00140 return total ? total : result;
00141 if (!result)
00142 if (i + 1 == data->length ||
00143 url_seek(nodes[++i].uc, 0, SEEK_SET) < 0)
00144 break;
00145 total += result;
00146 buf += result;
00147 size -= result;
00148 }
00149 data->current = i;
00150 return total;
00151 }
00152
00153 static int64_t concat_seek(URLContext *h, int64_t pos, int whence)
00154 {
00155 int64_t result;
00156 struct concat_data *data = h->priv_data;
00157 struct concat_nodes *nodes = data->nodes;
00158 size_t i;
00159
00160 switch (whence) {
00161 case SEEK_END:
00162 for (i = data->length - 1;
00163 i && pos < -nodes[i].size;
00164 i--)
00165 pos += nodes[i].size;
00166 break;
00167 case SEEK_CUR:
00168
00169 for (i = 0; i != data->current; i++)
00170 pos += nodes[i].size;
00171 pos += url_seek(nodes[i].uc, 0, SEEK_CUR);
00172 whence = SEEK_SET;
00173
00174 case SEEK_SET:
00175 for (i = 0; i != data->length - 1 && pos >= nodes[i].size; i++)
00176 pos -= nodes[i].size;
00177 break;
00178 default:
00179 return AVERROR(EINVAL);
00180 }
00181
00182 result = url_seek(nodes[i].uc, pos, whence);
00183 if (result >= 0) {
00184 data->current = i;
00185 while (i)
00186 result += nodes[--i].size;
00187 }
00188 return result;
00189 }
00190
00191 URLProtocol concat_protocol = {
00192 "concat",
00193 concat_open,
00194 concat_read,
00195 NULL,
00196 concat_seek,
00197 concat_close,
00198 };