Source

VPlayer / player_gst.py

Full commit
# -*- coding: utf-8 -*-

import gobject
gobject.threads_init()

import os
from time import sleep

import gst

from PyQt4 import QtCore, Qt

from vplayer.logger import log
from vplayer.source_gst import Source


class Player(QtCore.QThread):
    def __init__(self):
        QtCore.QThread.__init__(self)
        log.info('Initializing GStreamer player')
        self.player = None
        self.track = None
        self.new_track = False
        self.wait = True
        self.volume = None
        self.time_format = gst.FORMAT_TIME
        self.state = 'none'
        self.percent = 0

    def get_bitrate(self):
        if not self.track.local:
            source = self.player.get_by_name('bufsrc')
            if source:
                while not source.buf or self.wait:
                    sleep(0.1)
                while not source.buf.length or self.wait and not source.buf.failed:
                    sleep(0.1)
                filesize = source.buf.length * 8
                rate = float(filesize) / self.track.length / 1024
        else:
            filesize = os.stat(self.track.url).st_size * 8
            self.track.filesize = filesize
            rate =  float(filesize) / self.track.length / 1024
        rates = [64, 128, 192, 256, 320]
        for srate in rates:
            if abs(srate-rate)<10:
                rate = srate
                break
        rate = round(rate)
        self.track.filesize = filesize/8
        #self.track.bitrate = int(rate)
        return rate

    def _update_volume(self):
        self.player.get_by_name("volume").set_property("volume", self.volume)
        self.volume = None

    def run(self):
        while True:
            while self.wait:
                sleep(0.1)
            if self.new_track:
                try:
                    rate = self.get_bitrate()
                    self.emit(QtCore.SIGNAL('bitrate'), rate)
                    self.new_track = False
                except: pass
            state = None
            try:
                state = self.player.get_state()[1]
            except: continue
            if gst.STATE_PLAYING == state:
                if self.volume:
                    try:
                        self._update_volume()
                    except: pass
                try:
                    dur = self.player.query_duration(self.time_format, None)[0]
                    pos = self.player.query_position(self.time_format, None)[0]
                    self.percent = float(pos) / dur * 100
                    self.emit(QtCore.SIGNAL("time"),
                              (float(pos)/gst.SECOND*1000,
                               float(dur)/gst.SECOND*1000))
                except: pass
            sleep(0.5)


    def play_track(self, track, volume_value):
        self.wait = True
        self.new_track = True
        if self.player:
            self.player.set_state(gst.STATE_NULL)

        if self.track:
            self.track.set_playing(False)
        self.track = track
        self.track.set_playing(True)
        self.track.set_paused(False)
        self.player = gst.Pipeline("pipeline")
        bus = self.player.get_bus()
        bus.add_signal_watch()
        bus.connect("message", self.on_message)

        if track.local:
            source = gst.element_factory_make("filesrc", "filesrc")
            source.set_property("location", unicode(track.url).encode('utf-8'))
        else:
            source = Source("bufsrc")
            source.set_track(track)
            source.connect("database_changed",
                    lambda x: self.emit(QtCore.SIGNAL('database_changed')))


        self.player.add(source)

        def new_decode_pad(dbin, pad, islast):
            pad.link(conv.get_pad("sink"))

        decoder = gst.element_factory_make("decodebin2", "decodebin2")
        decoder.connect("new-decoded-pad", new_decode_pad)
        self.player.add(decoder)

        gst.element_link_many(source, decoder)

        conv = gst.element_factory_make("audioconvert", "converter")
        volume = gst.element_factory_make("volume", "volume")
        volume.set_property("volume", float(volume_value)/100)
        sink = gst.element_factory_make("autoaudiosink", "alsa-output")

        self.player.add(conv, volume, sink)
        gst.element_link_many(conv, volume, sink)

        self.player.set_state(gst.STATE_PLAYING)
        self.emit(QtCore.SIGNAL('status'), ('start', track))
        self.wait = False
        self.state = 'playing'

    def stop(self):
        if self.track:
            self.track.set_playing(False)
            self.track.set_paused(False)
        if self.player:
            self.player.set_state(gst.STATE_NULL)
        self.state = 'none'
        self.wait = True

    def pause(self):
        if self.state == 'playing':
            self.player.set_state(gst.STATE_PAUSED)
            self.state = 'paused'
            self.track.set_paused(True)
            self.emit(QtCore.SIGNAL("status"), ("pause", self.track))
        elif self.state == 'paused':
            self.player.set_state(gst.STATE_PLAYING)
            self.state = 'playing'
            self.track.set_paused(False)
            self.emit(QtCore.SIGNAL("status"), ("unpause", self.track))

    def on_message(self, bus, message):
        t = message.type
        if t == gst.MESSAGE_EOS:
            log.info('Finished playing track')
            self.player.set_state(gst.STATE_NULL)
            self.stop()
            self.emit(QtCore.SIGNAL('status'), ("end", self.track, self.percent))

        elif t == gst.MESSAGE_ERROR:
            log.error('Got GStreamer error')
            self.player.set_state(gst.STATE_NULL)
            self.stop()
            self.emit(QtCore.SIGNAL('status'), ("end", self.track, self.percent))

    def seek(self, pos):
        log.debug('Seek request to pos '+str(pos))
        dur = self.player.query_duration(gst.FORMAT_TIME, None)[0]
        newpos = float(dur) / 100 * pos
        self.player.seek_simple(gst.FORMAT_TIME,
                            gst.SEEK_FLAG_FLUSH|gst.SEEK_FLAG_ACCURATE, newpos)
        self.player.set_new_stream_time(0L)

    def set_volume(self, value):
        log.debug('setting volume to %d' % int(value))
        self.volume = float(value)/100

    def control(self, state):
        if state == 'stop':
            self.stop()
        elif state == 'pause':
            self.pause()