Libav
|
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 FFmpeg. 00008 * 00009 * FFmpeg 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 * FFmpeg 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 FFmpeg; 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 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 /* creating data */ 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 /* integer overflow */ 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 /* handle input */ 00089 if (!*uri) 00090 err = AVERROR(ENOENT); 00091 for (i = 0; *uri; i++) { 00092 /* parsing uri */ 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 /* creating URLContext */ 00103 if ((err = url_open(&uc, node_uri, flags)) < 0) 00104 break; 00105 00106 /* creating size */ 00107 if ((size = url_filesize(uc)) < 0) { 00108 url_close(uc); 00109 err = AVERROR(ENOSYS); 00110 break; 00111 } 00112 00113 /* assembling */ 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 /* get the absolute position */ 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 /* fall through with the absolute position */ 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 };