FFmpeg
Loading...
Searching...
No Matches
file.c
Go to the documentation of this file.
1/*
2 * buffered file I/O
3 * Copyright (c) 2001 Fabrice Bellard
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 <string.h>
23
24#include "config_components.h"
25
26#include "libavutil/avstring.h"
27#include "libavutil/error.h"
28#include "libavutil/file_open.h"
29#include "libavutil/internal.h"
30#include "libavutil/mem.h"
31#include "libavutil/opt.h"
32#include "avio.h"
33#if HAVE_DIRENT_H
34#include <dirent.h>
35#endif
36#include <fcntl.h>
37#if HAVE_IO_H
38#include <io.h>
39#endif
40#if HAVE_UNISTD_H
41#include <unistd.h>
42#endif
43#include <sys/stat.h>
44#include <stdlib.h>
45#include "os_support.h"
46#include "url.h"
47
48/* Some systems may not have S_ISFIFO */
49#ifndef S_ISFIFO
50# ifdef S_IFIFO
51# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
52# else
53# define S_ISFIFO(m) 0
54# endif
55#endif
56
57/* Not available in POSIX.1-1996 */
58#ifndef S_ISLNK
59# ifdef S_IFLNK
60# define S_ISLNK(m) (((m) & S_IFLNK) == S_IFLNK)
61# else
62# define S_ISLNK(m) 0
63# endif
64#endif
65
66/* Not available in POSIX.1-1996 */
67#ifndef S_ISSOCK
68# ifdef S_IFSOCK
69# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
70# else
71# define S_ISSOCK(m) 0
72# endif
73#endif
74
75/* S_ISREG not available on Windows */
76#ifndef S_ISREG
77# ifdef S_IFREG
78# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
79# else
80# define S_ISREG(m) 0
81# endif
82#endif
83
84/* S_ISBLK not available on Windows */
85#ifndef S_ISBLK
86# ifdef S_IFBLK
87# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
88# else
89# define S_ISBLK(m) 0
90# endif
91#endif
92
93/* standard file protocol */
94
95typedef struct FileContext {
96 const AVClass *class;
97 int fd;
98 int trunc;
103#if HAVE_DIRENT_H
104 DIR *dir;
105#endif
106#if CONFIG_WINDOWS_HANDLE_PROTOCOL
107 int64_t handle;
108#endif
110
111static const AVOption file_options[] = {
112 { "truncate", "truncate existing files on write", offsetof(FileContext, trunc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
113 { "blocksize", "set I/O operation maximum block size", offsetof(FileContext, blocksize), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
114 { "follow", "Follow a file as it is being written", offsetof(FileContext, follow), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_DECODING_PARAM },
115 { "seekable", "Sets if the file is seekable", offsetof(FileContext, seekable), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 0, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
116 { "pkt_size", "Maximum packet size", offsetof(FileContext, pkt_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
117 { NULL }
118};
119
120static const AVOption pipe_options[] = {
121 { "blocksize", "set I/O operation maximum block size", offsetof(FileContext, blocksize), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
122 { "fd", "set file descriptor", offsetof(FileContext, fd), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
123 { NULL }
124};
125
126static const AVClass file_class = {
127 .class_name = "file",
128 .item_name = av_default_item_name,
129 .option = file_options,
130 .version = LIBAVUTIL_VERSION_INT,
131};
132
133static const AVClass pipe_class = {
134 .class_name = "pipe",
135 .item_name = av_default_item_name,
136 .option = pipe_options,
137 .version = LIBAVUTIL_VERSION_INT,
138};
139
140static const AVClass fd_class = {
141 .class_name = "fd",
142 .item_name = av_default_item_name,
143 .option = pipe_options,
144 .version = LIBAVUTIL_VERSION_INT,
145};
146
147static int file_read(URLContext *h, unsigned char *buf, int size)
148{
149 FileContext *c = h->priv_data;
150 int ret;
151 size = FFMIN(size, c->blocksize);
152 ret = read(c->fd, buf, size);
153 if (ret == 0 && c->follow)
154 return AVERROR(EAGAIN);
155 if (ret == 0)
156 return AVERROR_EOF;
157 return (ret == -1) ? AVERROR(errno) : ret;
158}
159
160static int file_write(URLContext *h, const unsigned char *buf, int size)
161{
162 FileContext *c = h->priv_data;
163 int ret;
164 size = FFMIN(size, c->blocksize);
165 ret = write(c->fd, buf, size);
166 return (ret == -1) ? AVERROR(errno) : ret;
167}
168
170{
171 FileContext *c = h->priv_data;
172 return c->fd;
173}
174
175static int file_check(URLContext *h, int mask)
176{
177 int ret = 0;
178 const char *filename = h->filename;
179 av_strstart(filename, "file:", &filename);
180
181 {
182#if HAVE_ACCESS && defined(R_OK)
183 if (access(filename, F_OK) < 0)
184 return AVERROR(errno);
186 if (access(filename, R_OK) >= 0)
189 if (access(filename, W_OK) >= 0)
191#else
192 struct stat st;
193 ret = stat(filename, &st);
194 if (ret < 0)
195 return AVERROR(errno);
196
197 ret |= st.st_mode&S_IRUSR ? mask&AVIO_FLAG_READ : 0;
198 ret |= st.st_mode&S_IWUSR ? mask&AVIO_FLAG_WRITE : 0;
199#endif
200 }
201 return ret;
202}
203
204#if CONFIG_FD_PROTOCOL || CONFIG_PIPE_PROTOCOL
205static int fd_dup(URLContext *h, int oldfd)
206{
207 int newfd;
208
209#ifdef F_DUPFD_CLOEXEC
210 newfd = fcntl(oldfd, F_DUPFD_CLOEXEC, 0);
211#else
212 newfd = dup(oldfd);
213#endif
214 if (newfd == -1)
215 return newfd;
216
217#if HAVE_FCNTL
218 if (fcntl(newfd, F_SETFD, FD_CLOEXEC) == -1)
219 av_log(h, AV_LOG_DEBUG, "Failed to set close on exec\n");
220#endif
221
222#if HAVE_SETMODE
223 setmode(newfd, O_BINARY);
224#endif
225 return newfd;
226}
227#endif
228
229#if CONFIG_FD_PROTOCOL || CONFIG_PIPE_PROTOCOL || CONFIG_WINDOWS_HANDLE_PROTOCOL
230/* Without a check, avio_check() would open the descriptor, rewinding seekable
231 * output. It cannot pass the option selecting the descriptor, so just fail. */
232static int fd_check(URLContext *h, int mask)
233{
234 return AVERROR(ENOSYS);
235}
236#endif
237
239{
240 FileContext *c = h->priv_data;
241 int ret = close(c->fd);
242 return (ret == -1) ? AVERROR(errno) : 0;
243}
244
245/* XXX: use llseek */
247{
248 FileContext *c = h->priv_data;
249 int64_t ret;
250
251 if (c->follow && (whence == SEEK_END || whence == AVSEEK_SIZE))
252 return AVERROR(ENOSYS); /* true size is not known */
253
254 if (whence == AVSEEK_SIZE) {
255 struct stat st;
256 ret = fstat(c->fd, &st);
257 return ret < 0 ? AVERROR(errno) : (S_ISFIFO(st.st_mode) ? 0 : st.st_size);
258 }
259
260 ret = lseek(c->fd, pos, whence);
261
262 return ret < 0 ? AVERROR(errno) : ret;
263}
264
265#if CONFIG_FILE_PROTOCOL
266
267static int file_delete(URLContext *h)
268{
269#if HAVE_UNISTD_H
270 int ret;
271 const char *filename = h->filename;
272 av_strstart(filename, "file:", &filename);
273
274 ret = rmdir(filename);
275 if (ret < 0 && (errno == ENOTDIR
276# ifdef _WIN32
277 || errno == EINVAL
278# endif
279 ))
280 ret = unlink(filename);
281 if (ret < 0)
282 return AVERROR(errno);
283
284 return ret;
285#else
286 return AVERROR(ENOSYS);
287#endif /* HAVE_UNISTD_H */
288}
289
290static int file_move(URLContext *h_src, URLContext *h_dst)
291{
292 const char *filename_src = h_src->filename;
293 const char *filename_dst = h_dst->filename;
294 av_strstart(filename_src, "file:", &filename_src);
295 av_strstart(filename_dst, "file:", &filename_dst);
296
297 if (rename(filename_src, filename_dst) < 0)
298 return AVERROR(errno);
299
300 return 0;
301}
302
303static int file_open(URLContext *h, const char *filename, int flags)
304{
305 FileContext *c = h->priv_data;
306 int access;
307 int fd;
308 struct stat st;
309
310 av_strstart(filename, "file:", &filename);
311
313 access = O_CREAT | O_RDWR;
314 if (c->trunc)
315 access |= O_TRUNC;
316 } else if (flags & AVIO_FLAG_WRITE) {
317 access = O_CREAT | O_WRONLY;
318 if (c->trunc)
319 access |= O_TRUNC;
320 } else {
321 access = O_RDONLY;
322 }
323#ifdef O_BINARY
324 access |= O_BINARY;
325#endif
326 fd = avpriv_open(filename, access, 0666);
327 if (fd == -1)
328 return AVERROR(errno);
329 c->fd = fd;
330
331 h->is_streamed = !fstat(fd, &st) && S_ISFIFO(st.st_mode);
332
333 if (c->pkt_size) {
334 h->max_packet_size = c->pkt_size;
335 } else {
336 /* Buffer writes more than the default 32k to improve throughput especially
337 * with networked file systems */
338 if (!h->is_streamed && flags & AVIO_FLAG_WRITE)
339 h->max_packet_size = 262144;
340 }
341 /* Disable per-packet flushing by default to improve throughput especially
342 * with networked file systems */
343 if (!h->is_streamed && flags & AVIO_FLAG_WRITE)
344 h->min_packet_size = h->max_packet_size;
345
346 if (c->seekable >= 0)
347 h->is_streamed = !c->seekable;
348
349 return 0;
350}
351
352static int file_open_dir(URLContext *h)
353{
354#if HAVE_LSTAT
355 FileContext *c = h->priv_data;
356
357 c->dir = opendir(h->filename);
358 if (!c->dir)
359 return AVERROR(errno);
360
361 return 0;
362#else
363 return AVERROR(ENOSYS);
364#endif /* HAVE_LSTAT */
365}
366
367static int file_read_dir(URLContext *h, AVIODirEntry **next)
368{
369#if HAVE_LSTAT
370 FileContext *c = h->priv_data;
371 struct dirent *dir;
372 char *fullpath = NULL;
373
374 *next = ff_alloc_dir_entry();
375 if (!*next)
376 return AVERROR(ENOMEM);
377 do {
378 errno = 0;
379 dir = readdir(c->dir);
380 if (!dir) {
381 av_freep(next);
382 return AVERROR(errno);
383 }
384 } while (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."));
385
386 fullpath = av_append_path_component(h->filename, dir->d_name);
387 if (fullpath) {
388 struct stat st;
389 if (!lstat(fullpath, &st)) {
390 if (S_ISDIR(st.st_mode))
391 (*next)->type = AVIO_ENTRY_DIRECTORY;
392 else if (S_ISFIFO(st.st_mode))
393 (*next)->type = AVIO_ENTRY_NAMED_PIPE;
394 else if (S_ISCHR(st.st_mode))
395 (*next)->type = AVIO_ENTRY_CHARACTER_DEVICE;
396 else if (S_ISBLK(st.st_mode))
397 (*next)->type = AVIO_ENTRY_BLOCK_DEVICE;
398 else if (S_ISLNK(st.st_mode))
399 (*next)->type = AVIO_ENTRY_SYMBOLIC_LINK;
400 else if (S_ISSOCK(st.st_mode))
401 (*next)->type = AVIO_ENTRY_SOCKET;
402 else if (S_ISREG(st.st_mode))
403 (*next)->type = AVIO_ENTRY_FILE;
404 else
405 (*next)->type = AVIO_ENTRY_UNKNOWN;
406
407 (*next)->group_id = st.st_gid;
408 (*next)->user_id = st.st_uid;
409 (*next)->size = st.st_size;
410 (*next)->filemode = st.st_mode & 0777;
411 (*next)->modification_timestamp = INT64_C(1000000) * st.st_mtime;
412 (*next)->access_timestamp = INT64_C(1000000) * st.st_atime;
413 (*next)->status_change_timestamp = INT64_C(1000000) * st.st_ctime;
414 }
415 av_free(fullpath);
416 }
417
418 (*next)->name = av_strdup(dir->d_name);
419 return (*next)->name ? 0 : AVERROR(ENOMEM);
420#else
421 return AVERROR(ENOSYS);
422#endif /* HAVE_LSTAT */
423}
424
425static int file_close_dir(URLContext *h)
426{
427#if HAVE_LSTAT
428 FileContext *c = h->priv_data;
429 closedir(c->dir);
430 return 0;
431#else
432 return AVERROR(ENOSYS);
433#endif /* HAVE_LSTAT */
434}
435
437 .name = "file",
438 .url_open = file_open,
439 .url_read = file_read,
440 .url_write = file_write,
441 .url_seek = file_seek,
442 .url_close = file_close,
443 .url_get_file_handle = file_get_handle,
444 .url_check = file_check,
445 .url_delete = file_delete,
446 .url_move = file_move,
447 .priv_data_size = sizeof(FileContext),
448 .priv_data_class = &file_class,
449 .url_open_dir = file_open_dir,
450 .url_read_dir = file_read_dir,
451 .url_close_dir = file_close_dir,
452 .default_whitelist = "file,crypto,data"
453};
454
455#endif /* CONFIG_FILE_PROTOCOL */
456
457#if CONFIG_PIPE_PROTOCOL
458
459static int pipe_open(URLContext *h, const char *filename, int flags)
460{
461 FileContext *c = h->priv_data;
462 int fd;
463 char *final;
464
465 if (c->fd < 0) {
466 av_strstart(filename, "pipe:", &filename);
467
468 if (!*filename) {
469 if (flags & AVIO_FLAG_WRITE) {
470 fd = 1;
471 } else {
472 fd = 0;
473 }
474 } else {
475 fd = strtol(filename, &final, 10);
476 if (*final) /* No digits found, or something like 10ab */
477 return AVERROR(EINVAL);
478 }
479 c->fd = fd;
480 }
481
482 c->fd = fd_dup(h, c->fd);
483 if (c->fd == -1)
484 return AVERROR(errno);
485 h->is_streamed = 1;
486 return 0;
487}
488
490 .name = "pipe",
491 .url_open = pipe_open,
492 .url_read = file_read,
493 .url_write = file_write,
494 .url_close = file_close,
495 .url_get_file_handle = file_get_handle,
496 .url_check = fd_check,
497 .priv_data_size = sizeof(FileContext),
498 .priv_data_class = &pipe_class,
499 .default_whitelist = "crypto,data"
500};
501
502#endif /* CONFIG_PIPE_PROTOCOL */
503
504#if CONFIG_FD_PROTOCOL
505
506static int fd_open(URLContext *h, const char *filename, int flags)
507{
508 FileContext *c = h->priv_data;
509 struct stat st;
510
511 if (strcmp(filename, "fd:") != 0) {
512 av_log(h, AV_LOG_ERROR, "Doesn't support pass file descriptor via URL,"
513 " please set it via -fd {num}\n");
514 return AVERROR(EINVAL);
515 }
516
517 if (c->fd < 0) {
518 if (flags & AVIO_FLAG_WRITE) {
519 c->fd = 1;
520 } else {
521 c->fd = 0;
522 }
523 }
524 if (fstat(c->fd, &st) < 0)
525 return AVERROR(errno);
526 h->is_streamed = !(S_ISREG(st.st_mode) || S_ISBLK(st.st_mode));
527 c->fd = fd_dup(h, c->fd);
528 if (c->fd == -1)
529 return AVERROR(errno);
530
531 return 0;
532}
533
535 .name = "fd",
536 .url_open = fd_open,
537 .url_read = file_read,
538 .url_write = file_write,
539 .url_seek = file_seek,
540 .url_close = file_close,
541 .url_get_file_handle = file_get_handle,
542 .url_check = fd_check,
543 .priv_data_size = sizeof(FileContext),
544 .priv_data_class = &fd_class,
545 .default_whitelist = "crypto,data"
546};
547
548#endif /* CONFIG_FD_PROTOCOL */
549
550#if CONFIG_WINDOWS_HANDLE_PROTOCOL
551
552#include <windows.h>
553
554static const AVOption windows_handle_options[] = {
555 { "blocksize", "set I/O operation maximum block size", offsetof(FileContext, blocksize), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
556 { "handle", "set Windows handle", offsetof(FileContext, handle), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, AV_OPT_FLAG_ENCODING_PARAM },
557 { NULL }
558};
559
560static const AVClass windows_handle_class = {
561 .class_name = "windows_handle",
562 .item_name = av_default_item_name,
563 .option = windows_handle_options,
564 .version = LIBAVUTIL_VERSION_INT,
565};
566
567static int windows_handle_open(URLContext *h, const char *filename, int flags)
568{
569 FileContext *c = h->priv_data;
570 HANDLE handle = (HANDLE)(intptr_t)c->handle;
571 HANDLE dup_handle;
572 int fd;
573 struct stat st;
574
575 if (strcmp(filename, "handle:") != 0) {
576 av_log(h, AV_LOG_ERROR, "Doesn't support passing Windows handles via URL,"
577 " please set it via -handle {num}\n");
578 return AVERROR(EINVAL);
579 }
580
581 if (handle == INVALID_HANDLE_VALUE || !handle) {
583 handle = GetStdHandle(STD_OUTPUT_HANDLE);
584 else
585 handle = GetStdHandle(STD_INPUT_HANDLE);
586 if (handle == INVALID_HANDLE_VALUE || !handle)
587 return AVERROR(EBADF);
588 }
589
590 if (!DuplicateHandle(GetCurrentProcess(), handle,
591 GetCurrentProcess(), &dup_handle,
592 0, FALSE, DUPLICATE_SAME_ACCESS))
593 return GetLastError() == ERROR_INVALID_HANDLE ? AVERROR(EBADF)
594 : AVERROR(EIO);
595
596 fd = _open_osfhandle((intptr_t)dup_handle, O_BINARY);
597 if (fd == -1) {
598 CloseHandle(dup_handle);
599 return AVERROR(errno);
600 }
601
602 if (fstat(fd, &st) < 0) {
603 close(fd);
604 return AVERROR(errno);
605 }
606
607 c->fd = fd;
608 h->is_streamed = !(S_ISREG(st.st_mode) || S_ISBLK(st.st_mode));
609
610 return 0;
611}
612
614 .name = "handle",
615 .url_open = windows_handle_open,
616 .url_read = file_read,
617 .url_write = file_write,
618 .url_seek = file_seek,
619 .url_close = file_close,
620 .url_get_file_handle = file_get_handle,
621 .url_check = fd_check,
622 .priv_data_size = sizeof(FileContext),
623 .priv_data_class = &windows_handle_class,
624 .default_whitelist = "crypto,data"
625};
626
627#endif /* CONFIG_WINDOWS_HANDLE_PROTOCOL */
628
629#if CONFIG_ANDROID_CONTENT_PROTOCOL
630#include <jni.h>
631#include "libavcodec/ffjni.h"
632#include "libavcodec/jni.h"
633
634typedef struct JFields {
635 jclass uri_class;
636 jmethodID parse_id;
637
638 jclass context_class;
639 jmethodID get_content_resolver_id;
640
641 jclass content_resolver_class;
642 jmethodID open_file_descriptor_id;
643
644 jclass parcel_file_descriptor_class;
645 jmethodID detach_fd_id;
646} JFields;
647
648#define OFFSET(x) offsetof(JFields, x)
649static const struct FFJniField jfields_mapping[] = {
650 { "android/net/Uri", NULL, NULL, FF_JNI_CLASS, OFFSET(uri_class), 1 },
651 { "android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", FF_JNI_STATIC_METHOD, OFFSET(parse_id), 1 },
652
653 { "android/content/Context", NULL, NULL, FF_JNI_CLASS, OFFSET(context_class), 1 },
654 { "android/content/Context", "getContentResolver", "()Landroid/content/ContentResolver;", FF_JNI_METHOD, OFFSET(get_content_resolver_id), 1 },
655
656 { "android/content/ContentResolver", NULL, NULL, FF_JNI_CLASS, OFFSET(content_resolver_class), 1 },
657 { "android/content/ContentResolver", "openFileDescriptor", "(Landroid/net/Uri;Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;", FF_JNI_METHOD, OFFSET(open_file_descriptor_id), 1 },
658
659 { "android/os/ParcelFileDescriptor", NULL, NULL, FF_JNI_CLASS, OFFSET(parcel_file_descriptor_class), 1 },
660 { "android/os/ParcelFileDescriptor", "detachFd", "()I", FF_JNI_METHOD, OFFSET(detach_fd_id), 1 },
661
662 { NULL }
663};
664#undef OFFSET
665
666static int android_content_open(URLContext *h, const char *filename, int flags)
667{
668 FileContext *c = h->priv_data;
669 int fd, ret;
670 struct stat st;
671 const char *mode_str = "r";
672
673 JNIEnv *env;
674 JFields jfields = { 0 };
675 jobject application_context = NULL;
676 jobject url = NULL;
677 jobject mode = NULL;
678 jobject uri = NULL;
679 jobject content_resolver = NULL;
680 jobject parcel_file_descriptor = NULL;
681
682 env = ff_jni_get_env(c);
683 if (!env) {
684 return AVERROR(EINVAL);
685 }
686
687 ret = ff_jni_init_jfields(env, &jfields, jfields_mapping, 0, c);
688 if (ret < 0) {
689 av_log(c, AV_LOG_ERROR, "failed to initialize jni fields\n");
690 return ret;
691 }
692
693 application_context = av_jni_get_android_app_ctx();
694 if (!application_context) {
695 av_log(c, AV_LOG_ERROR, "application context is not set\n");
697 goto done;
698 }
699
700 url = ff_jni_utf_chars_to_jstring(env, filename, c);
701 if (!url) {
703 goto done;
704 }
705
707 mode_str = "rw";
708 else if (flags & AVIO_FLAG_WRITE)
709 mode_str = "w";
710
711 mode = ff_jni_utf_chars_to_jstring(env, mode_str, c);
712 if (!mode) {
714 goto done;
715 }
716
717 uri = (*env)->CallStaticObjectMethod(env, jfields.uri_class, jfields.parse_id, url);
718 ret = ff_jni_exception_check(env, 1, c);
719 if (ret < 0)
720 goto done;
721
722 content_resolver = (*env)->CallObjectMethod(env, application_context, jfields.get_content_resolver_id);
723 ret = ff_jni_exception_check(env, 1, c);
724 if (ret < 0)
725 goto done;
726
727 parcel_file_descriptor = (*env)->CallObjectMethod(env, content_resolver, jfields.open_file_descriptor_id, uri, mode);
728 ret = ff_jni_exception_check(env, 1, c);
729 if (ret < 0)
730 goto done;
731 if (!parcel_file_descriptor) {
732 av_log(c, AV_LOG_ERROR, "file descriptor is null\n");
734 goto done;
735 }
736
737 fd = (*env)->CallIntMethod(env, parcel_file_descriptor, jfields.detach_fd_id);
738 ret = ff_jni_exception_check(env, 1, c);
739 if (ret < 0)
740 goto done;
741
742 if (fstat(fd, &st) < 0) {
743 ret = AVERROR(errno);
744 close(fd);
745 goto done;
746 }
747
748 c->fd = fd;
749 h->is_streamed = !(S_ISREG(st.st_mode) || S_ISBLK(st.st_mode));
750
751done:
752 (*env)->DeleteLocalRef(env, url);
753 (*env)->DeleteLocalRef(env, mode);
754 (*env)->DeleteLocalRef(env, uri);
755 (*env)->DeleteLocalRef(env, content_resolver);
756 (*env)->DeleteLocalRef(env, parcel_file_descriptor);
757 ff_jni_reset_jfields(env, &jfields, jfields_mapping, 0, c);
758
759 return ret;
760}
761
762static const AVOption android_content_options[] = {
763 { "blocksize", "set I/O operation maximum block size", offsetof(FileContext, blocksize), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
764 { NULL }
765};
766
767static const AVClass android_content_class = {
768 .class_name = "android_content",
769 .item_name = av_default_item_name,
770 .option = android_content_options,
771 .version = LIBAVUTIL_VERSION_INT,
772};
773
775 .name = "content",
776 .url_open = android_content_open,
777 .url_read = file_read,
778 .url_write = file_write,
779 .url_seek = file_seek,
780 .url_close = file_close,
781 .url_get_file_handle = file_get_handle,
782 .priv_data_size = sizeof(FileContext),
783 .priv_data_class = &android_content_class,
784};
785
786#endif /* CONFIG_ANDROID_CONTENT_PROTOCOL */
Buffered I/O operations.
#define AVIO_FLAG_READ
read-only
Definition avio.h:630
#define AVSEEK_SIZE
Passing this as the "whence" parameter to a seek function causes it to return the filesize without se...
Definition avio.h:481
#define AVIO_FLAG_WRITE
write-only
Definition avio.h:631
@ AVIO_ENTRY_UNKNOWN
Definition avio.h:68
@ AVIO_ENTRY_NAMED_PIPE
Definition avio.h:72
@ AVIO_ENTRY_BLOCK_DEVICE
Definition avio.h:69
@ AVIO_ENTRY_SYMBOLIC_LINK
Definition avio.h:73
@ AVIO_ENTRY_DIRECTORY
Definition avio.h:71
@ AVIO_ENTRY_CHARACTER_DEVICE
Definition avio.h:70
@ AVIO_ENTRY_FILE
Definition avio.h:75
@ AVIO_ENTRY_SOCKET
Definition avio.h:74
static uint32_t BS_FUNC read(BSCTX *bc, unsigned int n)
Return n bits from the buffer, n has to be in the 0-32 range.
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static __device__ float trunc(float a)
error code definitions
@ FF_JNI_CLASS
Definition ffjni.h:91
@ FF_JNI_METHOD
Definition ffjni.h:94
@ FF_JNI_STATIC_METHOD
Definition ffjni.h:95
#define OFFSET(x)
int ret
Definition ffplay.c:391
SDL_atomic_t done
Definition ffplay.c:392
#define AV_OPT_FLAG_DECODING_PARAM
A generic parameter which can be set by the user for demuxing or decoding.
Definition opt.h:355
#define AV_OPT_FLAG_ENCODING_PARAM
A generic parameter which can be set by the user for muxing or encoding.
Definition opt.h:351
@ AV_OPT_TYPE_INT64
Underlying C type is int64_t.
Definition opt.h:262
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition error.h:59
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:247
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
char * av_append_path_component(const char *path, const char *component)
Append path component to the existing path.
Definition avstring.c:295
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
void * av_jni_get_android_app_ctx(void)
av_cold void CBS_FUNC close(CodedBitstreamContext **ctx_ptr)
Close a context and free all internal state.
Definition cbs.c:118
int ff_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx)
Definition ffjni.c:279
jstring ff_jni_utf_chars_to_jstring(JNIEnv *env, const char *utf_chars, void *log_ctx)
Definition ffjni.c:129
int ff_jni_reset_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx)
Definition ffjni.c:368
int ff_jni_exception_check(JNIEnv *env, int log, void *log_ctx)
Definition ffjni.c:246
JNIEnv * ff_jni_get_env(void *log_ctx)
Definition ffjni.c:53
static int file_get_handle(URLContext *h)
Definition file.c:169
static const AVClass fd_class
Definition file.c:140
static const AVClass file_class
Definition file.c:126
static int file_write(URLContext *h, const unsigned char *buf, int size)
Definition file.c:160
static int file_close(URLContext *h)
Definition file.c:238
static const AVOption file_options[]
Definition file.c:111
#define S_ISBLK(m)
Definition file.c:89
#define S_ISSOCK(m)
Definition file.c:71
#define S_ISFIFO(m)
Definition file.c:53
static const AVOption pipe_options[]
Definition file.c:120
#define S_ISLNK(m)
Definition file.c:62
static int64_t file_seek(URLContext *h, int64_t pos, int whence)
Definition file.c:246
static int file_read(URLContext *h, unsigned char *buf, int size)
Definition file.c:147
static const AVClass pipe_class
Definition file.c:133
#define S_ISREG(m)
Definition file.c:80
static int file_check(URLContext *h, int mask)
Definition file.c:175
int avpriv_open(const char *filename, int flags,...)
A wrapper for open() setting O_CLOEXEC.
Definition file_open.c:67
common internal API header
static const uint16_t mask[17]
Definition lzw.c:38
#define FFMIN(a, b)
Definition macros.h:49
Memory handling functions.
#define av_strdup(s)
Definition ops_static.c:55
AVOptions.
miscellaneous OS support macros and functions.
#define O_BINARY
Definition os_support.h:36
const URLProtocol ff_file_protocol
const URLProtocol ff_windows_handle_protocol
const URLProtocol ff_android_content_protocol
const URLProtocol ff_pipe_protocol
const URLProtocol ff_fd_protocol
unsigned int pos
Definition spdifenc.c:431
Describe the class of an AVClass context structure.
Definition log.h:76
Describes single entry of the directory.
Definition avio.h:87
AVOption.
Definition opt.h:428
int follow
Definition file.c:101
int trunc
Definition file.c:98
int seekable
Definition file.c:102
int fd
Definition file.c:97
int blocksize
Definition file.c:99
int pkt_size
Definition file.c:100
char * filename
specified URL
Definition url.h:39
Definition swscale.c:85
#define av_free(p)
#define av_freep(p)
#define av_log(a,...)
int size
AVIODirEntry * ff_alloc_dir_entry(void)
Allocate directory entry with default values.
Definition url.c:327
unbuffered private I/O API
static double c[64]