From 5c754fdaeeddb1bbeff165bbecb77e33b75b3c7d Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Tue, 22 Jan 2013 22:44:19 +0100 Subject: [PATCH] Added option to skip transcoding - If the video input matches the configurable rules, just copy it to the output without transcoding it. --- mediagoblin/config_spec.ini | 6 ++ mediagoblin/media_types/video/processing.py | 59 ++++++++++++------- mediagoblin/media_types/video/transcoders.py | 4 +- mediagoblin/media_types/video/util.py | 60 ++++++++++++++++++++ 4 files changed, 109 insertions(+), 20 deletions(-) create mode 100644 mediagoblin/media_types/video/util.py diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini index bee67d46..712d087e 100644 --- a/mediagoblin/config_spec.ini +++ b/mediagoblin/config_spec.ini @@ -97,6 +97,12 @@ vp8_quality = integer(default=8) # Range: -0.1..1 vorbis_quality = float(default=0.3) +[[skip_transcode]] +mime_types = string_list(default=list("video/webm")) +container_formats = string_list(default=list("Matroska")) +video_codecs = string_list(default=list("VP8 video")) +audio_codecs = string_list(default=list("Vorbis")) +dimensions_match = boolean(default=True) [media_type:mediagoblin.media_types.audio] keep_original = boolean(default=True) diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py index 4c9f0131..53fe1a73 100644 --- a/mediagoblin/media_types/video/processing.py +++ b/mediagoblin/media_types/video/processing.py @@ -24,6 +24,8 @@ from mediagoblin.processing import \ from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ from . import transcoders +from .util import skip_transcode + _log = logging.getLogger(__name__) _log.setLevel(logging.DEBUG) @@ -80,24 +82,43 @@ def process_video(entry, workbench=None): with tmp_dst: # Transcode queued file to a VP8/vorbis file that fits in a 640x640 square progress_callback = ProgressCallback(entry) - transcoder = transcoders.VideoTranscoder() - transcoder.transcode(queued_filename, tmp_dst.name, - vp8_quality=video_config['vp8_quality'], - vp8_threads=video_config['vp8_threads'], - vorbis_quality=video_config['vorbis_quality'], - progress_callback=progress_callback) - # Push transcoded video to public storage - _log.debug('Saving medium...') - mgg.public_store.copy_local_to_storage(tmp_dst.name, medium_filepath) - _log.debug('Saved medium') + dimensions = ( + mgg.global_config['media:medium']['max_width'], + mgg.global_config['media:medium']['max_height']) + + metadata = transcoders.VideoTranscoder().discover(queued_filename) + + if skip_transcode(metadata): + _log.debug('Skipping transcoding') + # Just push the submitted file to the tmp_dst + open(tmp_dst.name, 'wb').write(open(queued_filename, 'rb').read()) + + dst_dimensions = metadata['videowidth'], metadata['videoheight'] + else: + transcoder = transcoders.VideoTranscoder() + + transcoder.transcode(queued_filename, tmp_dst.name, + vp8_quality=video_config['vp8_quality'], + vp8_threads=video_config['vp8_threads'], + vorbis_quality=video_config['vorbis_quality'], + progress_callback=progress_callback, + dimensions=dimensions) + + dst_dimensions = transcoder.dst_data.videowidth,\ + transcoder.dst_data.videoheight + + # Push transcoded video to public storage + _log.debug('Saving medium...') + mgg.public_store.copy_local_to_storage(tmp_dst.name, medium_filepath) + _log.debug('Saved medium') - entry.media_files['webm_640'] = medium_filepath + entry.media_files['webm_640'] = medium_filepath - # Save the width and height of the transcoded video - entry.media_data_init( - width=transcoder.dst_data.videowidth, - height=transcoder.dst_data.videoheight) + # Save the width and height of the transcoded video + entry.media_data_init( + width=dst_dimensions[0], + height=dst_dimensions[1]) # Temporary file for the video thumbnail (cleaned up with workbench) tmp_thumb = NamedTemporaryFile(dir=workbench.dir, suffix='.jpg', delete=False) @@ -109,10 +130,10 @@ def process_video(entry, workbench=None): tmp_thumb.name, 180) - # Push the thumbnail to public storage - _log.debug('Saving thumbnail...') - mgg.public_store.copy_local_to_storage(tmp_thumb.name, thumbnail_filepath) - entry.media_files['thumb'] = thumbnail_filepath + # Push the thumbnail to public storage + _log.debug('Saving thumbnail...') + mgg.public_store.copy_local_to_storage(tmp_thumb.name, thumbnail_filepath) + entry.media_files['thumb'] = thumbnail_filepath if video_config['keep_original']: # Push original file to public storage diff --git a/mediagoblin/media_types/video/transcoders.py b/mediagoblin/media_types/video/transcoders.py index 152de288..8aa7121f 100644 --- a/mediagoblin/media_types/video/transcoders.py +++ b/mediagoblin/media_types/video/transcoders.py @@ -673,6 +673,7 @@ class VideoTranscoder: self._setup() self._run() + # XXX: This could be a static method. def discover(self, src): ''' Discover properties about a media file @@ -793,7 +794,8 @@ class VideoTranscoder: self.audioconvert = gst.element_factory_make('audioconvert', 'audioconvert') self.pipeline.add(self.audioconvert) - self.audiocapsfilter = gst.element_factory_make('capsfilter', 'audiocapsfilter') + self.audiocapsfilter = gst.element_factory_make('capsfilter', + 'audiocapsfilter') audiocaps = ['audio/x-raw-float'] self.audiocapsfilter.set_property( 'caps', diff --git a/mediagoblin/media_types/video/util.py b/mediagoblin/media_types/video/util.py new file mode 100644 index 00000000..93f098f7 --- /dev/null +++ b/mediagoblin/media_types/video/util.py @@ -0,0 +1,60 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import logging + +from mediagoblin import mg_globals as mgg + +_log = logging.getLogger(__name__) + + +def skip_transcode(metadata): + ''' + Checks video metadata against configuration values for skip_transcode. + + Returns True if the video matches the requirements in the configuration. + ''' + config = mgg.global_config['media_type:mediagoblin.media_types.video']\ + ['skip_transcode'] + + medium_config = mgg.global_config['media:medium'] + + _log.debug('skip_transcode config: {0}'.format(config)) + + if config['mime_types'] and metadata.get('mimetype'): + if not metadata['mimetype'] in config['mime_types']: + return False + + if config['container_formats'] and metadata['tags'].get('audio-codec'): + if not metadata['tags']['container-format'] in config['container_formats']: + return False + + if config['video_codecs'] and metadata['tags'].get('audio-codec'): + if not metadata['tags']['video-codec'] in config['video_codecs']: + return False + + if config['audio_codecs'] and metadata['tags'].get('audio-codec'): + if not metadata['tags']['audio-codec'] in config['audio_codecs']: + return False + + if config['dimensions_match']: + if not metadata['videoheight'] <= medium_config['max_height']: + return False + if not metadata['videowidth'] <= medium_config['max_width']: + return False + + return True + -- 2.25.1