7

I'm trying to call ffmpeg.c to trim a video based on this code 'video-trimmer'. So when I try to run the activity (that loads and uses the native lib) the first time I click trin it works and I could trim the video but when I try to run it again it crashes (and it only work with the application restarts).

So I spend three days looking for a solution for this issue, most of the answers says the issue with the static variables in ffmpeg.c and creating a lib that loads and unload the class fixes the issue (answer1, answer2). So I tried to apply the solution that is based on the answers and this github repo on the video-trimmer project but all my attempts failed.

Is there any one knows about a fork of the 'video-trimmer' project that fixes the issue?. or can anybody provide step by step answer of how to implement the solution in the 'video-trimmer' project (because I tried to follow all the solution on the web and apply them in that project but with no luck).

Community
  • 1
  • 1
Jimmy
  • 10,427
  • 18
  • 67
  • 122
  • Do you have some snapshot of your code? – Sruit A.Suk Jan 05 '13 at 07:47
  • Actually I just downloaded the project and tried to run it. Here's where the ffmpeg lib is called https://github.com/uday-rayala/video-trimmer/blob/master/jni/video-trimmer.c. – Jimmy Jan 06 '13 at 14:48
  • Give us a short example and directions so that we can reproduce it. http://sscce.org/ . If you didn't write any code then just the step-by-step instructions so that we can reproduce the error on our work stations. Be sure to mention the platform and the version numbers of the OS and related libraries. – Spundun Jan 17 '13 at 00:35
  • Please help me how can i solve this – koti Dec 09 '13 at 19:35
  • I had to write custom C Interface to call FFMPEG source code instead of calling the lib, I only recommend doing that if you have a lot of time to kill since not a lot of documentations are available for it. – Jimmy Dec 09 '13 at 19:41

4 Answers4

2

the problem seems to be with the initialized values (some variables are declared as global static vars, presumably for ease of access but breaks OOP principles and causes us problems like you're facing), however, there are a few ways round this that I can think of:

  • write a quick function to manually set the static vars back to their correct init values (quick and dirty but works). A list of methods which should not be allowed to fire off as and when they please follows:
    • avcodec_register_all(), avdevice_register_all(), av_register_all()
    • avcodec_find_encoder(), avcodec_find_decoder(), av_find_stream_info()
    • avcodec_open(), avcodec_close()
      • these could be wrapped in a boolean controlled method for example so that if they have run previously they cannot run again.
  • another way to control things is to manually force the variable values (by use of a class or struct to control the ffmpeg global vars) that are being re-initialised on subsequent runs, for example on running the method which currently causes the code to fail, the first step could be to manually set the variables back to their default settings so that they run correctly as at the moment I suspect you have data remaining resident between iterations, and thats what is causing problems.
  • you could utilse mutexes to ensure that the aforementioned methods behave more responsibly when used with threads.

Addendum:

  • also (at the C level) use libffmpeginvoke in preference to libffmpeg if you are going to invoke main() multiple times
  • forcibly invoke Garbage Collection (yep this is another 'ugly' fix) on the call to load the ffmpeg lib, which would then clean things up allowing you to call another instance

Let me know if you need something more in-depth: I can try making a test framework to replicate your problems and see where I get, although that needs access to my home PC as when I am at work I have no Android SDK.

GMasucci
  • 2,834
  • 22
  • 42
  • Forcibly re-initializing the global variables is a good idea if all can be found. As for garbage collecting, etc, do you have evidence that Android will actually unload a shared library from a running process? – Chris Stratton Jan 16 '13 at 18:29
  • Chris, you made a good point: when I got home I tried a couple of tests and had some unexpected results. – GMasucci Jan 17 '13 at 08:12
  • - Garbage Collection does not always free ram, and even when it does it will apparently not always unload unused libraries (this is a feature in android as this allows for rapid re-use of a previously used library) - dlclose() doesn't even guarantee the freeing up of a shared libraryHence I will have to amend myself to recommending a way to either lock the methods down with mutexes or controlling the problem variables manually via a method. – GMasucci Jan 17 '13 at 08:19
  • I have briefly played about (30mins or so) with ffmpeg and have found the libffmpeginvoke to work more stably under android, as this utilises a pre-existing instance rather than libffmpeg which tries to initialise a new instance, which with already altered global variables seems to cause problems. I will investigate further today/tonight(gmt). – GMasucci Jan 17 '13 at 08:20
  • @GMasucci: Thanks for your effort, let me know the result when you take a look at it. I did some testing and still had issues. – Jimmy Jan 18 '13 at 16:00
  • libffmpeginvoke seems to allow me to utilise ffmpeg fine in android, I shall continue testing and create a class to control the variables by hand, and see if that works fine with no/minimal performance hit – GMasucci Jan 23 '13 at 08:17
  • Sorry for the delay in getting back to you, I hope you have a solution that works for you at the moment, however I will be developing on Android this weekend again. – GMasucci Feb 01 '13 at 09:10
  • I still didn't find a solution for this. If you had time to look at it and solve it, I could start the bounty again. – Jimmy Feb 13 '13 at 19:48
  • Hi Jimmy, i can take a look at any code that causing you problems if you like, just give me a shout on here I will try making a wrapper system that can take care of the initialising, however that is liable to be a patchy solution at best, based on general principles and a better/cleaner solution can be coded I think. So far `libffmpeginvoke()` has solved any problems I get when using `libffmpeg()` – GMasucci Feb 14 '13 at 08:33
  • Also is **[this](https://github.com/uday-rayala/video-trimmer)** you project? if so i will branch it and try to replicate you problems and make a fix :) – GMasucci Feb 14 '13 at 08:37
  • Hi again, not had much time to look at your code, however I will If you have still not solved the issue, not this weekend but next it would be. – GMasucci Apr 02 '13 at 08:21
  • 1
    what about https://stackoverflow.com/questions/52916376/calling-ffmpeg-cs-main-twice-causes-app-crash – user924 Oct 21 '18 at 14:48
1

Help us help you, please provide your implemented code or a part of it. Also Crash Log will be helpful.

Hint: Initialise ffmpeg object/thread. Then use a call back interface. Once the VideoTrimmer gets over, give a callback. In that callback call the destroy/kill of the ffmpeg object/thread.

May be this link can help you.

I have recently used the "android-ffmpeg-java" project from github, this is a working library, I can guarantee. You just have to implement a wrapper (test application) which will do the work.
Check this link for Source : android-ffmpeg-java
Check this link for example : android-ffmpeg-cmdline. See if you can solve on with this.

Arpan
  • 613
  • 7
  • 18
  • I tried that, its not in the thread level. Here's where the ffmpeg lib is called https://github.com/uday-rayala/video-trimmer/blob/master/jni/video-trimmer.c. – Jimmy Jan 06 '13 at 14:49
  • The method calling Java_net_video_trimmer_natives_VideoTrimmer_trim should implement a thread. `CallVideoTrimmer() {` `//start_thread` `//register callback` `Java_net_video_trimmer_natives_VideoTrimmer_trim(env, myClass, inputFile, outFile, startTime, length);` `//give callback` `//end thread` – Arpan Jan 09 '13 at 09:49
  • I gave this a try and didn't work. Again it does not look like its in the scope of threads when you register the native method. – Jimmy Jan 15 '13 at 20:40
  • This answer is not based on an understanding of the problem with process-level static variables in Android. Posting the extent of these would be impractical here, though a small issue-demonstrating library could be written for testing purposes. – Chris Stratton Jan 16 '13 at 18:27
0

I am not sure if this will help, but C files typically have a header where you can use

ifndef

Please see the following: http://www.cprogramming.com/reference/preprocessor/ifndef.html

Use that syntax to sandwhich the declaration in the associated .h file to ensure multiple imports don't cause a crash in the importing code.

Good Luck!

Edit: Ok, looks like that would mean recompiling ffmpeg to the .so file. You should just try to verify that it has a mechanism as described above in the codebase and try to confirm it isn't somehow being loaded twice.

DrM
  • 1,092
  • 1
  • 8
  • 11
  • This has nothing to do with the problem, which occurs at runtime rather than compile time. The issue is when a new instance of the task is run in a re-used, existing process - a process ffmpeg and many other programs were not written in anticipation of, but is quite common on Android. – Chris Stratton Jan 16 '13 at 18:29
  • @Chris - ok, I just get suspicious when multiple languages start getting crossed. I really don't know what to predict if code is loaded dynamically more than once from a C library- do you? Anyhow assuming it was compiled from VLAN it should be good - http://git.videolan.org/?p=ffmpeg.git;a=blob;f=ffmpeg.h;h=1260563cb8c0bb526628abfc596dc8ad24556ac7;hb=HEAD – DrM Jan 16 '13 at 20:23
  • The code doesn't get loaded more than once, as the second load call in a process ends up doing nothing. The problem is that parts of the code that were never intended to be run a second time to do new work, are being run repeatedly as Android keeps the process around to re-use. Unless the vlan's version has been thoroughly revised to accomodate this unique Android behavior everywhere that problematic assumptions occur, it's not going to be the solution. Keep in mind that just using the ffmpeg codec's is not the same as using the whole thing including the code which strings them together. – Chris Stratton Jan 16 '13 at 22:19
0

While somewhat crude, a potential workaround could be to utilize/link to ffmpeg from a Service (you had better be doing that anyway) which is declared in the manifest to run in its own process rather than that of client Activities. Then have that process terminate itself - calling native exit() if needed - when the task is completely finished. Android won't particularly like that happening - it's not good practice - but you can probably make it work.

Re-engineering the library to be able to reset itself to a fresh state (or even make it entirely contextual) would be better, but for a huge legacy codebase may prove to be a large project.

Chris Stratton
  • 39,853
  • 6
  • 84
  • 117