Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Concat URL protocol
  3.  * Copyright (c) 2006 Steve Lhomme
  4.  * Copyright (c) 2007 Wolfram Gloger
  5.  * Copyright (c) 2010 Michele OrrĂ¹
  6.  *
  7.  * This file is part of FFmpeg.
  8.  *
  9.  * FFmpeg is free software; you can redistribute it and/or
  10.  * modify it under the terms of the GNU Lesser General Public
  11.  * License as published by the Free Software Foundation; either
  12.  * version 2.1 of the License, or (at your option) any later version.
  13.  *
  14.  * FFmpeg is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17.  * Lesser General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU Lesser General Public
  20.  * License along with FFmpeg; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22.  */
  23.  
  24. #include "libavutil/avstring.h"
  25. #include "libavutil/mem.h"
  26.  
  27. #include "avformat.h"
  28. #include "url.h"
  29.  
  30. #define AV_CAT_SEPARATOR "|"
  31.  
  32. struct concat_nodes {
  33.     URLContext *uc;                ///< node's URLContext
  34.     int64_t     size;              ///< url filesize
  35. };
  36.  
  37. struct concat_data {
  38.     struct concat_nodes *nodes;    ///< list of nodes to concat
  39.     size_t               length;   ///< number of cat'ed nodes
  40.     size_t               current;  ///< index of currently read node
  41. };
  42.  
  43. static av_cold int concat_close(URLContext *h)
  44. {
  45.     int err = 0;
  46.     size_t i;
  47.     struct concat_data  *data  = h->priv_data;
  48.     struct concat_nodes *nodes = data->nodes;
  49.  
  50.     for (i = 0; i != data->length; i++)
  51.         err |= ffurl_close(nodes[i].uc);
  52.  
  53.     av_freep(&data->nodes);
  54.  
  55.     return err < 0 ? -1 : 0;
  56. }
  57.  
  58. static av_cold int concat_open(URLContext *h, const char *uri, int flags)
  59. {
  60.     char *node_uri = NULL;
  61.     int err = 0;
  62.     int64_t size;
  63.     size_t len, i;
  64.     URLContext *uc;
  65.     struct concat_data  *data = h->priv_data;
  66.     struct concat_nodes *nodes;
  67.  
  68.     av_strstart(uri, "concat:", &uri);
  69.  
  70.     for (i = 0, len = 1; uri[i]; i++) {
  71.         if (uri[i] == *AV_CAT_SEPARATOR) {
  72.             /* integer overflow */
  73.             if (++len == UINT_MAX / sizeof(*nodes)) {
  74.                 av_freep(&h->priv_data);
  75.                 return AVERROR(ENAMETOOLONG);
  76.             }
  77.         }
  78.     }
  79.  
  80.     if (!(nodes = av_realloc(NULL, sizeof(*nodes) * len)))
  81.         return AVERROR(ENOMEM);
  82.     else
  83.         data->nodes = nodes;
  84.  
  85.     /* handle input */
  86.     if (!*uri)
  87.         err = AVERROR(ENOENT);
  88.     for (i = 0; *uri; i++) {
  89.         /* parsing uri */
  90.         len = strcspn(uri, AV_CAT_SEPARATOR);
  91.         if ((err = av_reallocp(&node_uri, len + 1)) < 0)
  92.             break;
  93.         av_strlcpy(node_uri, uri, len + 1);
  94.         uri += len + strspn(uri + len, AV_CAT_SEPARATOR);
  95.  
  96.         /* creating URLContext */
  97.         if ((err = ffurl_open(&uc, node_uri, flags,
  98.                               &h->interrupt_callback, NULL)) < 0)
  99.             break;
  100.  
  101.         /* creating size */
  102.         if ((size = ffurl_size(uc)) < 0) {
  103.             ffurl_close(uc);
  104.             err = AVERROR(ENOSYS);
  105.             break;
  106.         }
  107.  
  108.         /* assembling */
  109.         nodes[i].uc   = uc;
  110.         nodes[i].size = size;
  111.     }
  112.     av_free(node_uri);
  113.     data->length = i;
  114.  
  115.     if (err < 0)
  116.         concat_close(h);
  117.     else if (!(nodes = av_realloc(nodes, data->length * sizeof(*nodes)))) {
  118.         concat_close(h);
  119.         err = AVERROR(ENOMEM);
  120.     } else
  121.         data->nodes = nodes;
  122.     return err;
  123. }
  124.  
  125. static int concat_read(URLContext *h, unsigned char *buf, int size)
  126. {
  127.     int result, total = 0;
  128.     struct concat_data  *data  = h->priv_data;
  129.     struct concat_nodes *nodes = data->nodes;
  130.     size_t i                   = data->current;
  131.  
  132.     while (size > 0) {
  133.         result = ffurl_read(nodes[i].uc, buf, size);
  134.         if (result < 0)
  135.             return total ? total : result;
  136.         if (!result) {
  137.             if (i + 1 == data->length ||
  138.                 ffurl_seek(nodes[++i].uc, 0, SEEK_SET) < 0)
  139.                 break;
  140.         }
  141.         total += result;
  142.         buf   += result;
  143.         size  -= result;
  144.     }
  145.     data->current = i;
  146.     return total;
  147. }
  148.  
  149. static int64_t concat_seek(URLContext *h, int64_t pos, int whence)
  150. {
  151.     int64_t result;
  152.     struct concat_data  *data  = h->priv_data;
  153.     struct concat_nodes *nodes = data->nodes;
  154.     size_t i;
  155.  
  156.     switch (whence) {
  157.     case SEEK_END:
  158.         for (i = data->length - 1; i && pos < -nodes[i].size; i--)
  159.             pos += nodes[i].size;
  160.         break;
  161.     case SEEK_CUR:
  162.         /* get the absolute position */
  163.         for (i = 0; i != data->current; i++)
  164.             pos += nodes[i].size;
  165.         pos += ffurl_seek(nodes[i].uc, 0, SEEK_CUR);
  166.         whence = SEEK_SET;
  167.         /* fall through with the absolute position */
  168.     case SEEK_SET:
  169.         for (i = 0; i != data->length - 1 && pos >= nodes[i].size; i++)
  170.             pos -= nodes[i].size;
  171.         break;
  172.     default:
  173.         return AVERROR(EINVAL);
  174.     }
  175.  
  176.     result = ffurl_seek(nodes[i].uc, pos, whence);
  177.     if (result >= 0) {
  178.         data->current = i;
  179.         while (i)
  180.             result += nodes[--i].size;
  181.     }
  182.     return result;
  183. }
  184.  
  185. URLProtocol ff_concat_protocol = {
  186.     .name           = "concat",
  187.     .url_open       = concat_open,
  188.     .url_read       = concat_read,
  189.     .url_seek       = concat_seek,
  190.     .url_close      = concat_close,
  191.     .priv_data_size = sizeof(struct concat_data),
  192. };
  193.