a-schild / jave2

The JAVE (Java Audio Video Encoder) library is Java wrapper on the ffmpeg project
GNU General Public License v3.0
1.2k stars 245 forks source link

Cannot run program "/tmp/jave/ffmpeg-amd64-2.7.3": error=26, Text file busy #194

Closed raha007 closed 1 year ago

raha007 commented 2 years ago

When I was trying to execute the multiple threads parallelly. At the time getting the exception error = 26. Text file busy. Anyone has an idea how can we resolve this issue. JAVE

a-schild commented 2 years ago

How do you execute it in parallel? It should work, but you will have to use separate instances

raha007 commented 2 years ago

I have attached the logs. Creating new instance of Encoder. Please find the below code. final Encoder encoder = new Encoder(); // does this overwrite if an existing file encoder.encode(new MultimediaObject(source), target, attrs);

logs Caused by: ws.schild.jave.EncoderException: java.io.IOException: Cannot run program "/tmp/jave/ffmpeg-amd64-2.7.3": error=26, Text file busy at ws.schild.jave.Encoder.encode(Encoder.java:640) at ws.schild.jave.Encoder.encode(Encoder.java:398) at ws.schild.jave.Encoder.encode(Encoder.java:363) at com.uniphore.platform.core.helper.AudioEncoderHelper.convert(AudioEncoderHelper.java:60) ... 40 common frames omitted Caused by: java.io.IOException: Cannot run program "/tmp/jave/ffmpeg-amd64-2.7.3": error=26, Text file busy at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048) at java.lang.Runtime.exec(Runtime.java:621) at java.lang.Runtime.exec(Runtime.java:486) at ws.schild.jave.FFMPEGExecutor.execute(FFMPEGExecutor.java:119) at ws.schild.jave.FFMPEGExecutor.execute(FFMPEGExecutor.java:141) at ws.schild.jave.Encoder.encode(Encoder.java:637) ... 43 common frames omitted Caused by: java.io.IOException: error=26, Text file busy at java.lang.UNIXProcess.forkAndExec(Native Method) at java.lang.UNIXProcess.(UNIXProcess.java:247) at java.lang.ProcessImpl.start(ProcessImpl.java:134) at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)

a-schild commented 2 years ago

Can you have a look at this https://github.com/a-schild/jave2/issues/163

I see you use the old 2.7.3 release, please upgrade to the version mentioned in the other issue.

Anyway it's a good idea to use the latest version when you see errors, otherwise you just generate noise about already solved problems

raha007 commented 2 years ago

I have updated the lib to 3.2.0 still facing the race condition. Please find the below code and logs code: `final EncodingAttributes attrs = new EncodingAttributes(); attrs.setOutputFormat("wav"); attrs.setDecodingThreads(2); attrs.setEncodingThreads(2); attrs.setAudioAttributes(audio);

// Encode
try {
  //final FileEncoderProgressListener listener = new FileEncoderProgressListener(filePath);
  final Encoder encoder = new Encoder();
  // does this overwrite if an existing file
  encoder.encode(new MultimediaObject(source), target, attrs);`

logs ws.schild.jave.EncoderException: java.io.IOException: Cannot run program "/tmp/jave/ffmpeg-amd64-3.2.0": error=26, Text file busy at ws.schild.jave.Encoder.encode(Encoder.java:508) at ws.schild.jave.Encoder.encode(Encoder.java:351) at ws.schild.jave.Encoder.encode(Encoder.java:318) at com.uniphore.platform.core.helper.AudioEncoderHelper.convert(AudioEncoderHelper.java:61) ... 40 common frames omitted Caused by: java.io.IOException: Cannot run program "/tmp/jave/ffmpeg-amd64-3.2.0": error=26, Text file busy at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048) at java.lang.Runtime.exec(Runtime.java:621) at java.lang.Runtime.exec(Runtime.java:486) at ws.schild.jave.process.ProcessWrapper.execute(ProcessWrapper.java:103) at ws.schild.jave.process.ProcessWrapper.execute(ProcessWrapper.java:135) at ws.schild.jave.Encoder.encode(Encoder.java:506) ... 43 common frames omitted Caused by: java.io.IOException: error=26, Text file busy at java.lang.UNIXProcess.forkAndExec(Native Method) at java.lang.UNIXProcess.<init>(UNIXProcess.java:247) at java.lang.ProcessImpl.start(ProcessImpl.java:134) at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029

a-schild commented 2 years ago

Could you please show how you start them concurrently? Are you using separate jvm processes or threads, oder...?

raha007 commented 2 years ago

Can you please help me here? How can I fix this issue? Getting the request so frequently like very less span of time around 10 milliseconds of gap.

raha007 commented 2 years ago

using the executor service to pass the request to encode method. no. I'm not using the separate jvm.

a-schild commented 2 years ago

Please show the code

raha007 commented 2 years ago

`public void convert() throws PlatformException { log.debug("Got request to convert audio file from 8K bitrate to 16K bitrate"); final long start = System.currentTimeMillis(); final String filePath = this.fileData.getFilePath().get(); final File source = new File(filePath); String[] fileNameAndExtension = this.targetFilePath.split("\."); final File target = new File(fileNameAndExtension[0] + FileCollectionConstants.WAV_EXTENSION);

final AudioHeader header = this.fileData.getHeader().get();
// Audio Attributes
final AudioAttributes audio = new AudioAttributes();
audio.setCodec(FileCollectionConstants.ENCODING_PCM_S16LE);
audio.setBitRate(FileCollectionConstants.BIT_RATE_16);
audio.setSamplingRate(FileCollectionConstants.FILE_SAMPLE_RATE);
audio.setChannels(header.getChannels());

// Encoding attributes
final EncodingAttributes attrs = new EncodingAttributes();
attrs.setOutputFormat("wav");
attrs.setDecodingThreads(2);
attrs.setEncodingThreads(2);
attrs.setAudioAttributes(audio);

// Encode
try {
  //final FileEncoderProgressListener listener = new FileEncoderProgressListener(filePath);
  final Encoder encoder = new Encoder();
  // does this overwrite if an existing file
  encoder.encode(new MultimediaObject(source), target, attrs);
  log.debug("Time took {} ms to covert to 16 bit rate audio file {}",
      System.currentTimeMillis() - start, this.fileData);
} catch (IllegalArgumentException | EncoderException e) {
  throw new PlatformException(e);
}

}`

raha007 commented 2 years ago

We have written one API which publishes the data to Kafka and from Kafka we consume the data and start calling the convert method.

a-schild commented 2 years ago

Hmmm.. there we don't see how the threads are spawned...

In https://github.com/a-schild/jave2/blob/master/jave-core/src/main/java/ws/schild/jave/process/ffmpeg/DefaultFFMPEGLocator.java in the DefaultFFMPEGLocator()method we have a synchronized section which should prevent the concurrent unwarpping of the executabe from the jar file in the temp location.

If for some reason this does not work, it looks like there is a codepath which is missing some proper semaphore...

raha007 commented 2 years ago

Hi @a-schild can we use the same library(JAVE) for splitting the stereo file into two mono files?

a-schild commented 2 years ago

@raha007 Please create a new thread for this.

clemp6r commented 2 years ago

I have the same issue on Java 11 / Linux and Jave 3.3.1.

Cannot run program "/tmp/jave/ffmpeg-amd64-3.3.1": error=26, Text file busy

I run two operations (audio compression from WAV to AAC) in parallel as following:

val parallelExecutor = Executors.newFixedThreadPool(2)

val inputCompressionFuture = parallelExecutor.submit {
    ...instanciate a new Encoder, run encode, etc...
}

val outputCompressionFuture = parallelExecutor.submit {
    ...instanciate a new Encoder, run encode, etc...
}

inputCompressionFuture.get()
outputCompressionFuture.get()

in` the DefaultFFMPEGLocator()method we have a synchronized section which should prevent the concurrent unwarpping of the executabe from the jar file in the temp location.

As this is used as the monitor object that does not prevent concurrent executions from different instances of DefaultFFMPEGLocator. You may use instead an object that is unique (e.g: this.getClass() or something).

I tried using a shared instance of Encoder but this leads to another issue (ConcurrentModificationException).

A workaround that seem to work consists of instantiating a single DefaultFFMPEGLocator and reusing it in every place we instantiate an Encoder (optional constructor argument).

raha007 commented 1 year ago

use the updated version of library. most probably this issue should be resolved

leeychee commented 9 months ago

Hmmm.. there we don't see how the threads are spawned...

In https://github.com/a-schild/jave2/blob/master/jave-core/src/main/java/ws/schild/jave/process/ffmpeg/DefaultFFMPEGLocator.java in the DefaultFFMPEGLocator()method we have a synchronized section which should prevent the concurrent unwarpping of the executabe from the jar file in the temp location.

If for some reason this does not work, it looks like there is a codepath which is missing some proper semaphore...

@a-schild synchronized(this) may not block another thread to execute these code concurrently, every new DefaultFFMPEGLocator() create a different this.

Maybe the synchronized(DefaultFFMPEGLocator.class)?