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
+```