• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavformat/concat.c

Go to the documentation of this file.
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 };

Generated on Fri Sep 16 2011 17:17:48 for FFmpeg by  doxygen 1.7.1