def setup_pipeline(self, scores, width, height, src_format): """ Given a list of pipeline options ordered by their score and an input format (width, height and source pixel format), we try to create a working pipeline, trying each option until one succeeds. """ start = time.time() debug("setup_pipeline%s", (scores, width, height, src_format)) for option in scores: try: _, csc_spec, enc_in_format, encoder_spec = option debug("setup_pipeline: trying %s", option) speed = self.get_current_speed() quality = self.get_current_quality() if csc_spec: #TODO: no need to OR encoder mask if we are scaling... self.width_mask = csc_spec.width_mask & encoder_spec.width_mask self.height_mask = csc_spec.height_mask & encoder_spec.height_mask csc_width = width & self.width_mask csc_height = height & self.height_mask enc_width, enc_height = self.get_encoder_dimensions( csc_spec, encoder_spec, csc_width, csc_height) #csc speed is not very important compared to encoding speed, #so make sure it never degrades quality csc_speed = min(speed, 100 - quality / 2.0) csc_start = time.time() self._csc_encoder = csc_spec.codec_class() self._csc_encoder.init_context(csc_width, csc_height, src_format, enc_width, enc_height, enc_in_format, csc_speed) csc_end = time.time() debug("setup_pipeline: csc=%s, info=%s, setup took %.2fms", self._csc_encoder, self._csc_encoder.get_info(), (csc_end - csc_start) * 1000.0) else: #use the encoder's mask directly since that's all we have to worry about! self.width_mask = encoder_spec.width_mask self.height_mask = encoder_spec.height_mask enc_width = width & self.width_mask enc_height = height & self.height_mask enc_start = time.time() self._video_encoder = encoder_spec.codec_class() self._video_encoder.init_context(enc_width, enc_height, enc_in_format, quality, speed, self.encoding_options) enc_end = time.time() debug( "setup_pipeline: video encoder=%s, info: %s, setup took %.2fms", self._video_encoder, self._video_encoder.get_info(), (enc_end - enc_start) * 1000.0) return True except: log.warn("setup_pipeline failed for %s", option, exc_info=True) end = time.time() debug("setup_pipeline(..) failed! took %.2fms", (end - start) * 1000.0) return False
def do_check_pipeline(self, encoding, width, height, src_format): """ Checks that the current pipeline is still valid for the given input. If not, close it and make a new one. """ #must be called with video lock held! if self._video_encoder is None: return False if self._csc_encoder: csc_width = width & self.width_mask csc_height = height & self.height_mask if self._csc_encoder.get_src_format()!=src_format: debug("check_pipeline csc: switching source format from %s to %s", self._csc_encoder.get_src_format(), src_format) return False elif self._csc_encoder.get_src_width()!=csc_width or self._csc_encoder.get_src_height()!=csc_height: debug("check_pipeline csc: window dimensions have changed from %sx%s to %sx%s, csc info=%s", self._csc_encoder.get_src_width(), self._csc_encoder.get_src_height(), csc_width, csc_height, self._csc_encoder.get_info()) return False elif self._csc_encoder.get_dst_format()!=self._video_encoder.get_src_format(): log.warn("check_pipeline csc: intermediate format mismatch: %s vs %s, csc info=%s", self._csc_encoder.get_dst_format(), self._video_encoder.get_src_format(), self._csc_encoder.get_info()) return False #encoder will take its input from csc: encoder_src_width = self._csc_encoder.get_dst_width() encoder_src_height = self._csc_encoder.get_dst_height() else: #direct to video encoder without csc: encoder_src_width = width & self.width_mask encoder_src_height = height & self.height_mask if self._video_encoder.get_src_format()!=src_format: debug("check_pipeline video: invalid source format %s, expected %s", self._video_encoder.get_src_format(), src_format) return False if self._video_encoder.get_encoding()!=encoding: debug("check_pipeline video: invalid encoding %s, expected %s", self._video_encoder.get_encoding(), encoding) return False elif self._video_encoder.get_width()!=encoder_src_width or self._video_encoder.get_height()!=encoder_src_height: debug("check_pipeline video: window dimensions have changed from %sx%s to %sx%s", self._video_encoder.get_width(), self._video_encoder.get_height(), encoder_src_width, encoder_src_height) return False return True
def setup_pipeline(self, scores, width, height, src_format): """ Given a list of pipeline options ordered by their score and an input format (width, height and source pixel format), we try to create a working pipeline, trying each option until one succeeds. """ assert width>0 and height>0, "invalid dimensions: %sx%s" % (width, height) start = time.time() debug("setup_pipeline%s", (scores, width, height, src_format)) for option in scores: try: _, csc_spec, enc_in_format, encoder_spec = option debug("setup_pipeline: trying %s", option) scaling = self.calculate_scaling(width, height, encoder_spec.max_w, encoder_spec.max_h) encoder_scaling = scaling speed = self.get_current_speed() quality = self.get_current_quality() min_w = 1 min_h = 1 max_w = 16384 max_h = 16384 if csc_spec: #TODO: no need to OR encoder mask if we are scaling... self.width_mask = csc_spec.width_mask & encoder_spec.width_mask self.height_mask = csc_spec.height_mask & encoder_spec.height_mask min_w = max(min_w, csc_spec.min_w) min_h = max(min_h, csc_spec.min_h) max_w = min(max_w, csc_spec.max_w) max_h = min(max_h, csc_spec.max_h) csc_width = width & self.width_mask csc_height = height & self.height_mask enc_width, enc_height = self.get_encoder_dimensions(csc_spec, encoder_spec, csc_width, csc_height, scaling) encoder_scaling = (1, 1) #csc speed is not very important compared to encoding speed, #so make sure it never degrades quality csc_speed = min(speed, 100-quality/2.0) csc_start = time.time() self._csc_encoder = csc_spec.codec_class() self._csc_encoder.init_context(csc_width, csc_height, src_format, enc_width, enc_height, enc_in_format, csc_speed) csc_end = time.time() debug("setup_pipeline: csc=%s, info=%s, setup took %.2fms", self._csc_encoder, self._csc_encoder.get_info(), (csc_end-csc_start)*1000.0) else: #use the encoder's mask directly since that's all we have to worry about! self.width_mask = encoder_spec.width_mask self.height_mask = encoder_spec.height_mask #restrict limits: min_w = max(min_w, encoder_spec.min_w) min_h = max(min_h, encoder_spec.min_h) max_w = min(max_w, encoder_spec.max_w) max_h = min(max_h, encoder_spec.max_h) enc_width = width & self.width_mask enc_height = height & self.height_mask if encoder_scaling!=(1,1) and not encoder_spec.can_scale: debug("scaling is now enabled, so skipping %s", encoder_spec) continue if width<=0 or height<=0: #log.warn("skipping invalid dimensions..") continue enc_start = time.time() self._video_encoder = encoder_spec.codec_class() self._video_encoder.init_context(enc_width, enc_height, enc_in_format, encoder_spec.encoding, quality, speed, encoder_scaling, self.encoding_options) #record new actual limits: self.actual_scaling = scaling self.min_w = min_w self.min_h = min_h self.max_w = max_w self.max_h = max_h enc_end = time.time() debug("setup_pipeline: video encoder=%s, info: %s, setup took %.2fms", self._video_encoder, self._video_encoder.get_info(), (enc_end-enc_start)*1000.0) return True except TransientCodecException, e: log.warn("setup_pipeline failed for %s: %s", option, e) self.cleanup_codecs() except:
self._video_encoder.init_context(enc_width, enc_height, enc_in_format, encoder_spec.encoding, quality, speed, encoder_scaling, self.encoding_options) #record new actual limits: self.actual_scaling = scaling self.min_w = min_w self.min_h = min_h self.max_w = max_w self.max_h = max_h enc_end = time.time() debug("setup_pipeline: video encoder=%s, info: %s, setup took %.2fms", self._video_encoder, self._video_encoder.get_info(), (enc_end-enc_start)*1000.0) return True except TransientCodecException, e: log.warn("setup_pipeline failed for %s: %s", option, e) self.cleanup_codecs() except: log.warn("setup_pipeline failed for %s", option, exc_info=True) self.cleanup_codecs() end = time.time() debug("setup_pipeline(..) failed! took %.2fms", (end-start)*1000.0) return False def video_encode(self, encoding, image, options): """ This method is used by make_data_packet to encode frames using video encoders. Video encoders only deal with fixed dimensions, so we must clean and reinitialize the encoder if the window dimensions has changed. Since this runs in the non-UI thread 'data_to_packet', we must use the '_lock' to prevent races. """
def setup_pipeline(self, scores, width, height, src_format): """ Given a list of pipeline options ordered by their score and an input format (width, height and source pixel format), we try to create a working pipeline, trying each option until one succeeds. """ assert width > 0 and height > 0, "invalid dimensions: %sx%s" % (width, height) start = time.time() debug("setup_pipeline%s", (scores, width, height, src_format)) for option in scores: try: _, csc_spec, enc_in_format, encoder_spec = option debug("setup_pipeline: trying %s", option) scaling = self.calculate_scaling(width, height, encoder_spec.max_w, encoder_spec.max_h) encoder_scaling = scaling speed = self.get_current_speed() quality = self.get_current_quality() min_w = 1 min_h = 1 max_w = 16384 max_h = 16384 if csc_spec: #TODO: no need to OR encoder mask if we are scaling... self.width_mask = csc_spec.width_mask & encoder_spec.width_mask self.height_mask = csc_spec.height_mask & encoder_spec.height_mask min_w = max(min_w, csc_spec.min_w) min_h = max(min_h, csc_spec.min_h) max_w = min(max_w, csc_spec.max_w) max_h = min(max_h, csc_spec.max_h) csc_width = width & self.width_mask csc_height = height & self.height_mask enc_width, enc_height = self.get_encoder_dimensions( csc_spec, encoder_spec, csc_width, csc_height, scaling) encoder_scaling = (1, 1) #csc speed is not very important compared to encoding speed, #so make sure it never degrades quality csc_speed = min(speed, 100 - quality / 2.0) csc_start = time.time() self._csc_encoder = csc_spec.codec_class() self._csc_encoder.init_context(csc_width, csc_height, src_format, enc_width, enc_height, enc_in_format, csc_speed) csc_end = time.time() debug("setup_pipeline: csc=%s, info=%s, setup took %.2fms", self._csc_encoder, self._csc_encoder.get_info(), (csc_end - csc_start) * 1000.0) else: #use the encoder's mask directly since that's all we have to worry about! self.width_mask = encoder_spec.width_mask self.height_mask = encoder_spec.height_mask #restrict limits: min_w = max(min_w, encoder_spec.min_w) min_h = max(min_h, encoder_spec.min_h) max_w = min(max_w, encoder_spec.max_w) max_h = min(max_h, encoder_spec.max_h) enc_width = width & self.width_mask enc_height = height & self.height_mask if encoder_scaling != (1, 1) and not encoder_spec.can_scale: debug("scaling is now enabled, so skipping %s", encoder_spec) continue if width <= 0 or height <= 0: #log.warn("skipping invalid dimensions..") continue enc_start = time.time() self._video_encoder = encoder_spec.codec_class() self._video_encoder.init_context(enc_width, enc_height, enc_in_format, encoder_spec.encoding, quality, speed, encoder_scaling, self.encoding_options) #record new actual limits: self.actual_scaling = scaling self.min_w = min_w self.min_h = min_h self.max_w = max_w self.max_h = max_h enc_end = time.time() debug( "setup_pipeline: video encoder=%s, info: %s, setup took %.2fms", self._video_encoder, self._video_encoder.get_info(), (enc_end - enc_start) * 1000.0) return True except TransientCodecException, e: log.warn("setup_pipeline failed for %s: %s", option, e) self.cleanup_codecs() except:
def do_check_pipeline(self, encoding, width, height, src_format): """ Checks that the current pipeline is still valid for the given input. If not, close it and make a new one. """ #must be called with video lock held! if self._video_encoder is None: return False if self._csc_encoder: csc_width = width & self.width_mask csc_height = height & self.height_mask if self._csc_encoder.get_src_format() != src_format: debug( "check_pipeline csc: switching source format from %s to %s", self._csc_encoder.get_src_format(), src_format) return False elif self._csc_encoder.get_src_width( ) != csc_width or self._csc_encoder.get_src_height() != csc_height: debug( "check_pipeline csc: window dimensions have changed from %sx%s to %sx%s, csc info=%s", self._csc_encoder.get_src_width(), self._csc_encoder.get_src_height(), csc_width, csc_height, self._csc_encoder.get_info()) return False elif self._csc_encoder.get_dst_format( ) != self._video_encoder.get_src_format(): log.warn( "check_pipeline csc: intermediate format mismatch: %s vs %s, csc info=%s", self._csc_encoder.get_dst_format(), self._video_encoder.get_src_format(), self._csc_encoder.get_info()) return False #encoder will take its input from csc: encoder_src_width = self._csc_encoder.get_dst_width() encoder_src_height = self._csc_encoder.get_dst_height() else: #direct to video encoder without csc: encoder_src_width = width & self.width_mask encoder_src_height = height & self.height_mask if self._video_encoder.get_src_format() != src_format: debug( "check_pipeline video: invalid source format %s, expected %s", self._video_encoder.get_src_format(), src_format) return False if self._video_encoder.get_encoding() != encoding: debug("check_pipeline video: invalid encoding %s, expected %s", self._video_encoder.get_encoding(), encoding) return False elif self._video_encoder.get_width( ) != encoder_src_width or self._video_encoder.get_height( ) != encoder_src_height: debug( "check_pipeline video: window dimensions have changed from %sx%s to %sx%s", self._video_encoder.get_width(), self._video_encoder.get_height(), encoder_src_width, encoder_src_height) return False return True
self.actual_scaling = scaling self.min_w = min_w self.min_h = min_h self.max_w = max_w self.max_h = max_h enc_end = time.time() debug( "setup_pipeline: video encoder=%s, info: %s, setup took %.2fms", self._video_encoder, self._video_encoder.get_info(), (enc_end - enc_start) * 1000.0) return True except TransientCodecException, e: log.warn("setup_pipeline failed for %s: %s", option, e) self.cleanup_codecs() except: log.warn("setup_pipeline failed for %s", option, exc_info=True) self.cleanup_codecs() end = time.time() debug("setup_pipeline(..) failed! took %.2fms", (end - start) * 1000.0) return False def video_encode(self, encoding, image, options): """ This method is used by make_data_packet to encode frames using video encoders. Video encoders only deal with fixed dimensions, so we must clean and reinitialize the encoder if the window dimensions has changed. Since this runs in the non-UI thread 'data_to_packet', we must use the '_lock' to prevent races. """ debug("video_encode%s", (encoding, image, options))
def setup_pipeline(self, scores, width, height, src_format): """ Given a list of pipeline options ordered by their score and an input format (width, height and source pixel format), we try to create a working pipeline, trying each option until one succeeds. """ start = time.time() debug("setup_pipeline%s", (scores, width, height, src_format)) for option in scores: try: _, csc_spec, enc_in_format, encoder_spec = option debug("setup_pipeline: trying %s", option) speed = self.get_current_speed() quality = self.get_current_quality() if csc_spec: # TODO: no need to OR encoder mask if we are scaling... self.width_mask = csc_spec.width_mask & encoder_spec.width_mask self.height_mask = csc_spec.height_mask & encoder_spec.height_mask csc_width = width & self.width_mask csc_height = height & self.height_mask enc_width, enc_height = self.get_encoder_dimensions(csc_spec, encoder_spec, csc_width, csc_height) # csc speed is not very important compared to encoding speed, # so make sure it never degrades quality csc_speed = min(speed, 100 - quality / 2.0) csc_start = time.time() self._csc_encoder = csc_spec.codec_class() self._csc_encoder.init_context( csc_width, csc_height, src_format, enc_width, enc_height, enc_in_format, csc_speed ) csc_end = time.time() debug( "setup_pipeline: csc=%s, info=%s, setup took %.2fms", self._csc_encoder, self._csc_encoder.get_info(), (csc_end - csc_start) * 1000.0, ) else: # use the encoder's mask directly since that's all we have to worry about! self.width_mask = encoder_spec.width_mask self.height_mask = encoder_spec.height_mask enc_width = width & self.width_mask enc_height = height & self.height_mask enc_start = time.time() self._video_encoder = encoder_spec.codec_class() self._video_encoder.init_context( enc_width, enc_height, enc_in_format, quality, speed, self.encoding_options ) enc_end = time.time() debug( "setup_pipeline: video encoder=%s, info: %s, setup took %.2fms", self._video_encoder, self._video_encoder.get_info(), (enc_end - enc_start) * 1000.0, ) return True except: log.warn("setup_pipeline failed for %s", option, exc_info=True) end = time.time() debug("setup_pipeline(..) failed! took %.2fms", (end - start) * 1000.0) return False