/* * Copyright (c) 2020-2021 Taner Sener * * This file is part of FFmpegKit. * * FFmpegKit is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * FFmpegKit is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with FFmpegKit. If not, see . */ #include #include #include #include "config.h" #include "libavformat/avformat.h" #include "libavutil/avstring.h" #include "saf_wrapper.h" /** JNI wrapper in ffmpegkit.c */ void closeParcelFileDescriptor(int fd); // in these wrappers, we call the original functions, so we remove the shadow defines #undef avio_closep #undef avformat_close_input #undef avio_open #undef avio_open2 #undef avformat_open_input static int fd_read_packet(void* opaque, uint8_t* buf, int buf_size) { int fd = (int)opaque; return read(fd, buf, buf_size); } static int fd_write_packet(void* opaque, uint8_t* buf, int buf_size) { int fd = (int)opaque; return write(fd, buf, buf_size); } static int64_t fd_seek(void *opaque, int64_t offset, int whence) { int fd = (int)opaque; if (fd < 0) { return AVERROR(EINVAL); } int64_t ret; if (whence == AVSEEK_SIZE) { struct stat st; ret = fstat(fd, &st); return ret < 0 ? AVERROR(errno) : (S_ISFIFO(st.st_mode) ? 0 : st.st_size); } ret = lseek(fd, offset, whence); return ret < 0 ? AVERROR(errno) : ret; } /* * returns NULL if the filename is not of expected format (e.g. 'saf:72/video.md4') */ static AVIOContext *create_fd_avio_context(const char *filename, int flags) { union {int fd; void* opaque;} fdunion; fdunion.fd = -1; const char *fd_ptr = NULL; if (av_strstart(filename, "saf:", &fd_ptr)) { char *final; fdunion.fd = strtol(fd_ptr, &final, 10); if (fd_ptr == final) { /* No digits found */ fdunion.fd = -1; } } if (fdunion.fd >= 0) { int write_flag = flags & AVIO_FLAG_WRITE ? 1 : 0; return avio_alloc_context(av_malloc(4096), 4096, write_flag, fdunion.opaque, fd_read_packet, write_flag ? fd_write_packet : NULL, fd_seek); } return NULL; } static void close_fd_avio_context(AVIOContext *ctx) { if (fd_seek(ctx->opaque, 0, AVSEEK_SIZE) >= 0) { int fd = (int)ctx->opaque; close(fd); closeParcelFileDescriptor(fd); } ctx->opaque = NULL; } int android_avformat_open_input(AVFormatContext **ps, const char *filename, ff_const59 AVInputFormat *fmt, AVDictionary **options) { if (!(*ps) && !(*ps = avformat_alloc_context())) return AVERROR(ENOMEM); (*ps)->pb = create_fd_avio_context(filename, AVIO_FLAG_READ); return avformat_open_input(ps, filename, fmt, options); } int android_avio_open2(AVIOContext **s, const char *filename, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options) { AVIOContext *fd_context = create_fd_avio_context(filename, flags); if (fd_context) { *s = fd_context; return 0; } return avio_open2(s, filename, flags, int_cb, options); } int android_avio_open(AVIOContext **s, const char *url, int flags) { return android_avio_open2(s, url, flags, NULL, NULL); } int android_avio_closep(AVIOContext **s) { close_fd_avio_context(*s); return avio_closep(s); } void android_avformat_close_input(AVFormatContext **ps) { if (*ps && (*ps)->pb) { close_fd_avio_context((*ps)->pb); } avformat_close_input(ps); }