#!/usr/bin/env python3
import argparse
import gi
import sys

gi.require_version("Gst", "1.0")
from gi.repository import Gst, GObject


Gst.init(sys.argv)


class Example(object):
    def __init__(self, uri, use_funnel):
        self.pipeline = Gst.ElementFactory.make("playbin", None)
        self.pipeline.set_property("uri", uri)
        self.pipeline.set_property("flags", "text")
        
        if use_funnel:
            funnel = Gst.ElementFactory.make("funnel", None)
            self.pipeline.set_property("text-stream-combiner", funnel)
            
        appsink = Gst.ElementFactory.make("appsink", None)
        appsink.set_property("emit-signals", True)
        appsink.set_property("enable-last-sample", False)
        appsink.set_property("sync", False)
        appsink.connect("new-sample", self.on_sample)
        self.pipeline.set_property("text-sink", appsink)
        
        bus = self.pipeline.get_bus()
        bus.add_signal_watch()
        bus.connect("message::error", self.on_error)
        bus.connect("message::eos", self.on_eos)
        
        self.main_loop = GObject.MainLoop()

    def on_eos(self, bus, message):
        print("EOS")
        self.quit()

    def on_error(self, bus, message):
        print(message.parse_error())
        self.quit()

    def on_sample(self, appsink):
        sample = appsink.emit("pull-sample")
        buffer = sample.get_buffer()
        data = buffer.extract_dup(0, 18446744073709551615).decode("UTF-8")
        
        success, current_time = appsink.query_position(Gst.Format.TIME)
        current_time /= Gst.SECOND
        start_time = buffer.pts / Gst.SECOND
        end_time = (buffer.pts + buffer.duration) / Gst.SECOND
        late = "late " if current_time >= end_time else ""
        print("Got {}sample at {:05.2f}: {:05.2f} --> {:05.2f} {}".format(late,
            current_time, start_time, end_time, data))
        return Gst.FlowReturn.OK

    def quit(self):
        self.pipeline.set_state(Gst.State.NULL)
        self.main_loop.quit()

    def run(self):
        self.pipeline.set_state(Gst.State.PLAYING)
        self.main_loop.run()


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("uri")
    parser.add_argument("--no-funnel", action="store_true")
    args = parser.parse_args()

    Example(args.uri, not args.no_funnel).run()


if __name__ == "__main__":
    sys.exit(main())
