FFmpeg
async.c
Go to the documentation of this file.
1 /*
2  * Input async protocol.
3  * Copyright (c) 2015 Zhang Rui <bbcallen@gmail.com>
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  *
21  * Based on libavformat/cache.c by Michael Niedermayer
22  */
23 
24  /**
25  * @TODO
26  * support timeout
27  * support work with concatdec, hls
28  */
29 
30 #include "libavutil/avassert.h"
31 #include "libavutil/avstring.h"
32 #include "libavutil/error.h"
33 #include "libavutil/fifo.h"
34 #include "libavutil/log.h"
35 #include "libavutil/opt.h"
36 #include "libavutil/thread.h"
37 #include "url.h"
38 #include <stdint.h>
39 
40 #if HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 
44 #define BUFFER_CAPACITY (4 * 1024 * 1024)
45 #define READ_BACK_CAPACITY (4 * 1024 * 1024)
46 #define SHORT_SEEK_THRESHOLD (256 * 1024)
47 
48 typedef struct RingBuffer
49 {
52 
53  int read_pos;
54 } RingBuffer;
55 
56 typedef struct Context {
57  AVClass *class;
59 
61  int64_t seek_pos;
64  int64_t seek_ret;
65 
67  int io_error;
69 
70  int64_t logical_pos;
71  int64_t logical_size;
73 
78 
81 } Context;
82 
83 static int ring_init(RingBuffer *ring, unsigned int capacity, int read_back_capacity)
84 {
85  memset(ring, 0, sizeof(RingBuffer));
86  ring->fifo = av_fifo_alloc2(capacity + read_back_capacity, 1, 0);
87  if (!ring->fifo)
88  return AVERROR(ENOMEM);
89 
90  ring->read_back_capacity = read_back_capacity;
91  return 0;
92 }
93 
94 static void ring_destroy(RingBuffer *ring)
95 {
96  av_fifo_freep2(&ring->fifo);
97 }
98 
99 static void ring_reset(RingBuffer *ring)
100 {
101  av_fifo_reset2(ring->fifo);
102  ring->read_pos = 0;
103 }
104 
105 static int ring_size(RingBuffer *ring)
106 {
107  return av_fifo_can_read(ring->fifo) - ring->read_pos;
108 }
109 
110 static int ring_space(RingBuffer *ring)
111 {
112  return av_fifo_can_write(ring->fifo);
113 }
114 
115 static int ring_read(RingBuffer *ring, void *dest, int buf_size)
116 {
117  int ret = 0;
118 
119  av_assert2(buf_size <= ring_size(ring));
120  if (dest)
121  ret = av_fifo_peek(ring->fifo, dest, buf_size, ring->read_pos);
122  ring->read_pos += buf_size;
123 
124  if (ring->read_pos > ring->read_back_capacity) {
125  av_fifo_drain2(ring->fifo, ring->read_pos - ring->read_back_capacity);
126  ring->read_pos = ring->read_back_capacity;
127  }
128 
129  return ret;
130 }
131 
132 static int wrapped_url_read(void *src, void *dst, size_t *size)
133 {
134  URLContext *h = src;
135  Context *c = h->priv_data;
136  int ret;
137 
138  ret = ffurl_read(c->inner, dst, *size);
139  *size = ret > 0 ? ret : 0;
140  c->inner_io_error = ret < 0 ? ret : 0;
141 
142  return c->inner_io_error;
143 }
144 
145 static int ring_write(RingBuffer *ring, URLContext *h, size_t size)
146 {
147  int ret;
148 
149  av_assert2(size <= ring_space(ring));
151  if (ret < 0)
152  return ret;
153 
154  return size;
155 }
156 
158 {
159  return ring->read_pos;
160 }
161 
162 static int ring_drain(RingBuffer *ring, int offset)
163 {
165  av_assert2(offset <= ring_size(ring));
166  ring->read_pos += offset;
167  return 0;
168 }
169 
170 static int async_check_interrupt(void *arg)
171 {
172  URLContext *h = arg;
173  Context *c = h->priv_data;
174 
175  if (c->abort_request)
176  return 1;
177 
178  if (ff_check_interrupt(&c->interrupt_callback))
179  c->abort_request = 1;
180 
181  return c->abort_request;
182 }
183 
184 static void *async_buffer_task(void *arg)
185 {
186  URLContext *h = arg;
187  Context *c = h->priv_data;
188  RingBuffer *ring = &c->ring;
189  int ret = 0;
190  int64_t seek_ret;
191 
192  ff_thread_setname("async");
193 
194  while (1) {
195  int fifo_space, to_copy;
196 
197  pthread_mutex_lock(&c->mutex);
198  if (async_check_interrupt(h)) {
199  c->io_eof_reached = 1;
200  c->io_error = AVERROR_EXIT;
201  pthread_cond_signal(&c->cond_wakeup_main);
202  pthread_mutex_unlock(&c->mutex);
203  break;
204  }
205 
206  if (c->seek_request) {
207  seek_ret = ffurl_seek(c->inner, c->seek_pos, c->seek_whence);
208  if (seek_ret >= 0) {
209  c->io_eof_reached = 0;
210  c->io_error = 0;
211  ring_reset(ring);
212  }
213 
214  c->seek_completed = 1;
215  c->seek_ret = seek_ret;
216  c->seek_request = 0;
217 
218 
219  pthread_cond_signal(&c->cond_wakeup_main);
220  pthread_mutex_unlock(&c->mutex);
221  continue;
222  }
223 
224  fifo_space = ring_space(ring);
225  if (c->io_eof_reached || fifo_space <= 0) {
226  pthread_cond_signal(&c->cond_wakeup_main);
227  pthread_cond_wait(&c->cond_wakeup_background, &c->mutex);
228  pthread_mutex_unlock(&c->mutex);
229  continue;
230  }
231  pthread_mutex_unlock(&c->mutex);
232 
233  to_copy = FFMIN(4096, fifo_space);
234  ret = ring_write(ring, h, to_copy);
235 
236  pthread_mutex_lock(&c->mutex);
237  if (ret <= 0) {
238  c->io_eof_reached = 1;
239  if (c->inner_io_error < 0)
240  c->io_error = c->inner_io_error;
241  }
242 
243  pthread_cond_signal(&c->cond_wakeup_main);
244  pthread_mutex_unlock(&c->mutex);
245  }
246 
247  return NULL;
248 }
249 
250 static int async_open(URLContext *h, const char *arg, int flags, AVDictionary **options)
251 {
252  Context *c = h->priv_data;
253  int ret;
254  AVIOInterruptCB interrupt_callback = {.callback = async_check_interrupt, .opaque = h};
255 
256  av_strstart(arg, "async:", &arg);
257 
259  if (ret < 0)
260  goto fifo_fail;
261 
262  /* wrap interrupt callback */
263  c->interrupt_callback = h->interrupt_callback;
264  ret = ffurl_open_whitelist(&c->inner, arg, flags, &interrupt_callback, options, h->protocol_whitelist, h->protocol_blacklist, h);
265  if (ret != 0) {
266  av_log(h, AV_LOG_ERROR, "ffurl_open failed : %s, %s\n", av_err2str(ret), arg);
267  goto url_fail;
268  }
269 
270  c->logical_size = ffurl_size(c->inner);
271  h->is_streamed = c->inner->is_streamed;
272 
273  ret = pthread_mutex_init(&c->mutex, NULL);
274  if (ret != 0) {
275  ret = AVERROR(ret);
276  av_log(h, AV_LOG_ERROR, "pthread_mutex_init failed : %s\n", av_err2str(ret));
277  goto mutex_fail;
278  }
279 
280  ret = pthread_cond_init(&c->cond_wakeup_main, NULL);
281  if (ret != 0) {
282  ret = AVERROR(ret);
283  av_log(h, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", av_err2str(ret));
284  goto cond_wakeup_main_fail;
285  }
286 
287  ret = pthread_cond_init(&c->cond_wakeup_background, NULL);
288  if (ret != 0) {
289  ret = AVERROR(ret);
290  av_log(h, AV_LOG_ERROR, "pthread_cond_init failed : %s\n", av_err2str(ret));
291  goto cond_wakeup_background_fail;
292  }
293 
294  ret = pthread_create(&c->async_buffer_thread, NULL, async_buffer_task, h);
295  if (ret) {
296  ret = AVERROR(ret);
297  av_log(h, AV_LOG_ERROR, "pthread_create failed : %s\n", av_err2str(ret));
298  goto thread_fail;
299  }
300 
301  return 0;
302 
303 thread_fail:
304  pthread_cond_destroy(&c->cond_wakeup_background);
305 cond_wakeup_background_fail:
306  pthread_cond_destroy(&c->cond_wakeup_main);
307 cond_wakeup_main_fail:
308  pthread_mutex_destroy(&c->mutex);
309 mutex_fail:
310  ffurl_closep(&c->inner);
311 url_fail:
312  ring_destroy(&c->ring);
313 fifo_fail:
314  return ret;
315 }
316 
318 {
319  Context *c = h->priv_data;
320  int ret;
321 
322  pthread_mutex_lock(&c->mutex);
323  c->abort_request = 1;
324  pthread_cond_signal(&c->cond_wakeup_background);
325  pthread_mutex_unlock(&c->mutex);
326 
327  ret = pthread_join(c->async_buffer_thread, NULL);
328  if (ret != 0)
329  av_log(h, AV_LOG_ERROR, "pthread_join(): %s\n", av_err2str(ret));
330 
331  pthread_cond_destroy(&c->cond_wakeup_background);
332  pthread_cond_destroy(&c->cond_wakeup_main);
333  pthread_mutex_destroy(&c->mutex);
334  ffurl_closep(&c->inner);
335  ring_destroy(&c->ring);
336 
337  return 0;
338 }
339 
340 static int async_read_internal(URLContext *h, void *dest, int size)
341 {
342  Context *c = h->priv_data;
343  RingBuffer *ring = &c->ring;
344  int read_complete = !dest;
345  int to_read = size;
346  int ret = 0;
347 
348  pthread_mutex_lock(&c->mutex);
349 
350  while (to_read > 0) {
351  int fifo_size, to_copy;
352  if (async_check_interrupt(h)) {
353  ret = AVERROR_EXIT;
354  break;
355  }
356  fifo_size = ring_size(ring);
357  to_copy = FFMIN(to_read, fifo_size);
358  if (to_copy > 0) {
359  ring_read(ring, dest, to_copy);
360  if (dest)
361  dest = (uint8_t *)dest + to_copy;
362  c->logical_pos += to_copy;
363  to_read -= to_copy;
364  ret = size - to_read;
365 
366  if (to_read <= 0 || !read_complete)
367  break;
368  } else if (c->io_eof_reached) {
369  if (ret <= 0) {
370  if (c->io_error)
371  ret = c->io_error;
372  else
373  ret = AVERROR_EOF;
374  }
375  break;
376  }
377  pthread_cond_signal(&c->cond_wakeup_background);
378  pthread_cond_wait(&c->cond_wakeup_main, &c->mutex);
379  }
380 
381  pthread_cond_signal(&c->cond_wakeup_background);
382  pthread_mutex_unlock(&c->mutex);
383 
384  return ret;
385 }
386 
387 static int async_read(URLContext *h, unsigned char *buf, int size)
388 {
389  return async_read_internal(h, buf, size);
390 }
391 
392 static int64_t async_seek(URLContext *h, int64_t pos, int whence)
393 {
394  Context *c = h->priv_data;
395  RingBuffer *ring = &c->ring;
396  int64_t ret;
397  int64_t new_logical_pos;
398  int fifo_size;
399  int fifo_size_of_read_back;
400 
401  if (whence == AVSEEK_SIZE) {
402  av_log(h, AV_LOG_TRACE, "async_seek: AVSEEK_SIZE: %"PRId64"\n", (int64_t)c->logical_size);
403  return c->logical_size;
404  } else if (whence == SEEK_CUR) {
405  av_log(h, AV_LOG_TRACE, "async_seek: %"PRId64"\n", pos);
406  new_logical_pos = pos + c->logical_pos;
407  } else if (whence == SEEK_SET){
408  av_log(h, AV_LOG_TRACE, "async_seek: %"PRId64"\n", pos);
409  new_logical_pos = pos;
410  } else {
411  return AVERROR(EINVAL);
412  }
413  if (new_logical_pos < 0)
414  return AVERROR(EINVAL);
415 
416  fifo_size = ring_size(ring);
417  fifo_size_of_read_back = ring_size_of_read_back(ring);
418  if (new_logical_pos == c->logical_pos) {
419  /* current position */
420  return c->logical_pos;
421  } else if ((new_logical_pos >= (c->logical_pos - fifo_size_of_read_back)) &&
422  (new_logical_pos < (c->logical_pos + fifo_size + SHORT_SEEK_THRESHOLD))) {
423  int pos_delta = (int)(new_logical_pos - c->logical_pos);
424  /* fast seek */
425  av_log(h, AV_LOG_TRACE, "async_seek: fask_seek %"PRId64" from %d dist:%d/%d\n",
426  new_logical_pos, (int)c->logical_pos,
427  (int)(new_logical_pos - c->logical_pos), fifo_size);
428 
429  if (pos_delta > 0) {
430  // fast seek forwards
431  async_read_internal(h, NULL, pos_delta);
432  } else {
433  // fast seek backwards
434  ring_drain(ring, pos_delta);
435  c->logical_pos = new_logical_pos;
436  }
437 
438  return c->logical_pos;
439  } else if (c->logical_size <= 0) {
440  /* can not seek */
441  return AVERROR(EINVAL);
442  } else if (new_logical_pos > c->logical_size) {
443  /* beyond end */
444  return AVERROR(EINVAL);
445  }
446 
447  pthread_mutex_lock(&c->mutex);
448 
449  c->seek_request = 1;
450  c->seek_pos = new_logical_pos;
451  c->seek_whence = SEEK_SET;
452  c->seek_completed = 0;
453  c->seek_ret = 0;
454 
455  while (1) {
456  if (async_check_interrupt(h)) {
457  ret = AVERROR_EXIT;
458  break;
459  }
460  if (c->seek_completed) {
461  if (c->seek_ret >= 0)
462  c->logical_pos = c->seek_ret;
463  ret = c->seek_ret;
464  break;
465  }
466  pthread_cond_signal(&c->cond_wakeup_background);
467  pthread_cond_wait(&c->cond_wakeup_main, &c->mutex);
468  }
469 
470  pthread_mutex_unlock(&c->mutex);
471 
472  return ret;
473 }
474 
475 #define OFFSET(x) offsetof(Context, x)
476 #define D AV_OPT_FLAG_DECODING_PARAM
477 
478 static const AVOption options[] = {
479  {NULL},
480 };
481 
482 #undef D
483 #undef OFFSET
484 
485 static const AVClass async_context_class = {
486  .class_name = "Async",
487  .item_name = av_default_item_name,
488  .option = options,
489  .version = LIBAVUTIL_VERSION_INT,
490 };
491 
493  .name = "async",
494  .url_open2 = async_open,
495  .url_read = async_read,
496  .url_seek = async_seek,
497  .url_close = async_close,
498  .priv_data_size = sizeof(Context),
499  .priv_data_class = &async_context_class,
500 };
501 
502 #if 0
503 
504 #define TEST_SEEK_POS (1536)
505 #define TEST_STREAM_SIZE (2048)
506 
507 typedef struct TestContext {
508  AVClass *class;
509  int64_t logical_pos;
510  int64_t logical_size;
511 
512  /* options */
513  int opt_read_error;
514 } TestContext;
515 
516 static int async_test_open(URLContext *h, const char *arg, int flags, AVDictionary **options)
517 {
518  TestContext *c = h->priv_data;
519  c->logical_pos = 0;
520  c->logical_size = TEST_STREAM_SIZE;
521  return 0;
522 }
523 
524 static int async_test_close(URLContext *h)
525 {
526  return 0;
527 }
528 
529 static int async_test_read(URLContext *h, unsigned char *buf, int size)
530 {
531  TestContext *c = h->priv_data;
532  int i;
533  int read_len = 0;
534 
535  if (c->opt_read_error)
536  return c->opt_read_error;
537 
538  if (c->logical_pos >= c->logical_size)
539  return AVERROR_EOF;
540 
541  for (i = 0; i < size; ++i) {
542  buf[i] = c->logical_pos & 0xFF;
543 
544  c->logical_pos++;
545  read_len++;
546 
547  if (c->logical_pos >= c->logical_size)
548  break;
549  }
550 
551  return read_len;
552 }
553 
554 static int64_t async_test_seek(URLContext *h, int64_t pos, int whence)
555 {
556  TestContext *c = h->priv_data;
557  int64_t new_logical_pos;
558 
559  if (whence == AVSEEK_SIZE) {
560  return c->logical_size;
561  } else if (whence == SEEK_CUR) {
562  new_logical_pos = pos + c->logical_pos;
563  } else if (whence == SEEK_SET){
564  new_logical_pos = pos;
565  } else {
566  return AVERROR(EINVAL);
567  }
568  if (new_logical_pos < 0)
569  return AVERROR(EINVAL);
570 
571  c->logical_pos = new_logical_pos;
572  return new_logical_pos;
573 }
574 
575 #define OFFSET(x) offsetof(TestContext, x)
576 #define D AV_OPT_FLAG_DECODING_PARAM
577 
578 static const AVOption async_test_options[] = {
579  { "async-test-read-error", "cause read fail",
580  OFFSET(opt_read_error), AV_OPT_TYPE_INT, { .i64 = 0 }, INT_MIN, INT_MAX, .flags = D },
581  {NULL},
582 };
583 
584 #undef D
585 #undef OFFSET
586 
587 static const AVClass async_test_context_class = {
588  .class_name = "Async-Test",
589  .item_name = av_default_item_name,
590  .option = async_test_options,
591  .version = LIBAVUTIL_VERSION_INT,
592 };
593 
594 const URLProtocol ff_async_test_protocol = {
595  .name = "async-test",
596  .url_open2 = async_test_open,
597  .url_read = async_test_read,
598  .url_seek = async_test_seek,
599  .url_close = async_test_close,
600  .priv_data_size = sizeof(TestContext),
601  .priv_data_class = &async_test_context_class,
602 };
603 
604 int main(void)
605 {
606  URLContext *h = NULL;
607  int i;
608  int ret;
609  int64_t size;
610  int64_t pos;
611  int64_t read_len;
612  unsigned char buf[4096];
614 
615  ffurl_register_protocol(&ff_async_protocol);
616  ffurl_register_protocol(&ff_async_test_protocol);
617 
618  /*
619  * test normal read
620  */
621  ret = ffurl_open_whitelist(&h, "async:async-test:", AVIO_FLAG_READ,
622  NULL, NULL, NULL, NULL, NULL);
623  printf("open: %d\n", ret);
624 
625  size = ffurl_size(h);
626  printf("size: %"PRId64"\n", size);
627 
628  pos = ffurl_seek(h, 0, SEEK_CUR);
629  read_len = 0;
630  while (1) {
631  ret = ffurl_read(h, buf, sizeof(buf));
632  if (ret == AVERROR_EOF) {
633  printf("read-error: AVERROR_EOF at %"PRId64"\n", ffurl_seek(h, 0, SEEK_CUR));
634  break;
635  }
636  else if (ret == 0)
637  break;
638  else if (ret < 0) {
639  printf("read-error: %d at %"PRId64"\n", ret, ffurl_seek(h, 0, SEEK_CUR));
640  goto fail;
641  } else {
642  for (i = 0; i < ret; ++i) {
643  if (buf[i] != (pos & 0xFF)) {
644  printf("read-mismatch: actual %d, expecting %d, at %"PRId64"\n",
645  (int)buf[i], (int)(pos & 0xFF), pos);
646  break;
647  }
648  pos++;
649  }
650  }
651 
652  read_len += ret;
653  }
654  printf("read: %"PRId64"\n", read_len);
655 
656  /*
657  * test normal seek
658  */
659  ret = ffurl_read(h, buf, 1);
660  printf("read: %d\n", ret);
661 
662  pos = ffurl_seek(h, TEST_SEEK_POS, SEEK_SET);
663  printf("seek: %"PRId64"\n", pos);
664 
665  read_len = 0;
666  while (1) {
667  ret = ffurl_read(h, buf, sizeof(buf));
668  if (ret == AVERROR_EOF)
669  break;
670  else if (ret == 0)
671  break;
672  else if (ret < 0) {
673  printf("read-error: %d at %"PRId64"\n", ret, ffurl_seek(h, 0, SEEK_CUR));
674  goto fail;
675  } else {
676  for (i = 0; i < ret; ++i) {
677  if (buf[i] != (pos & 0xFF)) {
678  printf("read-mismatch: actual %d, expecting %d, at %"PRId64"\n",
679  (int)buf[i], (int)(pos & 0xFF), pos);
680  break;
681  }
682  pos++;
683  }
684  }
685 
686  read_len += ret;
687  }
688  printf("read: %"PRId64"\n", read_len);
689 
690  ret = ffurl_read(h, buf, 1);
691  printf("read: %d\n", ret);
692 
693  /*
694  * test read error
695  */
696  ffurl_close(h);
697  av_dict_set_int(&opts, "async-test-read-error", -10000, 0);
698  ret = ffurl_open_whitelist(&h, "async:async-test:", AVIO_FLAG_READ,
699  NULL, &opts, NULL, NULL, NULL);
700  printf("open: %d\n", ret);
701 
702  ret = ffurl_read(h, buf, 1);
703  printf("read: %d\n", ret);
704 
705 fail:
706  av_dict_free(&opts);
707  ffurl_close(h);
708  return 0;
709 }
710 
711 #endif
pthread_mutex_t
_fmutex pthread_mutex_t
Definition: os2threads.h:53
av_fifo_drain2
void av_fifo_drain2(AVFifo *f, size_t size)
Discard the specified amount of data from an AVFifo.
Definition: fifo.c:266
RingBuffer
Definition: async.c:48
pthread_join
static av_always_inline int pthread_join(pthread_t thread, void **value_ptr)
Definition: os2threads.h:94
av_fifo_can_write
size_t av_fifo_can_write(const AVFifo *f)
Definition: fifo.c:94
async_close
static int async_close(URLContext *h)
Definition: async.c:317
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
opt.h
ring_space
static int ring_space(RingBuffer *ring)
Definition: async.c:110
Context::mutex
pthread_mutex_t mutex
Definition: async.c:76
ffurl_seek
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: avio.c:428
thread.h
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
pthread_mutex_init
static av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
Definition: os2threads.h:104
async_buffer_task
static void * async_buffer_task(void *arg)
Definition: async.c:184
options
static const AVOption options[]
Definition: async.c:478
ring_write
static int ring_write(RingBuffer *ring, URLContext *h, size_t size)
Definition: async.c:145
Context::abort_request
int abort_request
Definition: async.c:79
Context::io_error
int io_error
Definition: async.c:67
AVOption
AVOption.
Definition: opt.h:251
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:474
Context::seek_pos
int64_t seek_pos
Definition: async.c:61
ffurl_close
int ffurl_close(URLContext *h)
Definition: avio.c:461
AVDictionary
Definition: dict.c:32
ring_size
static int ring_size(RingBuffer *ring)
Definition: async.c:105
URLProtocol
Definition: url.h:53
Context::async_buffer_thread
pthread_t async_buffer_thread
Definition: async.c:77
AVIOInterruptCB
Callback for checking whether to abort blocking functions.
Definition: avio.h:59
Context::cond_wakeup_background
pthread_cond_t cond_wakeup_background
Definition: async.c:75
Context::logical_size
int64_t logical_size
Definition: async.c:71
Context
Definition: async.c:56
fifo.h
Context::cond_wakeup_main
pthread_cond_t cond_wakeup_main
Definition: async.c:74
fail
#define fail()
Definition: checkasm.h:134
RingBuffer::read_pos
int read_pos
Definition: async.c:53
RingBuffer::fifo
AVFifo * fifo
Definition: async.c:50
Context::seek_whence
int seek_whence
Definition: async.c:62
ff_check_interrupt
int ff_check_interrupt(AVIOInterruptCB *cb)
Check if the user has requested to interrupt a blocking function associated with cb.
Definition: avio.c:664
Context::seek_request
int seek_request
Definition: async.c:60
BUFFER_CAPACITY
#define BUFFER_CAPACITY
@TODO support timeout support work with concatdec, hls
Definition: async.c:44
async_context_class
static const AVClass async_context_class
Definition: async.c:485
Context::seek_completed
int seek_completed
Definition: async.c:63
READ_BACK_CAPACITY
#define READ_BACK_CAPACITY
Definition: async.c:45
async_check_interrupt
static int async_check_interrupt(void *arg)
Definition: async.c:170
avassert.h
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:206
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
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:306
ring_destroy
static void ring_destroy(RingBuffer *ring)
Definition: async.c:94
Context::io_eof_reached
int io_eof_reached
Definition: async.c:68
wrapped_url_read
static int wrapped_url_read(void *src, void *dst, size_t *size)
Definition: async.c:132
ring_init
static int ring_init(RingBuffer *ring, unsigned int capacity, int read_back_capacity)
Definition: async.c:83
SHORT_SEEK_THRESHOLD
#define SHORT_SEEK_THRESHOLD
Definition: async.c:46
ring_read
static int ring_read(RingBuffer *ring, void *dest, int buf_size)
Definition: async.c:115
arg
const char * arg
Definition: jacosubdec.c:67
pthread_create
static av_always_inline int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
Definition: os2threads.h:80
opts
AVDictionary * opts
Definition: movenc.c:50
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
TestContext
Definition: opt.c:31
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:66
NULL
#define NULL
Definition: coverity.c:32
av_fifo_write_from_cb
int av_fifo_write_from_cb(AVFifo *f, AVFifoCB read_cb, void *opaque, size_t *nb_elems)
Write data from a user-provided callback into a FIFO.
Definition: fifo.c:193
Context::interrupt_callback
AVIOInterruptCB interrupt_callback
Definition: async.c:80
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:237
av_fifo_can_read
size_t av_fifo_can_read(const AVFifo *f)
Definition: fifo.c:87
c
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
pthread_mutex_unlock
#define pthread_mutex_unlock(a)
Definition: ffprobe.c:79
error.h
Context::ring
RingBuffer ring
Definition: async.c:72
main
int main(int argc, char **argv)
Definition: avio_http_serve_files.c:99
av_fifo_reset2
void av_fifo_reset2(AVFifo *f)
Definition: fifo.c:280
AVFifo
Definition: fifo.c:35
D
#define D
Definition: async.c:476
av_err2str
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:121
size
int size
Definition: twinvq_data.h:10344
URLProtocol::name
const char * name
Definition: url.h:54
async_open
static int async_open(URLContext *h, const char *arg, int flags, AVDictionary **options)
Definition: async.c:250
OFFSET
#define OFFSET(x)
Definition: async.c:475
printf
printf("static const uint8_t my_array[100] = {\n")
Context::inner_io_error
int inner_io_error
Definition: async.c:66
fifo_size
size_t fifo_size
Definition: dts2pts_bsf.c:368
offset
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
Definition: writing_filters.txt:86
av_dict_free
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition: dict.c:223
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:37
pthread_t
Definition: os2threads.h:44
pthread_cond_destroy
static av_always_inline int pthread_cond_destroy(pthread_cond_t *cond)
Definition: os2threads.h:144
pthread_mutex_destroy
static av_always_inline int pthread_mutex_destroy(pthread_mutex_t *mutex)
Definition: os2threads.h:112
av_fifo_peek
int av_fifo_peek(AVFifo *f, void *buf, size_t nb_elems, size_t offset)
Read data from a FIFO without modifying FIFO state.
Definition: fifo.c:255
async_read
static int async_read(URLContext *h, unsigned char *buf, int size)
Definition: async.c:387
av_assert2
#define av_assert2(cond)
assert() equivalent, that does lie in speed critical code.
Definition: avassert.h:64
URLContext
Definition: url.h:37
log.h
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
Context::seek_ret
int64_t seek_ret
Definition: async.c:64
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
url.h
pthread_cond_t
Definition: os2threads.h:58
RingBuffer::read_back_capacity
int read_back_capacity
Definition: async.c:51
Context::inner
URLContext * inner
Definition: async.c:58
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:438
ret
ret
Definition: filter_design.txt:187
async_seek
static int64_t async_seek(URLContext *h, int64_t pos, int whence)
Definition: async.c:392
AVClass::class_name
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:71
async_read_internal
static int async_read_internal(URLContext *h, void *dest, int size)
Definition: async.c:340
pos
unsigned int pos
Definition: spdifenc.c:413
av_fifo_alloc2
AVFifo * av_fifo_alloc2(size_t nb_elems, size_t elem_size, unsigned int flags)
Allocate and initialize an AVFifo with a given element size.
Definition: fifo.c:47
ff_async_protocol
const URLProtocol ff_async_protocol
Definition: async.c:492
pthread_cond_signal
static av_always_inline int pthread_cond_signal(pthread_cond_t *cond)
Definition: os2threads.h:152
Context::logical_pos
int64_t logical_pos
Definition: async.c:70
ffurl_read
int ffurl_read(URLContext *h, unsigned char *buf, int size)
Read up to size bytes from the resource accessed by h, and store the read bytes in buf.
Definition: avio.c:401
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Definition: opt.h:225
pthread_cond_wait
static av_always_inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
Definition: os2threads.h:192
av_dict_set_int
int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags)
Convenience wrapper for av_dict_set() that converts the value to a string and stores it.
Definition: dict.c:167
AVIO_FLAG_READ
#define AVIO_FLAG_READ
read-only
Definition: avio.h:623
ring_reset
static void ring_reset(RingBuffer *ring)
Definition: async.c:99
AVIOInterruptCB::callback
int(* callback)(void *)
Definition: avio.h:60
ring_size_of_read_back
static int ring_size_of_read_back(RingBuffer *ring)
Definition: async.c:157
src
INIT_CLIP pixel * src
Definition: h264pred_template.c:418
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:561
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:611
av_fifo_freep2
void av_fifo_freep2(AVFifo **f)
Free an AVFifo and reset pointer to NULL.
Definition: fifo.c:286
pthread_cond_init
static av_always_inline int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
Definition: os2threads.h:133
h
h
Definition: vp9dsp_template.c:2038
AVERROR_EXIT
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition: error.h:58
ring_drain
static int ring_drain(RingBuffer *ring, int offset)
Definition: async.c:162
avstring.h
int
int
Definition: ffmpeg_filter.c:156
pthread_mutex_lock
#define pthread_mutex_lock(a)
Definition: ffprobe.c:75
ff_thread_setname
static int ff_thread_setname(const char *name)
Definition: thread.h:195