aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mediagoblin/config_spec.ini12
-rw-r--r--mediagoblin/media_types/ascii/asciitoimage.py25
-rw-r--r--mediagoblin/media_types/ascii/processing.py10
-rw-r--r--mediagoblin/media_types/audio/processing.py7
-rw-r--r--mediagoblin/media_types/video/processing.py10
-rw-r--r--mediagoblin/media_types/video/transcoders.py57
-rw-r--r--mediagoblin/static/css/audio.css2
-rw-r--r--mediagoblin/static/js/audio.js10
8 files changed, 87 insertions, 46 deletions
diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini
index e30825de..01853e48 100644
--- a/mediagoblin/config_spec.ini
+++ b/mediagoblin/config_spec.ini
@@ -86,11 +86,23 @@ max_height = integer(default=180)
# Should we keep the original file?
keep_original = boolean(default=False)
+# 0 means autodetect, autodetect means number_of_CPUs - 1
+vp8_threads = integer(default=0)
+# Range: 0..10
+vp8_quality = integer(default=8)
+# Range: -0.1..1
+vorbis_quality = float(default=0.3)
+
+
[media_type:mediagoblin.media_types.audio]
# vorbisenc qualiy
quality = float(default=0.3)
create_spectrogram = boolean(default=True)
+spectrogram_fft_size = integer(default=4096)
+
+[media_type:mediagoblin.media_types.ascii]
+thumbnail_font = string(default=None)
[beaker.cache]
type = string(default="file")
diff --git a/mediagoblin/media_types/ascii/asciitoimage.py b/mediagoblin/media_types/ascii/asciitoimage.py
index 3017d2ad..108de023 100644
--- a/mediagoblin/media_types/ascii/asciitoimage.py
+++ b/mediagoblin/media_types/ascii/asciitoimage.py
@@ -34,31 +34,12 @@ class AsciiToImage(object):
- font_size: Font size, ``int``
default: 11
'''
-
- # Font file path
- _font = None
-
- _font_size = 11
-
- # ImageFont instance
- _if = None
-
- # ImageFont
- _if_dims = None
-
- # Image instance
- _im = None
-
def __init__(self, **kw):
- if kw.get('font'):
- self._font = kw.get('font')
- else:
- self._font = pkg_resources.resource_filename(
+ self._font = kw.get('font', pkg_resources.resource_filename(
'mediagoblin.media_types.ascii',
- os.path.join('fonts', 'Inconsolata.otf'))
+ os.path.join('fonts', 'Inconsolata.otf')))
- if kw.get('font_size'):
- self._font_size = kw.get('font_size')
+ self._font_size = kw.get('font_size', 11)
self._if = ImageFont.truetype(
self._font,
diff --git a/mediagoblin/media_types/ascii/processing.py b/mediagoblin/media_types/ascii/processing.py
index a2a52e9d..04d1166c 100644
--- a/mediagoblin/media_types/ascii/processing.py
+++ b/mediagoblin/media_types/ascii/processing.py
@@ -42,6 +42,7 @@ def process_ascii(entry):
'''
Code to process a txt file
'''
+ ascii_config = mgg.global_config['media_type:mediagoblin.media_types.ascii']
workbench = mgg.workbench_manager.create_workbench()
# Conversions subdirectory to avoid collisions
conversions_subdir = os.path.join(
@@ -77,7 +78,14 @@ def process_ascii(entry):
tmp_thumb_filename = os.path.join(
conversions_subdir, thumb_filepath[-1])
- converter = asciitoimage.AsciiToImage()
+ ascii_converter_args = {}
+
+ if ascii_config['thumbnail_font']:
+ ascii_converter_args.update(
+ {'font': ascii_config['thumbnail_font']})
+
+ converter = asciitoimage.AsciiToImage(
+ **ascii_converter_args)
thumb = converter._create_image(
queued_file.read())
diff --git a/mediagoblin/media_types/audio/processing.py b/mediagoblin/media_types/audio/processing.py
index c0ff7bff..f0b8d0f9 100644
--- a/mediagoblin/media_types/audio/processing.py
+++ b/mediagoblin/media_types/audio/processing.py
@@ -27,7 +27,7 @@ from mediagoblin.media_types.audio.transcoders import AudioTranscoder, \
_log = logging.getLogger(__name__)
def sniff_handler(media_file, **kw):
- try:
+ try:
transcoder = AudioTranscoder()
data = transcoder.discover(media_file.name)
except BadMediaFail:
@@ -94,7 +94,8 @@ def process_audio(entry):
thumbnailer.spectrogram(
wav_tmp.name,
spectrogram_tmp.name,
- width=mgg.global_config['media:medium']['max_width'])
+ width=mgg.global_config['media:medium']['max_width'],
+ fft_size=audio_config['spectrogram_fft_size'])
_log.debug('Saving spectrogram...')
mgg.public_store.get_file(spectrogram_filepath, 'wb').write(
@@ -121,7 +122,7 @@ def process_audio(entry):
entry.media_files['thumb'] = thumb_filepath
else:
entry.media_files['thumb'] = ['fake', 'thumb', 'path.jpg']
-
+
mgg.queue_store.delete_file(queued_filepath)
entry.save()
diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py
index d4b4e983..5bbcc92f 100644
--- a/mediagoblin/media_types/video/processing.py
+++ b/mediagoblin/media_types/video/processing.py
@@ -16,15 +16,12 @@
import tempfile
import logging
-import os
from mediagoblin import mg_globals as mgg
-from mediagoblin.processing import mark_entry_failed, \
+from mediagoblin.processing import \
create_pub_filepath, FilenameBuilder
from . import transcoders
-logging.basicConfig()
-
_log = logging.getLogger(__name__)
_log.setLevel(logging.DEBUG)
@@ -73,7 +70,10 @@ def process_video(entry):
with tmp_dst:
# Transcode queued file to a VP8/vorbis file that fits in a 640x640 square
transcoder = transcoders.VideoTranscoder()
- transcoder.transcode(queued_filename, tmp_dst.name)
+ 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'])
# Push transcoded video to public storage
_log.debug('Saving medium...')
diff --git a/mediagoblin/media_types/video/transcoders.py b/mediagoblin/media_types/video/transcoders.py
index 74821877..d5c162ba 100644
--- a/mediagoblin/media_types/video/transcoders.py
+++ b/mediagoblin/media_types/video/transcoders.py
@@ -72,6 +72,11 @@ class VideoThumbnailer:
Set up playbin pipeline in order to get video properties.
Initializes and runs the gobject.MainLoop()
+
+ Abstract
+ - Set up a playbin with a fake audio sink and video sink. Load the video
+ into the playbin
+ - Initialize
'''
self.errors = []
@@ -105,9 +110,10 @@ class VideoThumbnailer:
self.loop.run()
def _on_bus_message(self, bus, message):
- _log.debug(' BUS MESSAGE: {0}'.format(message))
+ _log.debug(' thumbnail playbin: {0}'.format(message))
if message.type == gst.MESSAGE_ERROR:
+ _log.error('thumbnail playbin: {0}'.format(message))
gobject.idle_add(self._on_bus_error)
elif message.type == gst.MESSAGE_STATE_CHANGED:
@@ -154,13 +160,14 @@ class VideoThumbnailer:
return False
def _on_thumbnail_bus_message(self, bus, message):
- _log.debug('Thumbnail bus called, message: {0}'.format(message))
+ _log.debug('thumbnail: {0}'.format(message))
if message.type == gst.MESSAGE_ERROR:
_log.error(message)
gobject.idle_add(self._on_bus_error)
if message.type == gst.MESSAGE_STATE_CHANGED:
+ _log.debug('State changed')
_prev, state, _pending = message.parse_state_changed()
if (state == gst.STATE_PAUSED and
@@ -184,6 +191,7 @@ class VideoThumbnailer:
break
# Apply the wadsworth constant, fallback to 1 second
+ # TODO: Will break if video is shorter than 1 sec
seek_amount = max(self.duration / 100 * 30, 1 * gst.SECOND)
_log.debug('seek amount: {0}'.format(seek_amount))
@@ -204,14 +212,19 @@ class VideoThumbnailer:
_log.info(message)
self.shutdown()
else:
- pass
- #self.thumbnail_pipeline.set_state(gst.STATE_PAUSED)
+ _log.debug('Seek successful')
+ self.thumbnail_pipeline.set_state(gst.STATE_PAUSED)
#pdb.set_trace()
+ else:
+ _log.debug('Won\'t seek: \t{0}\n\t{1}'.format(
+ self.state,
+ message.src))
def buffer_probe_handler_real(self, pad, buff, name):
'''
Capture buffers as gdk_pixbufs when told to.
'''
+ _log.info('Capturing frame')
try:
caps = buff.caps
if caps is None:
@@ -237,14 +250,16 @@ class VideoThumbnailer:
self.shutdown()
- except gst.QueryError:
- pass
+ except gst.QueryError as e:
+ _log.error('QueryError: {0}'.format(e))
+
return False
def buffer_probe_handler(self, pad, buff, name):
'''
Proxy function for buffer_probe_handler_real
'''
+ _log.debug('Attaching real buffer handler to gobject idle event')
gobject.idle_add(
lambda: self.buffer_probe_handler_real(pad, buff, name))
@@ -265,7 +280,7 @@ class VideoThumbnailer:
return self._get_duration(pipeline, retries + 1)
def _on_timeout(self):
- _log.error('TIMEOUT! DROP EVERYTHING!')
+ _log.error('Timeout in thumbnailer!')
self.shutdown()
def _on_bus_error(self, *args):
@@ -342,8 +357,25 @@ class VideoTranscoder:
self.source_path = src
self.destination_path = dst
- # Options
- self.destination_dimensions = kwargs.get('dimensions') or (640, 640)
+ # vp8enc options
+ self.destination_dimensions = kwargs.get('dimensions', (640, 640))
+ self.vp8_quality = kwargs.get('vp8_quality', 8)
+ # Number of threads used by vp8enc:
+ # number of real cores - 1 as per recommendation on
+ # <http://www.webmproject.org/tools/encoder-parameters/#6-multi-threaded-encode-and-decode>
+ self.vp8_threads = kwargs.get('vp8_threads', CPU_COUNT - 1)
+
+ # 0 means auto-detect, but dict.get() only falls back to CPU_COUNT
+ # if value is None, this will correct our incompatibility with
+ # dict.get()
+ # This will also correct cases where there's only 1 CPU core, see
+ # original self.vp8_threads assignment above.
+ if self.vp8_threads == 0:
+ self.vp8_threads = CPU_COUNT
+
+ # vorbisenc options
+ self.vorbis_quality = kwargs.get('vorbis_quality', 0.3)
+
self._progress_callback = kwargs.get('progress_callback') or None
if not type(self.destination_dimensions) == tuple:
@@ -456,8 +488,9 @@ class VideoTranscoder:
self.pipeline.add(self.capsfilter)
self.vp8enc = gst.element_factory_make('vp8enc', 'vp8enc')
- self.vp8enc.set_property('quality', 6)
- self.vp8enc.set_property('threads', 2)
+ self.vp8enc.set_property('quality', self.vp8_quality)
+ self.vp8enc.set_property('threads', self.vp8_threads)
+ self.vp8enc.set_property('max-latency', 25)
self.pipeline.add(self.vp8enc)
# Audio elements
@@ -480,7 +513,7 @@ class VideoTranscoder:
self.pipeline.add(self.audiocapsfilter)
self.vorbisenc = gst.element_factory_make('vorbisenc', 'vorbisenc')
- self.vorbisenc.set_property('quality', 1)
+ self.vorbisenc.set_property('quality', self.vorbis_quality)
self.pipeline.add(self.vorbisenc)
# WebMmux & filesink
diff --git a/mediagoblin/static/css/audio.css b/mediagoblin/static/css/audio.css
index 387278ec..e007a0e1 100644
--- a/mediagoblin/static/css/audio.css
+++ b/mediagoblin/static/css/audio.css
@@ -80,5 +80,5 @@
transition: opacity .1s ease-in-out;
}
.audio-spectrogram:hover .audio-volume {
- opacity: 1;
+ opacity: 0.7;
}
diff --git a/mediagoblin/static/js/audio.js b/mediagoblin/static/js/audio.js
index f50908a1..217a2160 100644
--- a/mediagoblin/static/js/audio.js
+++ b/mediagoblin/static/js/audio.js
@@ -210,8 +210,14 @@ var audioPlayer = new Object();
$('<div class="seekbar"></div>').appendTo(im.parent());
$('<div class="audio-control-play-pause paused">▶</div>').appendTo(im.parent());
$('<div class="audio-currentTime">00:00</div>').appendTo(im.parent());
- $('<input placeholder="Range input not supported" class="audio-volume"'
- +'type="range" min="0" max="1" step="0.01" />').appendTo(im.parent());
+ if (navigator && /Firefox/.test(navigator.userAgent)) {
+ $('<p class="message_warning">Sorry, Firefox does not support the '
+ + 'range input type, you won\'t be able to change the volume</p>')
+ .appendTo(im.parent().parent());
+ } else {
+ $('<input type="range" class="audio-volume"'
+ +'value="1" min="0" max="1" step="0.001" />').appendTo(im.parent());
+ }
$('.audio-spectrogram').trigger('attachedControls');
};
})(audioPlayer);