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  /* assembling */
117  nodes[i].uc = uc;
118  nodes[i].size = size;
119  total_size += size;
120  }
121  av_free(node_uri);
122  data->length = i;
123 
124  if (err < 0)
125  concat_close(h);
126  else if (!(nodes = av_realloc(nodes, data->length * sizeof(*nodes)))) {
127  concat_close(h);
128  err = AVERROR(ENOMEM);
129  } else
130  data->nodes = nodes;
131  data->total_size = total_size;
132  return err;
133 }
134 #endif
135 
136 static int concat_read(URLContext *h, unsigned char *buf, int size)
137 {
138  int result, total = 0;
139  struct concat_data *data = h->priv_data;
140  struct concat_nodes *nodes = data->nodes;
141  size_t i = data->current;
142 
143  while (size > 0) {
144  result = ffurl_read(nodes[i].uc, buf, size);
145  if (result == AVERROR_EOF) {
146  if (i + 1 == data->length ||
147  ffurl_seek(nodes[++i].uc, 0, SEEK_SET) < 0)
148  break;
149  result = 0;
150  }
151  if (result < 0)
152  return total ? total : result;
153  total += result;
154  buf += result;
155  size -= result;
156  }
157  data->current = i;
158  return total ? total : result;
159 }
160 
161 static int64_t concat_seek(URLContext *h, int64_t pos, int whence)
162 {
163  int64_t result;
164  struct concat_data *data = h->priv_data;
165  struct concat_nodes *nodes = data->nodes;
166  size_t i;
167 
168  if ((whence & AVSEEK_SIZE))
169  return data->total_size;
170  switch (whence) {
171  case SEEK_END:
172  for (i = data->length - 1; i && pos < -nodes[i].size; i--)
173  pos += nodes[i].size;
174  break;
175  case SEEK_CUR:
176  /* get the absolute position */
177  for (i = 0; i != data->current; i++)
178  pos += nodes[i].size;
179  pos += ffurl_seek(nodes[i].uc, 0, SEEK_CUR);
180  whence = SEEK_SET;
181  /* fall through with the absolute position */
182  case SEEK_SET:
183  for (i = 0; i != data->length - 1 && pos >= nodes[i].size; i++)
184  pos -= nodes[i].size;
185  break;
186  default:
187  return AVERROR(EINVAL);
188  }
189 
190  result = ffurl_seek(nodes[i].uc, pos, whence);
191  if (result >= 0) {
192  data->current = i;
193  while (i)
194  result += nodes[--i].size;
195  }
196  return result;
197 }
198 
199 #if CONFIG_CONCAT_PROTOCOL
201  .name = "concat",
202  .url_open = concat_open,
203  .url_read = concat_read,
204  .url_seek = concat_seek,
205  .url_close = concat_close,
206  .priv_data_size = sizeof(struct concat_data),
207  .default_whitelist = "concat,file,subfile",
208 };
209 #endif
210 
211 #if CONFIG_CONCATF_PROTOCOL
212 static av_cold int concatf_open(URLContext *h, const char *uri, int flags)
213 {
214  AVBPrint bp;
215  struct concat_data *data = h->priv_data;
216  AVIOContext *in = NULL;
217  const char *cursor;
218  int64_t total_size = 0;
219  unsigned int nodes_size = 0;
220  size_t i = 0;
221  int err;
222 
223  if (!av_strstart(uri, "concatf:", &uri)) {
224  av_log(h, AV_LOG_ERROR, "URL %s lacks prefix\n", uri);
225  return AVERROR(EINVAL);
226  }
227 
228  /* handle input */
229  if (!*uri)
230  return AVERROR(ENOENT);
231 
232  err = ffio_open_whitelist(&in, uri, AVIO_FLAG_READ, &h->interrupt_callback,
233  NULL, h->protocol_whitelist, h->protocol_blacklist);
234  if (err < 0)
235  return err;
236 
238  err = avio_read_to_bprint(in, &bp, SIZE_MAX);
239  avio_closep(&in);
240  if (err < 0) {
241  av_bprint_finalize(&bp, NULL);
242  return err;
243  }
244 
245  cursor = bp.str;
246  while (*cursor) {
247  struct concat_nodes *nodes;
248  URLContext *uc;
249  char *node_uri;
250  int64_t size;
251  size_t len = i;
252  int leading_spaces = strspn(cursor, " \n\t\r");
253 
254  if (!cursor[leading_spaces])
255  break;
256 
257  node_uri = av_get_token(&cursor, "\r\n");
258  if (!node_uri) {
259  err = AVERROR(ENOMEM);
260  break;
261  }
262  if (*cursor)
263  cursor++;
264 
265  if (++len == SIZE_MAX / sizeof(*nodes)) {
266  av_free(node_uri);
267  err = AVERROR(ENAMETOOLONG);
268  break;
269  }
270 
271  /* creating URLContext */
272  err = ffurl_open_whitelist(&uc, node_uri, flags,
273  &h->interrupt_callback, NULL, h->protocol_whitelist, h->protocol_blacklist, h);
274  av_free(node_uri);
275  if (err < 0)
276  break;
277 
278  /* creating size */
279  if ((size = ffurl_size(uc)) < 0) {
280  ffurl_close(uc);
281  err = AVERROR(ENOSYS);
282  break;
283  }
284 
285  nodes = av_fast_realloc(data->nodes, &nodes_size, sizeof(*nodes) * len);
286  if (!nodes) {
287  ffurl_close(uc);
288  err = AVERROR(ENOMEM);
289  break;
290  }
291  data->nodes = nodes;
292 
293  /* assembling */
294  data->nodes[i].uc = uc;
295  data->nodes[i++].size = size;
296  total_size += size;
297  }
298  av_bprint_finalize(&bp, NULL);
299  data->length = i;
300 
301  if (!data->length)
302  err = AVERROR_INVALIDDATA;
303  if (err < 0)
304  concat_close(h);
305 
306  data->total_size = total_size;
307  return err;
308 }
309 
311  .name = "concatf",
312  .url_open = concatf_open,
313  .url_read = concat_read,
314  .url_seek = concat_seek,
315  .url_close = concat_close,
316  .priv_data_size = sizeof(struct concat_data),
317  .default_whitelist = "concatf,concat,file,subfile",
318 };
319 #endif
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:470
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
concat_data::total_size
uint64_t total_size
Definition: concat.c:47
AVSEEK_SIZE
#define AVSEEK_SIZE
ORing this as the "whence" parameter to a seek function causes it to return the filesize without seek...
Definition: avio.h:468
data
const char data[16]
Definition: mxf.c:148
ffurl_close
int ffurl_close(URLContext *h)
Definition: avio.c:610
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:180
av_cold
#define av_cold
Definition: attributes.h:90
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:361
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:495
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:1250
av_realloc_array
void * av_realloc_array(void *ptr, size_t nmemb, size_t size)
Definition: mem.c:215
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:240
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:186
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:136
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
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:255
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:587
concat_seek
static int64_t concat_seek(URLContext *h, int64_t pos, int whence)
Definition: concat.c:161
pos
unsigned int pos
Definition: spdifenc.c:413
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:33
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:648
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:34
concat_data
Definition: concat.c:43
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:474
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:798
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
h
h
Definition: vp9dsp_template.c:2038
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:153
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