def probeVideo(self, filename=None): """ Probes a video file. Caveat: Supports only 1 video channel and 1 audio chanel @param: file Video file to probe @return Dictionary. Key "video" contains dictionary of VideoStream objects and key "audio" contains a dictionary of AudioStream objects """ loggerJobCreationRuntime.info("================================================================================") loggerJobCreationRuntime.info("Processing :" + str(filename)) # Prepare CL ffprobeCLBuilder = FFPROBECLGenerator() ffprobeCLBuilder.addInputFile(util.escapePathForOSIndependentShell(filename)) ffprobeCLBuilder.addShowStreams() cl = ffprobeCLBuilder.tocl() loggerJobCreationRuntime.info("ffprobe cl:" + str(cl)) # Run CL # clRunner = CLRunner(stdout=subprocess.PIPE, stderr=subprocess.PIPE) clRunner = CLRunner(shell=True) clRunner.run(cl) ffprobeRawOutput = clRunner.stdout() loggerJobCreationRuntime.info("ffprobe raw output:" + str(ffprobeRawOutput)) # Parse CL output ffprobeParser = FFprobeParser() streams = ffprobeParser.parseShowStreamsOuput(ffprobeRawOutput) # Second pass: Build media instances countStreams = len(streams) mediaStreams = list() if countStreams > 0: for i in range(0, countStreams, 1): stream = streams[i] mediaStream = None if stream["codec_type"] in "video": mediaStream = ApertureConverterPlugin.createVideoStream(d=stream) mediaStreams.append(mediaStream) elif stream["codec_type"] in "audio": mediaStream = ApertureConverterPlugin.createAudioStream(d=stream) mediaStreams.append(mediaStream) streamsMediaObjects = dict(video=dict(), audio=dict()) for i in range(0, len(mediaStreams)): mediaStream = mediaStreams[i] streams = None if mediaStream.getType() in "video": streams = (streamsMediaObjects["video"]) elif mediaStream.getType() in "audio": streams = (streamsMediaObjects["audio"]) streams[mediaStream.getStreamIndex()] = mediaStream loggerJobCreationRuntime.info("ffprobe converted output:" + str(streamsMediaObjects)) return streamsMediaObjects
def createVideoJob(self, sourceMediaFile=None): """ Creates a job to convert a video file to my own storage requirements @param sourceMediaFile Source MediaFile object @return Job instance to convert the video """ sourceVideoMediaStreams = sourceMediaFile.getVideoStreams() sourceAudioMediaStreams = sourceMediaFile.getAudioStreams() masterJob = None hanbrakeSourceMediaFile = copy.deepcopy(sourceMediaFile) hanbrakeDestinationMediaFile = MediaFile() ffmpegSourceMediaFile = MediaFile() ffmpegDestinationMediaFile = MediaFile() destinationHandbrakeVideoStreams = list() destinationHandbrakeAudioStreams = list() destinationHandbrakeVideoStream = None destinationHandbrakeAudioStream = None destinationFFMPEGVideoStreams = list() destinationFFMPEGAudioStreams = list() destinationFFMPEGVideoStream = None destinationFFMPEGAudioStream = None # Source video attributes sVWidth = None sVHeight = None sVCodecName = None sVCodecTag = None sVFramerateMin = None # Source audio attributes sACodecName = None sACodecTag = None sABitPerSample = None # Handbrake Destination video attributes dVHandbrakeCodecName = None dVHandbrakeStreamIndex = None dVHandbrakeWidth = None dVHandbrakeHeight = None dVHandbrakeQuality = None # Handbrake Destination audio attributes dAHandbrakeStreamIndex = None dAHandbrakeSampleRate = None dAHandbrakeCodecName = None # FFMPEG Destination video attributes dVFFMPEGCodecName = None # FFMPEG Destination audio attributes dAFFMPEGCodecName = None countSourceVideoStreams = len(sourceVideoMediaStreams) if countSourceVideoStreams == 1: vmsKey = sourceVideoMediaStreams.keys()[0] vms = sourceVideoMediaStreams[vmsKey] sVWidth = vms.getWidth() sVHeight = vms.getHeight() sVCodecName = vms.getCodecName() sVCodecTag = vms.getCodecTag() sVFramerateMin = vms.getFramerateMin() sACodecName = None sACodecTag = None sABitPerSample = None dVHandbrakeWidth = sVWidth dVHandbrakeHeight = sVHeight loggerCameraSourceType = "Not identified" skippedJobCreation = True skippedReason = "" countSourceAudioStreams = len(sourceAudioMediaStreams) if countSourceVideoStreams == 1: amsKey = sourceAudioMediaStreams.keys()[0] ams = sourceAudioMediaStreams[amsKey] sACodecName = ams.getCodecName() sACodecTag = ams.getCodecTag() sABitPerSample = ams.getBitPerSample() dAHandbrakeStreamIndex = "1" dAHandbrakeSampleRate = ams.getSampleRate() else: logger.warn("NOTE:" + sourceMediaFile.getFileName() + ": " + str(countSourceVideoStreams) + " audio stream found.") # Select appropriate destination media file convertion settings # Nikon D3100 if(sVWidth >= 1280 and sVHeight >= 720 and sVCodecName == "h264" and sVCodecTag == "0x31637661" and sACodecName == "pcm_s16le" and sACodecTag == "0x74776f73" and sABitPerSample == "16"): evfH264 = HandbrakeCLGenerator.ENCODER_VIDEO_FORMAT_H264 dVHandbrakeCodecName = evfH264 dVHandbrakeStreamIndex = "0" dVHandbrakeQuality = "25" dVHandbrakeWidth = 1280 dVHandbrakeHeight = 720 eafFAAC = HandbrakeCLGenerator.ENCODER_AUDIO_FORMAT_FAAC dAHandbrakeCodecName = eafFAAC cfMP4 = HandbrakeCLGenerator.CONTAINER_FORMAT_MP4 hanbrakeDestinationMediaFile.setContainerType(cfMP4) dVFFMPEGCodecName = FFMPEGCLGenerator.ENCODER_VIDEO_FORMAT_COPY dAFFMPEGCodecName = FFMPEGCLGenerator.ENCODER_AUDIO_FORMAT_COPY loggerCameraSourceType = "Nikon D3100" skippedJobCreation = False # GoPro Silver 3+ elif(sVCodecName == "h264" and sVCodecTag == "0x31637661" and sACodecName == "aac" and sACodecTag == "0x6134706d"): evfH264 = HandbrakeCLGenerator.ENCODER_VIDEO_FORMAT_H264 dVHandbrakeCodecName = evfH264 dVHandbrakeStreamIndex = "0" dVHandbrakeQuality = "23" eafFAAC = HandbrakeCLGenerator.ENCODER_AUDIO_FORMAT_FAAC dAHandbrakeCodecName = eafFAAC cfMP4 = HandbrakeCLGenerator.CONTAINER_FORMAT_MP4 hanbrakeDestinationMediaFile.setContainerType(cfMP4) dVFFMPEGCodecName = FFMPEGCLGenerator.ENCODER_VIDEO_FORMAT_COPY dAFFMPEGCodecName = FFMPEGCLGenerator.ENCODER_AUDIO_FORMAT_COPY loggerCameraSourceType = "GoPro 3+ Silver" skippedJobCreation = False # Canon Nexus 700 elif(sVWidth == 320 and sVHeight == 240 and sVCodecName == "mjpeg" and sVCodecTag == "0x47504a4d" and sACodecName == "pcm_u8" and sACodecTag == "0x0001" and sABitPerSample == "8"): evfH264 = HandbrakeCLGenerator.ENCODER_VIDEO_FORMAT_H264 dVHandbrakeCodecName = evfH264 dVHandbrakeStreamIndex = "0" dVHandbrakeQuality = "25" cfMP4 = HandbrakeCLGenerator.CONTAINER_FORMAT_MP4 hanbrakeDestinationMediaFile.setContainerType(cfMP4) dVFFMPEGCodecName = FFMPEGCLGenerator.ENCODER_VIDEO_FORMAT_COPY dAFFMPEGCodecName = FFMPEGCLGenerator.ENCODER_AUDIO_FORMAT_COPY loggerCameraSourceType = "Canon Nexus 700" skippedJobCreation = False # iPhone 3GS (NOT MBP 2007 iSight) elif(((sVWidth == 640 and sVHeight == 480) or (sVWidth == 480 and sVHeight == 360)) and sVCodecName == "h264" and sVCodecTag == "0x31637661" and sACodecName == "aac" and sACodecTag == "0x6134706d" and sABitPerSample == "0"): evfH264 = HandbrakeCLGenerator.ENCODER_VIDEO_FORMAT_H264 dVHandbrakeCodecName = evfH264 dVHandbrakeStreamIndex = "0" dVHandbrakeQuality = "30" eafFAAC = HandbrakeCLGenerator.ENCODER_AUDIO_FORMAT_FAAC dAHandbrakeCodecName = eafFAAC # quality=25 best quality=35 worst cfMP4 = HandbrakeCLGenerator.CONTAINER_FORMAT_MP4 hanbrakeDestinationMediaFile.setContainerType(cfMP4) dVFFMPEGCodecName = FFMPEGCLGenerator.ENCODER_VIDEO_FORMAT_COPY dAFFMPEGCodecName = FFMPEGCLGenerator.ENCODER_AUDIO_FORMAT_COPY loggerCameraSourceType = "iPhone 3GS" skippedJobCreation = False # MBP 2010 iSight elif(sVWidth == 320 and sVHeight == 240 and sVCodecName == "mjpeg" and sVCodecTag == "" and sACodecName == "pcm_u8" and sACodecTag == "" and sABitPerSample == "8"): evfH264 = HandbrakeCLGenerator.ENCODER_VIDEO_FORMAT_H264 dVHandbrakeCodecName = evfH264 dVHandbrakeStreamIndex = "0" dVHandbrakeQuality = "25" eafFAAC = HandbrakeCLGenerator.ENCODER_AUDIO_FORMAT_FAAC dAHandbrakeCodecName = eafFAAC cfMP4 = HandbrakeCLGenerator.CONTAINER_FORMAT_MP4 hanbrakeDestinationMediaFile.setContainerType(cfMP4) dVFFMPEGCodecName = FFMPEGCLGenerator.ENCODER_VIDEO_FORMAT_COPY dAFFMPEGCodecName = FFMPEGCLGenerator.ENCODER_AUDIO_FORMAT_COPY loggerCameraSourceType = "Macbook Pro iSight 2010" skippedJobCreation = False # Unknown elif(sVWidth == 640 and sVHeight == 480 and sVCodecName == "mjpeg" and sVCodecTag == "" and sACodecName == "pcm_mulaw" and sACodecTag == "" and sABitPerSample == "8"): evfH264 = HandbrakeCLGenerator.ENCODER_VIDEO_FORMAT_H264 dVHandbrakeCodecName = evfH264 dVHandbrakeStreamIndex = "0" dVHandbrakeQuality = "25" eafFAAC = HandbrakeCLGenerator.ENCODER_AUDIO_FORMAT_FAAC dAHandbrakeCodecName = eafFAAC cfMP4 = HandbrakeCLGenerator.CONTAINER_FORMAT_MP4 hanbrakeDestinationMediaFile.setContainerType(cfMP4) dVFFMPEGCodecName = FFMPEGCLGenerator.ENCODER_VIDEO_FORMAT_COPY dAFFMPEGCodecName = FFMPEGCLGenerator.ENCODER_AUDIO_FORMAT_COPY loggerCameraSourceType = "Unknown0" skippedJobCreation = False # Panasonic DMC FX-36 elif(sVWidth == 640 and sVHeight == 480 and sVCodecName == "mjpeg" and sVCodecTag == "0x6765706a" and sACodecName == "pcm_u8" and sACodecTag == "0x20776172" and sABitPerSample == "8"): evfH264 = HandbrakeCLGenerator.ENCODER_VIDEO_FORMAT_H264 dVHandbrakeCodecName = evfH264 dVHandbrakeStreamIndex = "0" dVHandbrakeQuality = "27" eafFAAC = HandbrakeCLGenerator.ENCODER_AUDIO_FORMAT_FAAC dAHandbrakeCodecName = eafFAAC # quality=25 best quality=35 worst cfMP4 = HandbrakeCLGenerator.CONTAINER_FORMAT_MP4 hanbrakeDestinationMediaFile.setContainerType(cfMP4) dVFFMPEGCodecName = FFMPEGCLGenerator.ENCODER_VIDEO_FORMAT_COPY dAFFMPEGCodecName = FFMPEGCLGenerator.ENCODER_AUDIO_FORMAT_COPY loggerCameraSourceType = "Panasonic DMC FX-36" skippedJobCreation = False # Unknown 1 elif(sVCodecName == None and sVCodecTag == None and sACodecName == "aac" and sACodecTag == "0x6134706d" and sABitPerSample == "0"): # No need to re-encode skippedJobCreation = True skippedReason = "No need to re-encode" else: skippedJobCreation = True skippedReason = ("No suitable converter configuration found. " + "Missing a convertion case ? " + "New video file ?" ) if not skippedJobCreation: try: masterJob = OnSuccessOnlyConverterJob() # Convert with HandBrake as Job #1 hanbrakeSourceMediaFile.setFileName(util.escapePathForOSIndependentShell(hanbrakeSourceMediaFile.getFileName())) destinationHandbrakeVideoStream = VideoStream(codecName=dVHandbrakeCodecName, streamIndex=dVHandbrakeStreamIndex, framerateMin=sVFramerateMin, width=dVHandbrakeWidth, height=dVHandbrakeHeight, quality=dVHandbrakeQuality) destinationHandbrakeAudioStream = AudioStream(streamIndex=dAHandbrakeStreamIndex, sampleRate=dAHandbrakeSampleRate, codecName=dAHandbrakeCodecName) destinationHandbrakeVideoStreams.append(destinationHandbrakeVideoStream) destinationHandbrakeAudioStreams.append(destinationHandbrakeAudioStream) hanbrakeDestinationMediaFile.setVideoStreams(destinationHandbrakeVideoStreams) hanbrakeDestinationMediaFile.setAudioStreams(destinationHandbrakeAudioStreams) handbrakeDestinationFileName = sourceMediaFile.getFileName() + ".tmp." + str(hanbrakeDestinationMediaFile.getContainerType()) hanbrakeDestinationMediaFile.setFileName(util.escapePathForOSIndependentShell(handbrakeDestinationFileName)) handbrakeCLIBuilder = HandbrakeCLGenerator.createFrom(sourceMediaFile=hanbrakeSourceMediaFile, destinationMediaFile=hanbrakeDestinationMediaFile) handbrakeCLIBuilder.addLooseAnamorphic() handbrakeCLIBuilder.addVerbosity() handbrakeCLIRunner = CLRunner(shell=True) masterJob.addJob(ConverterJob(clibuilder=handbrakeCLIBuilder, clirunner=handbrakeCLIRunner)) loggerJobCreationRuntime.info("Handbrake cl:" + str(handbrakeCLIBuilder.tocl())) # Convert with FFMpeg as Job #2 destinationFFMPEGVideoStream = VideoStream(codecName=dVFFMPEGCodecName) destinationFFMPEGAudioStream = AudioStream(codecName=dAFFMPEGCodecName) ffmpegSourceMediaFile.setFileName(hanbrakeDestinationMediaFile.getFileName()) ffmpegDestinationMediaFile.setFileName(util.escapePathForOSIndependentShell(sourceMediaFile.getFileName())) destinationFFMPEGVideoStreams.append(destinationFFMPEGVideoStream) destinationFFMPEGAudioStreams.append(destinationFFMPEGAudioStream) ffmpegDestinationMediaFile.setVideoStreams(destinationFFMPEGVideoStreams) ffmpegDestinationMediaFile.setAudioStreams(destinationFFMPEGAudioStreams) ffmpegCLIBuilder = FFMPEGCLGenerator.createFrom(sourceMediaFile=ffmpegSourceMediaFile, destinationMediaFile=ffmpegDestinationMediaFile) ffmpegCLIBuilder.addOverwriteOutputFileWithoutAsking() ffmpegCLIRunner = CLRunner(shell=True) loggerJobCreationRuntime.info("ffmpeg cl:" + str(ffmpegCLIBuilder.tocl())) masterJob.addJob(ConverterJob(clibuilder=ffmpegCLIBuilder, clirunner=ffmpegCLIRunner)) # Delete temporary file as Job #3 masterJob.addJob(DeleteFileJob(filename=handbrakeDestinationFileName)) loggerJobCreationRuntime.info("Will delete file:" + str(handbrakeDestinationFileName)) loggerJobCreationSuccess.info("JOB_CREATION_SUCCESS:" + sourceMediaFile.getFileName() + ": Type:" + loggerCameraSourceType) except BaseException: loggerJobCreationFailed.exception("JOB_CREATION_FAILED:" + sourceMediaFile.getFileName() + ": Type:" + loggerCameraSourceType + "Exception :") else: loggerJobCreationSkipped.info("JOB_CREATION_SKIPPED:" + sourceMediaFile.getFileName() + ": Type:" + loggerCameraSourceType + " Reason: " + skippedReason) else: loggerJobCreationFailed.error("JOB_CREATION_FAILED:" + sourceMediaFile.getFileName() + ": Reason: 1 video stream expected. " + str(countSourceVideoStreams) + " found.") if not masterJob: masterJob = Job() # Created only if proper convert job not created return masterJob
def createImageJob(self, sourceMediaFile=None): """ Creates a job to convert image file to my own storage requirements @param sourceMediaFile Source MediaFile object @return Job instance to convert the image """ sourceImageStreams = sourceMediaFile.getImageStreams() masterJob = None backupDestinationMediaFile = MediaFile() convertDestinationMediaFile = MediaFile() destinationBakupImageStreams = list() destinationConvertImageStreams = list() # Source video attributes sIWidth = None sIHeight = None sIDPIX = None sIDPIY = None sIQuality = None # Handbrake Destination video attributes dIWidth = None dIHeight = None dIDPIX = None dIDPIY = None dIQuality = None countSourceImageStreams = len(sourceImageStreams) if countSourceImageStreams == 1: imsKey = sourceImageStreams.keys()[0] ims = sourceImageStreams[imsKey] sIWidth = ims.getWidth() sIHeight = ims.getHeight() sIDPIX = ims.getDensityX()[0] sIDPIY = ims.getDensityY()[0] sIQuality = ims.getQuality() loggerCameraSourceType = "Not identified" skippedJobCreation = True skippedReason = "" sIQuotientHeightWidth = float(float(sIHeight)/float(sIWidth)) # Select appropriate destination media file convertion settings # Unknown1 if(sIDPIX == 300 and sIDPIY == 300 and sIWidth >= 3508 and sIHeight >= 2480): if sIQuotientHeightWidth >= 1.0: sIHeight=3508 else: dIWidth=2480 dIQuality=95 loggerCameraSourceType = "Unknown1" skippedJobCreation = False # GoPro 3+ Silver - 10MP Wide Mode elif(sIDPIX == 72 and sIDPIY == 72 and sIWidth == 3680 and sIHeight == 2760): dIQuality=92 loggerCameraSourceType = "GoPro 3+ Silver - 10MP Wide Mode" skippedJobCreation = False # Unknown2 elif((sIWidth <= 2480 and sIHeight <= 3508) or (sIDPIX <=300 and sIDPIY <=300)): # No need to re-encode skippedJobCreation = True skippedReason = "No need to re-encode" else: skippedJobCreation = True skippedReason = "No suitable converter configuration found. Missing a convertion case ? New image file ?" if not skippedJobCreation: try: masterJob = OnSuccessOnlyConverterJob() # Backup file as Job #1 sourceBackupFileName = sourceMediaFile.getFileName() destinationBackupFileName = str(sourceBackupFileName) + ".backup" destinationBackupMediaFile = MediaFile() destinationBackupMediaFile.setFileName(destinationBackupFileName) copyFileJob = CopyFileJob(sourceFileName=sourceMediaFile.getFileName(), destinationFileName=destinationBackupMediaFile.getFileName()) masterJob.addJob(copyFileJob) loggerJobCreationRuntime.info("Will backup file: " + str(sourceBackupFileName) + " to " + str(destinationBackupFileName)) # Convert with ImageMagick's mogrity tool as Job #2 convertSourceMediaFile = MediaFile() convertSourceMediaFile.setFileName(util.escapePathForOSIndependentShell(destinationBackupFileName)) convertDestinationFileName = sourceMediaFile.getFileName() convertDestinationMediaFile.setFileName(util.escapePathForOSIndependentShell(convertDestinationFileName)) destinationConvertImageStream = ImageStream(filename=convertDestinationFileName, width=dIWidth, height=sIHeight, quality=dIQuality, densityX=dIDPIX, densityY=dIDPIY) destinationConvertImageStreams.append(destinationConvertImageStream) convertDestinationMediaFile.setImageStreams(destinationConvertImageStreams) convertCLIBuilder = ConvertCLGenerator.createResizeJobFrom(sourceMediaFile=convertSourceMediaFile, destinationMediaFile=convertDestinationMediaFile) convertCLIRunner = CLRunner(shell=True) masterJob.addJob(ConverterJob(clibuilder=convertCLIBuilder, clirunner=convertCLIRunner)) loggerJobCreationRuntime.info("convert cl:" + str(convertCLIBuilder.tocl())) # Delete backup file as Job #3 masterJob.addJob(DeleteFileJob(filename=destinationBackupMediaFile.getFileName())) loggerJobCreationRuntime.info("Will delete file:" + str(destinationBackupMediaFile.getFileName())) loggerJobCreationSuccess.info("JOB_CREATION_SUCCESS:" + sourceMediaFile.getFileName() + ": Type:" + loggerCameraSourceType) except BaseException: loggerJobCreationFailed.exception("JOB_CREATION_FAILED:" + sourceMediaFile.getFileName() + ": Type:" + loggerCameraSourceType + "Exception :") else: loggerJobCreationSkipped.info("JOB_CREATION_SKIPPED:" + sourceMediaFile.getFileName() + ": Type:" + loggerCameraSourceType + " Reason: " +skippedReason) else: loggerJobCreationFailed.error("JOB_CREATION_FAILED:" + sourceMediaFile.getFileName() + ": Reason: 1 video stream expected. " + str(countSourceVideoStreams) + " found.") if not masterJob: masterJob = Job() # Created only if proper convert job not created return masterJob
def probeImage(self, filename=None): """ Probes an image file @param: file Image file to probe @return Dictionary. Key "image" contains dictionary of ImageStream objects """ loggerJobCreationRuntime.info("================================================================================") loggerJobCreationRuntime.info("Processing :" + str(filename)) # Get Image width identifyCLBuilder0 = IdentifyCLGenerator() identifyCLBuilder0.addInputFile(util.escapePathForOSIndependentShell(filename)) identifyCLBuilder0.addFormatOption() identifyCLBuilder0.addFormatWidthOption() cl0 = identifyCLBuilder0.tocl() loggerJobCreationRuntime.info("identify cl:" + str(cl0)) clRunner0 = CLRunner(shell=True) clRunner0.run(cl0) identifyCLRawOutput0 = clRunner0.stdout() identifyParser0 = IdentifyParser() width = identifyParser0.parseFormatWidthOption(identifyCLRawOutput0) # Get Image height identifyCLBuilder1 = IdentifyCLGenerator() identifyCLBuilder1.addInputFile(util.escapePathForOSIndependentShell(filename)) identifyCLBuilder1.addFormatOption() identifyCLBuilder1.addFormatHeightOption() cl1=identifyCLBuilder1.tocl() loggerJobCreationRuntime.info("identify cl:" + str(cl1)) clRunner1=CLRunner(shell=True) clRunner1.run(cl1) identifyCLRawOutput1=clRunner1.stdout() identifyParser1 = IdentifyParser() height = identifyParser1.parseFormatHeightOption(identifyCLRawOutput1) # Get Image DPI X identifyCLBuilder2 = IdentifyCLGenerator() identifyCLBuilder2.addInputFile(util.escapePathForOSIndependentShell(filename)) identifyCLBuilder2.addFormatOption() identifyCLBuilder2.addFormatHorizontalDPIOption() cl2=identifyCLBuilder2.tocl() loggerJobCreationRuntime.info("identify cl:" + str(cl2)) clRunner2=CLRunner(shell=True) clRunner2.run(cl2) identifyCLRawOutput2=clRunner2.stdout() identifyParser2 = IdentifyParser() dpiX = identifyParser2.parseFormatHorizontalDPIOption(identifyCLRawOutput2) # Get Image DPI Y identifyCLBuilder3 = IdentifyCLGenerator() identifyCLBuilder3.addInputFile(util.escapePathForOSIndependentShell(filename)) identifyCLBuilder3.addFormatOption() identifyCLBuilder3.addFormatVerticalDPIOption() cl3=identifyCLBuilder3.tocl() loggerJobCreationRuntime.info("identify cl:" + str(cl3)) clRunner3=CLRunner(shell=True) clRunner3.run(cl3) identifyCLRawOutput3=clRunner3.stdout() identifyParser3 = IdentifyParser() dpiY = identifyParser3.parseFormatVerticalDPIOption(identifyCLRawOutput3) # Get Image Quality identifyCLBuilder4 = IdentifyCLGenerator() identifyCLBuilder4.addInputFile(util.escapePathForOSIndependentShell(filename)) identifyCLBuilder4.addFormatOption() identifyCLBuilder4.addFormatQualityOption() cl4=identifyCLBuilder4.tocl() loggerJobCreationRuntime.info("identify cl:" + str(cl4)) clRunner4=CLRunner(shell=True) clRunner4.run(cl4) identifyCLRawOutput4=clRunner4.stdout() identifyParser4 = IdentifyParser() quality = identifyParser4.parseFormatQualityOption(identifyCLRawOutput4) imageStream = ImageStream(filename=filename, width=width, height=height, quality=quality, densityX=dpiX, densityY=dpiY) imageStreams = dict() imageStreams["0"] = imageStream streamsMediaObjects = dict(image=imageStreams) return streamsMediaObjects