Hello,

I am writing a multi-threaded Java application for video conversion and uploading to YouTube. I came across a strange feature - it’s even a plus, that is, it doesn’t bother me at all, but I understand that this is a consequence of an error and a curved design, and I want to understand where he did the stupidity.

There are several threads in the application:

  • the thread that starts the FFMpeg encoder process, takes data from its output (console buffer) - the class is inherited from Thread;
  • the thread that starts this thread, and binds to it via waitFor () - ServiceRunner, the class is inherited from Thread;
  • the main thread - in a loop on some timer checks whether the stop flag is set (if set, knocks the ffmpeg system process, since there is no other way to complete it, and performs finalization, calling the necessary logic of other classes;
  • flow processing SwingUI, interface rendering;
  • in the "only download without conversion" mode, there is another stream that updates the Elapsed time and Remaining time counters once a second by a timer;
  • Browser stream (extends Thread) - upload data to YouTube and access API, uses Apache HttpClient

Everything works quite predictably (except for small nuances like the fact that at the time of stopping due to the curved code, states in different classes may not be coordinated), except for one strange moment.

Namely, at startup, all threads (ServiceRunner and Main) are blocked until the launched HttpConnect stream (the static inner class inside the Browser) receives data. This HttpConnect is an embedded, simplest web server type. Its task is to accept the access token from YouTube sent by the link in the redirect. And display a link to the video control panel so that the user can use the open tab with benefit.

And here it is strange: a new thread starts, a socket is returned to the class constructor, returned via accept (), the similar code worked in most other projects. But here it does not work that way. Namely, until this socket receives the data, the encoding does not start. StreamGobbler, which receives data from ffmpeg, and in this mode also launches the Browser (since it didn’t work out from Main, all code wasn’t executed after the start of this stream) is not executed. As the debug output showed, the loop with timers in Main is not executed either. Nothing is executed except the stream where the code of the Browser class is executed. UI, however, works.

And because of this, we cannot start coding until the user gives the application access to YouTube. In the combined mode it may even be logical, but we are losing precious time. And they could do useful work.

How can I rewrite the code so that there is no problem?

  • as I understand, getting a token in another thread is also executed, but still everything hangs? - Senior Pomidor
  • Receiving a token is performed in the same stream, in which the file is loaded and all the work with the network takes place. There is also a logic that checks how many percent of the file has been converted, and how many bytes are already available on the disk at the moment (this is the old version of the condition, I did not remove it just in case). If the difference is less than N percent - the next segment is not loaded, instead fall asleep for 10 seconds. The same thread gets a token at the very beginning. - Alex654
  • I did not understand in what flow it is. all the same, the token is received in the main thread or somewhere else (and it doesn't matter what is done in this other thread) - Senior Pomidor
  • No, not the point. But the main one is slowed down - Alex654
  • Can I get the code? - Senior Pomidor

1 answer 1

The reason for blocking at the start is that the request for a token is not in a separate thread, but in this one. In the Browser class in the launch method:

instance = new Browser(); Main.browser = instance; instance.run(); 

A call to run does not create a stream; there is a start method for this.

PS: very bad practice inherited from the class Thread, for this there is an interface Runnable.