Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot run program "/data/user/0/com.package.name/files/ffmpeg": error=13, Permission denied #343

Open
budiardianata opened this issue Sep 17, 2019 · 23 comments · May be fixed by #361
Open

Comments

@budiardianata
Copy link

i have error "error=13, Permission denied" while trying to run Ffmpeg in android 10 (Q).

java.io.IOException: Cannot run program "/data/user/0/com.package.name/files/ffmpeg": error=13, Permission denied
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1050)
at java.lang.Runtime.exec(Runtime.java:698)
at java.lang.Runtime.exec(Runtime.java:563)
at com.github.hiteshsondhi88.libffmpeg.ShellCommand.run(ShellCommand.java:11)
at com.github.hiteshsondhi88.libffmpeg.FFmpegExecuteAsyncTask.doInBackground(FFmpegExecuteAsyncTask.java:40)
at com.github.hiteshsondhi88.libffmpeg.FFmpegExecuteAsyncTask.doInBackground(FFmpegExecuteAsyncTask.java:12)
at android.os.AsyncTask$3.call(AsyncTask.java:378)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
Caused by: java.io.IOException: error=13, Permission denied
at java.lang.UNIXProcess.forkAndExec(Native Method)
at java.lang.UNIXProcess.(UNIXProcess.java:133)
at java.lang.ProcessImpl.start(ProcessImpl.java:141)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
at java.lang.Runtime.exec(Runtime.java:698) 
at java.lang.Runtime.exec(Runtime.java:563) 
at com.github.hiteshsondhi88.libffmpeg.ShellCommand.run(ShellCommand.java:11) 
at com.github.hiteshsondhi88.libffmpeg.FFmpegExecuteAsyncTask.doInBackground(FFmpegExecuteAsyncTask.java:40) 
at com.github.hiteshsondhi88.libffmpeg.FFmpegExecuteAsyncTask.doInBackground(FFmpegExecuteAsyncTask.java:12) 
at android.os.AsyncTask$3.call(AsyncTask.java:378) 
at java.util.concurrent.FutureTask.run(FutureTask.java:266) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
at java.lang.Thread.run(Thread.java:919) 

@brisksvoronko
Copy link

Hey,

  1. First you need to get permissions for external storage.

if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_RQ);

                                           }
  1. Pay attention to the oder - first wait for ffmpeg lib to finish loading - only then start any commands

package appsforactors.com.myselftapeapp.Mp4Tasks;

import android.content.Context;
import android.util.Log;

import com.crashlytics.android.Crashlytics;
import com.github.hiteshsondhi88.libffmpeg.ExecuteBinaryResponseHandler;
import com.github.hiteshsondhi88.libffmpeg.FFmpeg;
import com.github.hiteshsondhi88.libffmpeg.LoadBinaryResponseHandler;
import com.github.hiteshsondhi88.libffmpeg.exceptions.FFmpegCommandAlreadyRunningException;
import com.github.hiteshsondhi88.libffmpeg.exceptions.FFmpegNotSupportedException;

import org.bytedeco.javacpp.presets.opencv_core;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import appsforactors.com.myselftapeapp.Utility.FileUtility;
import appsforactors.com.myselftapeapp.Utility.ProcessUtils;
import appsforactors.com.myselftapeapp.Utility.TimeUtilility;
import io.fabric.sdk.android.services.common.Crash;

/**

  • Created by nikhil on 2016-01-29.
    */
    public class FFmpegExtension {

    private FFmpeg mFFmpeg;
    private static final String TAG = "FFMPEG";

    private final String IMAGE_TO_MOVIE_COMMAND = "-loop^1^-i^%s^-i^%s^-c:v^libx264^-crf^23^-t^%d^-pix_fmt^yuv420p^-c:a^aac^-strict^-2^-b:a^192k^-b:v^2400000^-s^1280x720^-shortest^-preset^ultrafast^%s";

    private final String CONVERT_TO_INTERMEDIATE_FILE_COMMAND = "-i^%s^-c^copy^-bsf:v^h264_mp4toannexb^-f^mpegts^-preset^ultrafast^%s";

    // original
    //private final String MERGE_VIDEO_COMMAND = "-i^concat:%s^-c:a^aac^-crf^23^-b:v^1000000^-strict^-2^-bsf:a^aac_adtstoasc^-preset^ultrafast^%s";
    private final String MERGE_VIDEO_COMMAND = "-i^concat:%s^-c:a^aac^-crf^23^-b:v^1000000^-strict^-2^-bsf:a^aac_adtstoasc^-preset^ultrafast^-tune^film^-fflags^+genpts^%s";

    // remove transcoding
    //private final String MERGE_VIDEO_COMMAND = "-i^concat:%s^-bsf:a^aac_adtstoasc^-c^copy^%s";

    // http://unix.stackexchange.com/questions/28803/how-can-i-reduce-a-videos-size-with-ffmpeg
    private final String REDUCE_MEDIA_FILE_SIZE_COMMAND = "-i %s^-b:v 1000000^-strict^-2^-preset ultrafast^%s";

    private String mLastMessage;

    private String[] mCommand;

    public static String[] commandFromCaretString(String caretSeperatedString) {
    return caretSeperatedString.split("\^");
    }

    private Context mContext;
    private boolean mSuccess = false;

    private OnFFmpegListemer mListener;

    private class Command {
    public String command;
    public double duration;
    }

    private List commands = new ArrayList<>();

    private boolean loaded = false;

    public FFmpegExtension(Context context) {
    this.mContext = context;
    loadFFMpegBinary();
    }

    /**
    *

    • @param imageFileName
    • @param movieFileName
    • @param
    •  duration -> Duration of the video to create
      

    */
    public void setImageToMovieCommand(String imageFileName, String movieFileName, int duration) {
    String silenceAudioFilePath = FileUtility.getAssetsFile(mContext, "silence.wav").toString();
    String caretCommand = String.format(IMAGE_TO_MOVIE_COMMAND, imageFileName, silenceAudioFilePath, duration, movieFileName);
    if (loaded) {
    execFFmpegBinary(caretCommand, duration);
    }
    else {
    Command command = new Command();
    command.command = caretCommand;
    command.duration = duration;
    commands.add(command);
    }
    }

    public void setCreateIntermediateFileCommand(String videoFilePath, String videoFileName) {
    String intermediateMovieFileNamePath = FileUtility.getNewFilePath(mContext, videoFileName, "intermediate.ts");
    String caretCommand = String.format(CONVERT_TO_INTERMEDIATE_FILE_COMMAND, videoFilePath, intermediateMovieFileNamePath);
    if (loaded) {
    execFFmpegBinary(caretCommand, 0);
    }
    else {
    Command command = new Command();
    command.command = caretCommand;
    command.duration = 0;
    commands.add(command);
    }
    }

    /**
    *

    • @param videoFilePaths
    • @param videoFileNames
    • @param finalVideoPath
    • @param
    •  videoLength -> Resulting video duration in seconds (Cheap (and faster) way to do it instead of asking individual files for their times from ffmpeg).
      

    */
    public void setMergeVideoCommand(ArrayList videoFilePaths, ArrayList videoFileNames, String finalVideoPath, double videoLength) {
    String concatFilePath = "";
    for (int i = 0; i < videoFilePaths.size(); i++) {
    String intermediateMovieFileNamePath = FileUtility.getNewFilePath(mContext, videoFileNames.get(i), "intermediate.ts");
    concatFilePath += intermediateMovieFileNamePath;
    if (i == videoFilePaths.size() - 1) {
    break;
    }
    concatFilePath += "|";
    }
    String caretCommand = String.format(MERGE_VIDEO_COMMAND, concatFilePath, finalVideoPath);
    if (loaded) {
    execFFmpegBinary(caretCommand, videoLength);
    }
    else {
    Command command = new Command();
    command.command = caretCommand;
    command.duration = videoLength;
    commands.add(command);
    }
    }

    private void loadFFMpegBinary() {
    try {
    if (mFFmpeg == null) {
    mFFmpeg = FFmpeg.getInstance(mContext);
    }
    mFFmpeg.loadBinary(new LoadBinaryResponseHandler() {
    @OverRide
    public void onFailure() {
    Log.d(TAG, "Failure");
    }

             @Override
             public void onSuccess() {
                 Log.d(TAG, "<ffmpeg>mFFmpeg : correct Loaded");
                 loaded = true;
    
                 if (commands.size() > 0) {
                     for (Command command: commands) {
                         execFFmpegBinary(command.command, command.duration);
                     }
                 }
             }
         });
     } catch (FFmpegNotSupportedException e) {
         Crashlytics.logException(e);
         Log.d(TAG, "<ffmpeg>FFmpegNotSupportedException: " + e.getMessage());
     } catch (Exception e) {
         Crashlytics.logException(e);
         Log.d(TAG, "<ffmpeg>Exception no control: " + e.getMessage());
     }
    

    }

    private void execFFmpegBinary(String caretSeperatedCommand, final double duration) {

     final String[] command = commandFromCaretString(caretSeperatedCommand);
     Log.d(TAG,"<ffmpeg>Executing ffmpeg command: " + java.util.Arrays.toString(command));
     try {
         mFFmpeg.execute(command, new ExecuteBinaryResponseHandler() {
             @Override
             public void onFailure(String s) {
                 Log.d(TAG, "<ffmpeg>FAILED with output : " + s);
                 mSuccess = false;
                 mLastMessage = s;
             }
    
             @Override
             public void onSuccess(String s) {
                 Log.d(TAG, "<ffmpeg>SUCCESS with output : " + s);
                 mSuccess = true;
                 mLastMessage = s;
             }
    
             @Override
             public void onProgress(String s) {
                 if (s.contains("time=")) {
                     String time = s.substring(s.indexOf("time=") + "time=".length(), s.indexOf(" bitrate"));
                     Log.d(TAG, "<ffmpeg>Current Time: " + time);
    
                     try {
                         double timeProcessed = TimeUtilility.timeStringToSeconds(time);
                         mListener.ffmpegPercentComplete(timeProcessed / duration);
                     }
                     catch(Exception ex) {
                         Crashlytics.logException(ex);
                         // Do nothing. If we fail to report a progress, it's not a big deal.
                         // Just don't want the app to crash.
                     }
                 }
             }
    
             @Override
             public void onStart() {
                 Log.d(TAG, "<ffmpeg>Started command : mFFmpeg " + java.util.Arrays.toString(command));
             }
    
             @Override
             public void onFinish() {
                 Log.d(TAG, "<ffmpeg>Finished command : mFFmpeg " + java.util.Arrays.toString(command));
                 if (mSuccess) {
                     mListener.ffmpegSuccess(mLastMessage);
                 } else {
                     mListener.ffmpegFailed(mLastMessage);
                 }
             }
         });
     } catch (FFmpegCommandAlreadyRunningException e) {
         Crashlytics.logException(e);
         e.printStackTrace();
         mListener.ffmpegFailed("FFmpegCommandAlreadyRunningException");
     }
    

    }

    public boolean isRunning() {
    return mFFmpeg != null && mFFmpeg.isFFmpegCommandRunning();
    }

    public void killRunningProcess() {
    if (mFFmpeg == null) {
    return;
    }

     mFFmpeg.killRunningProcesses();
    
     try {
         Field asyncTaskField = mFFmpeg.getClass().getDeclaredField("ffmpegExecuteAsyncTask");
         asyncTaskField.setAccessible(true);
         Object ffmpegExecuteAsyncTask = asyncTaskField.get(mFFmpeg);
    
         if (ffmpegExecuteAsyncTask != null) {
             Field processField = ffmpegExecuteAsyncTask.getClass().getDeclaredField("process");
             processField.setAccessible(true);
             Process process = (Process) processField.get(ffmpegExecuteAsyncTask);
    
             if (process != null) {
                 ProcessUtils.killProcess(process);
                 if (mListener != null) {
                     mListener.ffmpegDidKillProcess();
                 }
             }
         }
     } catch (NoSuchFieldException | IllegalAccessException | ClassCastException ex) {
         throw new RuntimeException(ex);
     }
    

    }

    public void setmListener(OnFFmpegListemer mListener) {
    this.mListener = mListener;
    }

    public interface OnFFmpegListemer {
    void ffmpegSuccess(String message);

     void ffmpegPercentComplete(double percentComplete);
    
     void ffmpegFailed(String message);
    
     void ffmpegDidKillProcess();
    

    }
    }

@riddhee
Copy link

riddhee commented Dec 17, 2019

is this worked for u?

@kartik1225
Copy link

Any updates on this?

@st235
Copy link

st235 commented Jan 1, 2020

I suppose its the limitation of Android Q and target api 29, as the library executes binary file. Indeed it looks really tricky

@rkkalkii
Copy link

rkkalkii commented Jan 8, 2020

Hi there, i am facing the same issue with android Q on target api 29. Taking write permission and waiting for library to load is not helping. Do anyone has any solution??
Thanks.

@st235
Copy link

st235 commented Jan 8, 2020

@rkkalkii, I would recommend you to try MediaCodec API, it really works as ffmpeg. The only limitation is api 18+.

@appteamwebcontentor
Copy link

Does anybody got the solution for this ? I am also stuck here

@st235
Copy link

st235 commented Jan 22, 2020

Does anybody got the solution for this ? I am also stuck here

Yeah, as I wrote below, this solution will not work anymore until authors will not recompile binary file as a static library and wrap the code with JNI methods.

The optimal solution without using any library is to use MediaCodec API provided by Android since API 18+

@pezezzle
Copy link

i recommend google/android to remove this scoped storage shit. Same issue...

@gowthami77
Copy link

Hi............
Does anybody got the solution for this ? I am also stuck here..
Please send me reply

@alexict
Copy link

alexict commented Feb 25, 2020

@gowthami77 the temporary solution is set target api < 29 or you can use MediaCodec API.

@dmitriy-chernysh
Copy link

I have the same issue on Android 10+ with targetsdk 29. I can confirm it works fine with targetSdk 28. But I would like to force it work with the latest sdk. And I cannot use MediaCodec API due to limited functionallity.
Let me know if anybody has solved the issue. Thanks!

@aliraza96
Copy link

Also stuck on this issue. If anybody found a solution except for adding targetSdk 28. Please any help will be appreaciated.

@st235
Copy link

st235 commented Apr 13, 2020

@aliraza96, if MediaCodec is not applicable for you, its still possible to compile ffmpeg from sources as shared library. Here you may found some related info about compilation for Android. Also this one repo structured very well.

@gowthami77
Copy link

I found this library and it worked well on Android 10 https://github.com/tanersener/mobile-ffmpeg

@androidvk
Copy link

@gowthami77 is it working without any errors?? can you post a sample code over here.

@ShankyPatel
Copy link

@gowthami77 i tried to use library but it requires minsdk 24 so its useless.

@1nikolas 1nikolas linked a pull request Jul 4, 2020 that will close this issue
@DevMayur
Copy link

@gowthami77 i tried to use library but it requires minsdk 24 so its useless.
Its main releases support API 24+ but you can use LTS for minsdk 16+
i.e.
use
implementation 'com.arthenica:mobile-ffmpeg-full:4.4.LTS'
instead of
implementation 'com.arthenica:mobile-ffmpeg-full:4.4'

@bilal96aslam
Copy link

I found this library and it worked well on Android 10 https://github.com/tanersener/mobile-ffmpeg

can you please share how to implement this library because I can't find implementation about this library? Thanks

@bilal96aslam
Copy link

@gowthami77 i tried to use library but it requires minsdk 24 so its useless.

but in his documentation saying it requires API 16+

@yyms3275
Copy link

I solved the same problem as below.
I solved the problem by using a different library.

https://github.com/tanersener/mobile-ffmpeg

@dmitriy-chernysh
Copy link

I solved the same problem as below.
I solved the problem by using a different library.

https://github.com/tanersener/mobile-ffmpeg

Yeah. I started using this lib too. The problem has gone. Everything works fine on Android 11.

@natvar97
Copy link

Use below library,
https://github.com/tanersener/ffmpeg-kit/tree/main/android

and put below packagingOptions in build.gradle:

packagingOptions {
pickFirst 'lib/x86/libswscale.so'
pickFirst 'lib/x86/libavcodec.so'
pickFirst 'lib/x86_64/libavutil.so'
pickFirst 'lib/armeabi-v7a/libswscale_neon.so'
pickFirst 'lib/x86_64/libavcodec.so'
pickFirst 'lib/x86_64/libswscale.so'
pickFirst 'lib/x86_64/libavformat.so'
pickFirst 'lib/x86/libavfilter.so'
pickFirst 'lib/x86/libswresample.so'
pickFirst 'lib/arm64-v8a/libavcodec.so'
pickFirst 'lib/armeabi-v7a/libavfilter_neon.so'
pickFirst 'lib/arm64-v8a/libavformat.so'
pickFirst 'lib/x86/libavformat.so'
pickFirst 'lib/arm64-v8a/libavutil.so'
pickFirst 'lib/x86_64/libavdevice.so'
pickFirst 'lib/arm64-v8a/libavfilter.so'
pickFirst 'lib/x86_64/libswresample.so'
pickFirst 'lib/arm64-v8a/libswscale.so'
pickFirst 'lib/x86/libavdevice.so'
pickFirst 'lib/x86/libavutil.so'
pickFirst 'lib/armeabi-v7a/libavcodec_neon.so'
pickFirst 'lib/x86_64/libavfilter.so'
pickFirst 'lib/arm64-v8a/libswresample.so'
pickFirst 'lib/arm64-v8a/libavdevice.so'
}

it will solve your problem

FFmpegSession session = FFmpegKit.execute(command); if (ReturnCode.isSuccess(session.getReturnCode())) { progressbar_popup.setVisibility(View.GONE); pop_txt_progress.setVisibility(View.GONE); refreshAndroidGallery(Uri.parse(destPath)); // renameDialog.dismiss(); if (!PreferenceManager.getRemove()) { viewfullpagead(); } else { renameDialog.dismiss(); //card_pre_video.setVisibility(View.GONE); refreshwaiting(); //startActivity(new Intent(Home.this,VideoFolderList.class)); } } if (ReturnCode.isCancel(session.getReturnCode())) { }

this work for android 11 also (tested)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.