def makeAudioEncodeBin(config, analysis, tag, withRateControl=True, pipelineInfo=None, logger=None): logger = logger or log pipelineParts = list() bin = gst.Bin() # input queue element inqueue = gst.element_factory_make("queue", "audioinqueue-%s" % tag) # Cannot specify max_size_time property because of some buggy buffers # with invalid time that make the queue lock inqueue.props.max_size_time = 0 inqueue.props.max_size_buffers = 200 pipelineParts.append("queue") # audiorate element if withRateControl: rate = gst.element_factory_make("audiorate", "audiorate-%s" % tag) # Add a tolerance of 20ms to audiorate to fix cracking audio if gstreamer.element_has_property(rate, "tolerance"): rate.set_property("tolerance", DEFAULT_TOLERANCE) pipelineParts.append("audiorate") else: rate = None # audioconvert element convert = gst.element_factory_make("audioconvert", "audioconvert-%s" % tag) pipelineParts.append("audioconvert") # audioresample element # Use legacyresample if available because after 0.10.22 the old # audioresample element got renamed to legacyresample and replaced # by speexresample that cause audio/video synchronization issues. resamplerName = "audioresample" if gstreamer.element_factory_exists("legacyresample"): resamplerName = "legacyresample" if config.audioResampler: if gstreamer.element_factory_exists(config.audioResampler): resamplerName = config.audioResampler else: logger.warning("Audio resampler %s doesn't exist, defaulting to %s", config.audioResampler, resamplerName) resample = gst.element_factory_make(resamplerName, "%s-%s" % (resamplerName, tag)) pipelineParts.append(resamplerName) # capsfilter element capsfilter = gst.element_factory_make("capsfilter", "audiocapsfilter-%s" % tag) # Because the analysis not reliably give channel # and rate info, do not not rely on it. if config.audioRate or config.audioChannels: capsList = [] if config.audioRate: capsList.append("rate=%d" % config.audioRate) elif analysis.audioRate: capsList.append("rate=%d" % analysis.audioRate) if config.audioChannels: capsList.append("channels=%d" % config.audioChannels) elif analysis.audioChannels: capsList.append("channels=%d" % analysis.audioChannels) caps = ", ".join(capsList) if caps: fullcaps = "audio/x-raw-int, %s;audio/x-raw-float, %s" % (caps, caps) logger.debug("Audio capsfilter: '%s'", fullcaps) pipelineParts.append("'%s'" % fullcaps) capsfilter.props.caps = gst.caps_from_string(fullcaps) else: logger.debug("No audio capsfilter") # encoder elements encode = gstutils.parse_bin_from_description(config.audioEncoder, True) pipelineParts.extend(map(str.strip, config.audioEncoder.split("!"))) # output queue element outqueue = gst.element_factory_make("queue", "audioutqueue-%s" % tag) outqueue.props.max_size_time = gst.SECOND * 20 outqueue.props.max_size_buffers = 0 pipelineParts.append("queue") if rate: bin.add(inqueue, rate, convert, resample, capsfilter, encode, outqueue) gst.element_link_many(inqueue, rate, convert, resample, capsfilter, encode, outqueue) else: bin.add(inqueue, convert, resample, capsfilter, encode, outqueue) gst.element_link_many(inqueue, convert, resample, capsfilter, encode, outqueue) bin.add_pad(gst.GhostPad("sink", inqueue.get_pad("sink"))) bin.add_pad(gst.GhostPad("src", outqueue.get_pad("src"))) pipelineDesc = " ! ".join(pipelineParts) logger.debug("Audio pipeline: %s", pipelineDesc) if pipelineInfo != None: pipelineInfo["audio"] = pipelineDesc return bin
def generate(self): if self._deferred: return self._deferred self._deferred = defer.Deferred() self._deferred.addBoth(self.__bbShutdownPipeline) try: if not self.path: handle, self.path = tempfile.mkstemp() os.close(handle) self._deferred.addErrback(self.__ebRemoveTempFile) if self.videoCodec: if isinstance(self.videoRate, (int, long)): videoRate = (self.videoRate, 1) vRate = float(self.videoRate) elif isinstance(self.videoRate, (list, tuple)): videoRate = self.videoRate vRate = float(videoRate[0]) / float(videoRate[1]) aBlockSize = int(round(self.audioRate / vRate)) buffCount = int(round(vRate * self.duration)) + 1 else: aBlockSize = int(round(self.audioRate / 10)) buffCount = int(round(10 * self.duration)) + 1 self._pipeline = gst.Pipeline("GenMediaFile") filesink = gst.element_factory_make("filesink") filesink.props.location = self.path self._pipeline.add(filesink) if self.muxer: muxer = gst.parse_launch(self.muxer) self._pipeline.add(muxer) muxer.link(filesink) else: muxer = filesink if self.videoCodec: vCaps = ("width=(int)%d, height=(int)%d, framerate=(fraction)%d/%d, " "pixel-aspect-ratio=(fraction)%d/%d" % (self.videoWidth, self.videoHeight, videoRate[0], videoRate[1], self.videoPAR[0], self.videoPAR[1])) vCaps = "video/x-raw-rgb, %s;video/x-raw-yuv, %s" % (vCaps, vCaps) videotestsrc = gst.element_factory_make("videotestsrc") videotestsrc.props.num_buffers = buffCount videocaps = gst.element_factory_make("capsfilter") videocaps.props.caps = gst.caps_from_string(vCaps) videoencoder = gstutils.parse_bin_from_description(self.videoCodec, True) videoqueue = gst.element_factory_make("queue") self._pipeline.add(videotestsrc, videocaps, videoencoder, videoqueue) gst.element_link_many(videotestsrc, videocaps, videoencoder, videoqueue, muxer) if self.audioCodec: aCaps = ("rate=(int)%d, channels=(int)%d" % (self.audioRate, self.audioChannels)) aCaps = "audio/x-raw-int, %s;audio/x-raw-float, %s" % (aCaps, aCaps) audiotestsrc = gst.element_factory_make("audiotestsrc") audiotestsrc.props.num_buffers = buffCount audiotestsrc.props.samplesperbuffer = aBlockSize audioconvert = gst.element_factory_make("audioconvert") audiocaps = gst.element_factory_make("capsfilter") audiocaps.props.caps = gst.caps_from_string(aCaps) audioencoder = gstutils.parse_bin_from_description(self.audioCodec, True) audioqueue = gst.element_factory_make("queue") self._pipeline.add(audiotestsrc, audioconvert, audiocaps, audioencoder, audioqueue) gst.element_link_many(audiotestsrc, audioconvert, audiocaps, audioencoder, audioqueue, muxer) d = defer.Deferred() self._bus = self._pipeline.get_bus() self._bus.add_signal_watch() self._bus.connect("message", self._bus_message_callback) ret = self._pipeline.set_state(gst.STATE_PLAYING) if ret == gst.STATE_CHANGE_FAILURE: raise Exception("Fail to change pipeline state to PLAYING") return self._deferred except: self._deferred.errback(Failure()) return self._deferred
def makeVideoEncodeBin(config, analysis, tag, withRateControl=True, pipelineInfo=None, logger=None): logger = logger or log pipelineParts = list() bin = gst.Bin() # input queue element inqueue = gst.element_factory_make("queue", "videoinqueue-%s" % tag) # Cannot specify max_size_time property because of some buggy buffers # with invalid time that make the queue lock inqueue.props.max_size_time = 0 inqueue.props.max_size_buffers = 200 pipelineParts.append("queue") # ffmpegcolorspace element cspace = gst.element_factory_make("ffmpegcolorspace", "cspace-%s" % tag) pipelineParts.append("ffmpegcolorspace") # videorate element if withRateControl: rate = gst.element_factory_make("videorate", "videorate-%s" % tag) pipelineParts.append("videorate") else: rate = None # videoscale element scale = gst.element_factory_make("videoscale", "videoscale-%s" % tag) # use bilinear scaling for better image quality scale.props.method = 1 pipelineParts.append("videoscale method=1") # capsfilter element capsfilter = gst.element_factory_make("capsfilter", "videocapsfilter-%s" % tag) inputSize = _getInputVideoSize(config, analysis) logger.debug( "makeVideoEncodeBin - Input Video Size: %dx%d %d/%d" % (inputSize[0], inputSize[1], inputSize[2].num, inputSize[2].denom) ) _logPreferredSize(logger.debug, config, "makeVideoEncodeBin - Preferred Video Size:") outputSize = _getOutputVideoSize(config, analysis, inputSize) logger.debug( "makeVideoEncodeBin - Output Video Size: %dx%d %d/%d" % (outputSize[0], outputSize[1], outputSize[2].num, outputSize[2].denom) ) caps = _getOutputVideoCaps(config, analysis, outputSize) if caps: logger.debug("Video capsfilter: '%s'", caps) capsfilter.props.caps = gst.caps_from_string(caps) pipelineParts.append("'%s'" % caps) else: logger.debug("No video capsfilter") # videobox and videocrop elements box = _getOutputVideoBox(config, analysis, outputSize) videocrop = None videobox = None if box != (0, 0, 0, 0): # FIXME: Crop is a temporary hack to fix wrong behaviors # of the platform version of videobox with odd parameteres. # gstreamer-0.10.12, gstreamer-plugins-good-0.10.5 crop = tuple([v % 2 for v in box]) box = tuple([v - (v % 2) for v in box]) logger.debug("makeVideoEncodeBin - Output Video Boxing: %r" % (box,)) videobox = gst.element_factory_make("videobox", "videobox-%s" % tag) videobox.props.left = box[0] videobox.props.top = box[1] videobox.props.right = box[2] videobox.props.bottom = box[3] pipelineParts.append("videobox left=%d top=%d " "right=%d bottom=%d" % box[:4]) if crop != (0, 0, 0, 0): logger.debug("makeVideoEncodeBin - Output Video Cropping: %r" % (crop,)) videocrop = gst.element_factory_make("videocrop", "videocrop-%s" % tag) videocrop.props.left = crop[0] videocrop.props.top = crop[1] videocrop.props.right = crop[2] videocrop.props.bottom = crop[3] pipelineParts.append("videocrop left=%d top=%d " "right=%d bottom=%d" % crop[:4]) # encoder elements encode = gstutils.parse_bin_from_description(config.videoEncoder, True) pipelineParts.extend(map(str.strip, config.videoEncoder.split("!"))) # output queue element outqueue = gst.element_factory_make("queue", "videooutqueue-%s" % tag) outqueue.props.max_size_time = gst.SECOND * 20 outqueue.props.max_size_buffers = 0 pipelineParts.append("queue") # Add to pipeline and link all the elements bin.add(inqueue, cspace, scale, capsfilter, encode, outqueue) if rate: bin.add(rate) gst.element_link_many(inqueue, cspace, scale, rate, capsfilter) else: gst.element_link_many(inqueue, cspace, scale, capsfilter) if videobox: bin.add(videobox) if videocrop: bin.add(videocrop) gst.element_link_many(capsfilter, videobox, videocrop, encode) else: gst.element_link_many(capsfilter, videobox, encode) else: gst.element_link_many(capsfilter, encode) gst.element_link_many(encode, outqueue) bin.add_pad(gst.GhostPad("sink", inqueue.get_pad("sink"))) bin.add_pad(gst.GhostPad("src", outqueue.get_pad("src"))) pipelineDesc = " ! ".join(pipelineParts) logger.debug("Video pipeline: %s", pipelineDesc) if pipelineInfo != None: pipelineInfo["video"] = pipelineDesc return bin