Created
September 8, 2013 06:25
-
-
Save flexgrip/6482391 to your computer and use it in GitHub Desktop.
RetroAND transcoder... Brillaint
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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