03-HELP ME -batch replacement of audio tracks in video files-03

Started by unity, November 05, 2023, 12:06:38 PM

Previous topic - Next topic

unity

For some reason you are not answering (02-HELP - batch replacement of audio tracks in video files-02)

Thank you very much, dear 
verified
    1) everything works with new lines!

-------------------------------------------------- -------------------------------------------------- -
and I forgot to ask
How to batch export audio tracks from video files?
-------------------------------------------------- -------------------------------------------------- ---
2) "Do you mean automatically adding multiple external audio tracks for each source video?"

yes, how can this be implemented? through names - language postfix - audio track?

-----------------------
here is an example of a specific technical task - batch conversion -
there are, say, 100 videos
1) batch extraction of audio tracks (video remains without sound)
2) add -to these 100 videos (now without sound - after 1 step)
several audio tracks for each video (in different languages, and the number of added audio tracks should be controlled (in the script?), from two to (how many are possible in ?
"For a list of valid language descriptors, see
github"

how can this be implemented? through names - language postfix - audio track?
-----------------------------------
and tell me if it is possible to create a batch conversion (also 100 video files),
video file - with two audio tracks in different languages, audio track01 (in one language) in, say, the left audio channel (L), and audio track02 (in another language) in, say, the right audio channel (R)?
Thank you!

eumagga0x2a

I am not answering because I don't have spare time for Avidemux stuff right now. Maybe in the first half of the coming week.


unity

Dear eumagga0x2a, I'm really looking forward to your help!

eumagga0x2a

Quote from: unity on November 05, 2023, 12:06:38 PMHow to batch export audio tracks from video files?

You could try

#PY  <- Needed to identify #
#
ui = Gui()
adm = Avidemux()
ext = "mp4"
sep = "\\"
#
# Helper function to get extension
# We probably should reject HE-AAC (254), it is incompatible with ADTS envelope.
#
def identifyType():
    codec = adm.audioEncoding(atrack)
    if codec == 255 or codec == 254:
        return ".aac"
    elif codec == 8192:
        return ".ac3"
    elif codec == 8193:
        return ".dts"
    elif codec == 8194:
        return ".eac3"
    elif codec == 80:
        return ".mp2"
    elif codec == 85:
        return ".mp3"
    elif codec == 1:
        return ".wav"
    else:
        return "unsupported"
#
# Function to process an individual video
#
def extractAudio(vid, outdir):
    result = 0
    if not adm.loadVideo(vid):
        ui.displayError("Error","Cannot load \"" + vid + "\"")
        return result

    nbAudioTracks = adm.audioTotalTracksCount()
    if not nbAudioTracks:
        adm.closeVideo()
        return result

    track = 0
    filename = basename((splitext(vid))[0])

    while track < nbAudioTracks:
        adm.audioClearTracks()
        adm.audioAddTrack(track)
        audext = identifyType(0)
        if audext != "unsupported":
            adm.audioCodec(0, "copy")
            outfile = outdir + sep + filename + "_audio_track_" + str(track + 1) + audext
            result += adm.saveAudio(track, outfile)
        track += 1

    adm.closeVideo()
    return result
#
# Main
#
# -------- select input directory --------
inputFolder = ui.dirSelect("Select source folder")
if inputFolder is None:
    ui.displayError("Error", "No source folder selected")
    return 0

# -------- select audio output directory --------
outputFolder = ui.dirSelect("Select audio output folder")
if outputFolder is None:
    ui.displayError("Error", "No audio output folder selected")
    return 0

# -------- read content --------
vidList = get_folder_content(inputFolder, ext)
if vidList is None:
    ui.displayError("Oops", "No " + ext + " files found in \"" + inputFolder + "\"")
    return 0

# -------- process --------
success = 0

for video in vidList:
    success += extractAudio(video, outputFolder)

if not success:
    ui.displayInfo("Warning", "No audio tracks extracted")
elif success == 1:
    ui.displayInfo("Finished", "One audio track extracted, number of loaded videos: " + str(len(vidList)))
else:
    ui.displayInfo("Finished", str(success) + " audio tracks extracted, number of loaded videos: " + str(len(vidList)))

return success

The type or rather filename extension of input videos is hardcoded here as mp4, supported types of audio tracks are exported to selected folder. There is no method to get audio language of an audio track that could be used to add some hint to filenames.

The method saveAudio(int, str) doesn't use the first argument (the track number), making all that ugly dances with audioClearTracks() followed by audioAddTrack(int) necessary.

I'll try to comment on further requests later.

unity

Dear eumagga0x2a

How to batch export audio tracks from video files?
You could try
process-directory-save-audio-tracks.txt
2.43 KB


errors
----

TinyPy:Exception

Exception: (_tp_dict_get) KeyError:atrack
BackTrack:
File: py2bc.py,line53
File:  path  /process-directory-save-audio-tracks.py,line83
File:  path  /process-directory-save-audio-tracks.py,line49
File:  path  /process-directory-save-audio-tracks.py,line12

-----
?
help

eumagga0x2a


unity

Dear  eumagga0x2a
most use stable releases
(and nightly builds are for developers and beta testers, and if the script is for a nightly build, then as a rule they notify about the build (they give the link for the necessary assembly) - I don't know about that :-)
downloaded and installed the latest nightly build

avidemux_2.8.2 r231102_win64
=
not install (win10x64)
http://www.avidemux.org/nightly/win64/

downloaded, installed
Avidemux_2.8.2 VC++ 64bits 231105
http://www.avidemux.org/nightly/vsWin64/
=
install ok
but

error

the error is completely repeating, lines with errors
1) please check the script
2) maybe you have a VMware image where everything works (all dependencies and libraries are installed?)


earlier in your scripts
everything worked - ok

and by the way, ? create a page with scripts on Git Hub
   with requests and solutions in the form of scripts, if questions and requests are repeated on the forum, then a link to the git hub?

eumagga0x2a

My bad, I edited the ready working script in the last moment (changed the signature of identifyType(int) method to identifyType(void) and back) and didn't restart Avidemux between runs which meant that atrack used inside that helper function remained defined from earlier runs. On a clean fresh run, the script, of course, failed.

Please replace

def identifyType():
with

def identifyType(atrack):
I thought about adm.closeVideo() method which had been added recently. I should have carefully read the tinyPy error.

Quote from: unity on November 09, 2023, 06:48:21 PMnightly builds are for developers and beta testers

In case of Avidemux, nightly builds are most of the time just "releases" with many issues found in the last release fixed. Sometimes things get broken in the way, like packaging of "win64" cross-builds after MXE (mingw cross build environment) refresh. The mindset of nightly builds being for developers and beta testers ensures that they do not receive sufficient real world testing and releases remain as buggy as they are.



unity

Dear eumagga0x2a , Thank you very much!
Now everything works


And
and by the way, ? create a page with scripts on Git Hub
with requests and solutions in the form of scripts, if questions and requests are repeated on the forum, then a link to the git hub?

I'm leaving a working script here (just in case)

-----
#PY  <- Needed to identify #
#
ui = Gui()
adm = Avidemux()
ext = "mp4"
sep = "\\"
#
# Helper function to get extension
# We probably should reject HE-AAC (254), it is incompatible with ADTS envelope.
#
def identifyType(atrack):
    codec = adm.audioEncoding(atrack)
    if codec == 255 or codec == 254:
        return ".aac"
    elif codec == 8192:
        return ".ac3"
    elif codec == 8193:
        return ".dts"
    elif codec == 8194:
        return ".eac3"
    elif codec == 80:
        return ".mp2"
    elif codec == 85:
        return ".mp3"
    elif codec == 1:
        return ".wav"
    else:
        return "unsupported"
#
# Function to process an individual video
#
def extractAudio(vid, outdir):
    result = 0
    if not adm.loadVideo(vid):
        ui.displayError("Error","Cannot load \"" + vid + "\"")
        return result

    nbAudioTracks = adm.audioTotalTracksCount()
    if not nbAudioTracks:
        adm.closeVideo()
        return result

    track = 0
    filename = basename((splitext(vid))
  • )

    while track < nbAudioTracks:
        adm.audioClearTracks()
        adm.audioAddTrack(track)
        audext = identifyType(0)
        if audext != "unsupported":
            adm.audioCodec(0, "copy")
            outfile = outdir + sep + filename + "_audio_track_" + str(track + 1) + audext
            result += adm.saveAudio(track, outfile)
        track += 1

    adm.closeVideo()
    return result
#
# Main
#
# -------- select input directory --------
inputFolder = ui.dirSelect("Select source folder")
if inputFolder is None:
    ui.displayError("Error", "No source folder selected")
    return 0

# -------- select audio output directory --------
outputFolder = ui.dirSelect("Select audio output folder")
if outputFolder is None:
    ui.displayError("Error", "No audio output folder selected")
    return 0

# -------- read content --------
vidList = get_folder_content(inputFolder, ext)
if vidList is None:
    ui.displayError("Oops", "No " + ext + " files found in \"" + inputFolder + "\"")
    return 0

# -------- process --------
success = 0

for video in vidList:
    success += extractAudio(video, outputFolder)

if not success:
    ui.displayInfo("Warning", "No audio tracks extracted")
elif success == 1:
    ui.displayInfo("Finished", "One audio track extracted, number of loaded videos: " + str(len(vidList)))
else:
    ui.displayInfo("Finished", str(success) + " audio tracks extracted, number of loaded videos: " + str(len(vidList)))

return success



-----




unity

I'm really looking forward to your response to other points.
"I'll try to comment on further requests later."
I will repeat from (also just in case)

""""
2) "Do you mean automatically adding multiple external audio tracks for each source video?"

yes, how can this be implemented? through names - language postfix - audio track?

-----------------------
here is an example of a specific technical task - batch conversion -
there are, say, 100 videos
1) batch extraction of audio tracks (video remains without sound)
2) add -to these 100 videos (now without sound - after 1 step)
several audio tracks for each video (in different languages, and the number of added audio tracks should be controlled (in the script?), from two to (how many are possible in ?
"For a list of valid language descriptors, see
github"

how can this be implemented? through names - language postfix - audio track?
-----------------------------------
and tell me if it is possible to create a batch conversion (also 100 video files),
video file - with two audio tracks in different languages, audio track01 (in one language) in, say, the left audio channel (L), and audio track02 (in another language) in, say, the right audio channel (R)?
Thank you!
"""

eumagga0x2a

The amount of necessary testing makes fulfilling such complex requests impossible with available time budget.

For example, see a script which would add audio tracks named based on the pattern "video basename + underscore + two-char-language code + "." + one of compatible external audio track extensions" to video (e.g. some_example_vid.mp4, some_example_vid_en.mp3, some_example_vid_pl.aac --> /path/to/output_directory/some_example_vid_with_audio.mkv):

#PY  <- Needed to identify #
#
ui = Gui()
adm = Avidemux()
sep = "\\"

iso639 = [ "sq", "ar", "hy", "az", "be", "bg", "zh", "cs", "da", "de", "nl", "en", "et", "fi", "fr", "ka", "el", "he", "hi", "hu", "is", "it", "kk", "ky", "ko", "lv", "lt", "mn", "fa", "pl", "ro", "ru", "sr", "sk", "es", "sv", "th", "uk", "uz", "vi", "cy" ]
ext2try = [ "aac", "ac3", "mp2", "mp3" ]

def identifyLanguage(fn):
    pos = len(fn)
    if pos < 4:
        return "und"
    pos -= 3
    marker = fn[pos:]
    # The MP4 muxer doesn't accept two-character language codes, the MKV one does.
    for code in iso639:
        if marker == ("_" + code):
            return code
    return "und"
#
# Function to convert an individual video
#
def mux(vidin, outdir):
    if not adm.loadVideo(vidin):
        ui.displayError("Error", "Cannot load \"" + vidin + "\"")
        return 0

    adm.videoCodec("Copy")
    vidFolder = dirname(vidin)
    if vidFolder is None:
        return 0
    if not len(vidFolder):
        return 0
    vidname = (splitext(vidin))[0]
    vidname = basename(vidname)
    extAudList = []
    for ext in ext2try:
        auds = get_folder_content(vidFolder, ext)
        if auds is not None:
            for a in auds:
                abase = basename((splitext(a))[0])
                if (len(abase) == (len(vidname) + 3)) and (abase[:len(vidname)] == vidname):
                    extAudList.append(a)
    if not len(extAudList):
        ui.displayInfo("Warning", "No external audio tracks found for \"" + basename(vidin) + "\"")
        return 0
    extTrackCount = 0
    for aud in extAudList:
        if not adm.audioAddExternal(aud):
            ui.displayError("Error", "Cannot use \"" + aud + "\" as audio track")
            continue
        extTrackCount += 1
        nbTracks = adm.audioTracksCount()
        adm.setSourceTrackLanguage(nbTracks, identifyLanguage(basename(splitext(aud)[0])))
        adm.audioAddTrack(nbTracks)
        adm.audioCodec(nbTracks, "copy")
    filename = (splitext(vidin))[0]
    #adm.setContainer("MP4", "muxerType=0", "optimize=1", "forceAspectRatio=False", "aspectRatio=1", "displayWidth=1280", "rotation=0", "clockfreq=0")
    adm.setContainer("MKV")
    filename += "_with_audio.mkv"
    filename = basename(filename)
    return adm.save(outdir + sep + filename)
#
# Main
#
# -------- select input video directory --------
vidInputFolder = ui.dirSelect("Select video source folder")
if vidInputFolder is None:
    ui.displayError("Error", "No video source folder selected")
    return 0

# -------- read content --------
vidFileList = get_folder_content(vidInputFolder, "mp4")
if vidFileList is None:
    ui.displayError("Oops", "No mp4 files found in \"" + vidInputFolder + "\"")
    return 0

# -------- select output directory --------
outputFolder = ui.dirSelect("Select output folder")
if outputFolder is None:
    ui.displayError("Error", "No output folder selected")
    return 0

if vidInputFolder == outputFolder:
    ui.displayError("Error","Output folder cannot be the same as the video source one")
    return 0

# -------- process --------
total = 0
success = 0

for video in vidFileList:
    success += mux(video, outputFolder)
    total += 1

if not success:
    ui.displayInfo("Warning", "No video files processed")
elif success == 1:
    ui.displayInfo("Finished", "One video file out of " + str(total) + " processed")
else:
    ui.displayInfo("Finished", str(success) + " video files out of " + str(total) + " processed")

return success

To make it work with the MP4 muxer, you would need to replace two-character language codes with three-character ones. In general, if you need some scripts tailored to your requirements, you should do the work yourself.

On my part, I promise to investigate our options to make two-character language specifiers work with the MP4 muxer.

unity

OK,Thanks, I'll try!
--------------
and tell me if it is possible to create a batch conversion (also 100 video files),
video file - with two audio tracks in different languages, audio track01 (in one language) in, say, the left audio channel (L), and audio track02 (in another language) in, say, the right audio channel (R)?

eumagga0x2a

Creating audio tracks with individual channels originating from different sorces is not possible with Avidemux.