Adobe connect video: FLV to MP4 (export, convert)
Asked Answered
K

2

7

I would like to convert an adobe connect video from .flv in the downloaded zip to .mp4. I have already done the steps explained in this question and answer, however I get .flv files organised like this inside the .zip:

enter image description here

Moreover, I know that ffmpeg can merge video and sound files together as well as concatenating resulting clips directly from the command-line which could be quite useful: https://www.labnol.org/internet/useful-ffmpeg-commands/28490/

I can't ask the owner of the video to make it available as an .mp4 from within the adobe connect admin interface. Briefly, I would like to listen to those videos in x2 speed in VLC (just like what I do when listening to random math classes on YouTube - I put ON the x2 speed). The amount of time I would gain to watch adobe connect videos in x2 speed is MASSIVE.

I think I am not the only one that would like to do this. There are a lot of questions on forums about downloading adobe connect videos, but the .flv format mixed with some .xml is generally a killer when the host does not make the videos properly available in .mp4.

Dealing with the order of the .flv files is a puzzle. At least, I would not care to flush the chat away and leave some details like that behind, that would help to reconstruct the videos. Any scripts to automate the process would be useful.

Kneepan answered 8/2, 2017 at 0:58 Comment(5)
Share a link to the zip archive so we can see if ffmpeg can do anything with them.Derinna
I sent you an email with a download link :)Kneepan
"I would like to listen to those videos in x2 speed in VLC" So why not just play those FLV videos files inside VLC anyway at x2 speed? XML is just a text file so it's irrelevant to audio/video playback (ie: only a coded application would process xml or json data. A video format like mp4, flv, or avi does not read xml).Rinderpest
The video and audio are separated in the .flv files. Moreover, it would be interesting to have every file reassembled automatically. I suspect that audio files may swap at different times than video files and this may be described in one of the .xml files that might act as a main. There are many adobe connect conferences of 2 to 3 hours each that I would like to process that way (more than 20), so this would be a tedious process to reassemble everything manually... Yet I hope someone went through that process already and is willing to help many that would like to save those videos.Kneepan
I took a very brief look but ffmpeg could not properly decode anything except the nellymoser audio format in the camera* files. You may need to find another solution. Perhaps the "video" is actually vector Flash stuff?Derinna
B
7

On my side ffmpeg works fine with the cameraVoip__.xml files.

I wrote this Python script to export an Adobe Connect recording as a video (code repo: https://github.com/Franck-Dernoncourt/adobe-connect-video-downloader):

'''
Requirements:
- python 2.7 or 3
- wget, unzip, and ffmpeg accessible from command line.

Examples:
python connect2vid_v2.py https://my.adobeconnect.com/pqc06mcawjgn/  --output_filename=" Understanding how the Network impacts your service"

The script assumes that the .zip files contains screenshare__.flv files, which contain the screen share.

Please email Franck Dernoncourt <[email protected]> if you improve this code.
'''

import shlex
import subprocess
import os
import glob
import argparse
import sys
import re


def run_command(command):
    print('running command: {0}'.format(command))
    process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE)
    while True:
        output = process.stdout.readline()
        print(output.strip())
        if output == b'' and process.poll() is not None:
            print('Done running the command.')
            break
        if output:
            print(output.strip())
    rc = process.poll()
    return rc

def create_folder_if_not_exists(directory):
    '''
    Create the folder if it doesn't exist already.
    '''
    if not os.path.exists(directory):
        os.makedirs(directory)

def extract_connect_id(parser, args):
    '''
    Function written by Aaron Hertzmann
    '''
    # ----- extract the connectID or ZIP file  -----

    if len(args.URLorIDorZIP) < 1:
    #    print('Error: No Connect recording URL provided.')
        parser.print_help()
        sys.exit(0)

    if args.URLorIDorZIP[0][-4:].lower() == '.zip':
        sourceZIP = args.URLorIDorZIP[0]
        connectID = os.path.basename(sourceZIP[:-4])
    elif len(args.URLorIDorZIP[0]) == 12:
        connectID = args.URLorIDorZIP[0]
    else:
        s = args.URLorIDorZIP[0].split('/')
        connectID = None
        for i in range(len(s)-1):
            if 'adobeconnect.com' in s[i]:
                connectID = s[i+1]
                break
        if connectID == None:
            print("Error: couldn't parse URL")
            sys.exit(1)

    return connectID


def main():
    '''
    This is the main function
    '''

    # ================ parse the arguments (part of the parsing code was written by Aaron Hertzmann) ======================

    parser = argparse.ArgumentParser(description='Download an Adobe Connect recording and convert to a video file.')
    parser.add_argument('URLorIDorZIP', nargs='*', help='URL, code, or ZIP file for the Connect recording')
    parser.add_argument('--output_folder',default='output_videos',help='Folder for output files')
    parser.add_argument('--output_filename',default='noname', help='output_filename')
    args = parser.parse_args()

    #main_output_folder = "all_videos"
    main_output_folder = args.output_folder
    output_filename = args.output_filename
    output_filename =  re.sub(r'[^\w\s]','', output_filename)
    output_filename = output_filename.replace('@', '').strip()
    print('output_filename: {0}'.format(output_filename))
    connect_id = 'pul1pgdvpr87'
    connect_id = 'p6vwxp2d0c2f'
    connect_id = extract_connect_id(parser, args)
    video_filename = 'hello'
    video_filename = output_filename

    # ================ Download video  ======================
    output_folder = connect_id
    output_zip_filename = '{0}.zip'.format(connect_id)
    create_folder_if_not_exists(output_folder)
    create_folder_if_not_exists(main_output_folder)

    # Step 1: retrieve audio and video files
    connect_zip_url = 'https://my.adobeconnect.com/{0}/output/{0}.zip?download=zip'.format(connect_id)
    wget_command = 'wget -nc -O {1} {0}'.format(connect_zip_url, output_zip_filename) # -nc, --no-clobber: skip downloads that would download to existing files.
    run_command(wget_command)
    unzip_command = 'unzip -n {0} -d {1}'.format(output_zip_filename, output_folder) # -n: Unzip only newer files.
    run_command(unzip_command)

    # Step 2: create final video output
    cameraVoip_filepaths = []
    for filepaths in sorted(glob.glob(os.path.join(output_folder, 'cameraVoip_*.flv'))):
        cameraVoip_filepaths.append(filepaths)
    print('cameraVoip_filepaths: {0}'.format(cameraVoip_filepaths))

    screenshare_filepaths = []
    for filepaths in sorted(glob.glob(os.path.join(output_folder, 'screenshare_*.flv'))):
        screenshare_filepaths.append(filepaths)

    part = 0
    output_filepaths = []
    for cameraVoip_filepath, screenshare_filepath in zip(cameraVoip_filepaths, screenshare_filepaths):
        output_filepath = os.path.join(main_output_folder, '{0}_{1:04d}.flv'.format(video_filename, part))
        #output_filepath = '{0}_{1:04d}.flv'.format(video_filename, part)
        output_filepaths.append(output_filepath)
        # ffmpeg command from Oliver Wang / Yannick Hold-Geoffroy / Aaron Hertzmann
        conversion_command = 'ffmpeg -i "%s" -i "%s" -c copy -map 0:a:0 -map 1:v:0 -shortest -y "%s"'%(cameraVoip_filepath, screenshare_filepath, output_filepath)
        # -y: override output file if exists
        run_command(conversion_command)
        part += 1

    # Concatenate all videos into one single video
    # https://mcmap.net/q/53229/-how-to-concatenate-two-mp4-files-using-ffmpeg-closed
    video_list_filename = 'video_list.txt'
    video_list_file = open(video_list_filename, 'w')
    for output_filepath in output_filepaths:
        video_list_file.write("file '{0}'\n".format(output_filepath))
    video_list_file.close()
    final_output_filepath = '{0}.flv'.format(video_filename)
    # ffmpeg command from Oliver Wang / Yannick Hold-Geoffroy / Aaron Hertzmann
    conversion_command = 'ffmpeg -safe 0 -y -f concat -i "{1}" -c copy "{0}"'.format(final_output_filepath, video_list_filename)
    run_command(conversion_command)
    #os.remove(video_list_filename)

if __name__ == "__main__":
    main()
    #cProfile.run('main()') # if you want to do some profiling
Booboo answered 10/2, 2019 at 21:47 Comment(10)
Didn't try nor read as I won't need this anymore. I accepted the answer as it seems elaborate.Kneepan
code seems to work fine, thank you! But there seems to be an issue with the screenshare content. How have you managed to play the screenshare_.flv file? I just get a black screen. The flv-file seems to be encoded with On2's VP6.2 Video (Flash) (VP6F). I have tried with VLC-media player, VirtualDub, Windows Media Player with different codecs installed, but I unfortunately only get a black screen. Thank you for your feedback!Elli
The links that I have downloaded does not have the screenshare files also. I do not know what could be done. I tried the python code also. But it did not help muchDacoit
I find the general structure really useful, but this only works if each screenshare and each cameravoip come in matching pairs. I ran into multiple problems when the screenshare starts after the audio or there is a gap in the audio, because the presenter stopped the audio but not the recording during a break. I'm not yet able to merge those without reencoding which takes too long. The mainstream.xml contains timestamp of start and end of each .flv in the main recording, but I can't figure out how to properly merge everything into one video.Trueblood
Really useful, there is a problem sorting file names, for example _0_18.flv is appended before _0_4.flvPanatella
To Franck Dernoncourt, did you make any updated version of this script?Musa
@Musa sorry I didn'tBooboo
Do you have it in a repo or something? I made few modifications and it would be nice to push them. Actually I modified the code to have a small PyQt5 GUI, very rough and incomplete, but may be nice for those who don't want to dig into the CLI. If you make a repo of this, let me know :)Musa
@Musa thanks, good idea: github.com/Franck-Dernoncourt/adobe-connect-video-downloaderBooboo
For who is still interested: You can read the timings from the xml files so that you can sync multiple flv files with the mp3 filesIngulf
P
0


Hello
You should only use flv files, not xml files .
cameraVoip.xml file for microphone, camera video and screenshare.flv for shared screen (from desktop).

You can also get the start time of these files in the indexstream.xml file, which is embedded in tags in milliseconds.

Also, if you know how to work with ffmpeg or other software, you can download these files, get the schedules, and then combine the files in order.

But if you can not and only sound and videos are important to you, not text, you can use the program I wrote, which is better to look at my github address for a more complete explanation of the program.

It goes without saying that Adobe Connect files may be corrupted for any reason, so make sure they are safe and then work with Adobe files.

https://github.com/HosseinShams00/AdobeConnectDownloader

Platino answered 4/5, 2022 at 17:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.