aboutsummaryrefslogtreecommitdiffstats
path: root/mediagoblin
diff options
context:
space:
mode:
Diffstat (limited to 'mediagoblin')
-rw-r--r--mediagoblin/config_spec.ini9
-rw-r--r--mediagoblin/media_types/ascii/processing.py9
l---------mediagoblin/media_types/audio/audioprocessing.py1
-rw-r--r--mediagoblin/media_types/audio/processing.py65
-rw-r--r--mediagoblin/media_types/audio/transcoders.py90
-rw-r--r--mediagoblin/media_types/image/processing.py2
-rw-r--r--mediagoblin/media_types/video/processing.py15
-rw-r--r--mediagoblin/media_types/video/transcoders.py53
-rw-r--r--mediagoblin/templates/mediagoblin/media_displays/audio.html9
-rw-r--r--mediagoblin/tests/test_submission.py3
10 files changed, 228 insertions, 28 deletions
diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini
index 452d9745..b429677c 100644
--- a/mediagoblin/config_spec.ini
+++ b/mediagoblin/config_spec.ini
@@ -65,6 +65,14 @@ base_url = string(default="/mgoblin_media/")
storage_class = string(default="mediagoblin.storage.filestorage:BasicFileStorage")
base_dir = string(default="%(here)s/user_dev/media/queue")
+[media:medium]
+max_width = integer(default=640)
+max_height = integer(default=640)
+
+[media:thumb]
+max_width = integer(default=180)
+max_height = integer(default=180)
+
[media_type:mediagoblin.media_types.video]
# Should we keep the original file?
keep_original = boolean(default=False)
@@ -72,6 +80,7 @@ keep_original = boolean(default=False)
[media_type:mediagoblin.media_types.audio]
# vorbisenc qualiy
quality = float(default=0.3)
+create_spectrogram = boolean(default=False)
[beaker.cache]
diff --git a/mediagoblin/media_types/ascii/processing.py b/mediagoblin/media_types/ascii/processing.py
index f698b97a..75184c1f 100644
--- a/mediagoblin/media_types/ascii/processing.py
+++ b/mediagoblin/media_types/ascii/processing.py
@@ -24,7 +24,16 @@ from mediagoblin.media_types.ascii import asciitoimage
_log = logging.getLogger(__name__)
+SUPPORTED_EXTENSIONS = ['txt', 'asc', 'nfo']
+
def sniff_handler(media_file, **kw):
+ if not kw.get('media') == None:
+ name, ext = os.path.splitext(kw['media'].filename)
+ clean_ext = ext[1:].lower()
+
+ if clean_ext in SUPPORTED_EXTENSIONS:
+ return True
+
return False
def process_ascii(entry):
diff --git a/mediagoblin/media_types/audio/audioprocessing.py b/mediagoblin/media_types/audio/audioprocessing.py
new file mode 120000
index 00000000..c5e3c52c
--- /dev/null
+++ b/mediagoblin/media_types/audio/audioprocessing.py
@@ -0,0 +1 @@
+../../../extlib/freesound/audioprocessing.py \ No newline at end of file
diff --git a/mediagoblin/media_types/audio/processing.py b/mediagoblin/media_types/audio/processing.py
index 7aa7ace8..6769f605 100644
--- a/mediagoblin/media_types/audio/processing.py
+++ b/mediagoblin/media_types/audio/processing.py
@@ -21,9 +21,10 @@ import os
from mediagoblin import mg_globals as mgg
from mediagoblin.processing import create_pub_filepath
-from mediagoblin.media_types.audio.transcoders import AudioTranscoder
+from mediagoblin.media_types.audio.transcoders import AudioTranscoder, \
+ AudioThumbnailer
-_log = logging.getLogger()
+_log = logging.getLogger(__name__)
def sniff_handler(media_file, **kw):
transcoder = AudioTranscoder()
@@ -33,7 +34,9 @@ def sniff_handler(media_file, **kw):
if data.is_audio == True and data.is_video == False:
return True
except:
- return False
+ pass
+
+ return False
def process_audio(entry):
audio_config = mgg.global_config['media_type:mediagoblin.media_types.audio']
@@ -51,10 +54,9 @@ def process_audio(entry):
original=os.path.splitext(
queued_filepath[-1])[0]))
- ogg_tmp = tempfile.NamedTemporaryFile()
+ transcoder = AudioTranscoder()
- with ogg_tmp:
- transcoder = AudioTranscoder()
+ with tempfile.NamedTemporaryFile() as ogg_tmp:
transcoder.transcode(
queued_filename,
@@ -72,11 +74,54 @@ def process_audio(entry):
entry.media_data['audio'] = {
u'length': int(data.audiolength)}
- thumbnail_tmp = tempfile.NamedTemporaryFile()
-
- with thumbnail_tmp:
+ if audio_config['create_spectrogram']:
+ spectrogram_filepath = create_pub_filepath(
+ entry,
+ '{original}-spectrogram.jpg'.format(
+ original=os.path.splitext(
+ queued_filepath[-1])[0]))
+
+ with tempfile.NamedTemporaryFile(suffix='.wav') as wav_tmp:
+ _log.info('Creating WAV source for spectrogram')
+ transcoder.transcode(
+ queued_filename,
+ wav_tmp.name,
+ mux_string='wavenc')
+
+ thumbnailer = AudioThumbnailer()
+
+ with tempfile.NamedTemporaryFile(suffix='.jpg') as spectrogram_tmp:
+ thumbnailer.spectrogram(
+ wav_tmp.name,
+ spectrogram_tmp.name,
+ width=mgg.global_config['media:medium']['max_width'])
+
+ _log.debug('Saving spectrogram...')
+ mgg.public_store.get_file(spectrogram_filepath, 'wb').write(
+ spectrogram_tmp.read())
+
+ entry.media_files['spectrogram'] = spectrogram_filepath
+
+ with tempfile.NamedTemporaryFile(suffix='.jpg') as thumb_tmp:
+ thumbnailer.thumbnail_spectrogram(
+ spectrogram_tmp.name,
+ thumb_tmp.name,
+ (mgg.global_config['media:thumb']['max_width'],
+ mgg.global_config['media:thumb']['max_height']))
+
+ thumb_filepath = create_pub_filepath(
+ entry,
+ '{original}-thumbnail.jpg'.format(
+ original=os.path.splitext(
+ queued_filepath[-1])[0]))
+
+ mgg.public_store.get_file(thumb_filepath, 'wb').write(
+ thumb_tmp.read())
+
+ 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/audio/transcoders.py b/mediagoblin/media_types/audio/transcoders.py
index c5634964..7649309c 100644
--- a/mediagoblin/media_types/audio/transcoders.py
+++ b/mediagoblin/media_types/audio/transcoders.py
@@ -16,8 +16,10 @@
import pdb
import logging
+from PIL import Image
from mediagoblin.processing import BadMediaFail
+from mediagoblin.media_types.audio import audioprocessing
_log = logging.getLogger(__name__)
@@ -56,6 +58,73 @@ try:
except ImportError:
raise Exception('gst/pygst >= 0.10 could not be imported')
+import numpy
+
+class AudioThumbnailer(object):
+ def __init__(self):
+ _log.info('Initializing {0}'.format(self.__class__.__name__))
+
+ def spectrogram(self, src, dst, **kw):
+ width = kw['width']
+ height = int(kw.get('height', float(width) * 0.3))
+ fft_size = kw.get('fft_size', 2048)
+ callback = kw.get('progress_callback')
+
+ processor = audioprocessing.AudioProcessor(
+ src,
+ fft_size,
+ numpy.hanning)
+
+ samples_per_pixel = processor.audio_file.nframes / float(width)
+
+ spectrogram = audioprocessing.SpectrogramImage(width, height, fft_size)
+
+ for x in range(width):
+ if callback and x % (width / 10) == 0:
+ callback((x * 100) / width)
+
+ seek_point = int(x * samples_per_pixel)
+
+ (spectral_centroid, db_spectrum) = processor.spectral_centroid(
+ seek_point)
+
+ spectrogram.draw_spectrum(x, db_spectrum)
+
+ if callback:
+ callback(100)
+
+ spectrogram.save(dst)
+
+ def thumbnail_spectrogram(self, src, dst, thumb_size):
+ '''
+ Takes a spectrogram and creates a thumbnail from it
+ '''
+ if not (type(thumb_size) == tuple and len(thumb_size) == 2):
+ raise Exception('size argument should be a tuple(width, height)')
+
+ im = Image.open(src)
+
+ im_w, im_h = [float(i) for i in im.size]
+ th_w, th_h = [float(i) for i in thumb_size]
+
+ wadsworth_position = im_w * 0.3
+
+ start_x = max((
+ wadsworth_position - (th_w / 2.0),
+ 0.0))
+
+ stop_x = start_x + (im_h * (th_w / th_h))
+
+ th = im.crop((
+ int(start_x), 0,
+ int(stop_x), int(im_h)))
+
+ if th.size[0] > th_w or th.size[1] > th_h:
+ th.thumbnail(thumb_size, Image.ANTIALIAS)
+
+ th.save(dst)
+
+
class AudioTranscoder(object):
def __init__(self):
_log.info('Initializing {0}'.format(self.__class__.__name__))
@@ -103,17 +172,21 @@ class AudioTranscoder(object):
quality = kw.get('quality', 0.3)
+ mux_string = kw.get(
+ 'mux_string',
+ 'vorbisenc quality={0} ! webmmux'.format(quality))
+
# Set up pipeline
self.pipeline = gst.parse_launch(
'filesrc location="{src}" ! '
'decodebin2 ! queue ! audiorate tolerance={tolerance} ! '
'audioconvert ! audio/x-raw-float,channels=2 ! '
- 'vorbisenc quality={quality} ! webmmux ! '
+ '{mux_string} ! '
'progressreport silent=true ! '
'filesink location="{dst}"'.format(
src=src,
tolerance=80000000,
- quality=quality,
+ mux_string=mux_string,
dst=dst))
self.bus = self.pipeline.get_bus()
@@ -141,6 +214,9 @@ class AudioTranscoder(object):
self.halt()
def halt(self):
+ if getattr(self, 'pipeline', False):
+ self.pipeline.set_state(gst.STATE_NULL)
+ del self.pipeline
_log.info('Quitting MainLoop gracefully...')
gobject.idle_add(self._loop.quit)
@@ -149,8 +225,12 @@ if __name__ == '__main__':
logging.basicConfig()
_log.setLevel(logging.INFO)
- transcoder = AudioTranscoder()
- data = transcoder.discover(sys.argv[1])
- res = transcoder.transcode(*sys.argv[1:3])
+ #transcoder = AudioTranscoder()
+ #data = transcoder.discover(sys.argv[1])
+ #res = transcoder.transcode(*sys.argv[1:3])
+
+ thumbnailer = AudioThumbnailer()
+
+ thumbnailer.spectrogram(*sys.argv[1:], width=640)
pdb.set_trace()
diff --git a/mediagoblin/media_types/image/processing.py b/mediagoblin/media_types/image/processing.py
index 364a5afa..28cde2aa 100644
--- a/mediagoblin/media_types/image/processing.py
+++ b/mediagoblin/media_types/image/processing.py
@@ -42,7 +42,7 @@ def sniff_handler(media_file, **kw):
_log.info('Found file extension in supported filetypes')
return True
else:
- _log.debug('Media present, extension not found in {1}'.format(
+ _log.debug('Media present, extension not found in {0}'.format(
SUPPORTED_FILETYPES))
else:
_log.warning('Need additional information (keyword argument \'media\')'
diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py
index 1890ef0c..d2562e3b 100644
--- a/mediagoblin/media_types/video/processing.py
+++ b/mediagoblin/media_types/video/processing.py
@@ -29,6 +29,18 @@ _log = logging.getLogger(__name__)
_log.setLevel(logging.DEBUG)
def sniff_handler(media_file, **kw):
+ transcoder = transcoders.VideoTranscoder()
+ try:
+ data = transcoder.discover(media_file.name)
+
+ _log.debug('Discovered: {0}'.format(data.__dict__))
+
+ if data.is_video == True:
+ return True
+ except:
+ _log.error('Exception caught when trying to discover {0}'.format(
+ kw.get('media')))
+
return False
def process_video(entry):
@@ -61,7 +73,8 @@ def process_video(entry):
with tmp_dst:
# Transcode queued file to a VP8/vorbis file that fits in a 640x640 square
- transcoder = transcoders.VideoTranscoder(queued_filename, tmp_dst.name)
+ transcoder = transcoders.VideoTranscoder()
+ transcoder.transcode(queued_filename, tmp_dst.name)
# 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 903bd810..6c2e885e 100644
--- a/mediagoblin/media_types/video/transcoders.py
+++ b/mediagoblin/media_types/video/transcoders.py
@@ -25,8 +25,6 @@ import pdb
import urllib
_log = logging.getLogger(__name__)
-logging.basicConfig()
-_log.setLevel(logging.DEBUG)
CPU_COUNT = 2
try:
@@ -340,10 +338,15 @@ class VideoTranscoder:
that it was refined afterwards and therefore is done more
correctly.
'''
- def __init__(self, src, dst, **kwargs):
+ def __init__(self):
_log.info('Initializing VideoTranscoder...')
self.loop = gobject.MainLoop()
+
+ def transcode(self, src, dst, **kwargs):
+ '''
+ Transcode a video file into a 'medium'-sized version.
+ '''
self.source_path = src
self.destination_path = dst
@@ -357,6 +360,30 @@ class VideoTranscoder:
self._setup()
self._run()
+ def discover(self, src):
+ '''
+ Discover properties about a media file
+ '''
+ _log.info('Discovering {0}'.format(src))
+
+ self.source_path = src
+ self._setup_discover(discovered_callback=self.__on_discovered)
+
+ self.discoverer.discover()
+
+ self.loop.run()
+
+ return self._discovered_data
+
+ def __on_discovered(self, data, is_media):
+ if not is_media:
+ self.__stop()
+ raise Exception('Could not discover {0}'.format(self.source_path))
+
+ self._discovered_data = data
+
+ self.__stop_mainloop()
+
def _setup(self):
self._setup_discover()
self._setup_pipeline()
@@ -369,12 +396,14 @@ class VideoTranscoder:
_log.debug('Initializing MainLoop()')
self.loop.run()
- def _setup_discover(self):
+ def _setup_discover(self, **kw):
_log.debug('Setting up discoverer')
self.discoverer = discoverer.Discoverer(self.source_path)
# Connect self.__discovered to the 'discovered' event
- self.discoverer.connect('discovered', self.__discovered)
+ self.discoverer.connect(
+ 'discovered',
+ kw.get('discovered_callback', self.__discovered))
def __discovered(self, data, is_media):
'''
@@ -614,14 +643,15 @@ class VideoTranscoder:
if __name__ == '__main__':
os.nice(19)
+ logging.basicConfig()
from optparse import OptionParser
parser = OptionParser(
- usage='%prog [-v] -a [ video | thumbnail ] SRC DEST')
+ usage='%prog [-v] -a [ video | thumbnail | discover ] SRC [ DEST ]')
parser.add_option('-a', '--action',
dest='action',
- help='One of "video" or "thumbnail"')
+ help='One of "video", "discover" or "thumbnail"')
parser.add_option('-v',
dest='verbose',
@@ -645,13 +675,18 @@ if __name__ == '__main__':
_log.debug(args)
- if not len(args) == 2:
+ if not len(args) == 2 and not options.action == 'discover':
parser.print_help()
sys.exit()
+ transcoder = VideoTranscoder()
+
if options.action == 'thumbnail':
VideoThumbnailer(*args)
elif options.action == 'video':
def cb(data):
print('I\'m a callback!')
- transcoder = VideoTranscoder(*args, progress_callback=cb)
+ transcoder.transcode(*args, progress_callback=cb)
+ elif options.action == 'discover':
+ print transcoder.discover(*args).__dict__
+
diff --git a/mediagoblin/templates/mediagoblin/media_displays/audio.html b/mediagoblin/templates/mediagoblin/media_displays/audio.html
index 802a85c1..f130e323 100644
--- a/mediagoblin/templates/mediagoblin/media_displays/audio.html
+++ b/mediagoblin/templates/mediagoblin/media_displays/audio.html
@@ -20,7 +20,14 @@
{% block mediagoblin_media %}
<div class="audio-media">
- <audio controls="controls"
+ {% if 'spectrogram' in media.media_files %}
+ <div class="audio-spectrogram">
+ <img src="{{ request.app.public_store.file_url(
+ media.media_files.spectrogram) }}"
+ alt="Spectrogram" />
+ </div>
+ {% endif %}
+ <audio class="audio-player" controls="controls"
preload="metadata">
<source src="{{ request.app.public_store.file_url(
media.media_files.ogg) }}" type="video/webm; encoding=&quot;vorbis&quot;" />
diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py
index 217926a4..53ba25d8 100644
--- a/mediagoblin/tests/test_submission.py
+++ b/mediagoblin/tests/test_submission.py
@@ -231,7 +231,8 @@ class TestSubmission:
context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html']
form = context['submit_form']
- assert re.match(r'^Could not extract any file extension from ".*?"$', str(form.file.errors[0]))
+ assert 'Sorry, I don\'t support that file type :(' == \
+ str(form.file.errors[0])
assert len(form.file.errors) == 1
# NOTE: The following 2 tests will ultimately fail, but they