implement custom ffmpeg-kit protocols for android, fixes #39
This commit is contained in:
parent
de101cf731
commit
c356b059c7
|
@ -121,6 +121,9 @@ while [ ! $# -eq 0 ]; do
|
||||||
|
|
||||||
export API=${API_LEVEL}
|
export API=${API_LEVEL}
|
||||||
;;
|
;;
|
||||||
|
--no-ffmpeg-kit-protocols)
|
||||||
|
export NO_FFMPEG_KIT_PROTOCOLS="1"
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
print_unknown_option "$1"
|
print_unknown_option "$1"
|
||||||
;;
|
;;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "libavcodec/jni.h"
|
#include "libavcodec/jni.h"
|
||||||
#include "libavutil/bprint.h"
|
#include "libavutil/bprint.h"
|
||||||
|
#include "libavutil/file.h"
|
||||||
#include "fftools_ffmpeg.h"
|
#include "fftools_ffmpeg.h"
|
||||||
#include "ffmpegkit.h"
|
#include "ffmpegkit.h"
|
||||||
#include "ffprobekit.h"
|
#include "ffprobekit.h"
|
||||||
|
@ -560,12 +561,13 @@ void *callbackThreadFunction() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by saf_wrapper; is expected to be called from a Java thread, therefore we don't need attach/detach
|
* Used by fd and saf protocols; is expected to be called from a Java thread, therefore we don't need attach/detach
|
||||||
*/
|
*/
|
||||||
void closeParcelFileDescriptor(int fd) {
|
int close_parcel_file_descriptor(int fd) {
|
||||||
JNIEnv *env = NULL;
|
JNIEnv *env = NULL;
|
||||||
(*globalVm)->GetEnv(globalVm, (void**) &env, JNI_VERSION_1_6);
|
(*globalVm)->GetEnv(globalVm, (void**) &env, JNI_VERSION_1_6);
|
||||||
(*env)->CallStaticVoidMethod(env, configClass, closeParcelFileDescriptorMethod, fd);
|
(*env)->CallStaticVoidMethod(env, configClass, closeParcelFileDescriptorMethod, fd);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -643,6 +645,8 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||||
|
|
||||||
redirectionEnabled = 0;
|
redirectionEnabled = 0;
|
||||||
|
|
||||||
|
av_set_fd_close(close_parcel_file_descriptor);
|
||||||
|
|
||||||
return JNI_VERSION_1_6;
|
return JNI_VERSION_1_6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,8 +51,6 @@
|
||||||
#include "libavformat/avformat.h"
|
#include "libavformat/avformat.h"
|
||||||
#include "libswscale/swscale.h"
|
#include "libswscale/swscale.h"
|
||||||
|
|
||||||
#include "saf_wrapper.h"
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#undef main /* We don't want SDL to override our main() */
|
#undef main /* We don't want SDL to override our main() */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,139 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#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) {
|
|
||||||
return read(*(int*)opaque, buf, buf_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fd_write_packet(void* opaque, uint8_t* buf, int buf_size) {
|
|
||||||
return write(*(int*)opaque, buf, buf_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int64_t fd_seek(void *opaque, int64_t offset, int whence) {
|
|
||||||
int *fd = 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) {
|
|
||||||
int fd = -1;
|
|
||||||
const char* fd_ptr = NULL;
|
|
||||||
|
|
||||||
if (av_strstart(filename, "saf:", &fd_ptr)) {
|
|
||||||
char *final;
|
|
||||||
fd = strtol(fd_ptr, &final, 10);
|
|
||||||
if (fd_ptr == final) { /* No digits found */
|
|
||||||
fd = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fd >= 0) {
|
|
||||||
int *opaque = av_mallocz(sizeof(int));
|
|
||||||
*opaque = fd;
|
|
||||||
int write_flag = flags & AVIO_FLAG_WRITE ? 1 : 0;
|
|
||||||
return avio_alloc_context(av_malloc(4096), 4096, write_flag, opaque, fd_read_packet, write_flag ? fd_write_packet : NULL, fd_seek);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void close_fd_avio_context(AVIOContext *ctx) {
|
|
||||||
if (ctx) {
|
|
||||||
int *fd = ctx->opaque;
|
|
||||||
if (fd_seek((void*)fd, 0, AVSEEK_SIZE) >= 0) {
|
|
||||||
closeParcelFileDescriptor(*fd);
|
|
||||||
av_freep(&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);
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FFMPEG_KIT_SAF_WRAPPER_H
|
|
||||||
#define FFMPEG_KIT_SAF_WRAPPER_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
* These wrappers are intended to be used instead of the ffmpeg apis.
|
|
||||||
* You don't even need to change the source to call them.
|
|
||||||
* Instead, we redefine the public api names so that the wrapper be used.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int android_avio_closep(AVIOContext **s);
|
|
||||||
#define avio_closep android_avio_closep
|
|
||||||
|
|
||||||
void android_avformat_close_input(AVFormatContext **s);
|
|
||||||
#define avformat_close_input android_avformat_close_input
|
|
||||||
|
|
||||||
int android_avio_open(AVIOContext **s, const char *url, int flags);
|
|
||||||
#define avio_open android_avio_open
|
|
||||||
|
|
||||||
int android_avio_open2(AVIOContext **s, const char *url, int flags,
|
|
||||||
const AVIOInterruptCB *int_cb, AVDictionary **options);
|
|
||||||
#define avio_open2 android_avio_open2
|
|
||||||
|
|
||||||
int android_avformat_open_input(AVFormatContext **ps, const char *filename,
|
|
||||||
ff_const59 AVInputFormat *fmt, AVDictionary **options);
|
|
||||||
#define avformat_open_input android_avformat_open_input
|
|
||||||
|
|
||||||
#endif //FFMPEG_KIT_SAF_WRAPPER_H
|
|
|
@ -40,6 +40,7 @@ import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.StringTokenizer;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
@ -831,6 +832,20 @@ public class FFmpegKitConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String extractExtensionFromSafDisplayName(final String safDisplayName) {
|
||||||
|
String rawExtension = safDisplayName;
|
||||||
|
if (safDisplayName.lastIndexOf(".") >= 0) {
|
||||||
|
rawExtension = safDisplayName.substring(safDisplayName.lastIndexOf("."));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// workaround for https://issuetracker.google.com/issues/162440528: ANDROID_CREATE_DOCUMENT generating file names like "transcode.mp3 (2)"
|
||||||
|
return new StringTokenizer(rawExtension, " .").nextToken();
|
||||||
|
} catch (final Exception e) {
|
||||||
|
android.util.Log.w(TAG, String.format("Failed to extract extension from saf display name: %s.%s", safDisplayName, Exceptions.getStackTraceString(e)));
|
||||||
|
return "raw";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Converts the given Structured Access Framework Uri (<code>"content:…"</code>) into an
|
* <p>Converts the given Structured Access Framework Uri (<code>"content:…"</code>) into an
|
||||||
* input/output url that can be used in FFmpeg and FFprobe commands.
|
* input/output url that can be used in FFmpeg and FFprobe commands.
|
||||||
|
@ -863,14 +878,7 @@ public class FFmpegKitConfig {
|
||||||
android.util.Log.e(TAG, String.format("Failed to obtain %s parcelFileDescriptor for %s.%s", openMode, uri.toString(), Exceptions.getStackTraceString(t)));
|
android.util.Log.e(TAG, String.format("Failed to obtain %s parcelFileDescriptor for %s.%s", openMode, uri.toString(), Exceptions.getStackTraceString(t)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// workaround for https://issuetracker.google.com/issues/162440528: ANDROID_CREATE_DOCUMENT generating file names like "transcode.mp3 (2)"
|
return "saf:" + fd + "." + FFmpegKitConfig.extractExtensionFromSafDisplayName(displayName);
|
||||||
if (displayName.lastIndexOf('.') > 0 && displayName.lastIndexOf(' ') > displayName.lastIndexOf('.')) {
|
|
||||||
String extension = displayName.substring(displayName.lastIndexOf('.'), displayName.lastIndexOf(' '));
|
|
||||||
displayName += extension;
|
|
||||||
}
|
|
||||||
// spaces can break argument list parsing, see https://github.com/alexcohn/mobile-ffmpeg/pull/1#issuecomment-688643836
|
|
||||||
final char NBSP = (char) 0xa0;
|
|
||||||
return "saf:" + fd + "/" + displayName.replace(' ', NBSP);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -32,6 +32,10 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public class FFmpegKitConfigTest {
|
public class FFmpegKitConfigTest {
|
||||||
|
|
||||||
|
static {
|
||||||
|
System.setProperty("enable.ffmpeg.kit.test.mode", "true");
|
||||||
|
}
|
||||||
|
|
||||||
private static final String externalLibrariesCommandOutput = " configuration:\n" +
|
private static final String externalLibrariesCommandOutput = " configuration:\n" +
|
||||||
" --cross-prefix=i686-linux-android-\n" +
|
" --cross-prefix=i686-linux-android-\n" +
|
||||||
" --sysroot=/Users/taner/Library/Android/sdk/ndk-bundle/toolchains/ffmpeg-kit-i686/sysroot\n" +
|
" --sysroot=/Users/taner/Library/Android/sdk/ndk-bundle/toolchains/ffmpeg-kit-i686/sysroot\n" +
|
||||||
|
@ -152,6 +156,21 @@ public class FFmpegKitConfigTest {
|
||||||
Assert.assertEquals("https-gpl", listToPackageName(Arrays.asList("gnutls", "xvidcore")));
|
Assert.assertEquals("https-gpl", listToPackageName(Arrays.asList("gnutls", "xvidcore")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void extractExtensionFromSafDisplayName() {
|
||||||
|
String extension = FFmpegKitConfig.extractExtensionFromSafDisplayName("video.mp4 (2)");
|
||||||
|
Assert.assertEquals("mp4", extension);
|
||||||
|
|
||||||
|
extension = FFmpegKitConfig.extractExtensionFromSafDisplayName("video file name.mp3 (2)");
|
||||||
|
Assert.assertEquals("mp3", extension);
|
||||||
|
|
||||||
|
extension = FFmpegKitConfig.extractExtensionFromSafDisplayName("file.mp4");
|
||||||
|
Assert.assertEquals("mp4", extension);
|
||||||
|
|
||||||
|
extension = FFmpegKitConfig.extractExtensionFromSafDisplayName("file name.mp4");
|
||||||
|
Assert.assertEquals("mp4", extension);
|
||||||
|
}
|
||||||
|
|
||||||
private String listToPackageName(final List<String> externalLibraryList) {
|
private String listToPackageName(final List<String> externalLibraryList) {
|
||||||
boolean speex = externalLibraryList.contains("speex");
|
boolean speex = externalLibraryList.contains("speex");
|
||||||
boolean fribidi = externalLibraryList.contains("fribidi");
|
boolean fribidi = externalLibraryList.contains("fribidi");
|
||||||
|
|
|
@ -63,7 +63,7 @@ include $(BUILD_SHARED_LIBRARY)
|
||||||
|
|
||||||
$(call import-module, cpu-features)
|
$(call import-module, cpu-features)
|
||||||
|
|
||||||
MY_SRC_FILES := ffmpegkit.c ffprobekit.c ffmpegkit_exception.c fftools_cmdutils.c fftools_ffmpeg.c fftools_ffprobe.c fftools_ffmpeg_opt.c fftools_ffmpeg_hw.c fftools_ffmpeg_filter.c saf_wrapper.c
|
MY_SRC_FILES := ffmpegkit.c ffprobekit.c ffmpegkit_exception.c fftools_cmdutils.c fftools_ffmpeg.c fftools_ffprobe.c fftools_ffmpeg_opt.c fftools_ffmpeg_hw.c fftools_ffmpeg_filter.c
|
||||||
|
|
||||||
ifeq ($(TARGET_PLATFORM),android-16)
|
ifeq ($(TARGET_PLATFORM),android-16)
|
||||||
MY_SRC_FILES += android_lts_support.c
|
MY_SRC_FILES += android_lts_support.c
|
||||||
|
|
|
@ -350,6 +350,12 @@ export CFLAGS="${HIGH_PRIORITY_INCLUDES} ${CFLAGS}"
|
||||||
ulimit -n 2048 1>>"${BASEDIR}"/build.log 2>&1
|
ulimit -n 2048 1>>"${BASEDIR}"/build.log 2>&1
|
||||||
|
|
||||||
########################### CUSTOMIZATIONS #######################
|
########################### CUSTOMIZATIONS #######################
|
||||||
|
cd "${BASEDIR}" 1>>"${BASEDIR}"/build.log 2>&1 || exit 1
|
||||||
|
git checkout android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit.c 1>>"${BASEDIR}"/build.log 2>&1
|
||||||
|
cd "${BASEDIR}"/src/"${LIB_NAME}" 1>>"${BASEDIR}"/build.log 2>&1 || exit 1
|
||||||
|
git checkout libavformat/file.c 1>>"${BASEDIR}"/build.log 2>&1
|
||||||
|
git checkout libavformat/protocols.c 1>>"${BASEDIR}"/build.log 2>&1
|
||||||
|
git checkout libavutil 1>>"${BASEDIR}"/build.log 2>&1
|
||||||
|
|
||||||
# 1. Use thread local log levels
|
# 1. Use thread local log levels
|
||||||
${SED_INLINE} 's/static int av_log_level/__thread int av_log_level/g' "${BASEDIR}"/src/"${LIB_NAME}"/libavutil/log.c 1>>"${BASEDIR}"/build.log 2>&1 || exit 1
|
${SED_INLINE} 's/static int av_log_level/__thread int av_log_level/g' "${BASEDIR}"/src/"${LIB_NAME}"/libavutil/log.c 1>>"${BASEDIR}"/build.log 2>&1 || exit 1
|
||||||
|
@ -358,6 +364,19 @@ ${SED_INLINE} 's/static int av_log_level/__thread int av_log_level/g' "${BASEDIR
|
||||||
FFMPEG_VERSION="v$(get_user_friendly_ffmpeg_version)"
|
FFMPEG_VERSION="v$(get_user_friendly_ffmpeg_version)"
|
||||||
${SED_INLINE} "s/\$version/$FFMPEG_VERSION/g" "${BASEDIR}"/src/"${LIB_NAME}"/ffbuild/version.sh 1>>"${BASEDIR}"/build.log 2>&1 || exit 1
|
${SED_INLINE} "s/\$version/$FFMPEG_VERSION/g" "${BASEDIR}"/src/"${LIB_NAME}"/ffbuild/version.sh 1>>"${BASEDIR}"/build.log 2>&1 || exit 1
|
||||||
|
|
||||||
|
# 3. Enable ffmpeg-kit protocols
|
||||||
|
if [[ ${NO_FFMPEG_KIT_PROTOCOLS} == "1" ]]; then
|
||||||
|
${SED_INLINE} "s/ av_set_fd_close/\/\/av_set_fd_close/g" "${BASEDIR}"/android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit.c 1>>"${BASEDIR}"/build.log 2>&1
|
||||||
|
echo -e "\nINFO: Disabled custom ffmpeg-kit protocols\n" 1>>"${BASEDIR}"/build.log 2>&1
|
||||||
|
else
|
||||||
|
cat ../../tools/protocols/libavformat_file.c >> libavformat/file.c
|
||||||
|
cat ../../tools/protocols/libavutil_file.h >> libavutil/file.h
|
||||||
|
cat ../../tools/protocols/libavutil_file.c >> libavutil/file.c
|
||||||
|
awk '{gsub(/ff_file_protocol;/,"ff_file_protocol;\nextern const URLProtocol ff_saf_protocol;")}1' libavformat/protocols.c > libavformat/protocols.c.tmp
|
||||||
|
awk '{gsub(/ff_file_protocol;/,"ff_file_protocol;\nextern const URLProtocol ff_fd_protocol;")}1' libavformat/protocols.c.tmp > libavformat/protocols.c
|
||||||
|
echo -e "\nINFO: Enabled custom ffmpeg-kit protocols\n" 1>>"${BASEDIR}"/build.log 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
###################################################################
|
###################################################################
|
||||||
|
|
||||||
./configure \
|
./configure \
|
||||||
|
|
|
@ -423,6 +423,9 @@ if [[ -z ${NO_WORKSPACE_CLEANUP_ffmpeg} ]]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
########################### CUSTOMIZATIONS #######################
|
########################### CUSTOMIZATIONS #######################
|
||||||
|
git checkout libavformat/file.c 1>>"${BASEDIR}"/build.log 2>&1
|
||||||
|
git checkout libavformat/protocols.c 1>>"${BASEDIR}"/build.log 2>&1
|
||||||
|
git checkout libavutil 1>>"${BASEDIR}"/build.log 2>&1
|
||||||
|
|
||||||
# 1. Workaround to prevent adding of -mdynamic-no-pic flag
|
# 1. Workaround to prevent adding of -mdynamic-no-pic flag
|
||||||
${SED_INLINE} 's/check_cflags -mdynamic-no-pic && add_asflags -mdynamic-no-pic;/check_cflags -mdynamic-no-pic;/g' ./configure 1>>"${BASEDIR}"/build.log 2>&1 || exit 1
|
${SED_INLINE} 's/check_cflags -mdynamic-no-pic && add_asflags -mdynamic-no-pic;/check_cflags -mdynamic-no-pic;/g' ./configure 1>>"${BASEDIR}"/build.log 2>&1 || exit 1
|
||||||
|
|
|
@ -31,7 +31,7 @@ under the prebuilt folder.\n"
|
||||||
echo -e "Usage: ./$COMMAND [OPTION]... [VAR=VALUE]...\n"
|
echo -e "Usage: ./$COMMAND [OPTION]... [VAR=VALUE]...\n"
|
||||||
echo -e "Specify environment variables as VARIABLE=VALUE to override default build options.\n"
|
echo -e "Specify environment variables as VARIABLE=VALUE to override default build options.\n"
|
||||||
|
|
||||||
display_help_options " -l, --lts\t\t\tbuild lts packages to support API 16+ devices" " --api-level=api\t\toverride Android api level [${API}]"
|
display_help_options " -l, --lts\t\t\tbuild lts packages to support API 16+ devices" " --api-level=api\t\toverride Android api level" " --no-ffmpeg-kit-protocols\tdisable custom ffmpeg-kit protocols (fd, saf)"
|
||||||
display_help_licensing
|
display_help_licensing
|
||||||
|
|
||||||
echo -e "Architectures:"
|
echo -e "Architectures:"
|
||||||
|
|
|
@ -584,6 +584,9 @@ display_help_options() {
|
||||||
if [ -n "$2" ]; then
|
if [ -n "$2" ]; then
|
||||||
echo -e "$2"
|
echo -e "$2"
|
||||||
fi
|
fi
|
||||||
|
if [ -n "$3" ]; then
|
||||||
|
echo -e "$3"
|
||||||
|
fi
|
||||||
echo -e ""
|
echo -e ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
202
tools/protocols/libavformat_file.c
Normal file
202
tools/protocols/libavformat_file.c
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libavutil/file.h"
|
||||||
|
|
||||||
|
static int64_t fd_seek(URLContext *h, int64_t pos, int whence)
|
||||||
|
{
|
||||||
|
FileContext *c = h->priv_data;
|
||||||
|
int64_t ret;
|
||||||
|
|
||||||
|
if (whence == AVSEEK_SIZE) {
|
||||||
|
struct stat st;
|
||||||
|
ret = fstat(c->fd, &st);
|
||||||
|
return ret < 0 ? AVERROR(errno) : (S_ISFIFO(st.st_mode) ? 0 : st.st_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = lseek(c->fd, pos, whence);
|
||||||
|
|
||||||
|
return ret < 0 ? AVERROR(errno) : ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fd_open(URLContext *h, const char *filename, int flags)
|
||||||
|
{
|
||||||
|
FileContext *c = h->priv_data;
|
||||||
|
int fd;
|
||||||
|
struct stat st;
|
||||||
|
char *final;
|
||||||
|
char *saveptr = NULL;
|
||||||
|
char *fd_string = NULL;
|
||||||
|
char filename_backup[128];
|
||||||
|
|
||||||
|
av_strstart(filename, "fd:", &filename);
|
||||||
|
av_strstart(filename, "saf:", &filename);
|
||||||
|
av_strlcpy(filename_backup, filename, FFMIN(sizeof(filename), sizeof(filename_backup)));
|
||||||
|
fd_string = av_strtok(filename_backup, ".", &saveptr);
|
||||||
|
|
||||||
|
fd = strtol(fd_string, &final, 10);
|
||||||
|
if ((fd_string == final) || *final ) {
|
||||||
|
fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->fd = fd;
|
||||||
|
|
||||||
|
h->is_streamed = !fstat(fd, &st) && S_ISFIFO(st.st_mode);
|
||||||
|
|
||||||
|
/* Buffer writes more than the default 32k to improve throughput especially
|
||||||
|
* with networked file systems */
|
||||||
|
if (!h->is_streamed && flags & AVIO_FLAG_WRITE)
|
||||||
|
h->min_packet_size = h->max_packet_size = 262144;
|
||||||
|
|
||||||
|
if (c->seekable >= 0)
|
||||||
|
h->is_streamed = !c->seekable;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fd_check(URLContext *h, int mask)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
const char *filename = h->filename;
|
||||||
|
av_strstart(filename, "fd:", &filename);
|
||||||
|
av_strstart(filename, "saf:", &filename);
|
||||||
|
|
||||||
|
{
|
||||||
|
#if HAVE_ACCESS && defined(R_OK)
|
||||||
|
if (access(filename, F_OK) < 0)
|
||||||
|
return AVERROR(errno);
|
||||||
|
if (mask&AVIO_FLAG_READ)
|
||||||
|
if (access(filename, R_OK) >= 0)
|
||||||
|
ret |= AVIO_FLAG_READ;
|
||||||
|
if (mask&AVIO_FLAG_WRITE)
|
||||||
|
if (access(filename, W_OK) >= 0)
|
||||||
|
ret |= AVIO_FLAG_WRITE;
|
||||||
|
#else
|
||||||
|
struct stat st;
|
||||||
|
# ifndef _WIN32
|
||||||
|
ret = stat(filename, &st);
|
||||||
|
# else
|
||||||
|
ret = win32_stat(filename, &st);
|
||||||
|
# endif
|
||||||
|
if (ret < 0)
|
||||||
|
return AVERROR(errno);
|
||||||
|
|
||||||
|
ret |= st.st_mode&S_IRUSR ? mask&AVIO_FLAG_READ : 0;
|
||||||
|
ret |= st.st_mode&S_IWUSR ? mask&AVIO_FLAG_WRITE : 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fd_delete(URLContext *h)
|
||||||
|
{
|
||||||
|
#if HAVE_UNISTD_H
|
||||||
|
int ret;
|
||||||
|
const char *filename = h->filename;
|
||||||
|
av_strstart(filename, "fd:", &filename);
|
||||||
|
av_strstart(filename, "saf:", &filename);
|
||||||
|
|
||||||
|
ret = rmdir(filename);
|
||||||
|
if (ret < 0 && (errno == ENOTDIR
|
||||||
|
# ifdef _WIN32
|
||||||
|
|| errno == EINVAL
|
||||||
|
# endif
|
||||||
|
))
|
||||||
|
ret = unlink(filename);
|
||||||
|
if (ret < 0)
|
||||||
|
return AVERROR(errno);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
return AVERROR(ENOSYS);
|
||||||
|
#endif /* HAVE_UNISTD_H */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fd_move(URLContext *h_src, URLContext *h_dst)
|
||||||
|
{
|
||||||
|
const char *filename_src = h_src->filename;
|
||||||
|
const char *filename_dst = h_dst->filename;
|
||||||
|
av_strstart(filename_src, "fd:", &filename_src);
|
||||||
|
av_strstart(filename_src, "saf:", &filename_src);
|
||||||
|
av_strstart(filename_dst, "fd:", &filename_dst);
|
||||||
|
av_strstart(filename_dst, "saf:", &filename_dst);
|
||||||
|
|
||||||
|
if (rename(filename_src, filename_dst) < 0)
|
||||||
|
return AVERROR(errno);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fd_close(URLContext *h)
|
||||||
|
{
|
||||||
|
FileContext *c = h->priv_data;
|
||||||
|
|
||||||
|
fd_close_function custom_fd_close = av_get_fd_close();
|
||||||
|
if (custom_fd_close != NULL) {
|
||||||
|
return custom_fd_close(c->fd);
|
||||||
|
} else {
|
||||||
|
return close(c->fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const AVClass saf_class = {
|
||||||
|
.class_name = "saf",
|
||||||
|
.item_name = av_default_item_name,
|
||||||
|
.option = file_options,
|
||||||
|
.version = LIBAVUTIL_VERSION_INT,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const AVClass fd_class = {
|
||||||
|
.class_name = "fd",
|
||||||
|
.item_name = av_default_item_name,
|
||||||
|
.option = file_options,
|
||||||
|
.version = LIBAVUTIL_VERSION_INT,
|
||||||
|
};
|
||||||
|
|
||||||
|
const URLProtocol ff_saf_protocol = {
|
||||||
|
.name = "saf",
|
||||||
|
.url_open = fd_open,
|
||||||
|
.url_read = file_read,
|
||||||
|
.url_write = file_write,
|
||||||
|
.url_seek = fd_seek,
|
||||||
|
.url_close = fd_close,
|
||||||
|
.url_get_file_handle = file_get_handle,
|
||||||
|
.url_check = fd_check,
|
||||||
|
.url_delete = fd_delete,
|
||||||
|
.url_move = fd_move,
|
||||||
|
.priv_data_size = sizeof(FileContext),
|
||||||
|
.priv_data_class = &saf_class,
|
||||||
|
.default_whitelist = "saf,crypto,data"
|
||||||
|
};
|
||||||
|
|
||||||
|
const URLProtocol ff_fd_protocol = {
|
||||||
|
.name = "fd",
|
||||||
|
.url_open = fd_open,
|
||||||
|
.url_read = file_read,
|
||||||
|
.url_write = file_write,
|
||||||
|
.url_seek = fd_seek,
|
||||||
|
.url_close = fd_close,
|
||||||
|
.url_get_file_handle = file_get_handle,
|
||||||
|
.url_check = fd_check,
|
||||||
|
.url_delete = fd_delete,
|
||||||
|
.url_move = fd_move,
|
||||||
|
.priv_data_size = sizeof(FileContext),
|
||||||
|
.priv_data_class = &fd_class,
|
||||||
|
.default_whitelist = "fd,crypto,data"
|
||||||
|
};
|
28
tools/protocols/libavutil_file.c
Normal file
28
tools/protocols/libavutil_file.c
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static fd_close_function _fd_close_function = NULL;
|
||||||
|
|
||||||
|
fd_close_function av_get_fd_close() {
|
||||||
|
return _fd_close_function;
|
||||||
|
}
|
||||||
|
|
||||||
|
void av_set_fd_close(fd_close_function close_function) {
|
||||||
|
_fd_close_function = close_function;
|
||||||
|
}
|
29
tools/protocols/libavutil_file.h
Normal file
29
tools/protocols/libavutil_file.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AVUTIL_FILE_FFMPEG_KIT_PROTOCOLS_H
|
||||||
|
#define AVUTIL_FILE_FFMPEG_KIT_PROTOCOLS_H
|
||||||
|
|
||||||
|
typedef int (*fd_close_function)(int);
|
||||||
|
|
||||||
|
fd_close_function av_get_fd_close(void);
|
||||||
|
|
||||||
|
void av_set_fd_close(fd_close_function);
|
||||||
|
|
||||||
|
#endif /* AVUTIL_FILE_FFMPEG_KIT_PROTOCOLS_H */
|
Loading…
Reference in New Issue
Block a user