Skip to content

Instantly share code, notes, and snippets.

@flexgrip
Created September 8, 2013 06:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save flexgrip/6482391 to your computer and use it in GitHub Desktop.
Save flexgrip/6482391 to your computer and use it in GitHub Desktop.
RetroAND transcoder... Brillaint
import os
import time
from multiprocessing import Event, Process, Pipe
from Queue import Queue
from retroand.config import cfg
from retroand.log import logger
def transcode_process(connection, path, stop, format='mp3', bitrate=False):
import pygst
pygst.require('0.10')
import gst
# Check to make sure the bitrate is actually a number
try:
bitrate = int(bitrate)
except:
bitrate = False
log_message = "Transcoding %s to %s" % (path.encode(cfg['ENCODING']), format)
# Make the trans pipeline using these strings
transcoder = gst.parse_launch(pipeline[format])
# Bitrate needs to be given and set. Don't worry about the low quality sets
if bitrate in [40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320]:
log_message += " at %d kbps" % bitrate
encoder = transcoder.get_by_name('encoder')
muxer = transcoder.get_by_name('muxer')
if format is 'mp3':
encoder.set_property("target", "bitrate")
encoder.set_property("bitrate", bitrate)
elif format is 'ogg':
encoder.set_property("max-bitrate", bitrate * 1024)
elif format is 'm4a':
encoder.set_property("bitrate", bitrate * 1000)
# Put the file into the transcoder
log_message += "."
logger.info(log_message)
source = transcoder.get_by_name('source')
try:
source.set_property("location", path.encode('utf-8'))
# Make the output asynchronous so that everything fires up fast
# instead of in real time.
output = transcoder.get_by_name('output')
output.set_property("sync", False)
# Get data from pipe start
transcoder.set_state(gst.STATE_PLAYING)
transcoder.get_state()
try:
# Send chunks to the client that are encoded
while True:
output_buffer = output.emit('pull-buffer')
if output_buffer and not stop.is_set():
connection.send(output_buffer.data)
else:
break
except:
logger.warn("Transcoding Error.")
except:
logger.error("Failed to open file for transcoding. Check for non-ascii characters?")
finally:
try:
# Try this so it can free the memory used by the transcoder
transcoder.set_state(gst.STATE_NULL)
except:
pass
if not stop.is_set():
connection.send(False)
connection.close()
class Transcoder:
def __init__(self):
self.stopping = Event()
def stop(self):
logger.debug("Preventing new transcoding processes.")
self.stopping.set()
def transcode(self, path, format='mp3', bitrate=False):
if self.stopping.is_set():
return
try:
stop = Event()
start_time = time.time()
parent_connection, child_connection = Pipe()
process = Process(target=transcode_process,
args=(child_connection, path, stop, format, bitrate))
process.start()
while not (self.stopping.is_set() or stop.is_set()):
data = parent_connection.recv()
if not data:
break
yield data
logger.debug("Transcoded %s in %0.2f seconds." % (path.encode(cfg['ENCODING']), time.time() - start_time))
except GeneratorExit:
stop.set()
logger.debug("User canceled the request during transcoding.")
except:
stop.set()
logger.warn("Some type of error occured during transcoding.")
finally:
parent_connection.close()
process.join()
pipeline = {
'mp3': "filesrc name=source ! decodebin ! audioconvert ! lamemp3enc name=encoder ! id3mux name=muxer ! appsink name=out",
'ogg': "filesrc name=source ! decodebin ! audioconvert ! vorbisenc name=encoder ! oggmux name=muxer ! appsink name=out",
'm4a': "filesrc name=source ! decodebin ! audioconvert ! ffenc_aac name=encoder ! ffmux_mp4 name=muxer ! appsink name=out"
}
# Windows port of gstreamer is missing id3mux and id3v2mux. Lets try and use ffmux_mp3.
if os.name == "nt":
pipeline['mp3'] = "filesrc name=source ! decodebin ! audioconvert ! lamemp3enc name=encoder ! ffmux_mp3 name=muxer ! appsink name=out"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment