Skip to content
This repository was archived by the owner on Apr 21, 2025. It is now read-only.

Commit c356b05

Browse files
committed
implement custom ffmpeg-kit protocols for android, fixes #39
1 parent de101cf commit c356b05

File tree

15 files changed

+332
-201
lines changed

15 files changed

+332
-201
lines changed

android.sh

+3
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ while [ ! $# -eq 0 ]; do
121121

122122
export API=${API_LEVEL}
123123
;;
124+
--no-ffmpeg-kit-protocols)
125+
export NO_FFMPEG_KIT_PROTOCOLS="1"
126+
;;
124127
*)
125128
print_unknown_option "$1"
126129
;;

android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit.c

+6-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "config.h"
2626
#include "libavcodec/jni.h"
2727
#include "libavutil/bprint.h"
28+
#include "libavutil/file.h"
2829
#include "fftools_ffmpeg.h"
2930
#include "ffmpegkit.h"
3031
#include "ffprobekit.h"
@@ -560,12 +561,13 @@ void *callbackThreadFunction() {
560561
}
561562

562563
/**
563-
* Used by saf_wrapper; is expected to be called from a Java thread, therefore we don't need attach/detach
564+
* Used by fd and saf protocols; is expected to be called from a Java thread, therefore we don't need attach/detach
564565
*/
565-
void closeParcelFileDescriptor(int fd) {
566+
int close_parcel_file_descriptor(int fd) {
566567
JNIEnv *env = NULL;
567568
(*globalVm)->GetEnv(globalVm, (void**) &env, JNI_VERSION_1_6);
568569
(*env)->CallStaticVoidMethod(env, configClass, closeParcelFileDescriptorMethod, fd);
570+
return 0;
569571
}
570572

571573
/**
@@ -643,6 +645,8 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved) {
643645

644646
redirectionEnabled = 0;
645647

648+
av_set_fd_close(close_parcel_file_descriptor);
649+
646650
return JNI_VERSION_1_6;
647651
}
648652

android/ffmpeg-kit-android-lib/src/main/cpp/fftools_cmdutils.h

-2
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@
5151
#include "libavformat/avformat.h"
5252
#include "libswscale/swscale.h"
5353

54-
#include "saf_wrapper.h"
55-
5654
#ifdef _WIN32
5755
#undef main /* We don't want SDL to override our main() */
5856
#endif

android/ffmpeg-kit-android-lib/src/main/cpp/saf_wrapper.c

-139
This file was deleted.

android/ffmpeg-kit-android-lib/src/main/cpp/saf_wrapper.h

-46
This file was deleted.

android/ffmpeg-kit-android-lib/src/main/java/com/arthenica/ffmpegkit/FFmpegKitConfig.java

+18-10
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import java.util.LinkedList;
4141
import java.util.List;
4242
import java.util.Map;
43+
import java.util.StringTokenizer;
4344
import java.util.concurrent.ExecutorService;
4445
import java.util.concurrent.Executors;
4546
import java.util.concurrent.Future;
@@ -831,6 +832,20 @@ public static void setLogLevel(final Level level) {
831832
}
832833
}
833834

835+
static String extractExtensionFromSafDisplayName(final String safDisplayName) {
836+
String rawExtension = safDisplayName;
837+
if (safDisplayName.lastIndexOf(".") >= 0) {
838+
rawExtension = safDisplayName.substring(safDisplayName.lastIndexOf("."));
839+
}
840+
try {
841+
// workaround for https://issuetracker.google.com/issues/162440528: ANDROID_CREATE_DOCUMENT generating file names like "transcode.mp3 (2)"
842+
return new StringTokenizer(rawExtension, " .").nextToken();
843+
} catch (final Exception e) {
844+
android.util.Log.w(TAG, String.format("Failed to extract extension from saf display name: %s.%s", safDisplayName, Exceptions.getStackTraceString(e)));
845+
return "raw";
846+
}
847+
}
848+
834849
/**
835850
* <p>Converts the given Structured Access Framework Uri (<code>"content:…"</code>) into an
836851
* input/output url that can be used in FFmpeg and FFprobe commands.
@@ -863,14 +878,7 @@ private static String getSafParameter(final Context context, final Uri uri, fina
863878
android.util.Log.e(TAG, String.format("Failed to obtain %s parcelFileDescriptor for %s.%s", openMode, uri.toString(), Exceptions.getStackTraceString(t)));
864879
}
865880

866-
// workaround for https://issuetracker.google.com/issues/162440528: ANDROID_CREATE_DOCUMENT generating file names like "transcode.mp3 (2)"
867-
if (displayName.lastIndexOf('.') > 0 && displayName.lastIndexOf(' ') > displayName.lastIndexOf('.')) {
868-
String extension = displayName.substring(displayName.lastIndexOf('.'), displayName.lastIndexOf(' '));
869-
displayName += extension;
870-
}
871-
// spaces can break argument list parsing, see https://github.com/alexcohn/mobile-ffmpeg/pull/1#issuecomment-688643836
872-
final char NBSP = (char) 0xa0;
873-
return "saf:" + fd + "/" + displayName.replace(' ', NBSP);
881+
return "saf:" + fd + "." + FFmpegKitConfig.extractExtensionFromSafDisplayName(displayName);
874882
}
875883

876884
/**
@@ -880,7 +888,7 @@ private static String getSafParameter(final Context context, final Uri uri, fina
880888
* <p>Requires API Level &ge; 19. On older API levels it returns an empty url.
881889
*
882890
* @param context application context
883-
* @param uri saf uri
891+
* @param uri saf uri
884892
* @return input url that can be passed to FFmpegKit or FFprobeKit
885893
*/
886894
public static String getSafParameterForRead(final Context context, final Uri uri) {
@@ -894,7 +902,7 @@ public static String getSafParameterForRead(final Context context, final Uri uri
894902
* <p>Requires API Level &ge; 19. On older API levels it returns an empty url.
895903
*
896904
* @param context application context
897-
* @param uri saf uri
905+
* @param uri saf uri
898906
* @return output url that can be passed to FFmpegKit or FFprobeKit
899907
*/
900908
public static String getSafParameterForWrite(final Context context, final Uri uri) {

android/ffmpeg-kit-android-lib/src/test/java/com/arthenica/ffmpegkit/FFmpegKitConfigTest.java

+19
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
*/
3333
public class FFmpegKitConfigTest {
3434

35+
static {
36+
System.setProperty("enable.ffmpeg.kit.test.mode", "true");
37+
}
38+
3539
private static final String externalLibrariesCommandOutput = " configuration:\n" +
3640
" --cross-prefix=i686-linux-android-\n" +
3741
" --sysroot=/Users/taner/Library/Android/sdk/ndk-bundle/toolchains/ffmpeg-kit-i686/sysroot\n" +
@@ -152,6 +156,21 @@ public void getPackageName() {
152156
Assert.assertEquals("https-gpl", listToPackageName(Arrays.asList("gnutls", "xvidcore")));
153157
}
154158

159+
@Test
160+
public void extractExtensionFromSafDisplayName() {
161+
String extension = FFmpegKitConfig.extractExtensionFromSafDisplayName("video.mp4 (2)");
162+
Assert.assertEquals("mp4", extension);
163+
164+
extension = FFmpegKitConfig.extractExtensionFromSafDisplayName("video file name.mp3 (2)");
165+
Assert.assertEquals("mp3", extension);
166+
167+
extension = FFmpegKitConfig.extractExtensionFromSafDisplayName("file.mp4");
168+
Assert.assertEquals("mp4", extension);
169+
170+
extension = FFmpegKitConfig.extractExtensionFromSafDisplayName("file name.mp4");
171+
Assert.assertEquals("mp4", extension);
172+
}
173+
155174
private String listToPackageName(final List<String> externalLibraryList) {
156175
boolean speex = externalLibraryList.contains("speex");
157176
boolean fribidi = externalLibraryList.contains("fribidi");

android/jni/Android.mk

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ include $(BUILD_SHARED_LIBRARY)
6363

6464
$(call import-module, cpu-features)
6565

66-
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
66+
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
6767

6868
ifeq ($(TARGET_PLATFORM),android-16)
6969
MY_SRC_FILES += android_lts_support.c

scripts/android/ffmpeg.sh

+19
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,12 @@ export CFLAGS="${HIGH_PRIORITY_INCLUDES} ${CFLAGS}"
350350
ulimit -n 2048 1>>"${BASEDIR}"/build.log 2>&1
351351

352352
########################### CUSTOMIZATIONS #######################
353+
cd "${BASEDIR}" 1>>"${BASEDIR}"/build.log 2>&1 || exit 1
354+
git checkout android/ffmpeg-kit-android-lib/src/main/cpp/ffmpegkit.c 1>>"${BASEDIR}"/build.log 2>&1
355+
cd "${BASEDIR}"/src/"${LIB_NAME}" 1>>"${BASEDIR}"/build.log 2>&1 || exit 1
356+
git checkout libavformat/file.c 1>>"${BASEDIR}"/build.log 2>&1
357+
git checkout libavformat/protocols.c 1>>"${BASEDIR}"/build.log 2>&1
358+
git checkout libavutil 1>>"${BASEDIR}"/build.log 2>&1
353359

354360
# 1. Use thread local log levels
355361
${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
358364
FFMPEG_VERSION="v$(get_user_friendly_ffmpeg_version)"
359365
${SED_INLINE} "s/\$version/$FFMPEG_VERSION/g" "${BASEDIR}"/src/"${LIB_NAME}"/ffbuild/version.sh 1>>"${BASEDIR}"/build.log 2>&1 || exit 1
360366

367+
# 3. Enable ffmpeg-kit protocols
368+
if [[ ${NO_FFMPEG_KIT_PROTOCOLS} == "1" ]]; then
369+
${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
370+
echo -e "\nINFO: Disabled custom ffmpeg-kit protocols\n" 1>>"${BASEDIR}"/build.log 2>&1
371+
else
372+
cat ../../tools/protocols/libavformat_file.c >> libavformat/file.c
373+
cat ../../tools/protocols/libavutil_file.h >> libavutil/file.h
374+
cat ../../tools/protocols/libavutil_file.c >> libavutil/file.c
375+
awk '{gsub(/ff_file_protocol;/,"ff_file_protocol;\nextern const URLProtocol ff_saf_protocol;")}1' libavformat/protocols.c > libavformat/protocols.c.tmp
376+
awk '{gsub(/ff_file_protocol;/,"ff_file_protocol;\nextern const URLProtocol ff_fd_protocol;")}1' libavformat/protocols.c.tmp > libavformat/protocols.c
377+
echo -e "\nINFO: Enabled custom ffmpeg-kit protocols\n" 1>>"${BASEDIR}"/build.log 2>&1
378+
fi
379+
361380
###################################################################
362381

363382
./configure \

scripts/apple/ffmpeg.sh

+3
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,9 @@ if [[ -z ${NO_WORKSPACE_CLEANUP_ffmpeg} ]]; then
423423
fi
424424

425425
########################### CUSTOMIZATIONS #######################
426+
git checkout libavformat/file.c 1>>"${BASEDIR}"/build.log 2>&1
427+
git checkout libavformat/protocols.c 1>>"${BASEDIR}"/build.log 2>&1
428+
git checkout libavutil 1>>"${BASEDIR}"/build.log 2>&1
426429

427430
# 1. Workaround to prevent adding of -mdynamic-no-pic flag
428431
${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

scripts/function-android.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ under the prebuilt folder.\n"
3131
echo -e "Usage: ./$COMMAND [OPTION]... [VAR=VALUE]...\n"
3232
echo -e "Specify environment variables as VARIABLE=VALUE to override default build options.\n"
3333

34-
display_help_options " -l, --lts\t\t\tbuild lts packages to support API 16+ devices" " --api-level=api\t\toverride Android api level [${API}]"
34+
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)"
3535
display_help_licensing
3636

3737
echo -e "Architectures:"

0 commit comments

Comments
 (0)