introduce a method to generate saf protocol urls using a custom open mode, fixes #167
This commit is contained in:
parent
83d1fc6e72
commit
eda94ad613
@ -80,8 +80,11 @@ static jmethodID logMethod;
|
|||||||
/** Global reference of statistics redirection method in Java */
|
/** Global reference of statistics redirection method in Java */
|
||||||
static jmethodID statisticsMethod;
|
static jmethodID statisticsMethod;
|
||||||
|
|
||||||
/** Global reference of closeParcelFileDescriptor method in Java */
|
/** Global reference of safOpen method in Java */
|
||||||
static jmethodID closeParcelFileDescriptorMethod;
|
static jmethodID safOpenMethod;
|
||||||
|
|
||||||
|
/** Global reference of safClose method in Java */
|
||||||
|
static jmethodID safCloseMethod;
|
||||||
|
|
||||||
/** Global reference of String class in Java */
|
/** Global reference of String class in Java */
|
||||||
static jclass stringClass;
|
static jclass stringClass;
|
||||||
@ -561,13 +564,21 @@ void *callbackThreadFunction() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by fd and saf protocols; is expected to be called from a Java thread, therefore we don't need attach/detach
|
* Used by saf protocol; is expected to be called from a Java thread, therefore we don't need attach/detach
|
||||||
*/
|
*/
|
||||||
int close_parcel_file_descriptor(int fd) {
|
int saf_open(int safId) {
|
||||||
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);
|
return (*env)->CallStaticIntMethod(env, configClass, safOpenMethod, safId);
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by saf protocol; is expected to be called from a Java thread, therefore we don't need attach/detach
|
||||||
|
*/
|
||||||
|
int saf_close(int fd) {
|
||||||
|
JNIEnv *env = NULL;
|
||||||
|
(*globalVm)->GetEnv(globalVm, (void**) &env, JNI_VERSION_1_6);
|
||||||
|
return (*env)->CallStaticIntMethod(env, configClass, safCloseMethod, fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -615,9 +626,15 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|||||||
return JNI_FALSE;
|
return JNI_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
closeParcelFileDescriptorMethod = (*env)->GetStaticMethodID(env, localConfigClass, "closeParcelFileDescriptor", "(I)V");
|
safOpenMethod = (*env)->GetStaticMethodID(env, localConfigClass, "safOpen", "(I)I");
|
||||||
if (logMethod == NULL) {
|
if (logMethod == NULL) {
|
||||||
LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "closeParcelFileDescriptor");
|
LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "safOpen");
|
||||||
|
return JNI_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
safCloseMethod = (*env)->GetStaticMethodID(env, localConfigClass, "safClose", "(I)I");
|
||||||
|
if (logMethod == NULL) {
|
||||||
|
LOGE("OnLoad thread failed to GetStaticMethodID for %s.\n", "safClose");
|
||||||
return JNI_FALSE;
|
return JNI_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -645,7 +662,8 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|||||||
|
|
||||||
redirectionEnabled = 0;
|
redirectionEnabled = 0;
|
||||||
|
|
||||||
av_set_fd_close(close_parcel_file_descriptor);
|
av_set_saf_open(saf_open);
|
||||||
|
av_set_saf_close(saf_close);
|
||||||
|
|
||||||
return JNI_VERSION_1_6;
|
return JNI_VERSION_1_6;
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
package com.arthenica.ffmpegkit;
|
package com.arthenica.ffmpegkit;
|
||||||
|
|
||||||
|
import android.content.ContentProvider;
|
||||||
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@ -44,7 +46,7 @@ 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;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -52,6 +54,45 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||||||
*/
|
*/
|
||||||
public class FFmpegKitConfig {
|
public class FFmpegKitConfig {
|
||||||
|
|
||||||
|
static class SAFProtocolUrl {
|
||||||
|
private final Integer safId;
|
||||||
|
private final Uri uri;
|
||||||
|
private final String openMode;
|
||||||
|
private final ContentResolver contentResolver;
|
||||||
|
private ParcelFileDescriptor parcelFileDescriptor;
|
||||||
|
|
||||||
|
public SAFProtocolUrl(final Integer safId, final Uri uri, final String openMode, final ContentResolver contentResolver) {
|
||||||
|
this.safId = safId;
|
||||||
|
this.uri = uri;
|
||||||
|
this.openMode = openMode;
|
||||||
|
this.contentResolver = contentResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSafId() {
|
||||||
|
return safId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Uri getUri() {
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOpenMode() {
|
||||||
|
return openMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContentResolver getContentResolver() {
|
||||||
|
return contentResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParcelFileDescriptor(final ParcelFileDescriptor parcelFileDescriptor) {
|
||||||
|
this.parcelFileDescriptor = parcelFileDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ParcelFileDescriptor getParcelFileDescriptor() {
|
||||||
|
return parcelFileDescriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The tag used for logging.
|
* The tag used for logging.
|
||||||
*/
|
*/
|
||||||
@ -63,9 +104,9 @@ public class FFmpegKitConfig {
|
|||||||
static final String FFMPEG_KIT_NAMED_PIPE_PREFIX = "fk_pipe_";
|
static final String FFMPEG_KIT_NAMED_PIPE_PREFIX = "fk_pipe_";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates ids for named ffmpeg kit pipes.
|
* Generates ids for named ffmpeg kit pipes and saf protocol urls.
|
||||||
*/
|
*/
|
||||||
private static final AtomicLong pipeIndexGenerator;
|
private static final AtomicInteger uniqueIdGenerator;
|
||||||
|
|
||||||
private static Level activeLogLevel;
|
private static Level activeLogLevel;
|
||||||
|
|
||||||
@ -82,7 +123,8 @@ public class FFmpegKitConfig {
|
|||||||
private static LogCallback globalLogCallbackFunction;
|
private static LogCallback globalLogCallbackFunction;
|
||||||
private static StatisticsCallback globalStatisticsCallbackFunction;
|
private static StatisticsCallback globalStatisticsCallbackFunction;
|
||||||
private static ExecuteCallback globalExecuteCallbackFunction;
|
private static ExecuteCallback globalExecuteCallbackFunction;
|
||||||
private static final SparseArray<ParcelFileDescriptor> pfdMap;
|
private static final SparseArray<SAFProtocolUrl> safIdMap;
|
||||||
|
private static final SparseArray<SAFProtocolUrl> safFileDescriptorMap;
|
||||||
private static LogRedirectionStrategy globalLogRedirectionStrategy;
|
private static LogRedirectionStrategy globalLogRedirectionStrategy;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@ -102,7 +144,7 @@ public class FFmpegKitConfig {
|
|||||||
|
|
||||||
android.util.Log.i(FFmpegKitConfig.TAG, String.format("Loaded ffmpeg-kit-%s-%s-%s-%s.", NativeLoader.loadPackageName(), NativeLoader.loadAbi(), NativeLoader.loadVersion(), NativeLoader.loadBuildDate()));
|
android.util.Log.i(FFmpegKitConfig.TAG, String.format("Loaded ffmpeg-kit-%s-%s-%s-%s.", NativeLoader.loadPackageName(), NativeLoader.loadAbi(), NativeLoader.loadVersion(), NativeLoader.loadBuildDate()));
|
||||||
|
|
||||||
pipeIndexGenerator = new AtomicLong(1);
|
uniqueIdGenerator = new AtomicInteger(1);
|
||||||
|
|
||||||
/* NATIVE LOG LEVEL IS RECEIVED ONLY ON STARTUP */
|
/* NATIVE LOG LEVEL IS RECEIVED ONLY ON STARTUP */
|
||||||
activeLogLevel = Level.from(NativeLoader.loadLogLevel());
|
activeLogLevel = Level.from(NativeLoader.loadLogLevel());
|
||||||
@ -125,7 +167,8 @@ public class FFmpegKitConfig {
|
|||||||
globalStatisticsCallbackFunction = null;
|
globalStatisticsCallbackFunction = null;
|
||||||
globalExecuteCallbackFunction = null;
|
globalExecuteCallbackFunction = null;
|
||||||
|
|
||||||
pfdMap = new SparseArray<>();
|
safIdMap = new SparseArray<>();
|
||||||
|
safFileDescriptorMap = new SparseArray<>();
|
||||||
globalLogRedirectionStrategy = LogRedirectionStrategy.PRINT_LOGS_WHEN_NO_CALLBACKS_DEFINED;
|
globalLogRedirectionStrategy = LogRedirectionStrategy.PRINT_LOGS_WHEN_NO_CALLBACKS_DEFINED;
|
||||||
|
|
||||||
NativeLoader.enableRedirection();
|
NativeLoader.enableRedirection();
|
||||||
@ -458,7 +501,7 @@ public class FFmpegKitConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final String newFFmpegPipePath = MessageFormat.format("{0}{1}{2}{3}", pipesDir, File.separator, FFMPEG_KIT_NAMED_PIPE_PREFIX, pipeIndexGenerator.getAndIncrement());
|
final String newFFmpegPipePath = MessageFormat.format("{0}{1}{2}{3}", pipesDir, File.separator, FFMPEG_KIT_NAMED_PIPE_PREFIX, uniqueIdGenerator.getAndIncrement());
|
||||||
|
|
||||||
// FIRST CLOSE OLD PIPES WITH THE SAME NAME
|
// FIRST CLOSE OLD PIPES WITH THE SAME NAME
|
||||||
closeFFmpegPipe(newFFmpegPipePath);
|
closeFFmpegPipe(newFFmpegPipePath);
|
||||||
@ -833,13 +876,16 @@ public class FFmpegKitConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <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.
|
* SAF protocol url that can be used in FFmpeg and FFprobe commands.
|
||||||
*
|
*
|
||||||
* <p>Requires API Level >= 19. On older API levels it returns an empty url.
|
* <p>Requires API Level >= 19. On older API levels it returns an empty url.
|
||||||
*
|
*
|
||||||
|
* @param context application context
|
||||||
|
* @param uri SAF uri
|
||||||
|
* @param openMode file mode to use as defined in {@link ContentProvider#openFile ContentProvider.openFile}
|
||||||
* @return input/output url that can be passed to FFmpegKit or FFprobeKit
|
* @return input/output url that can be passed to FFmpegKit or FFprobeKit
|
||||||
*/
|
*/
|
||||||
private static String getSafParameter(final Context context, final Uri uri, final String openMode) {
|
public static String getSafParameter(final Context context, final Uri uri, final String openMode) {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||||
android.util.Log.i(TAG, String.format("getSafParameter is not supported on API Level %d", Build.VERSION.SDK_INT));
|
android.util.Log.i(TAG, String.format("getSafParameter is not supported on API Level %d", Build.VERSION.SDK_INT));
|
||||||
return "";
|
return "";
|
||||||
@ -855,27 +901,20 @@ public class FFmpegKitConfig {
|
|||||||
throw t;
|
throw t;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int fd;
|
final int safId = uniqueIdGenerator.getAndIncrement();
|
||||||
try {
|
safIdMap.put(safId, new SAFProtocolUrl(safId, uri, openMode, context.getContentResolver()));
|
||||||
ParcelFileDescriptor parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, openMode);
|
|
||||||
fd = parcelFileDescriptor.getFd();
|
|
||||||
pfdMap.put(fd, parcelFileDescriptor);
|
|
||||||
} catch (final Throwable t) {
|
|
||||||
android.util.Log.e(TAG, String.format("Failed to obtain %s parcelFileDescriptor for %s.%s", openMode, uri.toString(), Exceptions.getStackTraceString(t)));
|
|
||||||
throw new IllegalArgumentException(String.format("Failed to obtain %s parcelFileDescriptor for %s.", openMode, uri.toString()), t);
|
|
||||||
}
|
|
||||||
|
|
||||||
return "saf:" + fd + "." + FFmpegKitConfig.extractExtensionFromSafDisplayName(displayName);
|
return "saf:" + safId + "." + FFmpegKitConfig.extractExtensionFromSafDisplayName(displayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <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 url that can be used in FFmpeg and FFprobe commands.
|
* SAF protocol url that can be used in FFmpeg and FFprobe commands.
|
||||||
*
|
*
|
||||||
* <p>Requires API Level ≥ 19. On older API levels it returns an empty url.
|
* <p>Requires API Level ≥ 19. On older API levels it returns an empty url.
|
||||||
*
|
*
|
||||||
* @param context application context
|
* @param context application context
|
||||||
* @param uri saf uri
|
* @param uri SAF uri
|
||||||
* @return input url that can be passed to FFmpegKit or FFprobeKit
|
* @return input url that can be passed to FFmpegKit or FFprobeKit
|
||||||
*/
|
*/
|
||||||
public static String getSafParameterForRead(final Context context, final Uri uri) {
|
public static String getSafParameterForRead(final Context context, final Uri uri) {
|
||||||
@ -884,12 +923,12 @@ public class FFmpegKitConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <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
|
||||||
* output url that can be used in FFmpeg and FFprobe commands.
|
* SAF protocol url that can be used in FFmpeg and FFprobe commands.
|
||||||
*
|
*
|
||||||
* <p>Requires API Level ≥ 19. On older API levels it returns an empty url.
|
* <p>Requires API Level ≥ 19. On older API levels it returns an empty url.
|
||||||
*
|
*
|
||||||
* @param context application context
|
* @param context application context
|
||||||
* @param uri saf uri
|
* @param uri SAF uri
|
||||||
* @return output url that can be passed to FFmpegKit or FFprobeKit
|
* @return output url that can be passed to FFmpegKit or FFprobeKit
|
||||||
*/
|
*/
|
||||||
public static String getSafParameterForWrite(final Context context, final Uri uri) {
|
public static String getSafParameterForWrite(final Context context, final Uri uri) {
|
||||||
@ -897,20 +936,57 @@ public class FFmpegKitConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by saf_wrapper from native library to close a parcel file descriptor.
|
* Called from native library to open an SAF protocol url.
|
||||||
*
|
*
|
||||||
* @param fd parcel file descriptor created for a saf uri
|
* @param safId SAF id part of an SAF protocol url
|
||||||
|
* @return file descriptor created for this SAF id or 0 if an error occurs
|
||||||
*/
|
*/
|
||||||
private static void closeParcelFileDescriptor(final int fd) {
|
private static int safOpen(final int safId) {
|
||||||
try {
|
try {
|
||||||
ParcelFileDescriptor pfd = pfdMap.get(fd);
|
SAFProtocolUrl safUrl = safIdMap.get(safId);
|
||||||
if (pfd != null) {
|
if (safUrl != null) {
|
||||||
pfd.close();
|
final ParcelFileDescriptor parcelFileDescriptor = safUrl.getContentResolver().openFileDescriptor(safUrl.getUri(), safUrl.getOpenMode());
|
||||||
pfdMap.delete(fd);
|
safUrl.setParcelFileDescriptor(parcelFileDescriptor);
|
||||||
|
final int fd = parcelFileDescriptor.getFd();
|
||||||
|
safFileDescriptorMap.put(fd, safUrl);
|
||||||
|
return fd;
|
||||||
|
} else {
|
||||||
|
android.util.Log.e(TAG, String.format("SAF id %d not found.", safId));
|
||||||
}
|
}
|
||||||
} catch (final Throwable t) {
|
} catch (final Throwable t) {
|
||||||
android.util.Log.e(TAG, String.format("Failed to close file descriptor: %d.%s", fd, Exceptions.getStackTraceString(t)));
|
android.util.Log.e(TAG, String.format("Failed to open SAF id: %d.%s", safId, Exceptions.getStackTraceString(t)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called from native library to close a file descriptor created for a SAF protocol url.
|
||||||
|
*
|
||||||
|
* @param fileDescriptor file descriptor that belongs to a SAF protocol url
|
||||||
|
* @return 1 if the given file descriptor is closed successfully, 0 if an error occurs
|
||||||
|
*/
|
||||||
|
private static int safClose(final int fileDescriptor) {
|
||||||
|
try {
|
||||||
|
final SAFProtocolUrl safProtocolUrl = safFileDescriptorMap.get(fileDescriptor);
|
||||||
|
if (safProtocolUrl != null) {
|
||||||
|
ParcelFileDescriptor parcelFileDescriptor = safProtocolUrl.getParcelFileDescriptor();
|
||||||
|
if (parcelFileDescriptor != null) {
|
||||||
|
safFileDescriptorMap.delete(fileDescriptor);
|
||||||
|
safIdMap.delete(safProtocolUrl.getSafId());
|
||||||
|
parcelFileDescriptor.close();
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
android.util.Log.e(TAG, String.format("ParcelFileDescriptor for SAF fd %d not found.", fileDescriptor));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
android.util.Log.e(TAG, String.format("SAF fd %d not found.", fileDescriptor));
|
||||||
|
}
|
||||||
|
} catch (final Throwable t) {
|
||||||
|
android.util.Log.e(TAG, String.format("Failed to close SAF fd: %d.%s", fileDescriptor, Exceptions.getStackTraceString(t)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -380,7 +380,7 @@ else
|
|||||||
cat ../../tools/protocols/libavutil_file.h >> libavutil/file.h
|
cat ../../tools/protocols/libavutil_file.h >> libavutil/file.h
|
||||||
cat ../../tools/protocols/libavutil_file.c >> libavutil/file.c
|
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_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
|
cat libavformat/protocols.c.tmp > libavformat/protocols.c
|
||||||
echo -e "\nINFO: Enabled custom ffmpeg-kit protocols\n" 1>>"${BASEDIR}"/build.log 2>&1
|
echo -e "\nINFO: Enabled custom ffmpeg-kit protocols\n" 1>>"${BASEDIR}"/build.log 2>&1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -38,26 +38,35 @@ static int64_t fd_seek(URLContext *h, int64_t pos, int whence)
|
|||||||
static int fd_open(URLContext *h, const char *filename, int flags)
|
static int fd_open(URLContext *h, const char *filename, int flags)
|
||||||
{
|
{
|
||||||
FileContext *c = h->priv_data;
|
FileContext *c = h->priv_data;
|
||||||
int fd;
|
int saf_id;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char *final;
|
char *final;
|
||||||
char *saveptr = NULL;
|
char *saveptr = NULL;
|
||||||
char *fd_string = NULL;
|
char *saf_id_string = NULL;
|
||||||
char filename_backup[128];
|
char filename_backup[128];
|
||||||
|
|
||||||
av_strstart(filename, "fd:", &filename);
|
|
||||||
av_strstart(filename, "saf:", &filename);
|
av_strstart(filename, "saf:", &filename);
|
||||||
av_strlcpy(filename_backup, filename, FFMIN(sizeof(filename), sizeof(filename_backup)));
|
av_strlcpy(filename_backup, filename, FFMIN(sizeof(filename), sizeof(filename_backup)));
|
||||||
fd_string = av_strtok(filename_backup, ".", &saveptr);
|
saf_id_string = av_strtok(filename_backup, ".", &saveptr);
|
||||||
|
|
||||||
fd = strtol(fd_string, &final, 10);
|
saf_id = strtol(saf_id_string, &final, 10);
|
||||||
if ((fd_string == final) || *final ) {
|
if ((saf_id_string == final) || *final ) {
|
||||||
fd = -1;
|
saf_id = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->fd = fd;
|
saf_open_function custom_saf_open = av_get_saf_open();
|
||||||
|
if (custom_saf_open != NULL) {
|
||||||
|
int rc = custom_saf_open(saf_id);
|
||||||
|
if (rc) {
|
||||||
|
c->fd = rc;
|
||||||
|
} else {
|
||||||
|
c->fd = saf_id;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c->fd = saf_id;
|
||||||
|
}
|
||||||
|
|
||||||
h->is_streamed = !fstat(fd, &st) && S_ISFIFO(st.st_mode);
|
h->is_streamed = !fstat(saf_id, &st) && S_ISFIFO(st.st_mode);
|
||||||
|
|
||||||
/* Buffer writes more than the default 32k to improve throughput especially
|
/* Buffer writes more than the default 32k to improve throughput especially
|
||||||
* with networked file systems */
|
* with networked file systems */
|
||||||
@ -74,7 +83,6 @@ static int fd_check(URLContext *h, int mask)
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
const char *filename = h->filename;
|
const char *filename = h->filename;
|
||||||
av_strstart(filename, "fd:", &filename);
|
|
||||||
av_strstart(filename, "saf:", &filename);
|
av_strstart(filename, "saf:", &filename);
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -109,7 +117,6 @@ static int fd_delete(URLContext *h)
|
|||||||
#if HAVE_UNISTD_H
|
#if HAVE_UNISTD_H
|
||||||
int ret;
|
int ret;
|
||||||
const char *filename = h->filename;
|
const char *filename = h->filename;
|
||||||
av_strstart(filename, "fd:", &filename);
|
|
||||||
av_strstart(filename, "saf:", &filename);
|
av_strstart(filename, "saf:", &filename);
|
||||||
|
|
||||||
ret = rmdir(filename);
|
ret = rmdir(filename);
|
||||||
@ -132,9 +139,7 @@ static int fd_move(URLContext *h_src, URLContext *h_dst)
|
|||||||
{
|
{
|
||||||
const char *filename_src = h_src->filename;
|
const char *filename_src = h_src->filename;
|
||||||
const char *filename_dst = h_dst->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_src, "saf:", &filename_src);
|
||||||
av_strstart(filename_dst, "fd:", &filename_dst);
|
|
||||||
av_strstart(filename_dst, "saf:", &filename_dst);
|
av_strstart(filename_dst, "saf:", &filename_dst);
|
||||||
|
|
||||||
if (rename(filename_src, filename_dst) < 0)
|
if (rename(filename_src, filename_dst) < 0)
|
||||||
@ -147,11 +152,11 @@ static int fd_close(URLContext *h)
|
|||||||
{
|
{
|
||||||
FileContext *c = h->priv_data;
|
FileContext *c = h->priv_data;
|
||||||
|
|
||||||
fd_close_function custom_fd_close = av_get_fd_close();
|
saf_close_function custom_saf_close = av_get_saf_close();
|
||||||
if (custom_fd_close != NULL) {
|
if (custom_saf_close != NULL) {
|
||||||
return custom_fd_close(c->fd);
|
return custom_saf_close(c->fd);
|
||||||
} else {
|
} else {
|
||||||
return close(c->fd);
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,13 +167,6 @@ static const AVClass saf_class = {
|
|||||||
.version = LIBAVUTIL_VERSION_INT,
|
.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 = {
|
const URLProtocol ff_saf_protocol = {
|
||||||
.name = "saf",
|
.name = "saf",
|
||||||
.url_open = fd_open,
|
.url_open = fd_open,
|
||||||
@ -184,19 +182,3 @@ const URLProtocol ff_saf_protocol = {
|
|||||||
.priv_data_class = &saf_class,
|
.priv_data_class = &saf_class,
|
||||||
.default_whitelist = "saf,crypto,data"
|
.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"
|
|
||||||
};
|
|
||||||
|
@ -17,12 +17,21 @@
|
|||||||
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
* along with FFmpegKit. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static fd_close_function _fd_close_function = NULL;
|
static saf_open_function _saf_open_function = NULL;
|
||||||
|
static saf_close_function _saf_close_function = NULL;
|
||||||
|
|
||||||
fd_close_function av_get_fd_close() {
|
saf_open_function av_get_saf_open() {
|
||||||
return _fd_close_function;
|
return _saf_open_function;
|
||||||
}
|
}
|
||||||
|
|
||||||
void av_set_fd_close(fd_close_function close_function) {
|
saf_close_function av_get_saf_close() {
|
||||||
_fd_close_function = close_function;
|
return _saf_close_function;
|
||||||
|
}
|
||||||
|
|
||||||
|
void av_set_saf_open(saf_open_function open_function) {
|
||||||
|
_saf_open_function = open_function;
|
||||||
|
}
|
||||||
|
|
||||||
|
void av_set_saf_close(saf_close_function close_function) {
|
||||||
|
_saf_close_function = close_function;
|
||||||
}
|
}
|
||||||
|
@ -20,10 +20,16 @@
|
|||||||
#ifndef AVUTIL_FILE_FFMPEG_KIT_PROTOCOLS_H
|
#ifndef AVUTIL_FILE_FFMPEG_KIT_PROTOCOLS_H
|
||||||
#define AVUTIL_FILE_FFMPEG_KIT_PROTOCOLS_H
|
#define AVUTIL_FILE_FFMPEG_KIT_PROTOCOLS_H
|
||||||
|
|
||||||
typedef int (*fd_close_function)(int);
|
typedef int (*saf_open_function)(int);
|
||||||
|
|
||||||
fd_close_function av_get_fd_close(void);
|
typedef int (*saf_close_function)(int);
|
||||||
|
|
||||||
void av_set_fd_close(fd_close_function);
|
saf_open_function av_get_saf_open(void);
|
||||||
|
|
||||||
|
saf_close_function av_get_saf_close(void);
|
||||||
|
|
||||||
|
void av_set_saf_open(saf_open_function);
|
||||||
|
|
||||||
|
void av_set_saf_close(saf_close_function);
|
||||||
|
|
||||||
#endif /* AVUTIL_FILE_FFMPEG_KIT_PROTOCOLS_H */
|
#endif /* AVUTIL_FILE_FFMPEG_KIT_PROTOCOLS_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user