README.md in xmorph-0.1.6 vs README.md in xmorph-0.1.9

- old
+ new

@@ -1,2 +1,140 @@ -# xmorph -Morphs things from one kind to another. Transcodes, in local speak, for example. +# XMorph + +Morphs things from one kind to another. Transcodes, in local speak, for example.. + +# Features! + + - XMorph can get validate an asset against given set of validations (set of video and audio parameters). + - Can choose a pre-defined proifile based on asset's mediainfo, and transcode using the profiles corresponding command. + +# Installation: +```sh +$ gem install xmorph +``` +> For a specific version: +```sh +$ gem install xmorph -v 0.1.5 +``` + +# Usage + +Once you have written XMorph profile for a customer, test if it's working fine. +Get base class object for a given customer +```ruby +transcoder = XMorph::Base.get_transcode_template(HOST, ACCOUNT_DOMAIN, ACCOUNT_NAME, ASSET_PATH) + +transcoder = XMorph::Base.get_transcode_template("cinedigm", "Cinedigm", "amagi", "/home/tejaswini/volt/cinedigm/PRAYERLINK112718CC.mxf") +``` +transcoder is object for a customer class, in case XMorph is able to find corresponding customers transcoding setup, else it'll raise TranscoderError exception. +You can also pass extra param, which will return the filepath it loaded inorder to pick customer specific transcode setup. +```ruby +transcoder, loaded_filepath = XMorph::Base.get_transcode_template("cinedigm", "Cinedigm", "amagi", "/home/tejaswini/volt/cinedigm/PRAYERLINK112718CC.mxf", true) +``` +Here loaded_filepath will be +```ruby +/home/tejaswini/src/xmorph/lib/xmorph/customers/cinedigm/Cinedigm/transcode.rb +``` +Get mediainfo for the asset with: +```ruby +transcoder.get_asset_details +``` +If XMorph is not able to get mediainfo of the asset, it will raise exception. If it was success you can access mediainfo with, which will be a hash. +```ruby +transcoder.mediainfo_output +``` +Perform default validations on the asset once you get mediainfo. +```ruby +transcoder.validate_asset +``` +This function will validate the asset against the requirements mentioned in video_checks and audio_checks methods for a given customer. It will either return true or raise exception incase of failure. + +Once the asset is validated, try to get suitable profile for the same. +```ruby ffmpeg_command = transcoder.get_profile``` or ```profile_name, ffmpeg_cmd = transcoder.get_profile``` to get profile name as well. + +The ffmpeg command come with %{IN} and %{OUT} replace them with input filepath and output filepath and pass as parameter for, ```transcoder.transcode(updated_ffmpeg_command)``` + +# Execution +```sh +$ cd xmorph +$ ./bin/console +$ transcoder = XMorph::Base.get_transcode_template("cinedigm", "Cinedigm", "amagi", "/home/tejaswini/volt/cbn/PRAYERLINK112718CC.mxf") +$ transcoder, loaded_filepath = XMorph::Base.get_transcode_template("cinedigm", "Cinedigm", "amagi", "/home/tejaswini/volt/cbn/PRAYERLINK112718CC.mxf", true) +$ transcoder.get_asset_details +$ transcoder.validate_asset +$ ffmpeg_cmd = transcoder.get_profile +$ profile_name, ffmpeg_cmd = transcoder.get_profile(true) +$ transcoder.transcode(ffmpeg_cmd % {IN: asset_path, OUT: tmp_file.path}) +``` + +# Adding new XMorph profile for a customer +```sh +$ cd xmorph/lib/xmorph/customers +$ mkdir -p HOST/ACCOUNT_DOMAIN/ +$ cd HOST/ACCOUNT_DOMAIN/ +$ vi transcode.rb +``` +> Here, HOST is customer in customer.amagi.tv and ACCOUNT_DOMAIN is account.domain +> EX: for cinedigm.amagi.tv HOST is cinedigm and account's domain is Cinedigm +> Interfaces to be implemented in transcodee.rb, +```ruby +class Transcode < XMorph::Base + #define constants for set of profiles which says what the corresponding command does, or what the input asset is + SCALE_TO_720x480_4_3 = "720x480_4_3" + SCALE_TO_720x480_16_9 = "720x480_16_9" + SCALE_TO_1920x1080_16_9 = "1920x1080_16_9" + SCALE_TO_720x480_3_2 = "720x480_3_2" + #set the profiles using the constants defined earlier + def set_profiles + self.profiles = { + SCALE_TO_720x480_4_3 => "ffmpeg -y -i %{IN} $options to perform transcoding/encoding$ %{OUT} 2>&1", + SCALE_TO_720x480_16_9 => "ffmpeg -y -i %{IN} $options to perform transcoding/encoding$ %{OUT} 2>&1", + SCALE_TO_1920x1080_16_9 => "ffmpeg -y -i %{IN} $options to perform transcoding/encoding$ %{OUT} 2>&1", + SCALE_TO_720x480_3_2 => "ffmpeg -y -i %{IN} $options to perform transcoding/encoding$ %{OUT} 2>&1", + } + end + + #values for the sollowing validations can be Range, Array or IGNORE(upcase) + #Range - (n1..n2) - applicable if the values are numbers, validates if value x is between n1 and n2, it also includes fractions. ex 5: in (1..10) -> true and 29.97 in (25..30) -> true + #Array - [n1,n2] - validates if value x is in the given array. ex: 5 in [1,10] -> false and 1 in [1,10] -> true + #IGNORE will skip validation for the corresponding parameter. it will not even check if media has that parameter. i.e if mediainfo is not able to read parameter x for the asset, its validation will still return true. + #These methods are to be implemented in the sub class, there's no defaut method defined in the base class, exception is raised if these methods are not found. + + def video_checks + { + ALLOWED_ASPECT_RATIO => ["4:3", "16:9"] || IGNORE, + ALLOWED_HEIGHT => (400..1080) || [720, 1080, 546] || IGNORE, + ALLOWED_WIDTH => (640..720) || [720, 1920] || IGNORE, + ALLOWED_FRAME_RATE => (25..30) || [25, 29.970, 24] || IGNORE, + ALLOWED_VIDEO_BIT_RATE => (8..32) || [8, 32] || IGNORE, + ALLOWED_SCAN_TYPE => ['progressive', 'interlaced'] || IGNORE, + } + end + + def audio_checks + { + PRESENCE_OF_AUDIO_TRACK => IGNORE || VALIDATE, + ALLOWED_NUMBER_OF_AUDIO_TRACKS => (1..16)|| [2, 4, 6, 8] || IGNORE, + ALLOWED_AUDIO_CODECS => ['aac', 'ac-3', 'mp2', 'mp4', 'dolby e', 'mpeg audio'] || IGNORE, + ALLOWED_AUDIO_BIT_RATE => (120..317) || [192, 317] || IGNORE, + ALLOWED_NUMBER_OF_AUDIO_CHANNELS => (1..16) || [1, 2] || IGNORE, + } + end + + #Write summary as what are the combinations of profiles we get for this customer, and based on which parameters we choose the profile. + + # have a set of conditional statements to choose a profile defined above. + def set_profile_name + self.profile_name = nil + self.error = nil + mediainfo = self.mediainfo_output + video_info = mediainfo["Video"] + audio_tracks = mediainfo["Audio"] + #Once you have videoinfo and audiotracks info, write a set of if else statements to choose a profile from the above defined + #Assign profile name to self.profile_name + #Assign any error messages you want to display on UI to self.error, make sure error messages are unambiguous + #EX: self.error = "Got unexpected width-#{width} for video with AR-#{aspect_ratio}, expected width: 640 or 720" + #Ensure there's only if..elseif statements rather than if..else + XMorph::Base.logger.debug("XMorph#set_profile_name#Cinedigm: using profile #{self.profile_name}") unless self.profile_name.nil? + return true + end +```