FFmpeg
libcurl.c
Go to the documentation of this file.
1 /*
2  * libcurl based HTTP(S) protocol
3  * Copyright (C) 2026 Kacper Michajłow
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 
22 #include "config_components.h"
23 
24 #include <curl/curl.h>
25 #include <inttypes.h>
26 #include <limits.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "libavutil/avstring.h"
31 #include "libavutil/bprint.h"
32 #include "libavutil/error.h"
33 #include "libavutil/fifo.h"
34 #include "libavutil/log.h"
35 #include "libavutil/macros.h"
36 #include "libavutil/mem.h"
37 #include "libavutil/opt.h"
38 #include "libavutil/thread.h"
39 #include "libavutil/time.h"
40 
41 #include "avformat.h"
42 #include "http.h"
43 #include "internal.h"
44 #include "url.h"
45 #include "version.h"
46 
47 #define DEFAULT_USER_AGENT "Lavf/" AV_STRINGIFY(LIBAVFORMAT_VERSION)
48 #define CURL_DEFAULT_BUFFER_SIZE (4 << 20)
49 
50 /* Blocking waits wake up this often so url_read()/open can poll the interrupt
51  * callback. */
52 #define CURL_WAIT_US 100000
53 
54 typedef struct CurlContext CurlContext;
55 
56 enum cmd_kind {
57  CMD_ADD, /* add the easy handle to the multi and start the transfer */
58  CMD_REMOVE, /* remove the easy handle from the multi */
59  CMD_UNPAUSE, /* resume a transfer paused because the FIFO was full */
60  CMD_SEEK, /* restart the transfer at a new byte offset */
61 };
62 
63 typedef struct CurlCmd {
64  enum cmd_kind kind;
66  int64_t pos; /* CMD_SEEK target offset */
67  int sync; /* caller waits for completion */
68  int done;
69  struct CurlCmd *next;
70 } CurlCmd;
71 
72 typedef struct CurlLoop {
73  AVFormatContext *avfc; /* owning context (if any) */
74 
76  CURLM *multi;
77  CURLSH *share; /* shared cookies/HSTS */
78 
79  pthread_mutex_t mutex; /* guards the command queue, exit and cmd->done */
80  pthread_cond_t cond; /* signaled when a sync command completes */
82  int exit;
83 
84  /* Connection statistics (updated by loop thread) */
91 } CurlLoop;
92 
93 struct CurlContext {
94  const AVClass *class;
96 
98  int private_loop; /* loop is owned by this context (not shared) */
99  CURL *easy;
100  struct curl_slist *header_list;
101 
102  /* AVOptions. */
103  char *user_agent;
104  char *referer;
105  char *headers;
106  char *http_proxy;
107  char *cookies;
108  char *ca_file;
109  char *cert_file;
110  char *key_file;
111  char *location; /* effective URL after redirects (output) */
112  int64_t off; /* initial byte offset */
113  int64_t end_off; /* exclusive upper byte bound (0 = none) */
124 
125  int64_t logical_pos; /* next byte url_read() will return, caller side */
126 
127  /* Producer bookkeeping, touched only by the loop thread. */
128  int active; /* currently added to the multi */
129  int64_t request_start; /* absolute offset the current request began at */
130  int64_t request_received;/* bytes delivered in the current request */
131  int64_t request_end; /* expected end of request, or -1 if unknown */
132  int retry_count; /* consecutive recoverable failures */
133  int is_initial; /* using reduced request size */
134 
135  /* Per-response-block header scratch, loop thread only. */
138  int64_t hdr_content_start; /* inclusive start, or -1 */
139  int64_t hdr_content_end; /* inclusive end, or -1 */
140  int64_t hdr_content_total; /* if known, or -1 */
141 
142  /* Probe result. Set by the loop thread, read by url_open() once probed. */
143  int probed;
145  int seekable;
147 
148  /* Shared transfer state, guarded by mutex. */
152  int paused; /* write callback paused, FIFO was full */
153  int eof; /* producer delivered all data */
154  int error; /* AVERROR for an unrecoverable failure, or 0 */
155  int aborted; /* transfer should stop (open was interrupted) */
156 };
157 
158 /* Guards lazy creation of a format context's shared loop. */
160 
161 static int curlcode_to_averror(CURLcode code)
162 {
163  switch (code) {
164  case CURLE_OK: return 0;
165  case CURLE_URL_MALFORMAT:
166  case CURLE_UNSUPPORTED_PROTOCOL: return AVERROR(EINVAL);
167  case CURLE_COULDNT_RESOLVE_PROXY:
168  case CURLE_COULDNT_RESOLVE_HOST: return AVERROR(EHOSTUNREACH);
169  case CURLE_COULDNT_CONNECT: return AVERROR(ECONNREFUSED);
170  case CURLE_OPERATION_TIMEDOUT: return AVERROR(ETIMEDOUT);
171  case CURLE_LOGIN_DENIED:
172  case CURLE_REMOTE_ACCESS_DENIED: return AVERROR(EACCES);
173  case CURLE_OUT_OF_MEMORY: return AVERROR(ENOMEM);
174  case CURLE_PEER_FAILED_VERIFICATION:
175  case CURLE_SSL_CACERT_BADFILE: return AVERROR_INVALIDDATA;
176  default: return AVERROR(EIO);
177  }
178 }
179 
180 static int is_recoverable(CURLcode code)
181 {
182  switch (code) {
183  case CURLE_RECV_ERROR:
184  case CURLE_SEND_ERROR:
185  case CURLE_PARTIAL_FILE:
186  case CURLE_OPERATION_TIMEDOUT:
187  case CURLE_GOT_NOTHING:
188  case CURLE_COULDNT_CONNECT:
189  case CURLE_COULDNT_RESOLVE_HOST:
190  case CURLE_HTTP2:
191  case CURLE_HTTP2_STREAM:
192  return 1;
193  default:
194  return 0;
195  }
196 }
197 
198 /* ------------------------------------------------------------------------- */
199 /* curl callbacks (run on the loop thread) */
200 /* ------------------------------------------------------------------------- */
201 
202 static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
203 {
204  CurlContext *c = userdata;
205  size_t bytes = size * nmemb;
206  size_t space;
207 
208  pthread_mutex_lock(&c->mutex);
209 
210  if (c->aborted || !c->stream_ok) {
211  pthread_mutex_unlock(&c->mutex);
212  return CURL_WRITEFUNC_ERROR;
213  }
214 
215  space = av_fifo_can_write(c->fifo);
216  if (space < bytes) {
217  /* pause the transfer and wait for the consumer to drain. */
218  c->paused = 1;
219  pthread_mutex_unlock(&c->mutex);
220  return CURL_WRITEFUNC_PAUSE;
221  }
222 
223  av_fifo_write(c->fifo, ptr, bytes);
224  c->paused = 0;
225  c->request_received += bytes;
226  pthread_cond_broadcast(&c->cond);
227  pthread_mutex_unlock(&c->mutex);
228 
229  return bytes;
230 }
231 
232 static int64_t parse_offset(const char *s)
233 {
234  int64_t v = strtoll(s, NULL, 10);
235  return v < 0 ? -1 : v;
236 }
237 
238 /* "bytes $from-$to/$document_size" */
239 static void parse_content_range(CurlContext *c, const char *v)
240 {
241  while (av_isspace(*v))
242  v++;
243 
244  if (av_strncasecmp(v, "bytes ", 6))
245  return;
246 
247  const char *range = v + 6, *end;
248  if (range[0] != '*') {
249  c->hdr_content_start = parse_offset(range);
250  if ((end = strchr(range, '-')))
251  c->hdr_content_end = parse_offset(end + 1);
252  }
253 
254  const char *slash = strchr(range, '/');
255  if (slash && slash[1] != '*')
256  c->hdr_content_total = parse_offset(slash + 1);
257 }
258 
259 static size_t header_callback(char *ptr, size_t size, size_t nitems, void *userdata)
260 {
261  CurlContext *c = userdata;
262  size_t len = size * nitems;
263  size_t n = len;
264  long status = 0;
265 
266  if (av_strncasecmp(ptr, "HTTP/", 5) == 0) {
267  c->hdr_accept_ranges = 0;
268  c->hdr_compressed = 0;
269  c->hdr_content_start = -1;
270  c->hdr_content_end = -1;
271  c->hdr_content_total = -1;
272  return len;
273  }
274  if (av_strncasecmp(ptr, "Accept-Ranges:", 14) == 0) {
275  c->hdr_accept_ranges = !!av_stristr(ptr + 14, "bytes");
276  return len;
277  }
278  if (av_strncasecmp(ptr, "Content-Encoding:", 17) == 0) {
279  c->hdr_compressed = !av_stristr(ptr + 17, "identity");
280  return len;
281  }
282  if (av_strncasecmp(ptr, "Content-Range:", 14) == 0) {
283  parse_content_range(c, ptr + 14);
284  return len;
285  }
286 
287  /* Otherwise act only on the blank line that terminates the header block. */
288  while (n && (ptr[n - 1] == '\r' || ptr[n - 1] == '\n'))
289  n--;
290  if (n)
291  return len;
292 
293  curl_easy_getinfo(c->easy, CURLINFO_RESPONSE_CODE, &status);
294 
295  /* Interim (1xx) and redirect (3xx) responses produce an intermediate header
296  * block, wait for the final one. */
297  if (status < 200 || (status >= 300 && status < 400))
298  return len;
299 
300  pthread_mutex_lock(&c->mutex);
301  if (status >= 200 && status < 300) {
302  int64_t content_start = status == 206 ? c->hdr_content_start : 0;
303  /* The reply must start at the offset we requested: for follow-up
304  * requests always, for the initial one when an explicit nonzero
305  * offset was requested. */
306  if ((c->probed ? c->seekable : c->off > 0) &&
307  content_start != c->request_start) {
308  av_log(c->h, AV_LOG_ERROR, "Server sent back unexpected reply "
309  "with offset %"PRId64" (expected %"PRId64")\n",
310  content_start, c->request_start);
311  c->stream_ok = 0;
312  if (!c->error)
313  c->error = AVERROR(EIO);
314  pthread_cond_broadcast(&c->cond);
315  pthread_mutex_unlock(&c->mutex);
316  return len;
317  }
318 
319  c->stream_ok = 1;
320  /* Capture the post-redirect URL, this is exposed as "location" AVOption
321  * for compatibility with http.c. */
322  if (!c->probed) {
323  const char *eff = NULL;
324  if (curl_easy_getinfo(c->easy, CURLINFO_EFFECTIVE_URL, &eff) == CURLE_OK
325  && eff) {
326  char *dup = av_strdup(eff);
327  if (dup) {
328  av_free(c->location);
329  c->location = dup;
330  }
331  }
332  }
333  /* A compressed body is addressed in encoded form, so byte offsets are
334  * meaningless: not seekable. Note that we prefer compression over
335  * seekability, servers don't offer media in compressed form, so it
336  * gives us free compression for other payloads like text playlist. */
337  c->seekable = !c->hdr_compressed &&
338  (status == 206 || c->hdr_accept_ranges);
339  if (!c->hdr_compressed) {
340  int64_t total = c->hdr_content_total;
341  if (total < 0 && status != 206) {
342  curl_off_t cl = -1;
343  if (curl_easy_getinfo(c->easy, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T,
344  &cl) == CURLE_OK && cl >= 0)
345  total = cl;
346  }
347  /* Don't unlearn a known size when a reply omits it. */
348  if (total >= 0)
349  c->content_size = total;
350  }
351  if (c->seekable) {
352  if (c->hdr_content_end >= 0)
353  c->request_end = c->hdr_content_end;
354  else
355  c->request_end = c->content_size > 0 ? c->content_size - 1 : -1;
356  }
357  /* Apply the user override on every reply so re-evaluation of a
358  * follow-up reply doesn't clobber it. */
359  if (c->seekable_opt >= 0)
360  c->seekable = c->seekable_opt;
361  } else {
362  c->stream_ok = 0;
363  if (!c->error)
364  c->error = ff_http_averror(status, AVERROR(EIO));
365  }
366  c->probed = 1;
367  pthread_cond_broadcast(&c->cond);
368  pthread_mutex_unlock(&c->mutex);
369 
370  return len;
371 }
372 
373 static int xferinfo_callback(void *userdata, curl_off_t dltotal, curl_off_t dlnow,
374  curl_off_t ultotal, curl_off_t ulnow)
375 {
376  CurlContext *c = userdata;
377  int aborted;
378  pthread_mutex_lock(&c->mutex);
379  aborted = c->aborted;
380  pthread_mutex_unlock(&c->mutex);
381  return aborted; /* non-zero aborts the transfer */
382 }
383 
384 /* (Re)issue the request for the current offset and add it to the multi. Loop
385  * thread only. */
387 {
388  if (!c->probed || c->seekable) {
389  int64_t start = c->request_start;
390  char range[48];
391  int64_t request_size = c->request_size;
392  if (c->is_initial && c->initial_request_size > 0)
393  request_size = c->initial_request_size;
394  if (request_size > 0 || c->end_off > 0) {
395  int64_t end = INT64_MAX;
396  if (request_size > 0 && start <= INT64_MAX - request_size)
397  end = start + request_size - 1;
398  if (c->content_size > 0)
399  end = FFMIN(end, c->content_size - 1);
400  if (c->end_off > 0)
401  end = FFMIN(end, c->end_off - 1);
402  snprintf(range, sizeof(range), "%"PRId64"-%"PRId64, start, end);
403  } else {
404  snprintf(range, sizeof(range), "%"PRId64"-", start);
405  }
406  curl_easy_setopt(c->easy, CURLOPT_RANGE, range);
407  } else {
408  curl_easy_setopt(c->easy, CURLOPT_RANGE, NULL);
409  }
410  c->loop->num_requests++;
411  c->request_received = 0;
412  c->request_end = -1;
413  c->active = 1;
414  CURLMcode res = curl_multi_add_handle(c->loop->multi, c->easy);
415  if (res != CURLM_OK) {
416  av_log(c->h, AV_LOG_ERROR, "curl_multi_add_handle: %s\n",
417  curl_multi_strerror(res));
418  c->active = 0;
419  pthread_mutex_lock(&c->mutex);
420  if (!c->error)
421  c->error = AVERROR(EIO);
422  pthread_cond_broadcast(&c->cond);
423  pthread_mutex_unlock(&c->mutex);
424  }
425 }
426 
428 {
429  CurlLoop *loop = c->loop;
430  CURL *e = c->easy;
431 
432  curl_off_t recv = 0, time = 0;
433  curl_easy_getinfo(e, CURLINFO_SIZE_DOWNLOAD_T, &recv);
434  curl_easy_getinfo(e, CURLINFO_TOTAL_TIME_T, &time);
435 
436  if (recv) {
437  av_log(c->h, AV_LOG_DEBUG, "%"PRId64" bytes received in %"PRId64" ms\n",
438  (int64_t) recv, (int64_t) time / 1000);
439 
440  loop->total_bytes += recv;
441  loop->total_time_us += time;
442  }
443 
444  long num_conns = 0, num_redirs = 0;
445  curl_easy_getinfo(e, CURLINFO_NUM_CONNECTS, &num_conns);
446  curl_easy_getinfo(e, CURLINFO_REDIRECT_COUNT, &num_redirs);
447  loop->num_connections += (int) num_conns;
448  loop->num_redirects += (int) num_redirs;
449 }
450 
451 /* Transfer finished (or failed) */
452 static void on_done(CurlContext *c, CURLcode code)
453 {
454  int64_t received;
455  int aborted;
456 
457  pthread_mutex_lock(&c->mutex);
458  aborted = c->aborted;
459  received = c->request_received;
460  /* Advance past delivered bytes so a retry or seek resumes at the right offset. */
461  if (received > INT64_MAX - c->request_start) {
462  if (!c->error)
463  c->error = AVERROR(EIO);
464  received = 0;
465  aborted = 1;
466  pthread_cond_broadcast(&c->cond);
467  }
468  c->request_start += received;
469  c->request_received = 0;
470  pthread_mutex_unlock(&c->mutex);
472 
473  if (!c->probed) {
474  /* Connection died before any usable header arrived. */
475  pthread_mutex_lock(&c->mutex);
476  c->probed = 1;
477  c->stream_ok = 0;
478  if (!c->error)
479  c->error = curlcode_to_averror(code);
480  pthread_cond_broadcast(&c->cond);
481  pthread_mutex_unlock(&c->mutex);
482  return;
483  }
484 
485  if (code == CURLE_OK && !aborted && c->stream_ok) {
486  c->retry_count = 0;
487  int64_t file_end = c->content_size > 0 ? c->content_size - 1 : -1;
488  if (c->end_off > 0)
489  file_end = FFMIN(file_end, c->end_off - 1);
490  if (c->seekable && c->request_end >= 0 && c->request_end < file_end) {
491  c->is_initial = 0;
492  start_request(c);
493  return;
494  }
495  pthread_mutex_lock(&c->mutex);
496  c->eof = 1;
497  pthread_cond_broadcast(&c->cond);
498  pthread_mutex_unlock(&c->mutex);
499  return;
500  }
501 
502  /* Resume seekable transfers after a recoverable error. */
503  if (!aborted && c->seekable && is_recoverable(code) &&
504  c->retry_count < c->max_retries) {
505  c->retry_count++;
506  c->loop->num_retries++;
507  av_log(c->h, AV_LOG_WARNING, "%s, retrying (#%d) from %"PRId64"\n",
508  curl_easy_strerror(code), c->retry_count, c->request_start);
509  start_request(c);
510  return;
511  }
512 
513  if (!aborted) {
514  pthread_mutex_lock(&c->mutex);
515  if (!c->error)
516  c->error = curlcode_to_averror(code);
517  pthread_cond_broadcast(&c->cond);
518  pthread_mutex_unlock(&c->mutex);
519  }
520 }
521 
522 /* ------------------------------------------------------------------------- */
523 /* event loop thread + command queue */
524 /* ------------------------------------------------------------------------- */
525 
527 {
528  CurlContext *c = cmd->ctx;
529 
530  switch (cmd->kind) {
531  case CMD_ADD:
532  start_request(c);
533  break;
534  case CMD_REMOVE:
535  if (c->active) {
536  curl_multi_remove_handle(loop->multi, c->easy);
538  c->active = 0;
539  }
540  break;
541  case CMD_UNPAUSE:
542  pthread_mutex_lock(&c->mutex);
543  c->paused = 0;
544  pthread_mutex_unlock(&c->mutex);
545  curl_easy_pause(c->easy, CURLPAUSE_CONT);
546  break;
547  case CMD_SEEK:
548  if (c->active) {
549  curl_multi_remove_handle(loop->multi, c->easy);
550  c->active = 0;
551  }
552  pthread_mutex_lock(&c->mutex);
553  av_fifo_reset2(c->fifo);
554  c->paused = 0;
555  c->eof = 0;
556  c->error = 0;
557  pthread_mutex_unlock(&c->mutex);
558  c->request_start = cmd->pos;
559  c->retry_count = 0;
560  start_request(c);
561  break;
562  }
563 }
564 
565 static void *curl_worker(void *arg)
566 {
567  CurlLoop *loop = arg;
568 
569  ff_thread_setname("curl");
570 
571  while (1) {
572  CurlCmd *cmd;
573  CURLMsg *msg;
574  int running = 0, left = 0, do_exit;
575 
576  pthread_mutex_lock(&loop->mutex);
577  cmd = loop->cmd_head;
578  if (cmd) {
579  loop->cmd_head = cmd->next;
580  if (!loop->cmd_head)
581  loop->cmd_tail = NULL;
582  }
583  do_exit = loop->exit;
584  pthread_mutex_unlock(&loop->mutex);
585 
586  if (cmd) {
587  execute_command(loop, cmd);
588  if (cmd->sync) {
589  pthread_mutex_lock(&loop->mutex);
590  cmd->done = 1;
592  pthread_mutex_unlock(&loop->mutex);
593  } else {
594  av_free(cmd);
595  }
596  continue; /* drain the whole queue before pumping curl */
597  }
598 
599  if (do_exit)
600  break;
601 
602  curl_multi_perform(loop->multi, &running);
603 
604  while ((msg = curl_multi_info_read(loop->multi, &left))) {
605  CurlContext *c = NULL;
606  if (msg->msg != CURLMSG_DONE)
607  continue;
608  curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &c);
609  curl_multi_remove_handle(loop->multi, msg->easy_handle);
610  if (c) {
611  c->active = 0;
612  on_done(c, msg->data.result);
613  }
614  }
615 
616  curl_multi_poll(loop->multi, NULL, 0, 1000, NULL);
617  }
618 
619  return NULL;
620 }
621 
622 /* Dispatch a command to the loop. For sync commands the caller blocks until the
623  * loop thread has executed it. Returns 0 or a negative AVERROR. */
624 static int curl_dispatch(CurlLoop *loop, enum cmd_kind kind, CurlContext *c,
625  int64_t pos, int sync)
626 {
627  CurlCmd stackcmd = {0};
628  CurlCmd *cmd = sync ? &stackcmd : av_mallocz(sizeof(*cmd));
629 
630  if (!cmd)
631  return AVERROR(ENOMEM);
632 
633  cmd->kind = kind;
634  cmd->ctx = c;
635  cmd->pos = pos;
636  cmd->sync = sync;
637 
638  pthread_mutex_lock(&loop->mutex);
639  if (loop->cmd_tail)
640  loop->cmd_tail->next = cmd;
641  else
642  loop->cmd_head = cmd;
643  loop->cmd_tail = cmd;
644  curl_multi_wakeup(loop->multi);
645  if (sync) {
646  while (!cmd->done)
647  pthread_cond_wait(&loop->cond, &loop->mutex);
648  }
649  pthread_mutex_unlock(&loop->mutex);
650 
651  return 0;
652 }
653 
655 {
656  CurlLoop *loop = av_mallocz(sizeof(*loop));
657  if (!loop)
658  return NULL;
659  loop->avfc = avfc;
660 
661  if (pthread_mutex_init(&loop->mutex, NULL))
662  goto fail;
663  if (pthread_cond_init(&loop->cond, NULL)) {
664  pthread_mutex_destroy(&loop->mutex);
665  goto fail;
666  }
667 
668  if (curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK)
669  goto fail2;
670 
671  loop->multi = curl_multi_init();
672  if (!loop->multi)
673  goto fail3;
674  curl_multi_setopt(loop->multi, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
675 
676  loop->share = curl_share_init();
677  if (!loop->share)
678  goto fail3;
679  curl_share_setopt(loop->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
680  curl_share_setopt(loop->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_HSTS);
681 
682  if (pthread_create(&loop->thread, NULL, curl_worker, loop))
683  goto fail3;
684 
685  return loop;
686 
687 fail3:
688  curl_multi_cleanup(loop->multi);
689  curl_share_cleanup(loop->share);
690  curl_global_cleanup();
691 fail2:
692  pthread_cond_destroy(&loop->cond);
693  pthread_mutex_destroy(&loop->mutex);
694 fail:
695  av_free(loop);
696  return NULL;
697 }
698 
700 {
701  AVFormatContext *avfc = loop->avfc;
702  if (!loop->total_bytes)
703  return;
704 
705  double time = (double) loop->total_time_us / 1000000.0;
706  double avg = time ? loop->total_bytes / time : 0;
707  av_log(avfc, AV_LOG_VERBOSE,
708  "libcurl: Overall %"PRId64" bytes received in %.0f ms = %.0f kB/s\n",
709  loop->total_bytes, time * 1e3, avg / 1e3);
710 
711  av_log(avfc, AV_LOG_VERBOSE,
712  "libcurl: %d connections, %d redirects, %d requests, %d retries\n",
713  loop->num_connections, loop->num_redirects, loop->num_requests, loop->num_retries);
714 }
715 
717 {
718  pthread_mutex_lock(&loop->mutex);
719  loop->exit = 1;
720  curl_multi_wakeup(loop->multi);
721  pthread_mutex_unlock(&loop->mutex);
722 
723  pthread_join(loop->thread, NULL);
725 
726  curl_multi_cleanup(loop->multi);
727  curl_share_cleanup(loop->share);
728  pthread_cond_destroy(&loop->cond);
729  pthread_mutex_destroy(&loop->mutex);
730  av_free(loop);
731 
732  /* Released after the thread is joined and the multi handle is gone. */
733  curl_global_cleanup();
734 }
735 
736 /* Attach a context to its event loop. With an owning AVFormatContext the loop is
737  * created lazily, cached on it, and shared across the demuxer's transfers so curl
738  * reuses connections; it is freed at format teardown. Without one the context
739  * gets a private loop freed on close. */
741 {
742  if (!avfc) {
743  c->loop = curl_loop_create(NULL);
744  c->private_loop = 1;
745  return c->loop ? 0 : AVERROR(ENOMEM);
746  }
747 
749  c->loop = ffformatcontext(avfc)->curl_loop;
750  if (!c->loop) {
751  c->loop = curl_loop_create(avfc);
752  ffformatcontext(avfc)->curl_loop = c->loop;
753  }
755 
756  return c->loop ? 0 : AVERROR(ENOMEM);
757 }
758 
760 {
761  if (loop && *loop) {
763  *loop = NULL;
764  }
765 }
766 
767 /* ------------------------------------------------------------------------- */
768 /* URLProtocol callbacks */
769 /* ------------------------------------------------------------------------- */
770 
771 static int libcurl_close(URLContext *h);
772 
773 static int debug_callback(CURL *easy, curl_infotype type, char *data,
774  size_t size, void *userdata)
775 {
776  CurlContext *c = userdata;
777  const char *prefix, *p = data, *end = data + size;
778 
779  switch (type) {
780  case CURLINFO_TEXT: prefix = "* "; break;
781  case CURLINFO_HEADER_IN: prefix = "< "; break;
782  case CURLINFO_HEADER_OUT: prefix = "> "; break;
783  default: return 0;
784  }
785 
786  /* Split multiline payload into each log. */
787  while (p < end) {
788  const char *nl = memchr(p, '\n', end - p);
789  size_t len = (nl ? nl : end) - p;
790  while (len && p[len - 1] == '\r')
791  len--;
792  av_log(c->h, AV_LOG_DEBUG, "%s%.*s\n", prefix, (int)len, p);
793  if (!nl)
794  break;
795  p = nl + 1;
796  }
797  return 0;
798 }
799 
800 /* Build the custom request header list from the referer and headers options. */
801 static struct curl_slist *build_headers(CurlContext *c)
802 {
803  struct curl_slist *list = NULL;
804 
805  if (c->referer && c->referer[0]) {
806  char *h = av_asprintf("Referer: %s", c->referer);
807  if (h) {
808  list = curl_slist_append(list, h);
809  av_free(h);
810  }
811  }
812  if (c->headers && c->headers[0]) {
813  char *copy = av_strdup(c->headers);
814  char *line, *saveptr = NULL;
815  if (copy) {
816  for (line = av_strtok(copy, "\r\n", &saveptr); line;
817  line = av_strtok(NULL, "\r\n", &saveptr))
818  list = curl_slist_append(list, line);
819  av_free(copy);
820  }
821  }
822  return list;
823 }
824 
826 {
827  const char *wl = c->h->protocol_whitelist;
828  const char *bl = c->h->protocol_blacklist;
829  if (!wl && !bl)
830  return 0;
831 
832  AVBPrint bp;
834 
835  curl_version_info_data *info = curl_version_info(CURLVERSION_NOW);
836  for (const char *const *p = info->protocols; *p; p++) {
837  const char *proto = *p;
838  if (av_strcasecmp(proto, "http") && av_strcasecmp(proto, "https"))
839  continue; /* only http(s) are supported by libcurl.c at the moment */
840  if (wl && av_match_list(proto, wl, ',') <= 0)
841  continue;
842  if (bl && av_match_list(proto, bl, ',') > 0)
843  continue;
844  if (bp.len)
845  av_bprint_chars(&bp, ',', 1);
846  av_bprintf(&bp, "%s", proto);
847  }
848 
849  if (!av_bprint_is_complete(&bp)) {
850  av_bprint_finalize(&bp, NULL);
851  return AVERROR(ENOMEM);
852  }
853 
854  if (!bp.len) {
855  av_log(c->h, AV_LOG_ERROR, "Set of allowed protocols is empty.\n");
856  av_bprint_finalize(&bp, NULL);
857  return AVERROR(EINVAL);
858  }
859 
860  curl_easy_setopt(c->easy, CURLOPT_PROTOCOLS_STR, bp.str);
861  curl_easy_setopt(c->easy, CURLOPT_REDIR_PROTOCOLS_STR, bp.str);
862  av_bprint_finalize(&bp, NULL);
863  return 0;
864 }
865 
866 static void setup_curl(CurlContext *c)
867 {
868  CURL *e = c->easy;
869  const char *url = c->h->filename;
870 
871  /* Drop an optional "libcurl:" prefix that forces this protocol. */
872  av_strstart(url, "libcurl:", &url);
873 
874  curl_easy_setopt(e, CURLOPT_URL, url);
875  curl_easy_setopt(e, CURLOPT_PRIVATE, c);
876  curl_easy_setopt(e, CURLOPT_NOSIGNAL, 1L);
877  curl_easy_setopt(e, CURLOPT_SHARE, c->loop->share);
878 
879  curl_easy_setopt(e, CURLOPT_WRITEFUNCTION, write_callback);
880  curl_easy_setopt(e, CURLOPT_WRITEDATA, c);
881  curl_easy_setopt(e, CURLOPT_HEADERFUNCTION, header_callback);
882  curl_easy_setopt(e, CURLOPT_HEADERDATA, c);
883 
884  curl_easy_setopt(e, CURLOPT_NOPROGRESS, 0L);
885  curl_easy_setopt(e, CURLOPT_XFERINFOFUNCTION, xferinfo_callback);
886  curl_easy_setopt(e, CURLOPT_XFERINFODATA, c);
887 
888  if (av_log_get_level() >= AV_LOG_DEBUG) {
889  curl_easy_setopt(e, CURLOPT_VERBOSE, 1L);
890  curl_easy_setopt(e, CURLOPT_DEBUGFUNCTION, debug_callback);
891  curl_easy_setopt(e, CURLOPT_DEBUGDATA, c);
892  }
893 
894  curl_easy_setopt(e, CURLOPT_FOLLOWLOCATION, 1L);
895  curl_easy_setopt(e, CURLOPT_MAXREDIRS, (long)c->max_redirects);
896  curl_easy_setopt(e, CURLOPT_HTTP_VERSION, (long)c->http_version);
897  curl_easy_setopt(e, CURLOPT_TCP_KEEPALIVE, c->multiple_requests ? 1L : 0L);
898  curl_easy_setopt(e, CURLOPT_FORBID_REUSE, c->multiple_requests ? 0L : 1L);
899  curl_easy_setopt(e, CURLOPT_HSTS_CTRL, (long)CURLHSTS_ENABLE);
900  curl_easy_setopt(e, CURLOPT_ACCEPT_ENCODING,
901  c->off > 0 || c->end_off > 0 ? "identity" : "");
902  if (c->connect_timeout > 0)
903  curl_easy_setopt(e, CURLOPT_CONNECTTIMEOUT_MS,
904  (long)c->connect_timeout * 1000);
905 
906  if (c->user_agent && c->user_agent[0])
907  curl_easy_setopt(e, CURLOPT_USERAGENT, c->user_agent);
908  if (c->http_proxy && c->http_proxy[0])
909  curl_easy_setopt(e, CURLOPT_PROXY, c->http_proxy);
910 
911  curl_easy_setopt(e, CURLOPT_SSL_OPTIONS, (long)CURLSSLOPT_NATIVE_CA);
912  curl_easy_setopt(e, CURLOPT_SSL_VERIFYPEER, c->tls_verify ? 1L : 0L);
913  curl_easy_setopt(e, CURLOPT_SSL_VERIFYHOST, c->tls_verify ? 2L : 0L);
914  if (c->ca_file)
915  curl_easy_setopt(e, CURLOPT_CAINFO, c->ca_file);
916  if (c->cert_file)
917  curl_easy_setopt(e, CURLOPT_SSLCERT, c->cert_file);
918  if (c->key_file)
919  curl_easy_setopt(e, CURLOPT_SSLKEY, c->key_file);
920 
921  curl_easy_setopt(e, CURLOPT_COOKIEFILE, "");
922  if (c->cookies && c->cookies[0]) {
923  char *copy = av_strdup(c->cookies);
924  char *line, *saveptr = NULL;
925  if (copy) {
926  for (line = av_strtok(copy, "\r\n", &saveptr); line;
927  line = av_strtok(NULL, "\r\n", &saveptr)) {
928  char *sc = av_asprintf("Set-Cookie: %s", line);
929  if (sc) {
930  curl_easy_setopt(e, CURLOPT_COOKIELIST, sc);
931  av_free(sc);
932  }
933  }
934  av_free(copy);
935  }
936  }
937 
938  c->header_list = build_headers(c);
939  if (c->header_list)
940  curl_easy_setopt(e, CURLOPT_HTTPHEADER, c->header_list);
941 }
942 
944 {
946  struct timespec ts = { .tv_sec = t / 1000000,
947  .tv_nsec = (t % 1000000) * 1000 };
948  pthread_cond_timedwait(&c->cond, &c->mutex, &ts);
949 }
950 
951 /* Block until the transfer has been probed, the stream errored, or the open was
952  * interrupted. Returns 0, or a negative AVERROR. */
954 {
955  URLContext *h = c->h;
956  int ret = 0;
957 
958  pthread_mutex_lock(&c->mutex);
959  while (!c->probed && !c->error) {
960  if (ff_check_interrupt(&h->interrupt_callback)) {
961  c->aborted = 1;
962  ret = AVERROR_EXIT;
963  break;
964  }
965  curl_cond_wait(c);
966  }
967  if (!ret) {
968  if (!c->stream_ok)
969  ret = c->error ? c->error : AVERROR(EIO);
970  }
971  pthread_mutex_unlock(&c->mutex);
972 
973  return ret;
974 }
975 
976 static int libcurl_open(URLContext *h, const char *url, int flags,
978 {
979  /* Guard against non-thread-safe libcurl builds. This should never happen,
980  * since libcurl is used only on platforms with thread support, and thread
981  * safety is enabled unconditionally in libcurl when the platform supports
982  * threads or atomics. */
983  curl_version_info_data *info = curl_version_info(CURLVERSION_NOW);
984  if (!(info->features & CURL_VERSION_THREADSAFE))
985  return AVERROR(ENOSYS);
986 
987  CurlContext *c = h->priv_data;
988  const char *eff_url = h->filename;
989  int ret;
990 
991  c->h = h;
992  c->content_size = -1;
993  c->request_start = c->off;
994  c->request_end = -1;
995  c->logical_pos = c->off;
996  c->is_initial = 1;
997 
998  /* Report the request URL until header_callback replaces it post-redirect. */
999  av_strstart(eff_url, "libcurl:", &eff_url);
1000  av_freep(&c->location);
1001  c->location = av_strdup(eff_url);
1002 
1003  ret = pthread_mutex_init(&c->mutex, NULL);
1004  if (ret)
1005  return AVERROR(ret);
1006  ret = pthread_cond_init(&c->cond, NULL);
1007  if (ret) {
1008  pthread_mutex_destroy(&c->mutex);
1009  return AVERROR(ret);
1010  }
1011 
1012  c->fifo = av_fifo_alloc2(c->buffer_size, 1, 0);
1013  if (!c->fifo) {
1014  ret = AVERROR(ENOMEM);
1015  goto fail;
1016  }
1017 
1018  ret = curl_loop_attach(c, h->avfc);
1019  if (ret < 0)
1020  goto fail;
1021 
1022  c->easy = curl_easy_init();
1023  if (!c->easy) {
1024  ret = AVERROR(ENOMEM);
1025  goto fail;
1026  }
1027 
1028  ret = setup_protocols(c);
1029  if (ret < 0)
1030  goto fail;
1031 
1032  setup_curl(c);
1033 
1034  ret = curl_dispatch(c->loop, CMD_ADD, c, 0, 0);
1035  if (ret < 0)
1036  goto fail;
1037 
1038  ret = wait_for_probe(c);
1039  if (ret < 0)
1040  goto fail;
1041 
1042  pthread_mutex_lock(&c->mutex);
1043  h->is_streamed = !c->seekable;
1044  pthread_mutex_unlock(&c->mutex);
1045 
1046  return 0;
1047 
1048 fail:
1049  libcurl_close(h);
1050  return ret;
1051 }
1052 
1053 static int libcurl_read(URLContext *h, unsigned char *buf, int size)
1054 {
1055  CurlContext *c = h->priv_data;
1056  int nonblock = h->flags & AVIO_FLAG_NONBLOCK;
1057  int ret;
1058 
1059  pthread_mutex_lock(&c->mutex);
1060  while (1) {
1061  size_t avail = av_fifo_can_read(c->fifo);
1062 
1063  if (avail) {
1064  int n = FFMIN(avail, (size_t)size);
1065  int unpause;
1066  av_fifo_read(c->fifo, buf, n);
1067  /* Resume a paused transfer once the FIFO is at least half empty. */
1068  unpause = c->paused && av_fifo_can_write(c->fifo) * 2 >= c->buffer_size;
1069  c->logical_pos += n;
1070  pthread_mutex_unlock(&c->mutex);
1071  if (unpause)
1072  curl_dispatch(c->loop, CMD_UNPAUSE, c, 0, 0);
1073  return n;
1074  }
1075  if (c->error) {
1076  ret = c->error;
1077  break;
1078  }
1079  if (c->eof) {
1080  ret = AVERROR_EOF;
1081  break;
1082  }
1083  if (nonblock) {
1084  ret = AVERROR(EAGAIN);
1085  break;
1086  }
1087  curl_cond_wait(c);
1088  /* Return to the avio layer so it can poll the interrupt callback. */
1089  nonblock = 1;
1090  }
1091  pthread_mutex_unlock(&c->mutex);
1092 
1093  return ret;
1094 }
1095 
1097 {
1098  CurlContext *c = h->priv_data;
1099  int64_t newpos;
1100 
1101  pthread_mutex_lock(&c->mutex);
1102  const int64_t content_size = c->content_size;
1103  const int seekable = c->seekable;
1104  pthread_mutex_unlock(&c->mutex);
1105 
1106  if (whence == AVSEEK_SIZE)
1107  return content_size >= 0 ? content_size : AVERROR(ENOSYS);
1108 
1109  if (!seekable)
1110  return AVERROR(ENOSYS);
1111 
1112  switch (whence) {
1113  case SEEK_SET:
1114  newpos = pos;
1115  break;
1116  case SEEK_CUR:
1117  if (pos > INT64_MAX - c->logical_pos)
1118  return AVERROR(ERANGE);
1119  newpos = c->logical_pos + pos;
1120  break;
1121  case SEEK_END:
1122  if (content_size < 0)
1123  return AVERROR(ENOSYS);
1124  if (pos > INT64_MAX - content_size)
1125  return AVERROR(ERANGE);
1126  newpos = content_size + pos;
1127  break;
1128  default:
1129  return AVERROR(EINVAL);
1130  }
1131  if (newpos < 0)
1132  return AVERROR(EINVAL);
1133 
1134  if (newpos == c->logical_pos)
1135  return newpos;
1136 
1137  /* Restart the transfer at the new offset. Any failure of the new request
1138  * surfaces on the following url_read(). */
1139  curl_dispatch(c->loop, CMD_SEEK, c, newpos, 1);
1140  c->logical_pos = newpos;
1141 
1142  return newpos;
1143 }
1144 
1146 {
1147  CurlContext *c = h->priv_data;
1148 
1149  if (c->loop) {
1150  if (c->easy) {
1151  /* Ensure the handle is out of the multi before we free it. */
1152  curl_dispatch(c->loop, CMD_REMOVE, c, 0, 1);
1153  curl_easy_cleanup(c->easy);
1154  c->easy = NULL;
1155  }
1156  /* A shared loop outlives the transfer for connection reuse. */
1157  if (c->private_loop)
1158  curl_loop_destroy(c->loop);
1159  c->loop = NULL;
1160  }
1161 
1162  if (c->header_list)
1163  curl_slist_free_all(c->header_list);
1164  av_fifo_freep2(&c->fifo);
1165  pthread_cond_destroy(&c->cond);
1166  pthread_mutex_destroy(&c->mutex);
1167 
1168  return 0;
1169 }
1170 
1171 #define OFFSET(x) offsetof(CurlContext, x)
1172 #define D AV_OPT_FLAG_DECODING_PARAM
1173 #define E AV_OPT_FLAG_ENCODING_PARAM
1174 static const AVOption options[] = {
1175  { "user_agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, { .str = DEFAULT_USER_AGENT }, 0, 0, D },
1176  { "referer", "override Referer header", OFFSET(referer), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D },
1177  { "headers", "set custom HTTP headers, can override built in default headers", OFFSET(headers), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
1178  { "http_proxy", "set HTTP proxy to tunnel through", OFFSET(http_proxy), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
1179  { "cookies", "set cookies to be sent in applicable future requests, use newline delimited Set-Cookie HTTP field value syntax", OFFSET(cookies), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D },
1180  { "location", "the actual location of the data received", OFFSET(location), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
1181  { "offset", "initial byte offset", OFFSET(off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
1182  { "end_offset", "try to limit the request to bytes preceding this offset", OFFSET(end_off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
1183  { "seekable", "control seekability of connection", OFFSET(seekable_opt), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, D },
1184  { "tls_verify", "verify the peer certificate and hostname", OFFSET(tls_verify), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, D | E },
1185  { "ca_file", "certificate authority bundle file", OFFSET(ca_file), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
1186  { "cert_file", "client certificate file", OFFSET(cert_file), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
1187  { "key_file", "client private key file", OFFSET(key_file), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E },
1188  { "connect_timeout", "connection timeout in seconds (0 = libcurl default)", OFFSET(connect_timeout), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX / 1000, D | E },
1189  { "max_redirects", "maximum number of redirects to follow", OFFSET(max_redirects), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, INT_MAX, D },
1190  { "multiple_requests", "reuse the connection across requests (HTTP keep-alive)", OFFSET(multiple_requests), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, D | E },
1191  { "max_retries", "maximum number of retries after a recoverable error", OFFSET(max_retries), AV_OPT_TYPE_INT, { .i64 = 5 }, 0, INT_MAX, D },
1192  { "buffer_size", "receive buffer size in bytes", OFFSET(buffer_size), AV_OPT_TYPE_INT64, { .i64 = CURL_DEFAULT_BUFFER_SIZE }, CURL_MAX_WRITE_SIZE, INT_MAX, D },
1193  { "request_size", "split a transfer into ranged requests of at most this many bytes (0 = unlimited)", OFFSET(request_size), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
1194  { "initial_request_size", "size (in bytes) of initial requests made during probing / header parsing", OFFSET(initial_request_size), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
1195  { "http_version", "HTTP version to use", OFFSET(http_version), AV_OPT_TYPE_INT, { .i64 = CURL_HTTP_VERSION_NONE }, 0, INT_MAX, D, .unit = "http_version" },
1196  { "auto", "negotiate the best supported version", 0, AV_OPT_TYPE_CONST, { .i64 = CURL_HTTP_VERSION_NONE }, 0, 0, D, .unit = "http_version" },
1197  { "1.0", "HTTP/1.0", 0, AV_OPT_TYPE_CONST, { .i64 = CURL_HTTP_VERSION_1_0 }, 0, 0, D, .unit = "http_version" },
1198  { "1.1", "HTTP/1.1", 0, AV_OPT_TYPE_CONST, { .i64 = CURL_HTTP_VERSION_1_1 }, 0, 0, D, .unit = "http_version" },
1199  { "2", "HTTP/2", 0, AV_OPT_TYPE_CONST, { .i64 = CURL_HTTP_VERSION_2 }, 0, 0, D, .unit = "http_version" },
1200  { "2tls", "HTTP/2 over TLS only", 0, AV_OPT_TYPE_CONST, { .i64 = CURL_HTTP_VERSION_2TLS }, 0, 0, D, .unit = "http_version" },
1201  { "2-prior-knowledge", "HTTP/2 without an upgrade handshake", 0, AV_OPT_TYPE_CONST, { .i64 = CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE }, 0, 0, D, .unit = "http_version" },
1202  { "3", "HTTP/3, fall back to earlier versions", 0, AV_OPT_TYPE_CONST, { .i64 = CURL_HTTP_VERSION_3 }, 0, 0, D, .unit = "http_version" },
1203  { "3only", "HTTP/3 only", 0, AV_OPT_TYPE_CONST, { .i64 = CURL_HTTP_VERSION_3ONLY }, 0, 0, D, .unit = "http_version" },
1204  { NULL }
1205 };
1206 
1208  .class_name = "libcurl",
1209  .item_name = av_default_item_name,
1210  .option = options,
1211  .version = LIBAVUTIL_VERSION_INT,
1212 };
1213 
1215  .name = "libcurl",
1216  .url_open2 = libcurl_open,
1217  .url_read = libcurl_read,
1218  .url_seek = libcurl_seek,
1219  .url_close = libcurl_close,
1220  .priv_data_size = sizeof(CurlContext),
1221  .priv_data_class = &libcurl_context_class,
1223  .default_whitelist = "http,https,libcurl",
1224 };
CurlContext::paused
int paused
Definition: libcurl.c:152
av_strdup
#define av_strdup(s)
Definition: ops_static.c:47
do_exit
static void do_exit(VideoState *is)
Definition: ffplay.c:1346
pthread_mutex_t
_fmutex pthread_mutex_t
Definition: os2threads.h:53
pthread_join
static av_always_inline int pthread_join(pthread_t thread, void **value_ptr)
Definition: os2threads.h:94
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
CMD_ADD
@ CMD_ADD
Definition: libcurl.c:57
curl_loop_lock
static AVMutex curl_loop_lock
Definition: libcurl.c:159
CurlContext::probed
int probed
Definition: libcurl.c:143
CurlContext::initial_request_size
int64_t initial_request_size
Definition: libcurl.c:122
av_fifo_can_write
size_t av_fifo_can_write(const AVFifo *f)
Definition: fifo.c:94
CMD_SEEK
@ CMD_SEEK
Definition: libcurl.c:60
av_bprint_is_complete
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:218
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
CurlContext::end_off
int64_t end_off
Definition: libcurl.c:113
space
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated space
Definition: undefined.txt:4
CurlCmd::pos
int64_t pos
Definition: libcurl.c:66
URL_PROTOCOL_FLAG_NETWORK
#define URL_PROTOCOL_FLAG_NETWORK
Definition: url.h:33
av_bprint_init
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
OFFSET
#define OFFSET(x)
Definition: libcurl.c:1171
CurlContext::request_end
int64_t request_end
Definition: libcurl.c:131
setup_protocols
static int setup_protocols(CurlContext *c)
Definition: libcurl.c:825
ffformatcontext
static av_always_inline FFFormatContext * ffformatcontext(AVFormatContext *s)
Definition: internal.h:130
av_stristr
char * av_stristr(const char *s1, const char *s2)
Locate the first case-independent occurrence in the string haystack of the string needle.
Definition: avstring.c:58
setup_curl
static void setup_curl(CurlContext *c)
Definition: libcurl.c:866
thread.h
CurlContext::buffer_size
int64_t buffer_size
Definition: libcurl.c:120
AVERROR_EOF
#define AVERROR_EOF
End of file.
Definition: error.h:57
CurlLoop::share
CURLSH * share
Definition: libcurl.c:77
pthread_mutex_init
static av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
Definition: os2threads.h:104
CurlLoop::num_connections
int num_connections
Definition: libcurl.c:87
curl_worker
static void * curl_worker(void *arg)
Definition: libcurl.c:565
CurlLoop::num_requests
int num_requests
Definition: libcurl.c:89
int64_t
long long int64_t
Definition: coverity.c:34
av_asprintf
char * av_asprintf(const char *fmt,...)
Definition: avstring.c:115
av_strcasecmp
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition: avstring.c:208
av_isspace
static av_const int av_isspace(int c)
Locale-independent conversion of ASCII isspace.
Definition: avstring.h:218
curlcode_to_averror
static int curlcode_to_averror(CURLcode code)
Definition: libcurl.c:161
CurlLoop::multi
CURLM * multi
Definition: libcurl.c:76
CurlContext::http_version
int http_version
Definition: libcurl.c:119
wait_for_probe
static int wait_for_probe(CurlContext *c)
Definition: libcurl.c:953
pthread_mutex_lock
static av_always_inline int pthread_mutex_lock(pthread_mutex_t *mutex)
Definition: os2threads.h:119
AVOption
AVOption.
Definition: opt.h:428
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
print_statistics
static void print_statistics(CurlLoop *loop)
Definition: libcurl.c:699
CurlContext::http_proxy
char * http_proxy
Definition: libcurl.c:106
AV_LOG_VERBOSE
#define AV_LOG_VERBOSE
Detailed information.
Definition: log.h:226
CurlContext::fifo
AVFifo * fifo
Definition: libcurl.c:151
AVDictionary
Definition: dict.c:32
CMD_REMOVE
@ CMD_REMOVE
Definition: libcurl.c:58
CurlContext::cert_file
char * cert_file
Definition: libcurl.c:109
URLProtocol
Definition: url.h:53
libcurl_open
static int libcurl_open(URLContext *h, const char *url, int flags, AVDictionary **options)
Definition: libcurl.c:976
fifo.h
curl_loop_destroy
static void curl_loop_destroy(CurlLoop *loop)
Definition: libcurl.c:716
CurlCmd::kind
enum cmd_kind kind
Definition: libcurl.c:64
macros.h
av_fifo_write
int av_fifo_write(AVFifo *f, const void *buf, size_t nb_elems)
Write data into a FIFO.
Definition: fifo.c:188
parse_offset
static int64_t parse_offset(const char *s)
Definition: libcurl.c:232
debug_callback
static int debug_callback(CURL *easy, curl_infotype type, char *data, size_t size, void *userdata)
Definition: libcurl.c:773
AV_BPRINT_SIZE_AUTOMATIC
#define AV_BPRINT_SIZE_AUTOMATIC
CurlContext::eof
int eof
Definition: libcurl.c:153
type
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 type
Definition: writing_filters.txt:86
curl_loop_attach
static int curl_loop_attach(CurlContext *c, AVFormatContext *avfc)
Definition: libcurl.c:740
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:922
loop
static int loop
Definition: ffplay.c:337
CurlContext::retry_count
int retry_count
Definition: libcurl.c:132
CurlLoop::num_redirects
int num_redirects
Definition: libcurl.c:88
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
write_callback
static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
Definition: libcurl.c:202
av_fifo_read
int av_fifo_read(AVFifo *f, void *buf, size_t nb_elems)
Read data from a FIFO.
Definition: fifo.c:240
CurlContext::connect_timeout
int connect_timeout
Definition: libcurl.c:116
AVMutex
#define AVMutex
Definition: thread.h:184
CurlContext::location
char * location
Definition: libcurl.c:111
flags
#define flags(name, subs,...)
Definition: cbs_av1.c:504
pthread_mutex_unlock
static av_always_inline int pthread_mutex_unlock(pthread_mutex_t *mutex)
Definition: os2threads.h:126
is_recoverable
static int is_recoverable(CURLcode code)
Definition: libcurl.c:180
CurlContext::request_start
int64_t request_start
Definition: libcurl.c:129
cmd_kind
cmd_kind
Definition: libcurl.c:56
prefix
char prefix[8]
Definition: uops_macros_gen.c:49
info
MIPS optimizations info
Definition: mips.txt:2
av_strtok
char * av_strtok(char *s, const char *delim, char **saveptr)
Split the string into several tokens which can be accessed by successive calls to av_strtok().
Definition: avstring.c:179
CurlLoop::num_retries
int num_retries
Definition: libcurl.c:90
AV_OPT_TYPE_INT64
@ AV_OPT_TYPE_INT64
Underlying C type is int64_t.
Definition: opt.h:262
CurlContext::hdr_content_end
int64_t hdr_content_end
Definition: libcurl.c:139
update_statistics
static void update_statistics(CurlContext *c)
Definition: libcurl.c:427
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:231
CurlContext::easy
CURL * easy
Definition: libcurl.c:99
CurlCmd::sync
int sync
Definition: libcurl.c:67
CurlContext::hdr_compressed
int hdr_compressed
Definition: libcurl.c:137
headers
FFmpeg currently uses a custom build this text attempts to document some of its obscure features and options Makefile the full command issued by make and its output will be shown on the screen DESTDIR Destination directory for the install useful to prepare packages or install FFmpeg in cross environments GEN Set to ‘1’ to generate the missing or mismatched references Makefile builds all the libraries and the executables fate Run the fate test note that you must have installed it fate list List all fate regression test targets fate list failing List the fate tests that failed the last time they were executed fate clear reports Remove the test reports from previous test libraries and programs examples Build all examples located in doc examples checkheaders Check headers dependencies alltools Build all tools in tools directory config Reconfigure the project with the current configuration tools target_dec_< decoder > _fuzzer Build fuzzer to fuzz the specified decoder tools target_bsf_< filter > _fuzzer Build fuzzer to fuzz the specified bitstream filter Useful standard make this is useful to reduce unneeded rebuilding when changing headers
Definition: build_system.txt:59
CurlContext::loop
CurlLoop * loop
Definition: libcurl.c:97
limits.h
CurlCmd::ctx
CurlContext * ctx
Definition: libcurl.c:65
CurlContext::error
int error
Definition: libcurl.c:154
libcurl_read
static int libcurl_read(URLContext *h, unsigned char *buf, int size)
Definition: libcurl.c:1053
CurlContext::hdr_content_total
int64_t hdr_content_total
Definition: libcurl.c:140
av_mallocz
#define av_mallocz(s)
Definition: tableprint_vlc.h:31
pthread_cond_broadcast
static av_always_inline int pthread_cond_broadcast(pthread_cond_t *cond)
Definition: os2threads.h:162
arg
const char * arg
Definition: jacosubdec.c:65
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
CurlContext::header_list
struct curl_slist * header_list
Definition: libcurl.c:100
AVFormatContext
Format I/O context.
Definition: avformat.h:1333
av_log_get_level
int av_log_get_level(void)
Get the current log level.
Definition: log.c:472
fail
#define fail
Definition: test.h:478
internal.h
LIBAVUTIL_VERSION_INT
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
AVClass
Describe the class of an AVClass context structure.
Definition: log.h:76
NULL
#define NULL
Definition: coverity.c:32
libcurl_context_class
static const AVClass libcurl_context_class
Definition: libcurl.c:1207
av_match_list
int av_match_list(const char *name, const char *list, char separator)
Check if a name is in a list.
Definition: avstring.c:440
CurlContext::seekable_opt
int seekable_opt
Definition: libcurl.c:115
av_default_item_name
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:242
CurlContext::request_received
int64_t request_received
Definition: libcurl.c:130
CurlContext::ca_file
char * ca_file
Definition: libcurl.c:108
execute_command
static void execute_command(CurlLoop *loop, CurlCmd *cmd)
Definition: libcurl.c:526
av_fifo_can_read
size_t av_fifo_can_read(const AVFifo *f)
Definition: fifo.c:87
list
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 list
Definition: filter_design.txt:25
options
Definition: swscale.c:50
double
double
Definition: af_crystalizer.c:132
time.h
CurlContext::aborted
int aborted
Definition: libcurl.c:155
libcurl_seek
static int64_t libcurl_seek(URLContext *h, int64_t pos, int whence)
Definition: libcurl.c:1096
CurlContext::content_size
int64_t content_size
Definition: libcurl.c:146
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
CurlContext::active
int active
Definition: libcurl.c:128
error.h
CurlContext::user_agent
char * user_agent
Definition: libcurl.c:103
build_headers
static struct curl_slist * build_headers(CurlContext *c)
Definition: libcurl.c:801
av_strncasecmp
int av_strncasecmp(const char *a, const char *b, size_t n)
Locale-independent case-insensitive compare.
Definition: avstring.c:218
parse_content_range
static void parse_content_range(CurlContext *c, const char *v)
Definition: libcurl.c:239
av_fifo_reset2
void av_fifo_reset2(AVFifo *f)
Definition: fifo.c:280
CurlContext::cond
pthread_cond_t cond
Definition: libcurl.c:150
CurlContext::multiple_requests
int multiple_requests
Definition: libcurl.c:118
CurlContext::stream_ok
int stream_ok
Definition: libcurl.c:144
CurlLoop::avfc
AVFormatContext * avfc
Definition: libcurl.c:73
CurlLoop::total_time_us
int64_t total_time_us
Definition: libcurl.c:86
AVFifo
Definition: fifo.c:35
copy
static void copy(const float *p1, float *p2, const int length)
Definition: vf_vaguedenoiser.c:186
av_bprint_finalize
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
ff_libcurl_protocol
const URLProtocol ff_libcurl_protocol
Definition: libcurl.c:1214
AV_MUTEX_INITIALIZER
#define AV_MUTEX_INITIALIZER
Definition: thread.h:185
size
int size
Definition: twinvq_data.h:10344
CMD_UNPAUSE
@ CMD_UNPAUSE
Definition: libcurl.c:59
URLProtocol::name
const char * name
Definition: url.h:54
avg
#define avg(a, b, c, d)
Definition: colorspacedsp_template.c:28
header_callback
static size_t header_callback(char *ptr, size_t size, size_t nitems, void *userdata)
Definition: libcurl.c:259
CurlLoop::cmd_head
CurlCmd * cmd_head
Definition: libcurl.c:81
CURL_WAIT_US
#define CURL_WAIT_US
Definition: libcurl.c:52
range
enum AVColorRange range
Definition: mediacodec_wrapper.c:2594
CurlContext::off
int64_t off
Definition: libcurl.c:112
line
Definition: graph2dot.c:48
options
static const AVOption options[]
Definition: libcurl.c:1174
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
DEFAULT_USER_AGENT
#define DEFAULT_USER_AGENT
Definition: libcurl.c:47
pthread_t
Definition: os2threads.h:44
start_request
static void start_request(CurlContext *c)
Definition: libcurl.c:386
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
CurlContext::private_loop
int private_loop
Definition: libcurl.c:98
bprint.h
URLContext
Definition: url.h:35
log.h
code
and forward the test the status of outputs and forward it to the corresponding return FFERROR_NOT_READY If the filters stores internally one or a few frame for some it can consider them to be part of the FIFO and delay acknowledging a status change accordingly Example code
Definition: filter_design.txt:178
CurlLoop::mutex
pthread_mutex_t mutex
Definition: libcurl.c:79
curl_cond_wait
static void curl_cond_wait(CurlContext *c)
Definition: libcurl.c:943
CurlContext::referer
char * referer
Definition: libcurl.c:104
CurlLoop::total_bytes
int64_t total_bytes
Definition: libcurl.c:85
xferinfo_callback
static int xferinfo_callback(void *userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
Definition: libcurl.c:373
CurlContext
Definition: libcurl.c:93
s
uint8_t s
Definition: llvidencdsp.c:39
on_done
static void on_done(CurlContext *c, CURLcode code)
Definition: libcurl.c:452
CurlContext::seekable
int seekable
Definition: libcurl.c:145
FFMIN
#define FFMIN(a, b)
Definition: macros.h:49
CurlContext::key_file
char * key_file
Definition: libcurl.c:110
url.h
CURL_DEFAULT_BUFFER_SIZE
#define CURL_DEFAULT_BUFFER_SIZE
Definition: libcurl.c:48
CurlContext::request_size
int64_t request_size
Definition: libcurl.c:121
len
int len
Definition: vorbis_enc_data.h:426
pthread_cond_t
Definition: os2threads.h:58
CurlContext::hdr_accept_ranges
int hdr_accept_ranges
Definition: libcurl.c:136
CurlContext::max_retries
int max_retries
Definition: libcurl.c:123
D
#define D
Definition: libcurl.c:1172
version.h
request_size
static uint64_t request_size(URLContext *h)
Definition: http.c:1533
ret
ret
Definition: filter_design.txt:187
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:81
CurlContext::cookies
char * cookies
Definition: libcurl.c:107
ff_curl_loop_free
void ff_curl_loop_free(struct CurlLoop **loop)
Release a libcurl event loop and set *loop to NULL.
Definition: libcurl.c:759
pos
unsigned int pos
Definition: spdifenc.c:431
avformat.h
FFFormatContext::curl_loop
struct CurlLoop * curl_loop
Shared libcurl event loop, created on demand on the first use.
Definition: internal.h:127
av_bprintf
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:122
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
CurlLoop::cmd_tail
CurlCmd * cmd_tail
Definition: libcurl.c:81
left
Tag MUST be and< 10hcoeff half pel interpolation filter coefficients, hcoeff[0] are the 2 middle coefficients[1] are the next outer ones and so on, resulting in a filter like:...eff[2], hcoeff[1], hcoeff[0], hcoeff[0], hcoeff[1], hcoeff[2] ... the sign of the coefficients is not explicitly stored but alternates after each coeff and coeff[0] is positive, so ...,+,-,+,-,+,+,-,+,-,+,... hcoeff[0] is not explicitly stored but found by subtracting the sum of all stored coefficients with signs from 32 hcoeff[0]=32 - hcoeff[1] - hcoeff[2] - ... a good choice for hcoeff and htaps is htaps=6 hcoeff={40,-10, 2} an alternative which requires more computations at both encoder and decoder side and may or may not be better is htaps=8 hcoeff={42,-14, 6,-2}ref_frames minimum of the number of available reference frames and max_ref_frames for example the first frame after a key frame always has ref_frames=1spatial_decomposition_type wavelet type 0 is a 9/7 symmetric compact integer wavelet 1 is a 5/3 symmetric compact integer wavelet others are reserved stored as delta from last, last is reset to 0 if always_reset||keyframeqlog quality(logarithmic quantizer scale) stored as delta from last, last is reset to 0 if always_reset||keyframemv_scale stored as delta from last, last is reset to 0 if always_reset||keyframe FIXME check that everything works fine if this changes between framesqbias dequantization bias stored as delta from last, last is reset to 0 if always_reset||keyframeblock_max_depth maximum depth of the block tree stored as delta from last, last is reset to 0 if always_reset||keyframequant_table quantization tableHighlevel bitstream structure:==============================--------------------------------------------|Header|--------------------------------------------|------------------------------------|||Block0||||split?||||yes no||||......... intra?||||:Block01 :yes no||||:Block02 :....... ..........||||:Block03 ::y DC ::ref index:||||:Block04 ::cb DC ::motion x :||||......... :cr DC ::motion y :||||....... ..........|||------------------------------------||------------------------------------|||Block1|||...|--------------------------------------------|------------ ------------ ------------|||Y subbands||Cb subbands||Cr subbands||||--- ---||--- ---||--- ---|||||LL0||HL0||||LL0||HL0||||LL0||HL0|||||--- ---||--- ---||--- ---||||--- ---||--- ---||--- ---|||||LH0||HH0||||LH0||HH0||||LH0||HH0|||||--- ---||--- ---||--- ---||||--- ---||--- ---||--- ---|||||HL1||LH1||||HL1||LH1||||HL1||LH1|||||--- ---||--- ---||--- ---||||--- ---||--- ---||--- ---|||||HH1||HL2||||HH1||HL2||||HH1||HL2|||||...||...||...|||------------ ------------ ------------|--------------------------------------------Decoding process:=================------------|||Subbands|------------||||------------|Intra DC||||LL0 subband prediction ------------|\ Dequantization ------------------- \||Reference frames|\ IDWT|------- -------|Motion \|||Frame 0||Frame 1||Compensation . OBMC v -------|------- -------|--------------. \------> Frame n output Frame Frame<----------------------------------/|...|------------------- Range Coder:============Binary Range Coder:------------------- The implemented range coder is an adapted version based upon "Range encoding: an algorithm for removing redundancy from a digitised message." by G. N. N. Martin. The symbols encoded by the Snow range coder are bits(0|1). The associated probabilities are not fix but change depending on the symbol mix seen so far. bit seen|new state ---------+----------------------------------------------- 0|256 - state_transition_table[256 - old_state];1|state_transition_table[old_state];state_transition_table={ 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 194, 194, 195, 196, 197, 198, 199, 200, 201, 202, 202, 204, 205, 206, 207, 208, 209, 209, 210, 211, 212, 213, 215, 215, 216, 217, 218, 219, 220, 220, 222, 223, 224, 225, 226, 227, 227, 229, 229, 230, 231, 232, 234, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 248, 0, 0, 0, 0, 0, 0, 0};FIXME Range Coding of integers:------------------------- FIXME Neighboring Blocks:===================left and top are set to the respective blocks unless they are outside of the image in which case they are set to the Null block top-left is set to the top left block unless it is outside of the image in which case it is set to the left block if this block has no larger parent block or it is at the left side of its parent block and the top right block is not outside of the image then the top right block is used for top-right else the top-left block is used Null block y, cb, cr are 128 level, ref, mx and my are 0 Motion Vector Prediction:=========================1. the motion vectors of all the neighboring blocks are scaled to compensate for the difference of reference frames scaled_mv=(mv *(256 *(current_reference+1)/(mv.reference+1))+128)> the median of the scaled left
Definition: snow.txt:386
CurlCmd::done
int done
Definition: libcurl.c:68
CurlContext::h
URLContext * h
Definition: libcurl.c:95
status
ov_status_e status
Definition: dnn_backend_openvino.c:99
CurlCmd::next
struct CurlCmd * next
Definition: libcurl.c:69
CurlContext::tls_verify
int tls_verify
Definition: libcurl.c:114
AV_OPT_TYPE_INT
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition: opt.h:258
libcurl_close
static int libcurl_close(URLContext *h)
Definition: libcurl.c:1145
L
#define L(x)
Definition: vpx_arith.h:36
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
pthread_cond_wait
static av_always_inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
Definition: os2threads.h:192
CurlContext::mutex
pthread_mutex_t mutex
Definition: libcurl.c:149
CurlLoop::exit
int exit
Definition: libcurl.c:82
av_gettime
int64_t av_gettime(void)
Get the current time in microseconds.
Definition: time.c:40
CurlLoop::cond
pthread_cond_t cond
Definition: libcurl.c:80
mem.h
CurlLoop
Definition: libcurl.c:72
curl_loop_create
static CurlLoop * curl_loop_create(AVFormatContext *avfc)
Definition: libcurl.c:654
ff_http_averror
static int ff_http_averror(int status_code, int default_averror)
Definition: http.h:66
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
E
#define E
Definition: libcurl.c:1173
AV_OPT_TYPE_BOOL
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition: opt.h:326
AVIO_FLAG_NONBLOCK
#define AVIO_FLAG_NONBLOCK
Use non-blocking mode.
Definition: avio.h:636
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
CurlContext::logical_pos
int64_t logical_pos
Definition: libcurl.c:125
curl_dispatch
static int curl_dispatch(CurlLoop *loop, enum cmd_kind kind, CurlContext *c, int64_t pos, int sync)
Definition: libcurl.c:624
CurlLoop::thread
pthread_t thread
Definition: libcurl.c:75
CurlContext::hdr_content_start
int64_t hdr_content_start
Definition: libcurl.c:138
pthread_cond_timedwait
static av_always_inline int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
Definition: os2threads.h:170
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
av_fifo_freep2
void av_fifo_freep2(AVFifo **f)
Free an AVFifo and reset pointer to NULL.
Definition: fifo.c:286
AVERROR_INVALIDDATA
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:61
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:2070
AVERROR_EXIT
#define AVERROR_EXIT
Immediate exit was requested; the called function should not be restarted.
Definition: error.h:58
av_bprint_chars
void av_bprint_chars(AVBPrint *buf, char c, unsigned n)
Append char c n times to a print buffer.
Definition: bprint.c:130
CurlContext::headers
char * headers
Definition: libcurl.c:105
avstring.h
AV_OPT_TYPE_STRING
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition: opt.h:275
http.h
AV_OPT_TYPE_CONST
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition: opt.h:298
snprintf
#define snprintf
Definition: snprintf.h:34
CurlContext::is_initial
int is_initial
Definition: libcurl.c:133
CurlCmd
Definition: libcurl.c:63
line
The official guide to swscale for confused that consecutive non overlapping rectangles of slice_bottom special converter These generally are unscaled converters of common like for each output line the vertical scaler pulls lines from a ring buffer When the ring buffer does not contain the wanted line
Definition: swscale.txt:40
CurlContext::max_redirects
int max_redirects
Definition: libcurl.c:117
ff_thread_setname
static int ff_thread_setname(const char *name)
Definition: thread.h:216