summaryrefslogtreecommitdiff
path: root/pwg-statemanage-states.md
blob: 3d4a37d26c4c015a2e08c0968c3fc71c3991809b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
---
title: What are states?
...

# What are states?

A state describes whether the element instance is initialized, whether
it is ready to transfer data and whether it is currently handling data.
There are four states defined in GStreamer:

  - `GST_STATE_NULL`

  - `GST_STATE_READY`

  - `GST_STATE_PAUSED`

  - `GST_STATE_PLAYING`

which will from now on be referred to simply as “NULL”, “READY”,
“PAUSED” and “PLAYING”.

`GST_STATE_NULL` is the default state of an element. In this state, it
has not allocated any runtime resources, it has not loaded any runtime
libraries and it can obviously not handle data.

`GST_STATE_READY` is the next state that an element can be in. In the
READY state, an element has all default resources (runtime-libraries,
runtime-memory) allocated. However, it has not yet allocated or defined
anything that is stream-specific. When going from NULL to READY state
(`GST_STATE_CHANGE_NULL_TO_READY`), an element should allocate any
non-stream-specific resources and should load runtime-loadable libraries
(if any). When going the other way around (from READY to NULL,
`GST_STATE_CHANGE_READY_TO_NULL`), an element should unload these
libraries and free all allocated resources. Examples of such resources
are hardware devices. Note that files are generally streams, and these
should thus be considered as stream-specific resources; therefore, they
should *not* be allocated in this state.

`GST_STATE_PAUSED` is the state in which an element is ready to accept
and handle data. For most elements this state is the same as PLAYING.
The only exception to this rule are sink elements. Sink elements only
accept one single buffer of data and then block. At this point the
pipeline is 'prerolled' and ready to render data immediately.

`GST_STATE_PLAYING` is the highest state that an element can be in. For
most elements this state is exactly the same as PAUSED, they accept and
process events and buffers with data. Only sink elements need to
differentiate between PAUSED and PLAYING state. In PLAYING state, sink
elements actually render incoming data, e.g. output audio to a sound
card or render video pictures to an image sink.

## Managing filter state

If at all possible, your element should derive from one of the new base
classes ([Pre-made base classes](pwg-other-base.md)). There are
ready-made general purpose base classes for different types of sources,
sinks and filter/transformation elements. In addition to those,
specialised base classes exist for audio and video elements and others.

If you use a base class, you will rarely have to handle state changes
yourself. All you have to do is override the base class's start() and
stop() virtual functions (might be called differently depending on the
base class) and the base class will take care of everything for you.

If, however, you do not derive from a ready-made base class, but from
GstElement or some other class not built on top of a base class, you
will most likely have to implement your own state change function to be
notified of state changes. This is definitively necessary if your plugin
is a demuxer or a muxer, as there are no base classes for muxers or
demuxers yet.

An element can be notified of state changes through a virtual function
pointer. Inside this function, the element can initialize any sort of
specific data needed by the element, and it can optionally fail to go
from one state to another.

Do not g\_assert for unhandled state changes; this is taken care of by
the GstElement base class.

    static GstStateChangeReturn
    gst_my_filter_change_state (GstElement *element, GstStateChange transition);
    
    static void
    gst_my_filter_class_init (GstMyFilterClass *klass)
    {
      GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
    
      element_class->change_state = gst_my_filter_change_state;
    }
    
    
    
    static GstStateChangeReturn
    gst_my_filter_change_state (GstElement *element, GstStateChange transition)
    {
      GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
      GstMyFilter *filter = GST_MY_FILTER (element);
    
      switch (transition) {
        case GST_STATE_CHANGE_NULL_TO_READY:
          if (!gst_my_filter_allocate_memory (filter))
            return GST_STATE_CHANGE_FAILURE;
          break;
        default:
          break;
      }
    
      ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
      if (ret == GST_STATE_CHANGE_FAILURE)
        return ret;
    
      switch (transition) {
        case GST_STATE_CHANGE_READY_TO_NULL:
          gst_my_filter_free_memory (filter);
          break;
        default:
          break;
      }
    
      return ret;
    }

Note that upwards (NULL=\>READY, READY=\>PAUSED, PAUSED=\>PLAYING) and
downwards (PLAYING=\>PAUSED, PAUSED=\>READY, READY=\>NULL) state changes
are handled in two separate blocks with the downwards state change
handled only after we have chained up to the parent class's state change
function. This is necessary in order to safely handle concurrent access
by multiple threads.

The reason for this is that in the case of downwards state changes you
don't want to destroy allocated resources while your plugin's chain
function (for example) is still accessing those resources in another
thread. Whether your chain function might be running or not depends on
the state of your plugin's pads, and the state of those pads is closely
linked to the state of the element. Pad states are handled in the
GstElement class's state change function, including proper locking,
that's why it is essential to chain up before destroying allocated
resources.