Rewite code for music playing module
Create an abstract class for music playing backends. Change the gstreamer music playing module to implement this abstract class.
Check out this example code from Ubuntu application week about python and gst, in particular about signal handling:
#!/usr/bin/python
import sys
import os
from os import path
import time
import optparse
from subprocess import check_call
size_map = {
180: (320, 180),
315: (560, 315),
360: (640, 360),
450: (800, 450),
540: (960, 540),
720: (1280, 720),
1080: (1920, 1080),
}
sizes = sorted(size_map)
default_size = 315
default_freq = 64
vorbis = {
'enc': 'vorbisenc',
'caps': 'audio/
'props': {
'quality': 0.3,
},
}
flac = {
'enc': 'flacenc',
'caps': 'audio/x-raw-int',
}
codec_map = {
'theora': {
'video': {
'enc': 'theoraenc',
},
},
'audio': vorbis,
'mux': 'oggmux',
'ext': 'ogv',
},
'vp8': {
'video': {
'enc': 'vp8enc',
},
},
'audio': vorbis,
'mux': 'webmmux',
'ext': 'webm',
},
'h264': {
'video': {
'enc': 'x264enc',
# See http://
},
},
'audio': {
'enc': 'lame',
'caps': 'audio/x-raw-int',
},
},
'mux': 'mp4mux',
'ext': 'mp4',
}
}
codecs = sorted(codec_map)
default_codec = 'theora'
def minsec(seconds):
"""
Convert *seconds* to "minutes:seconds" string.
For example:
>>> minsec(194)
'3:14'
If *seconds* is a ``float``, it will be truncated. For example:
>>> minsec(59.99)
'0:59'
"""
if not isinstance(seconds, (int, float)):
raise TypeError (
)
return '%d:%02d' % (seconds / 60, seconds % 60)
parser = optparse.
usage='usage: %prog SOURCE [DESTINATION]',
)
parser.
help='one of %r; default is %r' % (codecs, default_codec),
metavar='NAME',
default=
)
parser.
help='one of %r; default is %r' % (sizes, default_size),
metavar='INT',
default=
type='int',
)
parser.
help='keyframe max frequency; default is %r' % default_freq,
metavar='INT',
default=
type='int',
)
parser.
help='audio channels (1 or 2); default is 2',
metavar='INT',
default=2,
type='int',
)
#parser.
# help='video quality; default is %r' % default_quality,
# metavar='INT',
# default=
# type='int',
#)
#parser.
# help='audio quality; default is 0.3',
# metavar='FLOAT',
# default=0.3,
# type='float',
#)
#parser.
# help='produce webm video',
# action=
# default=False,
#)
def error(msg):
parser.
print('\nERROR: ' + msg)
sys.exit(1)
(options, args) = parser.parse_args()
if options.size not in sizes:
error('SIZE must be on of %r; got %r' % (sizes, options.size))
if options.codec not in codecs:
error('CODEC must be one of %r; got %r' % (codecs, options.codec))
c = codec_map[
if len(args) < 1:
error('must provide SOURCE')
src = path.abspath(
if not path.isfile(src):
error('SOURCE is not file: %r' % src)
if len(args) == 2:
dst = path.abspath(
else:
(d, name) = path.split(src)
base = path.splitext(
dname = '%s_%dp.%s' % (
base,
c['ext'],
)
dst = path.join(d, dname)
if path.exists(dst):
error(
print 'SOURCE: %r' % src
print 'DESTINATION: %r' % dst
import gobject
import gst
gobject.
#mp4mux
def set_props(element, kind):
props = c[kind]
if not props:
return
for key in sorted(props):
value = props[key]
print ' %s: %r' % (key, value)
def make_enc(kind):
print 'creating %r encoder:' % kind
enc = c[kind]['enc']
print ' enc: %r' % enc
element = gst.element_
set_
return element
class AudioTranscoder
def __init__(self):
# Create elements
self._inq = gst.element_
self._conv = gst.element_
self._rate = gst.element_
self._enc = make_enc('audio')
self._outq = gst.element_
elements = (self._inq, self._conv, self._rate, self._enc, self._outq)
# Add to bin and link:
caps = gst.caps_
# Add ghostpads
class VideoTranscoder
def __init__(self):
# Create elements
self._inq = gst.element_
self._scale = gst.element_
self._enc = make_enc('video')
self._q = gst.element_
self._outq = gst.element_
# Set properties
# Add to bin and link:
self.add(
)
size = size_map.
if size:
caps = gst.caps_
)
else:
# Add ghostpads
class Transcoder(object):
def __init__(self, src, dst):
self.error = None
self._start = None
self._end = None
# Create bus and connect several handlers
self.bus = self.pipeline.
# Create elements
self.src = gst.element_
self.dec = gst.element_
self.audio = AudioTranscoder()
self.video = VideoTranscoder()
self.mux = gst.element_
self.sink = gst.element_
# Set properties
# Connect handler for 'new-decoded-pad' signal
# Add elements to pipeline
)
# Link *some* elements
# This is completed in self.on_
# Reference used in self.on_
self.apad = self.audio.
self.vpad = self.video.
def run(self):
print 'Starting pipeline...'
self._start = time.time()
def elpased(self):
if None in (self._start, self._end):
return
return minsec(self._end - self._start)
def kill(self):
print 'Killing pipeline...'
self._end = time.time()
def on_new_
caps = pad.get_caps()
name = caps[0].get_name()
print 'on_decoded_pad:', name
if name.startswith
if not self.apad.
elif name.startswith
if not self.vpad.
def on_eos(self, bus, msg):
print 'on_eos'
self.kill()
def on_tag(self, bus, msg):
taglist = msg.parse_tag()
print 'on_tag:'
for key in taglist.keys():
print ' %s = %s' % (key, taglist[key])
def on_error(self, bus, msg):
self.error = msg.parse_
self.kill()
t = Transcoder(src, dst)
t.run()
if t.error:
error(t.error)
#check_
print """
Source:
%r
Destination:
%r
Transcoded in %s
""" % (src, dst, t.elpased())
Whiteboard
The details are in the description. In the long run, this change will allow for other music playing modules to be made, e.g. using libvlc, which in turn will make windows support easier to accomplish.