Difference between revisions of "GStreamer Daemon - Python Video Player Example"

From RidgeRun Developer Connection
Jump to: navigation, search
m (Create page)
 
(8 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{GStreamer Daemon/Head | previous=API Examples | next=Troubleshooting}}
+
{{GStreamer Daemon/Head | previous=API Examples | next=Javascript Video Player Example}}
  
==Introduction==
+
==Introduction to GStreamer Daemon Python Video Player Example ==
 +
This is one concrete usage example of the GStreamer Daemon along with a Python Application. In this case, the application uses the Python GSTD API to communicate with GStreamer Daemon.
  
 +
The application consists of a Simple Video Player with several capabilities:
 +
# Regular video playback.
 +
# Trick modes (fast-forward, speed change, seek to position).
 +
# Read messages from the GSTD bus.
  
 +
==Usage==
  
 +
To execute, simply run:
 +
python3 simple_pipeline.py $VIDEO_PATH
  
 +
Within the application, you can use several commands. It supports the following commands:
 +
play: To play and run
 +
pause: To pause the video
 +
stop: To stop and close the playing
 +
set_speed $SPEED [negative or positive floating-point number]
 +
jump $TIME [positive number in seconds]
 +
exit
  
 +
==Code Analysis==
  
 +
This example application can be divided into 3 sections:
 +
# Init Sequence & Command Parser
 +
# GstcPlayer Class
 +
## Error Handler
  
 +
===Init Sequence & Command Parser===
 +
This section is pretty straightforward. You just need to pas the video file path as the only argument.
  
 +
<syntaxhighlight lang=python>
 +
  if __name__ == "__main__":
 +
  print("Sample PyGstC Video Player")
 +
'''
 +
  .
 +
  .
 +
  .  '''
 +
</syntaxhighlight>
  
 +
Once the application is started. Automatically, it will open and reproduce the video. On the command prompt, you can specify any of the supported commands.
  
 +
===GstcPlayer Class===
 +
This class contains all the necessary calls to communicate with the GStreamer Daemon, through the Python GstdClient.
  
 +
Firs of all the Python GstdClient needs to be imported with:
 +
<syntaxhighlight lang=python>
 +
from pygstc.gstc import GstcError, GstdError, GstdClient
 +
from pygstc.logger import CustomLogger
 +
</syntaxhighlight>
  
 +
There are two main objects to manipulate the GstdClient over Python. First the Logger class (''CustomLogger'') and the GstdClient itself. The logger can have different information levels, for example you can pass an 'ERROR' level.
 +
<syntaxhighlight lang=python>
 +
class GstcPlayer:
  
 +
  def __init__(self, videoPath):
 +
    self.gstd_logger = CustomLogger('simple_playback', loglevel='WARNING')
 +
    self.gstc = GstdClient(logger=self.gstd_logger)
 +
</syntaxhighlight>
  
 +
Once those objects are created. The [https://developer.ridgerun.com/wiki/index.php?title=GStreamer_Daemon_-_Python_API Python API] offers a set of calls to communicate with the GStreamer Daemon. For example, when the ''play'' command is executed, the following actions are executed:
 +
<syntaxhighlight lang=python>
 +
  def playVideo(self):
 +
    self.gstc.pipeline_create(self.pipeName, self.pipeline)
 +
    self.gstc.pipeline_play(self.pipeName)
 +
</syntaxhighlight>
  
 +
Let's say you just want to pause the video and continue from that point. Then you can modify the playing function similar to:
 +
<syntaxhighlight lang=python>
 +
  def playVideo(self):
 +
    if (not self.pipe_exists(self.pipeName)):
 +
      self.gstc.pipeline_create(self.pipeName, self.pipeline)
 +
    self.gstc.pipeline_play(self.pipeName)
  
 +
  def pipe_exists(self, pipe_name):
 +
    #Check if pipe is already created
 +
    existing_pipes = self.gstc.list_pipelines()
 +
    if (existing_pipes == []):
 +
      ret = False
 +
    elif( existing_pipes[0]['name'] == pipe_name):
 +
      ret = True
 +
    else:
 +
      ret = False
 +
    return ret
 +
</syntaxhighlight>
  
 +
Then a ''pause'' call can be created with:
 +
<syntaxhighlight lang=python>
 +
  def pauseVideo(self):
 +
    self.gstc.pipeline_pause(self.pipeName)
 +
</syntaxhighlight>
  
 +
And to use the same ''play'' command:
  
 +
Similar, when the command stop is executed there are some instructions to achieve this:
 +
<syntaxhighlight lang=python>
 +
  def stopVideo(self)
 +
    self.gstc.pipeline_stop(self.pipeName)
 +
    self.gstc.pipeline_delete(self.pipeName)
 +
</syntaxhighlight>
  
{{GStreamer Daemon/Foot | previous=API Examples | next=Troubleshooting}}
+
The same process was used to implement changes in playback speed, by using:
 +
<syntaxhighlight lang=python>
 +
    self.gstc.event_seek(self.pipeName, rate=self.playingSpeed, format=3, flags=1, start_type=1, start=0, end_type=1, end=-1)
 +
</syntaxhighlight>
 +
You can use the same ''event_seek'' call to select a time to jump on the video.
 +
 
 +
====Error Handler====
 +
The Python API offers calls to read messages from the GStreamer Daemon Bus. The very basic command to read from the bus is:
 +
<syntaxhighlight lang=python>
 +
resp = self.gstc.bus_read(self.pipeName)
 +
</syntaxhighlight>
 +
 
 +
This call does '''not''' need any use thread to be executed. It can be called at any moment by the user application.
 +
 
 +
For the Video Player, this function is contained within a separate thread just to avoid manually reading from the bus with a command. By doing so we achieved a more complete application, and also for the demonstration purposes. This thread function configures the reading from the bus with a timeout, so we can gracefully exit the thread whenever the user demands so. Also, it is possible to filter the messages by specific types, such as errors or warnings.
 +
 
 +
<syntaxhighlight lang=python>
 +
def errPlayerHandler(self):
 +
    self.gstc.bus_timeout(self.pipeName, 1000)
 +
    self.gstc.bus_filter(self.pipeName, "error+eos+warning")
 +
 
 +
    if(self.pipe_exists(self.pipeName)):
 +
        resp = self.gstc.bus_read(self.pipeName)
 +
        if (resp != None and resp["type"] == "error"):
 +
          print("Info: Video stopped")
 +
          self.gstc.pipeline_pause(self.pipeName)
 +
          self.gstc.pipeline_stop(self.pipeName)
 +
        elif (resp != None and resp["type"] == "eos"):
 +
          print("Info: Video stream ended")
 +
          self.gstc.pipeline_pause(self.pipeName)
 +
</syntaxhighlight>
 +
 
 +
With the implemented filters two main actions are detected:
 +
# When the Video finalize reproducing, and then the pipeline is paused.
 +
# If an error occurred the pipeline is stopped.
 +
 
 +
If you inspect the code, you will find that this function has locking objects to avoid race conditions. But for basic understanding, we presented the essentials instructions from the application.
 +
 
 +
 
 +
 
 +
{{GStreamer Daemon/Foot | previous=API Examples | next=Javascript Video Player Example}}

Latest revision as of 12:59, 19 February 2021


Previous: API Examples Index Next: Javascript Video Player Example




Introduction to GStreamer Daemon Python Video Player Example

This is one concrete usage example of the GStreamer Daemon along with a Python Application. In this case, the application uses the Python GSTD API to communicate with GStreamer Daemon.

The application consists of a Simple Video Player with several capabilities:

  1. Regular video playback.
  2. Trick modes (fast-forward, speed change, seek to position).
  3. Read messages from the GSTD bus.

Usage

To execute, simply run:

python3 simple_pipeline.py $VIDEO_PATH

Within the application, you can use several commands. It supports the following commands:

play: To play and run
pause: To pause the video
stop: To stop and close the playing
set_speed $SPEED [negative or positive floating-point number]
jump $TIME [positive number in seconds]
exit

Code Analysis

This example application can be divided into 3 sections:

  1. Init Sequence & Command Parser
  2. GstcPlayer Class
    1. Error Handler

Init Sequence & Command Parser

This section is pretty straightforward. You just need to pas the video file path as the only argument.

  if __name__ == "__main__":
  print("Sample PyGstC Video Player")
'''
   .
   .
   .   '''

Once the application is started. Automatically, it will open and reproduce the video. On the command prompt, you can specify any of the supported commands.

GstcPlayer Class

This class contains all the necessary calls to communicate with the GStreamer Daemon, through the Python GstdClient.

Firs of all the Python GstdClient needs to be imported with:

from pygstc.gstc import GstcError, GstdError, GstdClient
from pygstc.logger import CustomLogger

There are two main objects to manipulate the GstdClient over Python. First the Logger class (CustomLogger) and the GstdClient itself. The logger can have different information levels, for example you can pass an 'ERROR' level.

class GstcPlayer:

  def __init__(self, videoPath):
    self.gstd_logger = CustomLogger('simple_playback', loglevel='WARNING')
    self.gstc = GstdClient(logger=self.gstd_logger)

Once those objects are created. The Python API offers a set of calls to communicate with the GStreamer Daemon. For example, when the play command is executed, the following actions are executed:

  def playVideo(self):
    self.gstc.pipeline_create(self.pipeName, self.pipeline)
    self.gstc.pipeline_play(self.pipeName)

Let's say you just want to pause the video and continue from that point. Then you can modify the playing function similar to:

  def playVideo(self):
    if (not self.pipe_exists(self.pipeName)):
      self.gstc.pipeline_create(self.pipeName, self.pipeline)
    self.gstc.pipeline_play(self.pipeName)

  def pipe_exists(self, pipe_name):
    #Check if pipe is already created
    existing_pipes = self.gstc.list_pipelines()
    if (existing_pipes == []):
      ret = False
    elif( existing_pipes[0]['name'] == pipe_name):
      ret = True
    else:
      ret = False
    return ret

Then a pause call can be created with:

  def pauseVideo(self):
    self.gstc.pipeline_pause(self.pipeName)

And to use the same play command:

Similar, when the command stop is executed there are some instructions to achieve this:

  def stopVideo(self)
    self.gstc.pipeline_stop(self.pipeName)
    self.gstc.pipeline_delete(self.pipeName)

The same process was used to implement changes in playback speed, by using:

    self.gstc.event_seek(self.pipeName, rate=self.playingSpeed, format=3, flags=1, start_type=1, start=0, end_type=1, end=-1)

You can use the same event_seek call to select a time to jump on the video.

Error Handler

The Python API offers calls to read messages from the GStreamer Daemon Bus. The very basic command to read from the bus is:

resp = self.gstc.bus_read(self.pipeName)

This call does not need any use thread to be executed. It can be called at any moment by the user application.

For the Video Player, this function is contained within a separate thread just to avoid manually reading from the bus with a command. By doing so we achieved a more complete application, and also for the demonstration purposes. This thread function configures the reading from the bus with a timeout, so we can gracefully exit the thread whenever the user demands so. Also, it is possible to filter the messages by specific types, such as errors or warnings.

def errPlayerHandler(self):
    self.gstc.bus_timeout(self.pipeName, 1000)
    self.gstc.bus_filter(self.pipeName, "error+eos+warning")

    if(self.pipe_exists(self.pipeName)):
        resp = self.gstc.bus_read(self.pipeName)
        if (resp != None and resp["type"] == "error"):
          print("Info: Video stopped")
          self.gstc.pipeline_pause(self.pipeName)
          self.gstc.pipeline_stop(self.pipeName)
        elif (resp != None and resp["type"] == "eos"):
          print("Info: Video stream ended")
          self.gstc.pipeline_pause(self.pipeName)

With the implemented filters two main actions are detected:

  1. When the Video finalize reproducing, and then the pipeline is paused.
  2. If an error occurred the pipeline is stopped.

If you inspect the code, you will find that this function has locking objects to avoid race conditions. But for basic understanding, we presented the essentials instructions from the application.



Previous: API Examples Index Next: Javascript Video Player Example