Mercurial > libavformat.hg
view concat.c @ 6142:bd851edc58ac libavformat
RTMP: Return from rtmp_read as soon as some data is available
Earlier, the function only returned when the enough data to fill the
requested buffer was available. This lead to high latency when receiving
low-bandwidth streams.
author | mstorsjo |
---|---|
date | Fri, 18 Jun 2010 12:02:51 +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, };