stbt.py: Refactor: Separate source & sink pipelines, joined with app{sink,src}
stbt.py: Refactor: Separate source & sink pipelines, joined with app{sink,src}

This will allow the caller of `stbt.Display.frames` to modify the
GStreamer buffer (the video frame) before passing it to the sink
pipeline. The next commit will do just that.

This is very similar to 5a0770e6's change to the source restarting
mechanism (which was reverted in a189e0c9) but using appsink/appsrc
instead of udpsink/udpsrc.

The implementation is as follows. We split the GStreamer pipeline into
two separate pipelines: A "source pipeline" ending in an appsink, and a
"sink pipeline" starting with an appsrc.

    -source pipeline--   on_new_buffer/frames   -sink pipeline--
    | ... ! appsink  |  --------buffer------->  | appsrc ! ... |
    ------------------                          ----------------

Every time a new buffer is available on the source pipeline's appsink,
we push it to the sink pipeline's appsrc (see `Display.on_new_buffer`).

But when we're inside `Display.frames` (i.e. inside `wait_for_match` or
similar) we *don't* want to display new frames, we only want to display
the frames processed by `wait_for_match`. Note that the `wait_for_match`
image-processing algorithm is slow, so it only processes one out of
every few frames (and we drop the rest). If we displayed the unprocessed
frames in between the frames that `wait_for_match` *did* process, the
user wouldn't see the `wait_for_match` visualisation (see the next
commit) because it would only be present in one out of every few frames.

So we use a lock to disable `on_new_buffer` while we're inside `frames`.
Note that `frames` calls arbitrary user code (via `yield`) which may
throw an exception; thus exceptions from `frames` are not necessarily
fatal and may even be caught in the calling user code. So it's important
that `frames` always releases the lock.

Note that `stbt.get_frame` can be safely called at any time -- we don't
need to lock there, because `Display.last_frame` has its own locking
built-in. `Display.on_new_buffer` pushes the buffer to
`Display.last_frame` even when the lock is held by `Display.frames`, in
case the user calls `stbt.get_frame`.

Note that `Display.init` keeps a reference to `sink_pipeline`, even
though it isn't referenced elsewhere, just to keep it alive.

martynjarvis/stb-tester,LewisHaley/stb-tester,LewisHaley/stb-tester,wmanley/stb-tester,stb-tester/stb-tester,wmanley/stb-tester,LewisHaley/stb-tester,martynjarvis/stb-tester,martynjarvis/stb-tester,stb-tester/stb-tester,LewisHaley/stb-tester,stb-tester/stb-tester,wmanley/stb-tester,LewisHaley/stb-tester,martynjarvis/stb-tester,wmanley/stb-tester,wmanley/stb-tester,LewisHaley/stb-tester,martynjarvis/stb-tester,stb-tester/stb-tester,martynjarvis/stb-tester,LewisHaley/stb-tester,martynjarvis/stb-tester