Best JavaScript code snippet using wpt
rippy.py
Source:rippy.py
1#!/usr/bin/env python2"""Rippy!3This script helps to convert video from one format to another.4This is useful for ripping DVD to mpeg4 video (XviD, DivX).5Features:6 * automatic crop detection7 * mp3 audio compression with resampling options8 * automatic bitrate calculation based on desired target size9 * optional interlace removal, b/w video optimization, video scaling10Run the script with no arguments to start with interactive prompts:11 rippy.py12Run the script with the filename of a config to start automatic mode:13 rippy.py rippy.conf14After Rippy is finished it saves the current configuation in a file called15'rippy.conf' in the local directoy. This can be used to rerun process using the16exact same settings by passing the filename of the conf file as an argument to17Rippy. Rippy will read the options from the file instead of asking you for18options interactively. So if you run rippy with 'dry_run=1' then you can run19the process again later using the 'rippy.conf' file. Don't forget to edit20'rippy.conf' to set 'dry_run=0'!21If you run rippy with 'dry_run' and 'verbose' true then the output generated is22valid command line commands. you could (in theory) cut-and-paste the commands23to a shell prompt. You will need to tweak some values such as crop area and bit24rate because these cannot be calculated in a dry run. This is useful if you25want to get an idea of what Rippy plans to do.26For all the trouble that Rippy goes through to calculate the best bitrate for a27desired target video size it sometimes fails to get it right. Sometimes the28final video size will differ more than you wanted from the desired size, but if29you are really motivated and have a lot of time on your hands then you can run30Rippy again with a manually calculated bitrate. After all compression is done31the first time Rippy will recalculate the bitrate to give you the nearly exact32bitrate that would have worked. You can then edit the 'rippy.conf' file; set33the video_bitrate with this revised bitrate; and then run Rippy all over again.34There is nothing like 4-pass video compression to get it right! Actually, this35could be done in three passes since I don't need to do the second pass36compression before I calculate the revised bitrate. I'm also considering an37enhancement where Rippy would compress ten spread out chunks, 1-minute in38length to estimate the bitrate.39Free, open source, and all that good stuff.40Rippy Copyright (c) 2006 Noah Spurrier41Permission is hereby granted, free of charge, to any person obtaining a copy42of this software and associated documentation files (the "Software"), to deal43in the Software without restriction, including without limitation the rights44to use, copy, modify, merge, publish, distribute, sublicense, and/or sell45copies of the Software, and to permit persons to whom the Software is46furnished to do so, subject to the following conditions:47The above copyright notice and this permission notice shall be included in all48copies or substantial portions of the Software.49THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,50EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF51MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.52IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,53DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR54OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE55USE OR OTHER DEALINGS IN THE SOFTWARE.56Noah Spurrier57$Id: rippy.py 498 2007-12-17 13:44:19Z noah $58"""59import sys, os, re, math, stat, getopt, traceback, types, time60import pexpect61__version__ = '1.2'62__revision__ = '$Revision: 11 $'63__all__ = ['main', __version__, __revision__]64GLOBAL_LOGFILE_NAME = "rippy_%d.log" % os.getpid()65GLOBAL_LOGFILE = open (GLOBAL_LOGFILE_NAME, "wb")66###############################################################################67# This giant section defines the prompts and defaults used in interactive mode.68###############################################################################69# Python dictionaries are unordered, so70# I have this list that maintains the order of the keys.71prompts_key_order = (72'verbose_flag',73'dry_run_flag',74'video_source_filename',75'video_chapter',76'video_final_filename',77'video_length',78'video_aspect_ratio',79'video_scale',80'video_encode_passes',81'video_codec',82'video_fourcc_override',83'video_bitrate',84'video_bitrate_overhead',85'video_target_size',86'video_crop_area',87'video_deinterlace_flag',88'video_gray_flag',89'subtitle_id',90'audio_id',91'audio_codec',92'audio_raw_filename',93'audio_volume_boost',94'audio_sample_rate',95'audio_bitrate',96#'audio_lowpass_filter',97'delete_tmp_files_flag'98)99#100# The 'prompts' dictionary holds all the messages shown to the user in101# interactive mode. The 'prompts' dictionary schema is defined as follows:102# prompt_key : ( default value, prompt string, help string, level of difficulty (0,1,2) )103#104prompts = {105'video_source_filename':("dvd://1", 'video source filename?', """This is the filename of the video that you want to convert from.106It can be any file that mencoder supports.107You can also choose a DVD device using the dvd://1 syntax.108Title 1 is usually the main title on a DVD.""",0),109'video_chapter':("none",'video chapter?',"""This is the chapter number. Usually disks such as TV series seasons will be divided into chapters. Maybe be set to none.""",0),110'video_final_filename':("video_final.avi", "video final filename?", """This is the name of the final video.""",0),111'audio_raw_filename':("audiodump.wav", "audio raw filename?", """This is the audio raw PCM filename. This is prior to compression.112Note that mplayer automatically names this audiodump.wav, so don't change this.""",1000),113#'audio_compressed_filename':("audiodump.mp3","Audio compressed filename?", """This is the name of the compressed audio that will be mixed114#into the final video. Normally you don't need to change this.""",2),115'video_length':("none","video length in seconds?","""This sets the length of the video in seconds. This is used to estimate the116bitrate for a target video file size. Set to 'calc' to have Rippy calculate117the length. Set to 'none' if you don't want rippy to estimate the bitrate --118you will have to manually specify bitrate.""",1),119'video_aspect_ratio':("calc","aspect ratio?","""This sets the aspect ratio of the video. Most DVDs are 16/9 or 4/3.""",1),120'video_scale':("none","video scale?","""This scales the video to the given output size. The default is to do no scaling.121You may type in a resolution such as 320x240 or you may use presets.122 qntsc: 352x240 (NTSC quarter screen)123 qpal: 352x288 (PAL quarter screen)124 ntsc: 720x480 (standard NTSC)125 pal: 720x576 (standard PAL)126 sntsc: 640x480 (square pixel NTSC)127 spal: 768x576 (square pixel PAL)""",1),128'video_codec':("mpeg4","video codec?","""This is the video compression to use. This is passed directly to mencoder, so129any format that it recognizes should work. For XviD or DivX use mpeg4.130Almost all MS Windows systems support wmv2 out of the box.131Some common codecs include:132mjpeg, h263, h263p, h264, mpeg4, msmpeg4, wmv1, wmv2, mpeg1video, mpeg2video, huffyuv, ffv1.133""",2),134'audio_codec':("mp3","audio codec?","""This is the audio compression to use. This is passed directly to mencoder, so135any format that it recognizes will work.136Some common codecs include:137mp3, mp2, aac, pcm138See mencoder manual for details.""",2),139'video_fourcc_override':("XVID","force fourcc code?","""This forces the fourcc codec to the given value. XVID is safest for Windows.140The following are common fourcc values:141 FMP4 - This is the mencoder default. This is the "real" value.142 XVID - used by Xvid (safest)143 DX50 -144 MP4S - Microsoft""",2),145'video_encode_passes':("1","number of encode passes?","""This sets how many passes to use to encode the video. You can choose 1 or 2.146Using two pases takes twice as long as one pass, but produces a better147quality video. I found that the improvement is not that impressive.""",1),148'verbose_flag':("Y","verbose output?","""This sets verbose output. If true then all commands and arguments are printed149before they are run. This is useful to see exactly how commands are run.""",1),150'dry_run_flag':("N","dry run?","""This sets 'dry run' mode. If true then commands are not run. This is useful151if you want to see what would the script would do.""",1),152'video_bitrate':("calc","video bitrate?","""This sets the video bitrate. This overrides video_target_size.153Set to 'calc' to automatically estimate the bitrate based on the154video final target size. If you set video_length to 'none' then155you will have to specify this video_bitrate.""",1),156'video_target_size':("737280000","video final target size?","""This sets the target video size that you want to end up with.157This is over-ridden by video_bitrate. In other words, if you specify158video_bitrate then video_target_size is ignored.159Due to the unpredictable nature of VBR compression the final video size160may not exactly match. The following are common CDR sizes:161 180MB CDR (21 minutes) holds 193536000 bytes162 550MB CDR (63 minutes) holds 580608000 bytes163 650MB CDR (74 minutes) holds 681984000 bytes164 700MB CDR (80 minutes) holds 737280000 bytes""",0),165'video_bitrate_overhead':("1.0","bitrate overhead factor?","""Adjust this value if you want to leave more room for166other files such as subtitle files.167If you specify video_bitrate then this value is ignored.""",2),168'video_crop_area':("detect","crop area?","""This sets the crop area to remove black bars from the top or sides of the video.169This helps save space. Set to 'detect' to automatically detect the crop area.170Set to 'none' to not crop the video. Normally you don't need to change this.""",1),171'video_deinterlace_flag':("N","is the video interlaced?","""This sets the deinterlace flag. If set then mencoder will be instructed172to filter out interlace artifacts (using '-vf pp=md').""",1),173'video_gray_flag':("N","is the video black and white (gray)?","""This improves output for black and white video.""",1),174'subtitle_id':("None","Subtitle ID stream?","""This selects the subtitle stream to extract from the source video.175Normally, 0 is the English subtitle stream for a DVD.176Subtitles IDs with higher numbers may be other languages.""",1),177'audio_id':("128","audio ID stream?","""This selects the audio stream to extract from the source video.178If your source is a VOB file (DVD) then stream IDs start at 128.179Normally, 128 is the main audio track for a DVD.180Tracks with higher numbers may be other language dubs or audio commentary.""",1),181'audio_sample_rate':("32000","audio sample rate (Hz) 48000, 44100, 32000, 24000, 12000","""This sets the rate at which the compressed audio will be resampled.182DVD audio is 48 kHz whereas music CDs use 44.1 kHz. The higher the sample rate183the more space the audio track will take. That will leave less space for video.18432 kHz is a good trade-off if you are trying to fit a video onto a CD.""",1),185'audio_bitrate':("96","audio bitrate (kbit/s) 192, 128, 96, 64?","""This sets the bitrate for MP3 audio compression.186The higher the bitrate the more space the audio track will take.187That will leave less space for video. Most people find music to be acceptable188at 128 kBitS. 96 kBitS is a good trade-off if you are trying to fit a video onto a CD.""",1),189'audio_volume_boost':("none","volume dB boost?","""Many DVDs have very low audio volume. This sets an audio volume boost in Decibels.190Values of 6 to 10 usually adjust quiet DVDs to a comfortable level.""",1),191#'audio_lowpass_filter':("16","audio lowpass filter (kHz)?","""This sets the low-pass filter for the audio.192#Normally this should be half of the audio sample rate.193#This improves audio compression and quality.194#Normally you don't need to change this.""",1),195'delete_tmp_files_flag':("N","delete temporary files when finished?","""If Y then %s, audio_raw_filename, and 'divx2pass.log' will be deleted at the end."""%GLOBAL_LOGFILE_NAME,1)196}197##############################################################################198# This is the important convert control function199##############################################################################200def convert (options):201 """This is the heart of it all -- this performs an end-to-end conversion of202 a video from one format to another. It requires a dictionary of options.203 The conversion process will also add some keys to the dictionary204 such as length of the video and crop area. The dictionary is returned.205 This options dictionary could be used again to repeat the convert process206 (it is also saved to rippy.conf as text).207 """208 if options['subtitle_id'] is not None:209 print "# extract subtitles"210 apply_smart (extract_subtitles, options)211 else:212 print "# do not extract subtitles."213 # Optimization214 # I really only need to calculate the exact video length if the user215 # selected 'calc' for video_bitrate216 # or217 # selected 'detect' for video_crop_area.218 if options['video_bitrate']=='calc' or options['video_crop_area']=='detect':219 # As strange as it seems, the only reliable way to calculate the length220 # of a video (in seconds) is to extract the raw, uncompressed PCM audio stream221 # and then calculate the length of that. This is because MP4 video is VBR, so222 # you cannot get exact time based on compressed size.223 if options['video_length']=='calc':224 print "# extract PCM raw audio to %s" % (options['audio_raw_filename'])225 apply_smart (extract_audio, options)226 options['video_length'] = apply_smart (get_length, options)227 print "# Length of raw audio file : %d seconds (%0.2f minutes)" % (options['video_length'], float(options['video_length'])/60.0)228 if options['video_bitrate']=='calc':229 options['video_bitrate'] = options['video_bitrate_overhead'] * apply_smart (calc_video_bitrate, options) 230 print "# video bitrate : " + str(options['video_bitrate'])231 if options['video_crop_area']=='detect':232 options['video_crop_area'] = apply_smart (crop_detect, options)233 print "# crop area : " + str(options['video_crop_area'])234 print "# compression estimate"235 print apply_smart (compression_estimate, options)236 print "# compress video"237 apply_smart (compress_video, options)238 'audio_volume_boost',239 print "# delete temporary files:",240 if options['delete_tmp_files_flag']:241 print "yes"242 apply_smart (delete_tmp_files, options)243 else:244 print "no"245 # Finish by saving options to rippy.conf and 246 # calclating if final_size is less than target_size.247 o = ["# options used to create video\n"]248 video_actual_size = get_filesize (options['video_final_filename'])249 if options['video_target_size'] != 'none':250 revised_bitrate = calculate_revised_bitrate (options['video_bitrate'], options['video_target_size'], video_actual_size)251 o.append("# revised video_bitrate : %d\n" % revised_bitrate)252 for k,v in options.iteritems():253 o.append (" %30s : %s\n" % (k, v))254 print '# '.join(o)255 fout = open("rippy.conf","wb").write(''.join(o))256 print "# final actual video size = %d" % video_actual_size257 if options['video_target_size'] != 'none':258 if video_actual_size > options['video_target_size']:259 print "# FINAL VIDEO SIZE IS GREATER THAN DESIRED TARGET"260 print "# final video size is %d bytes over target size" % (video_actual_size - options['video_target_size'])261 else:262 print "# final video size is %d bytes under target size" % (options['video_target_size'] - video_actual_size)263 print "# If you want to run the entire compression process all over again"264 print "# to get closer to the target video size then trying using a revised"265 print "# video_bitrate of %d" % revised_bitrate266 return options267##############################################################################268def exit_with_usage(exit_code=1):269 print globals()['__doc__']270 print 'version:', globals()['__version__']271 sys.stdout.flush()272 os._exit(exit_code)273def check_missing_requirements ():274 """This list of missing requirements (mencoder, mplayer, lame, and mkvmerge).275 Returns None if all requirements are in the execution path.276 """277 missing = []278 if pexpect.which("mencoder") is None:279 missing.append("mencoder")280 if pexpect.which("mplayer") is None:281 missing.append("mplayer")282 #if pexpect.which("lame") is None:283 # missing.append("lame")284 #if pexpect.which("mkvmerge") is None:285 # missing.append("mkvmerge")286 if len(missing)==0:287 return None288 return missing289def input_option (message, default_value="", help=None, level=0, max_level=0):290 """This is a fancy raw_input function.291 If the user enters '?' then the contents of help is printed.292 293 The 'level' and 'max_level' are used to adjust which advanced options294 are printed. 'max_level' is the level of options that the user wants295 to see. 'level' is the level of difficulty for this particular option.296 If this level is <= the max_level the user wants then the297 message is printed and user input is allowed; otherwise, the298 default value is returned automatically without user input.299 """300 if default_value != '':301 message = "%s [%s] " % (message, default_value)302 if level > max_level:303 return default_value304 while 1:305 user_input = raw_input (message)306 if user_input=='?':307 print help308 elif user_input=='':309 return default_value310 else:311 break312 return user_input313def progress_callback (d=None):314 """This callback simply prints a dot to show activity.315 This is used when running external commands with pexpect.run.316 """317 sys.stdout.write (".")318 sys.stdout.flush()319def run(cmd):320 global GLOBAL_LOGFILE321 print >>GLOBAL_LOGFILE, cmd322 (command_output, exitstatus) = pexpect.run(cmd, events={pexpect.TIMEOUT:progress_callback}, timeout=5, withexitstatus=True, logfile=GLOBAL_LOGFILE)323 if exitstatus != 0:324 print "RUN FAILED. RETURNED EXIT STATUS:", exitstatus325 print >>GLOBAL_LOGFILE, "RUN FAILED. RETURNED EXIT STATUS:", exitstatus326 return (command_output, exitstatus)327def apply_smart (func, args):328 """This is similar to func(**args), but this won't complain about 329 extra keys in 'args'. This ignores keys in 'args' that are 330 not required by 'func'. This passes None to arguments that are331 not defined in 'args'. That's fine for arguments with a default valeue, but332 that's a bug for required arguments. I should probably raise a TypeError.333 The func parameter can be a function reference or a string.334 If it is a string then it is converted to a function reference.335 """336 if type(func) is type(''):337 if func in globals():338 func = globals()[func]339 else:340 raise NameError("name '%s' is not defined" % func)341 if hasattr(func,'im_func'): # Handle case when func is a class method.342 func = func.im_func343 argcount = func.func_code.co_argcount344 required_args = dict([(k,args.get(k)) for k in func.func_code.co_varnames[:argcount]])345 return func(**required_args)346def count_unique (items):347 """This takes a list and returns a sorted list of tuples with a count of each unique item in the list.348 Example 1:349 count_unique(['a','b','c','a','c','c','a','c','c'])350 returns:351 [(5,'c'), (3,'a'), (1,'b')]352 Example 2 -- get the most frequent item in a list:353 count_unique(['a','b','c','a','c','c','a','c','c'])[0][1]354 returns:355 'c'356 """357 stats = {}358 for i in items:359 if i in stats:360 stats[i] = stats[i] + 1361 else:362 stats[i] = 1363 stats = [(v, k) for k, v in stats.items()]364 stats.sort()365 stats.reverse()366 return stats367def calculate_revised_bitrate (video_bitrate, video_target_size, video_actual_size):368 """This calculates a revised video bitrate given the video_bitrate used,369 the actual size that resulted, and the video_target_size.370 This can be used if you want to compress the video all over again in an371 attempt to get closer to the video_target_size.372 """373 return int(math.floor(video_bitrate * (float(video_target_size) / float(video_actual_size))))374def get_aspect_ratio (video_source_filename):375 """This returns the aspect ratio of the original video.376 This is usualy 1.78:1(16/9) or 1.33:1(4/3).377 This function is very lenient. It basically guesses 16/9 whenever378 it cannot figure out the aspect ratio.379 """380 cmd = "mplayer '%s' -vo png -ao null -frames 1" % video_source_filename381 (command_output, exitstatus) = run(cmd)382 ar = re.findall("Movie-Aspect is ([0-9]+\.?[0-9]*:[0-9]+\.?[0-9]*)", command_output)383 if len(ar)==0:384 return '16/9'385 if ar[0] == '1.78:1':386 return '16/9'387 if ar[0] == '1.33:1':388 return '4/3'389 return '16/9'390 #idh = re.findall("ID_VIDEO_HEIGHT=([0-9]+)", command_output)391 #if len(idw)==0 or len(idh)==0:392 # print 'WARNING!'393 # print 'Could not get aspect ration. Assuming 1.78:1 (16/9).'394 # return 1.78395 #return float(idw[0])/float(idh[0])396#ID_VIDEO_WIDTH=720397#ID_VIDEO_HEIGHT=480398#Movie-Aspect is 1.78:1 - prescaling to correct movie aspect.399def get_aid_list (video_source_filename):400 """This returns a list of audio ids in the source video file.401 TODO: Also extract ID_AID_nnn_LANG to associate language. Not all DVDs include this.402 """403 cmd = "mplayer '%s' -vo null -ao null -frames 0 -identify" % video_source_filename404 (command_output, exitstatus) = run(cmd)405 idl = re.findall("ID_AUDIO_ID=([0-9]+)", command_output)406 idl.sort()407 return idl408def get_sid_list (video_source_filename):409 """This returns a list of subtitle ids in the source video file.410 TODO: Also extract ID_SID_nnn_LANG to associate language. Not all DVDs include this.411 """412 cmd = "mplayer '%s' -vo null -ao null -frames 0 -identify" % video_source_filename413 (command_output, exitstatus) = run(cmd)414 idl = re.findall("ID_SUBTITLE_ID=([0-9]+)", command_output)415 idl.sort()416 return idl417 418def extract_audio (video_source_filename, audio_id=128, verbose_flag=0, dry_run_flag=0):419 """This extracts the given audio_id track as raw uncompressed PCM from the given source video.420 Note that mplayer always saves this to audiodump.wav.421 At this time there is no way to set the output audio name.422 """423 #cmd = "mplayer %(video_source_filename)s -vc null -vo null -aid %(audio_id)s -ao pcm:fast -noframedrop" % locals()424 cmd = "mplayer -quiet '%(video_source_filename)s' -vc dummy -vo null -aid %(audio_id)s -ao pcm:fast -noframedrop" % locals()425 if verbose_flag: print cmd426 if not dry_run_flag:427 run(cmd)428 print429def extract_subtitles (video_source_filename, subtitle_id=0, verbose_flag=0, dry_run_flag=0):430 """This extracts the given subtitle_id track as VOBSUB format from the given source video.431 """432 cmd = "mencoder -quiet '%(video_source_filename)s' -o /dev/null -nosound -ovc copy -vobsubout subtitles -vobsuboutindex 0 -sid %(subtitle_id)s" % locals()433 if verbose_flag: print cmd434 if not dry_run_flag:435 run(cmd)436 print437def get_length (audio_raw_filename):438 """This attempts to get the length of the media file (length is time in seconds).439 This should not be confused with size (in bytes) of the file data.440 This is best used on a raw PCM AUDIO file because mplayer cannot get an accurate441 time for many compressed video and audio formats -- notably MPEG4 and MP3.442 Weird...443 This returns -1 if it cannot get the length of the given file.444 """445 cmd = "mplayer %s -vo null -ao null -frames 0 -identify" % audio_raw_filename446 (command_output, exitstatus) = run(cmd)447 idl = re.findall("ID_LENGTH=([0-9.]*)", command_output)448 idl.sort()449 if len(idl) != 1:450 print "ERROR: cannot get length of raw audio file."451 print "command_output of mplayer identify:"452 print command_output453 print "parsed command_output:"454 print str(idl)455 return -1456 return float(idl[0])457def get_filesize (filename):458 """This returns the number of bytes a file takes on storage."""459 return os.stat(filename)[stat.ST_SIZE]460def calc_video_bitrate (video_target_size, audio_bitrate, video_length, extra_space=0, dry_run_flag=0):461 """This gives an estimate of the video bitrate necessary to462 fit the final target size. This will take into account room to463 fit the audio and extra space if given (for container overhead or whatnot).464 video_target_size is in bytes,465 audio_bitrate is bits per second (96, 128, 256, etc.) ASSUMING CBR,466 video_length is in seconds,467 extra_space is in bytes.468 a 180MB CDR (21 minutes) holds 193536000 bytes.469 a 550MB CDR (63 minutes) holds 580608000 bytes.470 a 650MB CDR (74 minutes) holds 681984000 bytes.471 a 700MB CDR (80 minutes) holds 737280000 bytes.472 """473 if dry_run_flag:474 return -1475 if extra_space is None: extra_space = 0476 #audio_size = os.stat(audio_compressed_filename)[stat.ST_SIZE]477 audio_size = (audio_bitrate * video_length * 1000) / 8.0478 video_target_size = video_target_size - audio_size - extra_space479 return (int)(calc_video_kbitrate (video_target_size, video_length))480def calc_video_kbitrate (target_size, length_secs):481 """Given a target byte size free for video data, this returns the bitrate in kBit/S.482 For mencoder vbitrate 1 kBit = 1000 Bits -- not 1024 bits.483 target_size = bitrate * 1000 * length_secs / 8484 target_size = bitrate * 125 * length_secs485 bitrate = target_size/(125*length_secs)486 """487 return int(target_size / (125.0 * length_secs))488def crop_detect (video_source_filename, video_length, dry_run_flag=0):489 """This attempts to figure out the best crop for the given video file.490 Basically it runs crop detect for 10 seconds on five different places in the video.491 It picks the crop area that was most often detected.492 """493 skip = int(video_length/9) # offset to skip (-ss option in mencoder)494 sample_length = 10495 cmd1 = "mencoder '%s' -quiet -ss %d -endpos %d -o /dev/null -nosound -ovc lavc -vf cropdetect" % (video_source_filename, skip, sample_length)496 cmd2 = "mencoder '%s' -quiet -ss %d -endpos %d -o /dev/null -nosound -ovc lavc -vf cropdetect" % (video_source_filename, 2*skip, sample_length)497 cmd3 = "mencoder '%s' -quiet -ss %d -endpos %d -o /dev/null -nosound -ovc lavc -vf cropdetect" % (video_source_filename, 4*skip, sample_length)498 cmd4 = "mencoder '%s' -quiet -ss %d -endpos %d -o /dev/null -nosound -ovc lavc -vf cropdetect" % (video_source_filename, 6*skip, sample_length)499 cmd5 = "mencoder '%s' -quiet -ss %d -endpos %d -o /dev/null -nosound -ovc lavc -vf cropdetect" % (video_source_filename, 8*skip, sample_length)500 if dry_run_flag:501 return "0:0:0:0"502 (command_output1, exitstatus1) = run(cmd1)503 (command_output2, exitstatus2) = run(cmd2)504 (command_output3, exitstatus3) = run(cmd3)505 (command_output4, exitstatus4) = run(cmd4)506 (command_output5, exitstatus5) = run(cmd5)507 idl = re.findall("-vf crop=([0-9]+:[0-9]+:[0-9]+:[0-9]+)", command_output1)508 idl = idl + re.findall("-vf crop=([0-9]+:[0-9]+:[0-9]+:[0-9]+)", command_output2)509 idl = idl + re.findall("-vf crop=([0-9]+:[0-9]+:[0-9]+:[0-9]+)", command_output3)510 idl = idl + re.findall("-vf crop=([0-9]+:[0-9]+:[0-9]+:[0-9]+)", command_output4)511 idl = idl + re.findall("-vf crop=([0-9]+:[0-9]+:[0-9]+:[0-9]+)", command_output5)512 items_count = count_unique(idl)513 return items_count[0][1]514def build_compression_command (video_source_filename, video_final_filename, video_target_size, audio_id=128, video_bitrate=1000, video_codec='mpeg4', audio_codec='mp3', video_fourcc_override='FMP4', video_gray_flag=0, video_crop_area=None, video_aspect_ratio='16/9', video_scale=None, video_encode_passes=2, video_deinterlace_flag=0, audio_volume_boost=None, audio_sample_rate=None, audio_bitrate=None, seek_skip=None, seek_length=None, video_chapter=None):515#Notes:For DVD, VCD, and SVCD use acodec=mp2 and vcodec=mpeg2video:516#mencoder movie.avi -o movie.VOB -ovc lavc -oac lavc -lavcopts acodec=mp2:abitrate=224:vcodec=mpeg2video:vbitrate=2000517 #518 # build video filter (-vf) argument 519 #520 video_filter = ''521 if video_crop_area and video_crop_area.lower()!='none':522 video_filter = video_filter + 'crop=%s' % video_crop_area523 if video_deinterlace_flag:524 if video_filter != '':525 video_filter = video_filter + ','526 video_filter = video_filter + 'pp=md'527 if video_scale and video_scale.lower()!='none':528 if video_filter != '':529 video_filter = video_filter + ','530 video_filter = video_filter + 'scale=%s' % video_scale531 # optional video rotation -- were you holding your camera sideways?532 #if video_filter != '':533 # video_filter = video_filter + ','534 #video_filter = video_filter + 'rotate=2' 535 if video_filter != '':536 video_filter = '-vf ' + video_filter537 #538 # build chapter argument539 #540 if video_chapter is not None:541 chapter = '-chapter %d-%d' %(video_chapter,video_chapter)542 else:543 chapter = ''544# chapter = '-chapter 2-2'545 #546 # build audio_filter argument547 #548 audio_filter = ''549 if audio_sample_rate:550 if audio_filter != '':551 audio_filter = audio_filter + ','552 audio_filter = audio_filter + 'lavcresample=%s' % audio_sample_rate 553 if audio_volume_boost is not None:554 if audio_filter != '':555 audio_filter = audio_filter + ','556 audio_filter = audio_filter + 'volume=%0.1f:1'%audio_volume_boost557 if audio_filter != '':558 audio_filter = '-af ' + audio_filter559 #560 #if audio_sample_rate:561 # audio_filter = ('-srate %d ' % audio_sample_rate) + audio_filter562 #563 # build lavcopts argument564 #565 #lavcopts = '-lavcopts vcodec=%s:vbitrate=%d:mbd=2:aspect=%s:acodec=%s:abitrate=%d:vpass=1' % (video_codec,video_bitrate,audio_codec,audio_bitrate)566 lavcopts = '-lavcopts vcodec=%(video_codec)s:vbitrate=%(video_bitrate)d:mbd=2:aspect=%(video_aspect_ratio)s:acodec=%(audio_codec)s:abitrate=%(audio_bitrate)d:vpass=1' % (locals())567 if video_gray_flag:568 lavcopts = lavcopts + ':gray'569 seek_filter = ''570 if seek_skip is not None:571 seek_filter = '-ss %s' % (str(seek_skip))572 if seek_length is not None:573 seek_filter = seek_filter + ' -endpos %s' % (str(seek_length))574 cmd = "mencoder -quiet -info comment='Arkivist' '%(video_source_filename)s' %(seek_filter)s %(chapter)s -aid %(audio_id)s -o '%(video_final_filename)s' -ffourcc %(video_fourcc_override)s -ovc lavc -oac lavc %(lavcopts)s %(video_filter)s %(audio_filter)s" % locals()575 return cmd576def compression_estimate (video_length, video_source_filename, video_final_filename, video_target_size, audio_id=128, video_bitrate=1000, video_codec='mpeg4', audio_codec='mp3', video_fourcc_override='FMP4', video_gray_flag=0, video_crop_area=None, video_aspect_ratio='16/9', video_scale=None, video_encode_passes=2, video_deinterlace_flag=0, audio_volume_boost=None, audio_sample_rate=None, audio_bitrate=None):577 """This attempts to figure out the best compression ratio for a given set of compression options.578 """579 # TODO Need to account for AVI overhead.580 skip = int(video_length/9) # offset to skip (-ss option in mencoder)581 sample_length = 10582 cmd1 = build_compression_command (video_source_filename, "compression_test_1.avi", video_target_size, audio_id, video_bitrate, video_codec, audio_codec, video_fourcc_override, video_gray_flag, video_crop_area, video_aspect_ratio, video_scale, video_encode_passes, video_deinterlace_flag, audio_volume_boost, audio_sample_rate, audio_bitrate, skip, sample_length)583 cmd2 = build_compression_command (video_source_filename, "compression_test_2.avi", video_target_size, audio_id, video_bitrate, video_codec, audio_codec, video_fourcc_override, video_gray_flag, video_crop_area, video_aspect_ratio, video_scale, video_encode_passes, video_deinterlace_flag, audio_volume_boost, audio_sample_rate, audio_bitrate, skip*2, sample_length)584 cmd3 = build_compression_command (video_source_filename, "compression_test_3.avi", video_target_size, audio_id, video_bitrate, video_codec, audio_codec, video_fourcc_override, video_gray_flag, video_crop_area, video_aspect_ratio, video_scale, video_encode_passes, video_deinterlace_flag, audio_volume_boost, audio_sample_rate, audio_bitrate, skip*4, sample_length)585 cmd4 = build_compression_command (video_source_filename, "compression_test_4.avi", video_target_size, audio_id, video_bitrate, video_codec, audio_codec, video_fourcc_override, video_gray_flag, video_crop_area, video_aspect_ratio, video_scale, video_encode_passes, video_deinterlace_flag, audio_volume_boost, audio_sample_rate, audio_bitrate, skip*6, sample_length)586 cmd5 = build_compression_command (video_source_filename, "compression_test_5.avi", video_target_size, audio_id, video_bitrate, video_codec, audio_codec, video_fourcc_override, video_gray_flag, video_crop_area, video_aspect_ratio, video_scale, video_encode_passes, video_deinterlace_flag, audio_volume_boost, audio_sample_rate, audio_bitrate, skip*8, sample_length)587 run(cmd1)588 run(cmd2)589 run(cmd3)590 run(cmd4)591 run(cmd5)592 size = get_filesize ("compression_test_1.avi")+get_filesize ("compression_test_2.avi")+get_filesize ("compression_test_3.avi")+get_filesize ("compression_test_4.avi")+get_filesize ("compression_test_5.avi")593 return (size / 5.0)594def compress_video (video_source_filename, video_final_filename, video_target_size, audio_id=128, video_bitrate=1000, video_codec='mpeg4', audio_codec='mp3', video_fourcc_override='FMP4', video_gray_flag=0, video_crop_area=None, video_aspect_ratio='16/9', video_scale=None, video_encode_passes=2, video_deinterlace_flag=0, audio_volume_boost=None, audio_sample_rate=None, audio_bitrate=None, seek_skip=None, seek_length=None, video_chapter=None, verbose_flag=0, dry_run_flag=0):595 """This compresses the video and audio of the given source video filename to the transcoded filename.596 This does a two-pass compression (I'm assuming mpeg4, I should probably make this smarter for other formats).597 """598 #599 # do the first pass video compression600 #601 #cmd = "mencoder -quiet '%(video_source_filename)s' -ss 65 -endpos 20 -aid %(audio_id)s -o '%(video_final_filename)s' -ffourcc %(video_fourcc_override)s -ovc lavc -oac lavc %(lavcopts)s %(video_filter)s %(audio_filter)s" % locals()602 cmd = build_compression_command (video_source_filename, video_final_filename, video_target_size, audio_id, video_bitrate, video_codec, audio_codec, video_fourcc_override, video_gray_flag, video_crop_area, video_aspect_ratio, video_scale, video_encode_passes, video_deinterlace_flag, audio_volume_boost, audio_sample_rate, audio_bitrate, seek_skip, seek_length, video_chapter)603 if verbose_flag: print cmd604 if not dry_run_flag:605 run(cmd)606 print607 # If not doing two passes then return early.608 if video_encode_passes!='2':609 return610 if verbose_flag:611 video_actual_size = get_filesize (video_final_filename)612 if video_actual_size > video_target_size:613 print "======================================================="614 print "WARNING!"615 print "First pass compression resulted in"616 print "actual file size greater than target size."617 print "Second pass will be too big."618 print "======================================================="619 #620 # do the second pass video compression621 #622 cmd = cmd.replace ('vpass=1', 'vpass=2')623 if verbose_flag: print cmd624 if not dry_run_flag:625 run(cmd)626 print627 return628def compress_audio (audio_raw_filename, audio_compressed_filename, audio_lowpass_filter=None, audio_sample_rate=None, audio_bitrate=None, verbose_flag=0, dry_run_flag=0):629 """This is depricated.630 This compresses the raw audio file to the compressed audio filename.631 """632 cmd = 'lame -h --athaa-sensitivity 1' # --cwlimit 11"633 if audio_lowpass_filter:634 cmd = cmd + ' --lowpass ' + audio_lowpass_filter635 if audio_bitrate:636 #cmd = cmd + ' --abr ' + audio_bitrate637 cmd = cmd + ' --cbr -b ' + audio_bitrate638 if audio_sample_rate:639 cmd = cmd + ' --resample ' + audio_sample_rate640 cmd = cmd + ' ' + audio_raw_filename + ' ' + audio_compressed_filename641 if verbose_flag: print cmd642 if not dry_run_flag:643 (command_output, exitstatus) = run(cmd)644 print645 if exitstatus != 0:646 raise Exception('ERROR: lame failed to compress raw audio file.')647def mux (video_final_filename, video_transcoded_filename, audio_compressed_filename, video_container_format, verbose_flag=0, dry_run_flag=0):648 """This is depricated. I used to use a three-pass encoding where I would mix the audio track separately, but649 this never worked very well (loss of audio sync)."""650 if video_container_format.lower() == 'mkv': # Matroska651 mux_mkv (video_final_filename, video_transcoded_filename, audio_compressed_filename, verbose_flag, dry_run_flag)652 if video_container_format.lower() == 'avi':653 mux_avi (video_final_filename, video_transcoded_filename, audio_compressed_filename, verbose_flag, dry_run_flag)654def mux_mkv (video_final_filename, video_transcoded_filename, audio_compressed_filename, verbose_flag=0, dry_run_flag=0):655 """This is depricated."""656 cmd = 'mkvmerge -o %s --noaudio %s %s' % (video_final_filename, video_transcoded_filename, audio_compressed_filename)657 if verbose_flag: print cmd658 if not dry_run_flag:659 run(cmd)660 print661def mux_avi (video_final_filename, video_transcoded_filename, audio_compressed_filename, verbose_flag=0, dry_run_flag=0):662 """This is depricated."""663 cmd = "mencoder -quiet -oac copy -ovc copy -o '%s' -audiofile %s '%s'" % (video_final_filename, audio_compressed_filename, video_transcoded_filename)664 if verbose_flag: print cmd665 if not dry_run_flag:666 run(cmd)667 print668def delete_tmp_files (audio_raw_filename, verbose_flag=0, dry_run_flag=0):669 global GLOBAL_LOGFILE_NAME670 file_list = ' '.join([GLOBAL_LOGFILE_NAME, 'divx2pass.log', audio_raw_filename ])671 cmd = 'rm -f ' + file_list672 if verbose_flag: print cmd673 if not dry_run_flag:674 run(cmd)675 print676 677##############################################################################678# This is the interactive Q&A that is used if a conf file was not given.679##############################################################################680def interactive_convert ():681 global prompts, prompts_key_order682 print globals()['__doc__']683 print684 print "=============================================="685 print " Enter '?' at any question to get extra help."686 print "=============================================="687 print688 689 # Ask for the level of options the user wants. 690 # A lot of code just to print a string!691 level_sort = {0:'', 1:'', 2:''} 692 for k in prompts:693 level = prompts[k][3]694 if level < 0 or level > 2:695 continue696 level_sort[level] += " " + prompts[k][1] + "\n"697 level_sort_string = "This sets the level for advanced options prompts. Set 0 for simple, 1 for advanced, or 2 for expert.\n"698 level_sort_string += "[0] Basic options:\n" + str(level_sort[0]) + "\n"699 level_sort_string += "[1] Advanced options:\n" + str(level_sort[1]) + "\n"700 level_sort_string += "[2] Expert options:\n" + str(level_sort[2])701 c = input_option("Prompt level (0, 1, or 2)?", "1", level_sort_string)702 max_prompt_level = int(c)703 options = {}704 for k in prompts_key_order:705 if k == 'video_aspect_ratio':706 guess_aspect = get_aspect_ratio(options['video_source_filename'])707 options[k] = input_option (prompts[k][1], guess_aspect, prompts[k][2], prompts[k][3], max_prompt_level)708 elif k == 'audio_id':709 aid_list = get_aid_list (options['video_source_filename'])710 default_id = '128'711 if max_prompt_level>=prompts[k][3]: 712 if len(aid_list) > 1:713 print "This video has more than one audio stream. The following stream audio IDs were found:"714 for aid in aid_list:715 print " " + aid716 default_id = aid_list[0]717 else:718 print "WARNING!"719 print "Rippy was unable to get the list of audio streams from this video."720 print "If reading directly from a DVD then the DVD device might be busy."721 print "Using a default setting of stream id 128 (main audio on most DVDs)."722 default_id = '128'723 options[k] = input_option (prompts[k][1], default_id, prompts[k][2], prompts[k][3], max_prompt_level)724 elif k == 'subtitle_id':725 sid_list = get_sid_list (options['video_source_filename'])726 default_id = 'None'727 if max_prompt_level>=prompts[k][3]:728 if len(sid_list) > 0:729 print "This video has one or more subtitle streams. The following stream subtitle IDs were found:"730 for sid in sid_list:731 print " " + sid732 #default_id = sid_list[0]733 default_id = prompts[k][0]734 else:735 print "WARNING!"736 print "Unable to get the list of subtitle streams from this video. It may have none."737 print "Setting default to None."738 default_id = 'None'739 options[k] = input_option (prompts[k][1], default_id, prompts[k][2], prompts[k][3], max_prompt_level)740 elif k == 'audio_lowpass_filter':741 lowpass_default = "%.1f" % (math.floor(float(options['audio_sample_rate']) / 2.0))742 options[k] = input_option (prompts[k][1], lowpass_default, prompts[k][2], prompts[k][3], max_prompt_level)743 elif k == 'video_bitrate':744 if options['video_length'].lower() == 'none':745 options[k] = input_option (prompts[k][1], '1000', prompts[k][2], prompts[k][3], max_prompt_level)746 else:747 options[k] = input_option (prompts[k][1], prompts[k][0], prompts[k][2], prompts[k][3], max_prompt_level)748 else:749 # don't bother asking for video_target_size or video_bitrate_overhead if video_bitrate was set750 if (k=='video_target_size' or k=='video_bitrate_overhead') and options['video_bitrate']!='calc':751 continue752 # don't bother with crop area if video length is none753 if k == 'video_crop_area' and options['video_length'].lower() == 'none':754 options['video_crop_area'] = 'none'755 continue756 options[k] = input_option (prompts[k][1], prompts[k][0], prompts[k][2], prompts[k][3], max_prompt_level)757 #options['video_final_filename'] = options['video_final_filename'] + "." + options['video_container_format']758 print "=========================================================================="759 print "Ready to Rippy!"760 print761 print "The following options will be used:"762 for k,v in options.iteritems():763 print "%27s : %s" % (k, v)764 print765 c = input_option("Continue?", "Y")766 c = c.strip().lower()767 if c[0] != 'y':768 print "Exiting..."769 os._exit(1)770 return options771def clean_options (d):772 """This validates and cleans up the options dictionary.773 After reading options interactively or from a conf file774 we need to make sure that the values make sense and are775 converted to the correct type.776 1. Any key with "_flag" in it becomes a boolean True or False.777 2. Values are normalized ("No", "None", "none" all become "none";778 "Calcluate", "c", "CALC" all become "calc").779 3. Certain values are converted from string to int.780 4. Certain combinations of options are invalid or override each other.781 This is a rather annoying function, but then so it most cleanup work.782 """783 for k in d:784 d[k] = d[k].strip()785 # convert all flag options to 0 or 1786 if '_flag' in k:787 if type(d[k]) is types.StringType:788 if d[k].strip().lower()[0] in 'yt1': #Yes, True, 1789 d[k] = 1790 else:791 d[k] = 0792 d['video_bitrate'] = d['video_bitrate'].lower()793 if d['video_bitrate'][0]=='c':794 d['video_bitrate']='calc'795 else:796 d['video_bitrate'] = int(float(d['video_bitrate']))797 try:798 d['video_target_size'] = int(d['video_target_size'])799 # shorthand magic numbers get automatically expanded800 if d['video_target_size'] == 180:801 d['video_target_size'] = 193536000802 elif d['video_target_size'] == 550:803 d['video_target_size'] = 580608000804 elif d['video_target_size'] == 650:805 d['video_target_size'] = 681984000806 elif d['video_target_size'] == 700:807 d['video_target_size'] = 737280000808 except:809 d['video_target_size'] = 'none'810 try:811 d['video_chapter'] = int(d['video_chapter'])812 except:813 d['video_chapter'] = None814 try:815 d['subtitle_id'] = int(d['subtitle_id'])816 except:817 d['subtitle_id'] = None818 819 try:820 d['video_bitrate_overhead'] = float(d['video_bitrate_overhead'])821 except:822 d['video_bitrate_overhead'] = -1.0823 d['audio_bitrate'] = int(d['audio_bitrate'])824 d['audio_sample_rate'] = int(d['audio_sample_rate'])825 d['audio_volume_boost'] = d['audio_volume_boost'].lower()826 if d['audio_volume_boost'][0]=='n':827 d['audio_volume_boost'] = None828 else:829 d['audio_volume_boost'] = d['audio_volume_boost'].replace('db','')830 d['audio_volume_boost'] = float(d['audio_volume_boost'])831# assert (d['video_bitrate']=='calc' and d['video_target_size']!='none')832# or (d['video_bitrate']!='calc' and d['video_target_size']=='none')833 d['video_scale'] = d['video_scale'].lower()834 if d['video_scale'][0]=='n':835 d['video_scale']='none'836 else:837 al = re.findall("([0-9]+).*?([0-9]+)", d['video_scale'])838 d['video_scale']=al[0][0]+':'+al[0][1]839 d['video_crop_area'] = d['video_crop_area'].lower()840 if d['video_crop_area'][0]=='n':841 d['video_crop_area']='none'842 d['video_length'] = d['video_length'].lower()843 if d['video_length'][0]=='c':844 d['video_length']='calc'845 elif d['video_length'][0]=='n':846 d['video_length']='none'847 else:848 d['video_length'] = int(float(d['video_length']))849 if d['video_length']==0:850 d['video_length'] = 'none'851 assert (not (d['video_length']=='none' and d['video_bitrate']=='calc'))852 return d853def main ():854 try:855 optlist, args = getopt.getopt(sys.argv[1:], 'h?', ['help','h','?'])856 except Exception, e:857 print str(e)858 exit_with_usage()859 command_line_options = dict(optlist)860 # There are a million ways to cry for help. These are but a few of them.861 if [elem for elem in command_line_options if elem in ['-h','--h','-?','--?','--help']]:862 exit_with_usage(0)863 missing = check_missing_requirements()864 if missing is not None:865 print866 print "=========================================================================="867 print "ERROR!"868 print "Some required external commands are missing."869 print "please install the following packages:"870 print str(missing)871 print "=========================================================================="872 print873 c = input_option("Continue?", "Y")874 c = c.strip().lower()875 if c[0] != 'y':876 print "Exiting..."877 os._exit(1)878 if len(args) > 0:879 # cute one-line string-to-dictionary parser (two-lines if you count this comment):880 options = dict(re.findall('([^: \t\n]*)\s*:\s*(".*"|[^ \t\n]*)', file(args[0]).read()))881 options = clean_options(options)882 convert (options)883 else:884 options = interactive_convert ()885 options = clean_options(options)886 convert (options)887 print "# Done!"888 889if __name__ == "__main__":890 try:891 start_time = time.time()892 print time.asctime()893 main()894 print time.asctime()895 print "TOTAL TIME IN MINUTES:",896 print (time.time() - start_time) / 60.0897 except Exception, e:898 tb_dump = traceback.format_exc()899 print "=========================================================================="900 print "ERROR -- Unexpected exception in script."901 print str(e)902 print str(tb_dump)903 print "=========================================================================="904 print >>GLOBAL_LOGFILE, "=========================================================================="905 print >>GLOBAL_LOGFILE, "ERROR -- Unexpected exception in script."906 print >>GLOBAL_LOGFILE, str(e)907 print >>GLOBAL_LOGFILE, str(tb_dump)908 print >>GLOBAL_LOGFILE, "=========================================================================="...
video_keyframe_dataset.py
Source:video_keyframe_dataset.py
1# -*- coding: utf-8 -*-2# Copyright (c) Facebook, Inc. and its affiliates.3import csv4import logging5import numpy as np6from typing import Any, Callable, Dict, List, Optional, Union7import av8import torch9from torch.utils.data.dataset import Dataset10from detectron2.utils.file_io import PathManager11from ..utils import maybe_prepend_base_path12from .frame_selector import FrameSelector, FrameTsList13FrameList = List[av.frame.Frame] # pyre-ignore[16]14FrameTransform = Callable[[torch.Tensor], torch.Tensor]15def list_keyframes(video_fpath: str, video_stream_idx: int = 0) -> FrameTsList:16 """17 Traverses all keyframes of a video file. Returns a list of keyframe18 timestamps. Timestamps are counts in timebase units.19 Args:20 video_fpath (str): Video file path21 video_stream_idx (int): Video stream index (default: 0)22 Returns:23 List[int]: list of keyframe timestaps (timestamp is a count in timebase24 units)25 """26 try:27 with PathManager.open(video_fpath, "rb") as io:28 container = av.open(io, mode="r")29 stream = container.streams.video[video_stream_idx]30 keyframes = []31 pts = -132 # Note: even though we request forward seeks for keyframes, sometimes33 # a keyframe in backwards direction is returned. We introduce tolerance34 # as a max count of ignored backward seeks35 tolerance_backward_seeks = 236 while True:37 try:38 container.seek(pts + 1, backward=False, any_frame=False, stream=stream)39 except av.AVError as e:40 # the exception occurs when the video length is exceeded,41 # we then return whatever data we've already collected42 logger = logging.getLogger(__name__)43 logger.debug(44 f"List keyframes: Error seeking video file {video_fpath}, "45 f"video stream {video_stream_idx}, pts {pts + 1}, AV error: {e}"46 )47 return keyframes48 except OSError as e:49 logger = logging.getLogger(__name__)50 logger.warning(51 f"List keyframes: Error seeking video file {video_fpath}, "52 f"video stream {video_stream_idx}, pts {pts + 1}, OS error: {e}"53 )54 return []55 packet = next(container.demux(video=video_stream_idx))56 if packet.pts is not None and packet.pts <= pts:57 logger = logging.getLogger(__name__)58 logger.warning(59 f"Video file {video_fpath}, stream {video_stream_idx}: "60 f"bad seek for packet {pts + 1} (got packet {packet.pts}), "61 f"tolerance {tolerance_backward_seeks}."62 )63 tolerance_backward_seeks -= 164 if tolerance_backward_seeks == 0:65 return []66 pts += 167 continue68 tolerance_backward_seeks = 269 pts = packet.pts70 if pts is None:71 return keyframes72 if packet.is_keyframe:73 keyframes.append(pts)74 return keyframes75 except OSError as e:76 logger = logging.getLogger(__name__)77 logger.warning(78 f"List keyframes: Error opening video file container {video_fpath}, " f"OS error: {e}"79 )80 except RuntimeError as e:81 logger = logging.getLogger(__name__)82 logger.warning(83 f"List keyframes: Error opening video file container {video_fpath}, "84 f"Runtime error: {e}"85 )86 return []87def read_keyframes(88 video_fpath: str, keyframes: FrameTsList, video_stream_idx: int = 089) -> FrameList: # pyre-ignore[11]90 """91 Reads keyframe data from a video file.92 Args:93 video_fpath (str): Video file path94 keyframes (List[int]): List of keyframe timestamps (as counts in95 timebase units to be used in container seek operations)96 video_stream_idx (int): Video stream index (default: 0)97 Returns:98 List[Frame]: list of frames that correspond to the specified timestamps99 """100 try:101 with PathManager.open(video_fpath, "rb") as io:102 container = av.open(io)103 stream = container.streams.video[video_stream_idx]104 frames = []105 for pts in keyframes:106 try:107 container.seek(pts, any_frame=False, stream=stream)108 frame = next(container.decode(video=0))109 frames.append(frame)110 except av.AVError as e:111 logger = logging.getLogger(__name__)112 logger.warning(113 f"Read keyframes: Error seeking video file {video_fpath}, "114 f"video stream {video_stream_idx}, pts {pts}, AV error: {e}"115 )116 container.close()117 return frames118 except OSError as e:119 logger = logging.getLogger(__name__)120 logger.warning(121 f"Read keyframes: Error seeking video file {video_fpath}, "122 f"video stream {video_stream_idx}, pts {pts}, OS error: {e}"123 )124 container.close()125 return frames126 except StopIteration:127 logger = logging.getLogger(__name__)128 logger.warning(129 f"Read keyframes: Error decoding frame from {video_fpath}, "130 f"video stream {video_stream_idx}, pts {pts}"131 )132 container.close()133 return frames134 container.close()135 return frames136 except OSError as e:137 logger = logging.getLogger(__name__)138 logger.warning(139 f"Read keyframes: Error opening video file container {video_fpath}, OS error: {e}"140 )141 except RuntimeError as e:142 logger = logging.getLogger(__name__)143 logger.warning(144 f"Read keyframes: Error opening video file container {video_fpath}, Runtime error: {e}"145 )146 return []147def video_list_from_file(video_list_fpath: str, base_path: Optional[str] = None):148 """149 Create a list of paths to video files from a text file.150 Args:151 video_list_fpath (str): path to a plain text file with the list of videos152 base_path (str): base path for entries from the video list (default: None)153 """154 video_list = []155 with PathManager.open(video_list_fpath, "r") as io:156 for line in io:157 video_list.append(maybe_prepend_base_path(base_path, str(line.strip())))158 return video_list159def read_keyframe_helper_data(fpath: str):160 """161 Read keyframe data from a file in CSV format: the header should contain162 "video_id" and "keyframes" fields. Value specifications are:163 video_id: int164 keyframes: list(int)165 Example of contents:166 video_id,keyframes167 2,"[1,11,21,31,41,51,61,71,81]"168 Args:169 fpath (str): File containing keyframe data170 Return:171 video_id_to_keyframes (dict: int -> list(int)): for a given video ID it172 contains a list of keyframes for that video173 """174 video_id_to_keyframes = {}175 try:176 with PathManager.open(fpath, "r") as io:177 csv_reader = csv.reader(io) # pyre-ignore[6]178 header = next(csv_reader)179 video_id_idx = header.index("video_id")180 keyframes_idx = header.index("keyframes")181 for row in csv_reader:182 video_id = int(row[video_id_idx])183 assert (184 video_id not in video_id_to_keyframes185 ), f"Duplicate keyframes entry for video {fpath}"186 video_id_to_keyframes[video_id] = (187 [int(v) for v in row[keyframes_idx][1:-1].split(",")]188 if len(row[keyframes_idx]) > 2189 else []190 )191 except Exception as e:192 logger = logging.getLogger(__name__)193 logger.warning(f"Error reading keyframe helper data from {fpath}: {e}")194 return video_id_to_keyframes195class VideoKeyframeDataset(Dataset):196 """197 Dataset that provides keyframes for a set of videos.198 """199 _EMPTY_FRAMES = torch.empty((0, 3, 1, 1))200 def __init__(201 self,202 video_list: List[str],203 category_list: Union[str, List[str], None] = None,204 frame_selector: Optional[FrameSelector] = None,205 transform: Optional[FrameTransform] = None,206 keyframe_helper_fpath: Optional[str] = None,207 ):208 """209 Dataset constructor210 Args:211 video_list (List[str]): list of paths to video files212 category_list (Union[str, List[str], None]): list of animal categories for each213 video file. If it is a string, or None, this applies to all videos214 frame_selector (Callable: KeyFrameList -> KeyFrameList):215 selects keyframes to process, keyframes are given by216 packet timestamps in timebase counts. If None, all keyframes217 are selected (default: None)218 transform (Callable: torch.Tensor -> torch.Tensor):219 transforms a batch of RGB images (tensors of size [B, 3, H, W]),220 returns a tensor of the same size. If None, no transform is221 applied (default: None)222 """223 if type(category_list) == list:224 self.category_list = category_list225 else:226 self.category_list = [category_list] * len(video_list)227 assert len(video_list) == len(228 self.category_list229 ), "length of video and category lists must be equal"230 self.video_list = video_list231 self.frame_selector = frame_selector232 self.transform = transform233 self.keyframe_helper_data = (234 read_keyframe_helper_data(keyframe_helper_fpath)235 if keyframe_helper_fpath is not None236 else None237 )238 def __getitem__(self, idx: int) -> Dict[str, Any]:239 """240 Gets selected keyframes from a given video241 Args:242 idx (int): video index in the video list file243 Returns:244 A dictionary containing two keys:245 images (torch.Tensor): tensor of size [N, H, W, 3] or of size246 defined by the transform that contains keyframes data247 categories (List[str]): categories of the frames248 """249 categories = [self.category_list[idx]]250 fpath = self.video_list[idx]251 keyframes = (252 list_keyframes(fpath)253 if self.keyframe_helper_data is None or idx not in self.keyframe_helper_data254 else self.keyframe_helper_data[idx]255 )256 transform = self.transform257 frame_selector = self.frame_selector258 if not keyframes:259 return {"images": self._EMPTY_FRAMES, "categories": []}260 if frame_selector is not None:261 keyframes = frame_selector(keyframes)262 frames = read_keyframes(fpath, keyframes)263 if not frames:264 return {"images": self._EMPTY_FRAMES, "categories": []}265 frames = np.stack([frame.to_rgb().to_ndarray() for frame in frames])266 frames = torch.as_tensor(frames, device=torch.device("cpu"))267 frames = frames[..., [2, 1, 0]] # RGB -> BGR268 frames = frames.permute(0, 3, 1, 2).float() # NHWC -> NCHW269 if transform is not None:270 frames = transform(frames)271 return {"images": frames, "categories": categories}272 def __len__(self):...
videointelligenceml.py
Source:videointelligenceml.py
...116 self.timeout = timeout117 self.counter = Metrics.counter(self.__class__, "API Calls")118 def start_bundle(self):119 self._client = get_videointelligence_client()120 def _annotate_video(self, element, video_context):121 if isinstance(element, text_type): # Is element an URI to a GCS bucket122 response = self._client.annotate_video(123 input_uri=element,124 features=self.features,125 video_context=video_context,126 location_id=self.location_id,127 metadata=self.metadata)128 else: # Is element raw bytes129 response = self._client.annotate_video(130 input_content=element,131 features=self.features,132 video_context=video_context,133 location_id=self.location_id,134 metadata=self.metadata)135 return response136 def process(self, element, context_side_input=None, *args, **kwargs):137 if context_side_input: # If we have a side input video context, use that138 video_context = context_side_input.get(element)139 else:140 video_context = None141 response = self._annotate_video(element, video_context)142 self.counter.inc()143 yield response.result(timeout=self.timeout)144class AnnotateVideoWithContext(AnnotateVideo):145 """A ``PTransform`` for annotating video using the GCP Video Intelligence API146 ref: https://cloud.google.com/video-intelligence/docs147 Sends each element to the GCP Video Intelligence API.148 Element is a tuple of149 (Union[text_type, binary_type],150 Optional[videointelligence.types.VideoContext])151 where the former is either an URI (e.g. a GCS URI) or152 binary_type base64-encoded video data153 """154 def __init__(self, features, location_id=None, metadata=None, timeout=120):155 """156 Args:157 features: (List[``videointelligence_v1.enums.Feature``]) Required.158 the Video Intelligence API features to detect159 location_id: (str) Optional.160 Cloud region where annotation should take place.161 If no region is specified, a region will be determined162 based on video file location.163 metadata: (Sequence[Tuple[str, str]]) Optional.164 Additional metadata that is provided to the method.165 timeout: (int) Optional.166 The time in seconds to wait for the response from the167 Video Intelligence API168 """169 super(AnnotateVideoWithContext, self).__init__(170 features=features,171 location_id=location_id,172 metadata=metadata,173 timeout=timeout)174 def expand(self, pvalue):175 return pvalue | ParDo(176 _VideoAnnotateFnWithContext(177 features=self.features,178 location_id=self.location_id,179 metadata=self.metadata,180 timeout=self.timeout))181@typehints.with_input_types(182 Tuple[Union[text_type, binary_type],183 Optional[videointelligence.types.VideoContext]])184class _VideoAnnotateFnWithContext(_VideoAnnotateFn):185 """A DoFn that unpacks each input tuple to element, video_context variables186 and sends these to the GCP Video Intelligence API service and outputs187 an element with the return result of the API188 (``google.cloud.videointelligence_v1.types.AnnotateVideoResponse``).189 """190 def __init__(self, features, location_id, metadata, timeout):191 super(_VideoAnnotateFnWithContext, self).__init__(192 features=features,193 location_id=location_id,194 metadata=metadata,195 timeout=timeout)196 def process(self, element, *args, **kwargs):197 element, video_context = element # Unpack (video, video_context) tuple198 response = self._annotate_video(element, video_context)199 self.counter.inc()...
app.py
Source:app.py
1from flask import Flask, render_template, Response, request, jsonify, flash2import cv23from handDetect import capture_hand4from pen_version2 import board_gen, clear_board5from haze_removal import HazeRemoval6app = Flask(__name__)7app.secret_key = 'dont tell anyone'8video_camera = None9global_frame = None10record = False11palmCascade = cv2.CascadeClassifier('palm_cascade.xml')12message = 'Not allowed to speak yet'13canvas = None14@app.route('/')15def stream():16 global video_camera17 if video_camera is not None:18 video_camera.release()19 cv2.destroyAllWindows()20 video_camera = cv2.VideoCapture(0)21 return render_template('index.html')22@app.route('/applause')23def applause():24 global video_camera25 if video_camera is not None:26 video_camera.release()27 cv2.destroyAllWindows()28 video_camera = cv2.VideoCapture(0)29 return render_template('applause.html')30@app.route('/board')31def board():32 global video_camera33 if video_camera is not None:34 video_camera.release()35 cv2.destroyAllWindows()36 video_camera = cv2.VideoCapture(0)37 return render_template('board.html')38@app.route('/refining')39def refining():40 global video_camera41 if video_camera is not None:42 video_camera.release()43 cv2.destroyAllWindows()44 video_camera = cv2.VideoCapture(0)45 return render_template('refining.html')46def create_message():47 global message48 yield message49@app.route('/my_message')50def my_message():51 return Response(create_message())52def generate_frame():53 global video_camera54 global global_frame55 global record56 global palmCascade57 global message58 record = not record59 if video_camera is None and record is True:60 video_camera = cv2.VideoCapture(0)61 while record is True:62 # get camera frame63 # ret, frame = video_camera.read()64 hand_flag, frame = capture_hand(video_capture=video_camera, palmCascade=palmCascade)65 if frame is not None:66 # frame = cv2.flip(frame, 1)67 ret, frame = cv2.imencode('.jpg', frame)68 frame = frame.tobytes()69 global_frame = frame70 # flash(message)71 yield b'--frame\r\n' + b'Content-Type: image/jpeg\r\n\r\n' + global_frame + b'\r\n\r\n'72 else:73 yield b'--frame\r\n' + b'Content-Type: image/jpeg\r\n\r\n' + global_frame + b'\r\n\r\n'74 # if hand_flag:75 # video_camera.release()76@app.route('/record_status', methods=['POST'])77def record_status():78 global video_camera79 json = request.get_json()80 status = json['status']81 if status == "true":82 video_camera = cv2.VideoCapture(0)83 return jsonify(result="started")84 else:85 video_camera.release()86 return jsonify(result="stopped")87@app.route('/video_feed')88def video_feed():89 return Response(generate_frame(), mimetype='multipart/x-mixed-replace; boundary=frame')90def generate_board():91 global video_camera92 global global_frame93 global record94 global message95 global canvas96 record = not record97 if video_camera is None and record is True:98 video_camera = cv2.VideoCapture(0)99 while record is True:100 # get camera frame101 # ret, frame = video_camera.read()102 _, frame = video_camera.read()103 frame = board_gen(video_camera, canvas, frame)104 if frame is not None:105 # frame = cv2.flip(frame, 1)106 ret, frame = cv2.imencode('.jpg', frame)107 frame = frame.tobytes()108 global_frame = frame109 # flash(message)110 yield b'--frame\r\n' + b'Content-Type: image/jpeg\r\n\r\n' + global_frame + b'\r\n\r\n'111 else:112 yield b'--frame\r\n' + b'Content-Type: image/jpeg\r\n\r\n' + global_frame + b'\r\n\r\n'113 # if hand_flag:114 # video_camera.release()115@app.route('/board_feed')116def board_feed():117 return Response(generate_board(), mimetype='multipart/x-mixed-replace; boundary=frame')118@app.route('/clear', methods=['GET'])119def clear():120 clear_board()121def generate_refined_frame():122 global video_camera123 global global_frame124 global record125 global palmCascade126 global message127 record = not record128 if video_camera is None and record is True:129 video_camera = cv2.VideoCapture(0)130 while record is True:131 # get camera frame132 # ret, frame = video_camera.read()133 _, frame = video_camera.read()134 if frame is not None:135 # frame = cv2.imencode('.jpg', frame)136 frame = cv2.flip(frame, 1)137 hr = HazeRemoval()138 hr.open_image(frame)139 hr.get_dark_channel()140 hr.get_air_light()141 hr.get_transmission()142 hr.guided_filter()143 hr.recover()144 frame = hr.show()145 if frame is not None:146 # frame = cv2.flip(frame, 1)147 ret, frame = cv2.imencode('.jpg', frame)148 frame = frame.tobytes()149 global_frame = frame150 # flash(message)151 yield b'--frame\r\n' + b'Content-Type: image/jpeg\r\n\r\n' + global_frame + b'\r\n\r\n'152 else:153 yield b'--frame\r\n' + b'Content-Type: image/jpeg\r\n\r\n' + global_frame + b'\r\n\r\n'154 # if hand_flag:155 # video_camera.release()156@app.route('/refined_video_feed')157def refined_video_feed():158 return Response(generate_refined_frame(), mimetype='multipart/x-mixed-replace; boundary=frame')159if __name__ == '__main__':...
videos.py
Source:videos.py
1# -*- coding: utf-8 -*-2"""è§é¢åå¨"""3import datetime4from sqlalchemy import (5 Column,6 String,7 Integer,8 SmallInteger,9 DateTime,10)11from spider.models import (12 DBSession,13 BaseModel,14)15class Videos(BaseModel):16 __tablename__ = 'web_video'17 id = Column(Integer, primary_key=True)18 source = Column(String(10), nullable=False)19 task_id = Column(Integer, nullable=False)20 img_url = Column(String(200), nullable=False)21 duration = Column(Integer, nullable=False)22 title = Column(String(200), nullable=False)23 video_url = Column(String(200), nullable=False)24 video_url_md5 = Column(String(32), nullable=False)25 created_at = Column(DateTime, nullable=False, default=datetime.datetime.now)26 @classmethod27 def filter_exist(cls, videos):28 """å°å·²ç»åå¨è¡¨ä¸çæ°æ®æ»¤é¤29 Args:30 videos (list<WebVideo>): video ä¸è½½é¾æ¥31 Returns:32 list<WebVideo> è¿åä¸åå¨çè§é¢é¾æ¥33 """34 if not videos:35 return []36 video_url_md5s = [x.video_url_md5 for x in videos]37 session = DBSession()38 query_result = session.query(cls.video_url_md5).\39 filter(cls.video_url_md5.in_(video_url_md5s)).all()40 session.commit()41 exist_urls = {x[0] for x in query_result}42 return [x for x in videos if x.video_url_md5 not in exist_urls]43 @classmethod44 def batch_add(cls, videos):45 """æ¹éæ·»å è®°å½46 Args:47 videos (list<WebVideo>): video ä¸è½½é¾æ¥48 """49 if not videos:50 return51 records = [cls(52 source=x.source,53 task_id=x.task_id,54 img_url=x.img_url,55 duration=x.duration,56 title=x.title,57 video_url=x.video_url,58 video_url_md5=x.video_url_md5,59 ) for x in videos]60 session = DBSession()61 session.add_all(records)62 session.flush()63 session.commit()64 return records65class DownloadInfo(BaseModel):66 __tablename__ = 'download_info'67 id = Column(Integer, primary_key=True)68 video_id = Column(Integer, nullable=False)69 video_url = Column(String(200), nullable=False)70 video_title = Column(String(200), nullable=False)71 video_size = Column(Integer, nullable=False)72 status = Column(SmallInteger, nullable=False, default=0)73 created_at = Column(DateTime, nullable=False, default=datetime.datetime.now)74 updated_at = Column(DateTime, nullable=False, default=datetime.datetime.now,75 onupdate=datetime.datetime.now)76 @classmethod77 def add(cls, video_info):78 """æ·»å è®°å½79 Args:80 video_info (VideoInfo): æ ¼å¼ä¿¡æ¯81 """82 record = cls(83 video_id=video_info.video_id,84 video_url=video_info.video_url,85 video_title=video_info.title,86 video_size=video_info.size,87 )88 session = DBSession()89 session.add(record)90 session.flush()91 session.commit()92 return record93 @classmethod94 def update_status(cls, video_id, status=1):95 """æ·»å è®°å½96 Args:97 video_id (int): è§é¢id98 status (int): 1ä¸è½½å®æ 0æªä¸è½½99 """100 session = DBSession()101 target = session.query(cls).filter(cls.video_id == video_id)102 target.update({'status': status})...
you_get.py
Source:you_get.py
...51 logger.info('you-get info success: url:{} video:{}'.format(52 play_url, video_id))53 DownloadInfo.add(video_info)54 return video_info55def download_video(video_info):56 """ä¸è½½è§é¢57 Args:58 video_info (VideoInfo): è§é¢ä¸è½½ä¿¡æ¯59 """60 try:61 download_comd = "you-get {}".format(video_info.video_url)62 p = subprocess.Popen(download_comd,63 shell=True, cwd=params['download_path'])64 p.wait(int(params['download_timeout']))65 if p.returncode != 0:66 raise Exception("download failed")67 except Exception as exc:68 statsd_client.incr('youget.download.exc')69 logger.error('you-get download failure: url:{} video:{}'.format(...
controller.py
Source:controller.py
...6import urllib27import logging8def crawl(request, video_url, depth):9 # Execute crawling algorithm10 video = parse_video(video_url)11 crawl_video(video, depth)12 return views.video(request, video)13def parse_video(video_url):14 try:15 video=Video.objects.get(video_id = video_url.split('=')[1].split('&')[0])16 except Video.DoesNotExist:17 video=Video(video_id = video_url.split('=')[1].split('&')[0])18 video.video_api_url = 'https://www.googleapis.com/youtube/v3/videos?key=AIzaSyBp-A5_icKU-m0KuFLf0wOvQwbayFC-JEM&id='+video.video_id19 video.video_url = "http://www.youtube.com/watch?v="+video.video_id20 video_info =json.loads(urllib2.urlopen(video.video_api_url+'&part=snippet,statistics,player&fields=items(id,snippet/title,snippet/description,snippet/thumbnails/default/url,snippet/channelTitle,snippet/channelId,snippet/tags,statistics/viewCount,player/embedHtml)').read())21 video.description = video_info['items'][0]['snippet']['description']22 video.embed_html = (video_info['items'][0]['player']['embedHtml'])[0:-2]+"></iframe>"23 video.owner_id=video_info['items'][0]['snippet']['channelId']24 video.owner_name=video_info['items'][0]['snippet']['channelTitle']25 video.owner_url='http://www.youtube.com/channel/'+video_info['items'][0]['snippet']['channelId']26 video.thumbnail_url = video_info['items'][0]['snippet']['thumbnails']['default']['url']27 video.title = video_info['items'][0]['snippet']['title']28 video.views_total = video_info['items'][0]['statistics']['viewCount']29 video.save()30 return video31def get_related_videos_urls(video):32 related_videos_urls = []33 related_videos_data = json.loads(urllib2.urlopen("https://www.googleapis.com/youtube/v3/search?part=snippet&type=video&key=AIzaSyBp-A5_icKU-m0KuFLf0wOvQwbayFC-JEM&relatedToVideoId="+video.video_id).read())['items']34 for related_video_data in related_videos_data:35 related_videos_urls.append("http://www.youtube.com/watch?v="+related_video_data['id']['videoId'])36 return related_videos_urls37def add_related_videos(video):38 related_videos_urls = get_related_videos_urls(video)39 for related_video_url in related_videos_urls:40 related_video = parse_video(related_video_url)41 video.related.add(related_video)42def crawl_video(video, depth):43 add_related_videos(video)44 if depth > 0:45 depth -= 146 for related_video in video.related.all():47 logging.warning(depth)...
urls.py
Source:urls.py
1from django.urls import path2from . import views3urlpatterns = [4 path('', views.dashboard, name="dashboard"),5 path('department-store/video/', views.department_store_video, name="department_store_video"),6 path('wholesale/video/', views.wholesale_video, name="wholesale_video"),7 path('retail/video/', views.retail_video, name="retail_video"),8 path('chainstore/video/', views.vending_store_video, name="vending_store_video"),9 path('video/', views.video_video, name="video_video"),10 path('retail/game/', views.retail_game, name="retail_game"),11 path('internal_trade/video/', views.internal_trade_video, name="internal_trade_video"),12 path('department-store/visit/', views.department_store_visit, name="department_store_visit"),13 14 15 path('ep1/video/', views.ep1_video, name="ep1_video"),16 path('ep2/video/', views.ep2_video, name="ep2_video"),17 path('ep3/video/', views.ep3_video, name="ep3_video"),18 path('ep4/video/', views.ep4_video, name="ep4_video"),19 path('ep5/video/', views.ep5_video, name="ep5_video"),20 path('ep6/video/', views.ep6_video, name="ep6_video"),21 path('ep7/video/', views.ep7_video, name="ep7_video"),22 path('ep8/video/', views.ep8_video, name="ep8_video"),23 path('quiz/', views.quiz_index, name="quiz_index"),24 path('quiz/game/', views.quiz_game, name="quiz_game"),25 path('quiz/highscores/', views.quiz_highscores, name="quiz_highscores"),26 path('quiz/end/', views.quiz_end, name="quiz_end"),27 28 path('quiz1/', views.quiz_for_index, name="quiz_for_index"),29 path('quiz1/game/', views.quiz_for_game, name="quiz_for_game"),30 path('quiz1/end/', views.quiz_for_end, name="quiz_for_end"),31 32 path('quiz2/', views.quiz_of_index, name="quiz_of_index"),33 path('quiz2/game/', views.quiz_of_game, name="quiz_of_game"),34 path('quiz2/end/', views.quiz_of_end, name="quiz_of_end"),35 path('quiz3/', views.quiz_in_index, name="quiz_in_index"),36 path('quiz3/game/', views.quiz_in_game, name="quiz_in_game"),37 path('quiz3/end/', views.quiz_in_end, name="quiz_in_end"),38 path('quiz4/', views.quiz_and_index, name="quiz_and_index"),39 path('quiz4/game/', views.quiz_and_game, name="quiz_and_game"),40 path('quiz4/end/', views.quiz_and_end, name="quiz_and_end"),41 42]...
Using AI Code Generation
1const wpt = require('wpt-api')('API_KEY');2const fs = require('fs');3const path = require('path');4const options = {5};6wpt.runTest(testUrl, options, (err, data) => {7 if (err) {8 console.log(err);9 } else {10 console.log(data);11 wpt.getVideo(data.data.testId, (err, data) => {12 if (err) {13 console.log(err);14 } else {15 console.log(data);16 fs.writeFileSync(path.join(__dirname, 'video.mp4'), data);17 }18 });19 }20});
Using AI Code Generation
1var video = require('webpagetest');2var video = require('webpagetest');3var wpt = new video('API_KEY');4var options = {5 videoParams: {6 },7 timelineParams: {8 },9};10 if (err) return console.error(err);11 console.log(data);12 wpt.getVideo(data.data.testId, function(err, data) {13 if (err) return console.error(err);14 console.log(data);15 });16});17var video = require('webpagetest');18var wpt = new video('API_KEY');19var options = {20 videoParams: {21 },22 timelineParams: {23 },24};25 if (err) return console.error(err);26 console.log(data);27 wpt.getVideo(data.data.testId, function(err, data) {28 if (err) return console.error(err);29 console.log(data);30 });31});32var video = require('webpagetest');33var wpt = new video('API_KEY');34var options = {
Using AI Code Generation
1p.iduVido();2wpdoteo(ff3p.idoVide();4####rVido()5####popVid()664()7### geVideoFramesBse64(8### getVideoFramesBase64Url()9###ogetVideoUrm()10###geVideoFamsUrl()11### gVidFamsBae64Url()12### geViFrameBae64ZipUl()
Using AI Code Generation
1 wpt.getVideo(data.data.testId, (err, data) => {2 if (err) {3 console.log(err);4 } else {5 console.log(data);6 fs.writeFileSync(path.join(__dirname, 'video.mp4'), data);7 }8 });9 }10});
Using AI Code Generation
1var video = require('webpagetest');2var video = require('webpagetest');3var wpt = new video('API_KEY');4var options = {5 videoParams: {6 },7 timelineParams: {8 },9};10 if (err) return console.error(err);11 console.log(data);12 wpt.getVideo(data.data.testId, function(err, data) {13 if (err) return console.error(err);14 console.log(data);15 });16});17var video = require('webpagetest');18var wpt = new video('API_KEY');19var options = {20 videoParams: {21 },22 timelineParams: {23 },24};25 if (err) return console.error(err);26 console.log(data);27 wpt.getVideo(data.data.testId, function(err, data) {28 if (err) return console.error(err);29 console.log(data);30 });31});32var video = require('webpagetest');33var wpt = new video('API_KEY');34var options = {
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!