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