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