FFmpeg
concat.c
Go to the documentation of this file.
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 <string.h>
25 
26 #include "config_components.h"
27 
28 #include "libavutil/avstring.h"
29 #include "libavutil/bprint.h"
30 #include "libavutil/error.h"
31 #include "libavutil/mem.h"
32 
33 #include "avio_internal.h"
34 #include "url.h"
35 
36 #define AV_CAT_SEPARATOR "|"
37 
38 struct concat_nodes {
39  URLContext *uc; ///< node's URLContext
40  int64_t size; ///< url filesize
41 };
42 
43 struct concat_data {
44  struct concat_nodes *nodes; ///< list of nodes to concat
45  size_t length; ///< number of cat'ed nodes
46  size_t current; ///< index of currently read node
47  uint64_t total_size;
48 };
49 
51 {
52  int err = 0;
53  size_t i;
54  struct concat_data *data = h->priv_data;
55  struct concat_nodes *nodes = data->nodes;
56 
57  for (i = 0; i != data->length; i++)
58  err |= ffurl_closep(&nodes[i].uc);
59 
60  av_freep(&data->nodes);
61 
62  return err < 0 ? -1 : 0;
63 }
64 
65 #if CONFIG_CONCAT_PROTOCOL
66 static av_cold int concat_open(URLContext *h, const char *uri, int flags)
67 {
68  char *node_uri = NULL;
69  int err = 0;
70  int64_t size, total_size = 0;
71  size_t len, i;
72  URLContext *uc;
73  struct concat_data *data = h->priv_data;
74  struct concat_nodes *nodes;
75 
76  if (!av_strstart(uri, "concat:", &uri)) {
77  av_log(h, AV_LOG_ERROR, "URL %s lacks prefix\n", uri);
78  return AVERROR(EINVAL);
79  }
80 
81  for (i = 0, len = 1; uri[i]; i++) {
82  if (uri[i] == *AV_CAT_SEPARATOR) {
83  len++;
84  }
85  }
86 
87  if (!(nodes = av_realloc_array(NULL, len, sizeof(*nodes))))
88  return AVERROR(ENOMEM);
89  else
90  data->nodes = nodes;
91 
92  /* handle input */
93  if (!*uri)
94  err = AVERROR(ENOENT);
95  for (i = 0; *uri; i++) {
96  /* parsing uri */
97  len = strcspn(uri, AV_CAT_SEPARATOR);
98  if ((err = av_reallocp(&node_uri, len + 1)) < 0)
99  break;
100  av_strlcpy(node_uri, uri, len + 1);
101  uri += len + strspn(uri + len, AV_CAT_SEPARATOR);
102 
103  /* creating URLContext */
104  err = ffurl_open_whitelist(&uc, node_uri, flags,
105  &h->interrupt_callback, NULL, h->protocol_whitelist, h->protocol_blacklist, h);
106  if (err < 0)
107  break;
108 
109  /* creating size */
110  if ((size = ffurl_size(uc)) < 0) {
111  ffurl_close(uc);
112  err = AVERROR(ENOSYS);
113  break;
114  }
115 
116  if (total_size > INT64_MAX - size) {
117  ffurl_close(uc);
118  err = AVERROR_INVALIDDATA;
119  break;
120  }
121 
122  /* assembling */
123  nodes[i].uc = uc;
124  nodes[i].size = size;
125  total_size += size;
126  }
127  av_free(node_uri);
128  data->length = i;
129 
130  if (err < 0)
131  concat_close(h);
132  else if (!(nodes = av_realloc(nodes, data->length * sizeof(*nodes)))) {
133  concat_close(h);
134  err = AVERROR(ENOMEM);
135  } else
136  data->nodes = nodes;
137  data->total_size = total_size;
138  return err;
139 }
140 #endif
141 
142 static int concat_read(URLContext *h, unsigned char *buf, int size)
143 {
144  int result, total = 0;
145  struct concat_data *data = h->priv_data;
146  struct concat_nodes *nodes = data->nodes;
147  size_t i = data->current;
148 
149  while (size > 0) {
150  result = ffurl_read(nodes[i].uc, buf, size);
151  if (result == AVERROR_EOF) {
152  if (i + 1 == data->length ||
153  ffurl_seek(nodes[++i].uc, 0, SEEK_SET) < 0)
154  break;
155  result = 0;
156  }
157  if (result < 0)
158  return total ? total : result;
159  total += result;
160  buf += result;
161  size -= result;
162  }
163  data->current = i;
164  return total ? total : result;
165 }
166 
167 static int64_t concat_seek(URLContext *h, int64_t pos, int whence)
168 {
169  int64_t result;
170  struct concat_data *data = h->priv_data;
171  struct concat_nodes *nodes = data->nodes;
172  size_t i;
173 
174  if ((whence & AVSEEK_SIZE))
175  return data->total_size;
176  switch (whence) {
177  case SEEK_END:
178  for (i = data->length - 1; i && pos < -nodes[i].size; i--)
179  pos += nodes[i].size;
180  break;
181  case SEEK_CUR:
182  /* get the absolute position */
183  for (i = 0; i != data->current; i++)
184  pos += nodes[i].size;
185  pos += ffurl_seek(nodes[i].uc, 0, SEEK_CUR);
186  whence = SEEK_SET;
187  /* fall through with the absolute position */
188  case SEEK_SET:
189  for (i = 0; i != data->length - 1 && pos >= nodes[i].size; i++)
190  pos -= nodes[i].size;
191  break;
192  default:
193  return AVERROR(EINVAL);
194  }
195 
196  result = ffurl_seek(nodes[i].uc, pos, whence);
197  if (result >= 0) {
198  data->current = i;
199  while (i)
200  result += nodes[--i].size;
201  }
202  return result;
203 }
204 
205 #if CONFIG_CONCAT_PROTOCOL
207  .name = "concat",
208  .url_open = concat_open,
209  .url_read = concat_read,
210  .url_seek = concat_seek,
211  .url_close = concat_close,
212  .priv_data_size = sizeof(struct concat_data),
213  .default_whitelist = "concat,file,subfile",
214 };
215 #endif
216 
217 #if CONFIG_CONCATF_PROTOCOL
218 static av_cold int concatf_open(URLContext *h, const char *uri, int flags)
219 {
220  AVBPrint bp;
221  struct concat_data *data = h->priv_data;
222  AVIOContext *in = NULL;
223  const char *cursor;
224  int64_t total_size = 0;
225  unsigned int nodes_size = 0;
226  size_t i = 0;
227  int err;
228 
229  if (!av_strstart(uri, "concatf:", &uri)) {
230  av_log(h, AV_LOG_ERROR, "URL %s lacks prefix\n", uri);
231  return AVERROR(EINVAL);
232  }
233 
234  /* handle input */
235  if (!*uri)
236  return AVERROR(ENOENT);
237 
238  err = ffio_open_whitelist(&in, uri, AVIO_FLAG_READ, &h->interrupt_callback,
239  NULL, h->protocol_whitelist, h->protocol_blacklist);
240  if (err < 0)
241  return err;
242 
244  err = avio_read_to_bprint(in, &bp, SIZE_MAX);
245  avio_closep(&in);
246  if (err < 0) {
247  av_bprint_finalize(&bp, NULL);
248  return err;
249  }
250 
251  cursor = bp.str;
252  while (*cursor) {
253  struct concat_nodes *nodes;
254  URLContext *uc;
255  char *node_uri;
256  int64_t size;
257  size_t len = i;
258  int leading_spaces = strspn(cursor, " \n\t\r");
259 
260  if (!cursor[leading_spaces])
261  break;
262 
263  node_uri = av_get_token(&cursor, "\r\n");
264  if (!node_uri) {
265  err = AVERROR(ENOMEM);
266  break;
267  }
268  if (*cursor)
269  cursor++;
270 
271  if (++len == SIZE_MAX / sizeof(*nodes)) {
272  av_free(node_uri);
273  err = AVERROR(ENAMETOOLONG);
274  break;
275  }
276 
277  /* creating URLContext */
278  err = ffurl_open_whitelist(&uc, node_uri, flags,
279  &h->interrupt_callback, NULL, h->protocol_whitelist, h->protocol_blacklist, h);
280  av_free(node_uri);
281  if (err < 0)
282  break;
283 
284  /* creating size */
285  if ((size = ffurl_size(uc)) < 0) {
286  ffurl_close(uc);
287  err = AVERROR(ENOSYS);
288  break;
289  }
290 
291  if (total_size > INT64_MAX - size) {
292  ffurl_close(uc);
293  err = AVERROR_INVALIDDATA;
294  break;
295  }
296 
297  nodes = av_fast_realloc(data->nodes, &nodes_size, sizeof(*nodes) * len);
298  if (!nodes) {
299  ffurl_close(uc);
300  err = AVERROR(ENOMEM);
301  break;
302  }
303  data->nodes = nodes;
304 
305  /* assembling */
306  data->nodes[i].uc = uc;
307  data->nodes[i++].size = size;
308  total_size += size;
309  }
310  av_bprint_finalize(&bp, NULL);
311  data->length = i;
312 
313  if (!data->length)
314  err = AVERROR_INVALIDDATA;
315  if (err < 0)
316  concat_close(h);
317 
318  data->total_size = total_size;
319  return err;
320 }
321 
323  .name = "concatf",
324  .url_open = concatf_open,
325  .url_read = concat_read,
326  .url_seek = concat_seek,
327  .url_close = concat_close,
328  .priv_data_size = sizeof(struct concat_data),
329  .default_whitelist = "concatf,concat,file,subfile",
330 };
331 #endif
flags
const SwsFlags flags[]
Definition: swscale.c:61
ffurl_seek
static int64_t ffurl_seek(URLContext *h, int64_t pos, int whence)
Change the position that will be used by the next read/write operation on the resource accessed by h.
Definition: url.h:222
ffio_open_whitelist
int ffio_open_whitelist(AVIOContext **s, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options, const char *whitelist, const char *blacklist)
Definition: avio.c:472
AV_BPRINT_SIZE_UNLIMITED
#define AV_BPRINT_SIZE_UNLIMITED
concat_data::length
size_t length
number of cat'ed nodes
Definition: concat.c:45
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
int64_t
long long int64_t
Definition: coverity.c:34
concat_data::total_size
uint64_t total_size
Definition: concat.c:47
AVSEEK_SIZE
#define AVSEEK_SIZE
Passing this as the "whence" parameter to a seek function causes it to return the filesize without se...
Definition: avio.h:468
data
const char data[16]
Definition: mxf.c:149
ffurl_close
int ffurl_close(URLContext *h)
Definition: avio.c:612
URLProtocol
Definition: url.h:51
AV_CAT_SEPARATOR
#define AV_CAT_SEPARATOR
Definition: concat.c:36
concat_nodes::size
int64_t size
url filesize
Definition: concat.c:40
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
av_cold
#define av_cold
Definition: attributes.h:111
ffurl_open_whitelist
int ffurl_open_whitelist(URLContext **puc, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options, const char *whitelist, const char *blacklist, URLContext *parent)
Create an URLContext for accessing to the resource indicated by url, and open it.
Definition: avio.c:363
av_fast_realloc
void * av_fast_realloc(void *ptr, unsigned int *size, size_t min_size)
Reallocate the given buffer if it is not large enough, otherwise do nothing.
Definition: mem.c:497
avio_read_to_bprint
int avio_read_to_bprint(AVIOContext *h, struct AVBPrint *pb, size_t max_size)
Read contents of h into print buffer, up to max_size bytes, or up to EOF.
Definition: aviobuf.c:1254
av_realloc_array
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition: mem.c:217
ff_concat_protocol
const URLProtocol ff_concat_protocol
result
and forward the result(frame or status change) to the corresponding input. If nothing is possible
NULL
#define NULL
Definition: coverity.c:32
error.h
AVIOContext
Bytestream IO Context.
Definition: avio.h:160
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
size
int size
Definition: twinvq_data.h:10344
concat_data::nodes
struct concat_nodes * nodes
list of nodes to concat
Definition: concat.c:44
av_reallocp
int av_reallocp(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory through a pointer to a pointer.
Definition: mem.c:188
URLProtocol::name
const char * name
Definition: url.h:52
concat_read
static int concat_read(URLContext *h, unsigned char *buf, int size)
Definition: concat.c:142
av_strstart
int av_strstart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str.
Definition: avstring.c:36
ff_concatf_protocol
const URLProtocol ff_concatf_protocol
bprint.h
URLContext
Definition: url.h:35
avio_internal.h
url.h
len
int len
Definition: vorbis_enc_data.h:426
concat_data::current
size_t current
index of currently read node
Definition: concat.c:46
ffurl_closep
int ffurl_closep(URLContext **hh)
Close the resource accessed by the URLContext h, and free the memory used by it.
Definition: avio.c:589
concat_seek
static int64_t concat_seek(URLContext *h, int64_t pos, int whence)
Definition: concat.c:167
pos
unsigned int pos
Definition: spdifenc.c:414
concat_nodes::uc
URLContext * uc
node's URLContext
Definition: concat.c:39
av_get_token
char * av_get_token(const char **buf, const char *term)
Unescape the given string until a non escaped terminating char, and return the token corresponding to...
Definition: avstring.c:143
AVIO_FLAG_READ
#define AVIO_FLAG_READ
read-only
Definition: avio.h:617
mem.h
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
avio_closep
int avio_closep(AVIOContext **s)
Close the resource accessed by the AVIOContext *s, free it and set the pointer pointing to it to NULL...
Definition: avio.c:650
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
concat_data
Definition: concat.c:43
av_strlcpy
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:85
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
ffurl_size
int64_t ffurl_size(URLContext *h)
Return the filesize of the resource accessed by h, AVERROR(ENOSYS) if the operation is not supported ...
Definition: avio.c:800
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
h
h
Definition: vp9dsp_template.c:2070
concat_close
static av_cold int concat_close(URLContext *h)
Definition: concat.c:50
avstring.h
concat_nodes
Definition: concat.c:38
av_realloc
void * av_realloc(void *ptr, size_t size)
Allocate, reallocate, or free a block of memory.
Definition: mem.c:155
ffurl_read
static int ffurl_read(URLContext *h, uint8_t *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf.
Definition: url.h:181