Libav 0.7.1
|
00001 /* 00002 * Concat URL protocol 00003 * Copyright (c) 2006 Steve Lhomme 00004 * Copyright (c) 2007 Wolfram Gloger 00005 * Copyright (c) 2010 Michele OrrĂ¹ 00006 * 00007 * This file is part of Libav. 00008 * 00009 * Libav is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2.1 of the License, or (at your option) any later version. 00013 * 00014 * Libav is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with Libav; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 /* creating data */ 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 /* integer overflow */ 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 /* handle input */ 00090 if (!*uri) 00091 err = AVERROR(ENOENT); 00092 for (i = 0; *uri; i++) { 00093 /* parsing uri */ 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 /* creating URLContext */ 00104 if ((err = ffurl_open(&uc, node_uri, flags)) < 0) 00105 break; 00106 00107 /* creating size */ 00108 if ((size = ffurl_size(uc)) < 0) { 00109 ffurl_close(uc); 00110 err = AVERROR(ENOSYS); 00111 break; 00112 } 00113 00114 /* assembling */ 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 /* get the absolute position */ 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 /* fall through with the absolute position */ 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 };