view concat.c @ 6133:4040ce73a1ed libavformat

Add compatibility wrappers for functions moved from lavf to lavc When symbol versioning is enabled, moving symbols from one library to another breaks binary compatibility. This adds wrappers with the old version tag for the av_*packet functions recently moved to lavc.
author mru
date Tue, 15 Jun 2010 13:26:52 +0000
parents d3d45b140065
children
line wrap: on
line source

/*
 * Concat URL protocol
 * Copyright (c) 2006 Steve Lhomme
 * Copyright (c) 2007 Wolfram Gloger
 * Copyright (c) 2010 Michele OrrĂ¹
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "avformat.h"
#include "libavutil/avstring.h"
#include "libavutil/mem.h"

#define AV_CAT_SEPARATOR "|"

struct concat_nodes {
    URLContext *uc;                ///< node's URLContext
    int64_t     size;              ///< url filesize
};

struct concat_data {
    struct concat_nodes *nodes;    ///< list of nodes to concat
    size_t               length;   ///< number of cat'ed nodes
    size_t               current;  ///< index of currently read node
};

static av_cold int concat_close(URLContext *h)
{
    int err = 0;
    size_t i;
    struct concat_data  *data  = h->priv_data;
    struct concat_nodes *nodes = data->nodes;

    for (i = 0; i != data->length; i++)
        err |= url_close(nodes[i].uc);

    av_freep(&data->nodes);
    av_freep(&h->priv_data);

    return err < 0 ? -1 : 0;
}

static av_cold int concat_open(URLContext *h, const char *uri, int flags)
{
    char *node_uri = NULL, *tmp_uri;
    int err = 0;
    int64_t size;
    size_t  len, i;
    URLContext *uc;
    struct concat_data  *data;
    struct concat_nodes *nodes;

    av_strstart(uri, "concat:", &uri);

    /* creating data */
    if (!(data = av_mallocz(sizeof(*data))))
        return AVERROR(ENOMEM);
    h->priv_data = data;

    for (i = 0, len = 1; uri[i]; i++)
        if (uri[i] == *AV_CAT_SEPARATOR)
            /* integer overflow */
            if (++len == UINT_MAX / sizeof(*nodes)) {
                av_freep(&h->priv_data);
                return AVERROR(ENAMETOOLONG);
            }

    if (!(nodes = av_malloc(sizeof(*nodes) * len))) {
        av_freep(&h->priv_data);
        return AVERROR(ENOMEM);
    } else
        data->nodes = nodes;

    /* handle input */
    if (!*uri)
        err = AVERROR(ENOENT);
    for (i = 0; *uri; i++) {
        /* parsing uri */
        len = strcspn(uri, AV_CAT_SEPARATOR);
        if (!(tmp_uri = av_realloc(node_uri, len+1))) {
            err = AVERROR(ENOMEM);
            break;
        } else
            node_uri = tmp_uri;
        av_strlcpy(node_uri, uri, len+1);
        uri += len + strspn(uri+len, AV_CAT_SEPARATOR);

        /* creating URLContext */
        if ((err = url_open(&uc, node_uri, flags)) < 0)
            break;

        /* creating size */
        if ((size = url_filesize(uc)) < 0) {
            url_close(uc);
            err = AVERROR(ENOSYS);
            break;
        }

        /* assembling */
        nodes[i].uc   = uc;
        nodes[i].size = size;
    }
    av_free(node_uri);
    data->length = i;

    if (err < 0)
        concat_close(h);
    else if (!(nodes = av_realloc(nodes, data->length * sizeof(*nodes)))) {
        concat_close(h);
        err = AVERROR(ENOMEM);
    } else
        data->nodes = nodes;
    return err;
}

static int concat_read(URLContext *h, unsigned char *buf, int size)
{
    int result, total = 0;
    struct concat_data  *data  = h->priv_data;
    struct concat_nodes *nodes = data->nodes;
    size_t i = data->current;

    while (size > 0) {
        result = url_read(nodes[i].uc, buf, size);
        if (result < 0)
            return total ? total : result;
        if (!result)
            if (i + 1 == data->length ||
                url_seek(nodes[++i].uc, 0, SEEK_SET) < 0)
                break;
        total += result;
        buf   += result;
        size  -= result;
    }
    data->current = i;
    return total;
}

static int64_t concat_seek(URLContext *h, int64_t pos, int whence)
{
    int64_t result;
    struct concat_data  *data  = h->priv_data;
    struct concat_nodes *nodes = data->nodes;
    size_t i;

    switch (whence) {
    case SEEK_END:
        for (i = data->length - 1;
             i && pos < -nodes[i].size;
             i--)
            pos += nodes[i].size;
        break;
    case SEEK_CUR:
        /* get the absolute position */
        for (i = 0; i != data->current; i++)
            pos += nodes[i].size;
        pos += url_seek(nodes[i].uc, 0, SEEK_CUR);
        whence = SEEK_SET;
        /* fall through with the absolute position */
    case SEEK_SET:
        for (i = 0; i != data->length - 1 && pos >= nodes[i].size; i++)
            pos -= nodes[i].size;
        break;
    default:
        return AVERROR(EINVAL);
    }

    result = url_seek(nodes[i].uc, pos, whence);
    if (result >= 0) {
        data->current = i;
        while (i)
            result += nodes[--i].size;
    }
    return result;
}

URLProtocol concat_protocol = {
    "concat",
    concat_open,
    concat_read,
    NULL,
    concat_seek,
    concat_close,
};