1 2This short document gives some guidelines to plugin writers. 3 4 5chain-based plugins 6=================== 7 8 - the plugin has a chain function on each sink pad (can be the same function) 9 10! 11! chain (GstPad *pad, GstBuffer *buffer) 12! { 13! MyElement *elem = MY_ELEMENT (gst_pad_get_parent (pad)); 14! GstBuffer *new_buffer; 15! 16! ... 17! (process the buffer) 18! ... 19! 20! /* you can push as many buffers (0 or more) as you want */ 21! while (!done) { 22! ... 23! (process some more 24! ... 25! gst_pad_push (elem->some_sink_pad, new_buffer); 26! ... 27! /* if you're like going to send a large amount of buffers 28! * it's a good idea to call _yield from time to time after 29! * the buffer has been pushed */ 30! (optional gst_element_yield (GST_ELEMENT (elem)); ) 31! } 32! } 33! 34 35 - chain based functions are usually easy and recommended. 36 - use gst_element_yield if you are going to push a lot of buffers. 37 38 39 40loop-based plugins 41================== 42 43 - one loop function for the element. 44 - required for bytestream based plugins. 45 46simple case 47----------- 48 49 - one pull at the start 50 51 - if you do something like this, you really should consider using a 52 chain function as it can be significantly optimised by the scheduler. 53 54! 55! loop (GstElement *element) 56! { 57! MyElement *elem = MY_ELEMENT (element); 58! GstBuffer *buffer; 59! GstBuffer *new_buffer; 60! 61! buffer = gst_pad_pull (elem->sinkpad); 62! 63! ... 64! (do something) 65! ... 66! 67! /* you can push as many buffers (0 or more) as you want */ 68! while (!done) { 69! ... 70! (process some more 71! ... 72! gst_pad_push (elem->some_sink_pad, new_buffer); 73! ... 74! /* if you're like going to send a large amount of buffers 75! * it's a good idea to call _yield from time to time after 76! * the buffer has been pushed */ 77! (optional gst_element_yield (GST_ELEMENT (elem)); ) 78! } 79! } 80! 81 82DONT!! 83 84- infinite loop 85 86! 87! loop (element) 88! { 89! while (TRUE) { 90! ... 91! _pull () 92! ... 93! 94! ... 95! _push () 96! ... 97! } 98! } 99! 100 101* you can fix this by either: 102 103 - setting the GST_ELEMENT_INFINITE_LOOP flag on the element. this is 104 not recommended, if all plugins in the pipeline (or depending on the 105 pipeline, some plugins) have this flag, the pipeline will not run. 106 - calling break; from time to time to get out of the loop. (duh, then 107 it's not an infinite loop anymore). beware that the next time the loop 108 function is called, it will be started from the top. 109 - calling gst_element_yield() from time to time (see NOTES). 110 - this is fine (albeit rather useless, use a chain function): 111 ! 112 ! loop (element) 113 ! { 114 ! ... 115 ! _pull () 116 ! ... 117 ! 118 ! ... 119 ! _push () 120 ! ... 121 ! } 122 ! 123 - so is this (albeit rather useless, consider removing the while and the _yield): 124 ! 125 ! loop (element) 126 ! { 127 ! while (TRUE) { 128 ! ... 129 ! _pull () 130 ! ... 131 ! 132 ! ... 133 ! _push () 134 ! ... 135 ! gst_element_yield (element); 136 ! } 137 ! } 138 ! 139 140 141DONT!! 142 143- allocate data, loop, free data 144 145! 146! loop (element) 147! { 148! 149! (my funky malloc) 150! 151! while (TRUE) { 152! 153! ... 154! _pull () 155! ... 156! 157! ... 158! _push () 159! ... 160! 161! _yield () 162! } 163! 164! (my funky free) 165! 166! } 167! 168 169 - the free will NEVER happen!. 170 171* You can fix this by: 172 173 - allocating/freeing data in the state change function 174 - you could think the following code would work too: 175 ! 176 ! (*WRONG* example follows) 177 ! 178 ! loop (element) 179 ! { 180 ! 181 ! (my funky malloc) 182 ! 183 ! while (TRUE) { 184 ! 185 ! ... 186 ! _pull () 187 ! if (EOS) 188 ! break; 189 ! 190 ! ... 191 ! _push () 192 ! ... 193 ! 194 ! _yield () 195 ! } 196 ! 197 ! (my funky free) 198 ! 199 ! } 200 ! 201 but it'll only free the data if the pipeline was shut down with 202 and EOS so don't try it. Besides, on EOS, a state change will happen 203 anyway so free the data there. 204 205 206bytestream/multiple pull case 207----------------------------- 208 209 - same as the simple case, but you can't use a chain based function unless 210 you want to make things a little harder then they should be. 211 212 213complicated case 214---------------- 215 216 - push and pull are completely mixed. 217 - the flow is usually something like this: 218 219! 220! loop (element) 221! { 222! 223! while (TRUE) { 224! 225! while (something) { 226! ... 227! do some _pull () 228! ... 229! do some _push () 230! ... 231! while (something_else) { 232! ... 233! if (testing) 234! do some _pull () 235! ... 236! do some _push () 237! } 238! } 239! 240! while (something_useful) { 241! ... 242! _push () 243! ... 244! } 245! } 246! } 247! 248(example made complicated on purpose, but vorbisdec comes close) 249 250 - you cannot call break to avoid infinite loops and there are loops that 251 take a significant amount of time to execute, possibly pushing/pulling 252 a lot of buffers. 253 254* You can fix this by: 255 256 - inserting gst_element_yield () in sane places, don't exaggerate because 257 every yield can potentially never return so you need to keep track of 258 allocations (see the NOTES below). 259 260 261 262NOTES: 263====== 264 265 - a call to _yield() can never return. if you have data allocated on the 266 stack before the yield, keep a pointer to it in the element struct 267 and free it in the state change function. 268 269 270IMPLEMENTATION DETAILS 271====================== 272 273The infinite loops are only problematic if the scheduler chooses to select 274the plugin as an entry point in the chain. _yield() will be a nop if this is 275not the case. The scheduler will not select plugins with the INFINITE_LOOP 276flag set as entries in a chain. 277 278A _yield in an entry will hand over control to the main thread context, allowing 279state changes and other actions to be performed. It will basically exit the 280_iterate() function. spending a long time in a loop will degrade app responsiveness 281because _iterate will take a long time. 282 283Calling yield, pulling, pushing can potentially never return because a state change 284might have happened, killing off execution of the plugin. pulling/pushing buffers 285will cause no leaks in this case because the core will free pending buffers in a 286state change to READY. The plugin must free allocated data/buffers itself in the state 287change function if the yield didn't return. 288 289 290 291 292 293 294 295 296