mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-01 06:01:04 +00:00
59241d5e74
Original commit message from CVS: * ext/ogg/Makefile.am: * ext/ogg/README: * ext/ogg/gstoggdemux.c: (gst_ogg_pad_typefind), (gst_ogg_pad_submit_packet), (gst_ogg_demux_sink_activate), (gst_ogg_print): * ext/ogg/gstoggmux.c: (gst_ogg_mux_init), (gst_ogg_mux_request_new_pad), (gst_ogg_mux_next_buffer), (gst_ogg_mux_push_page), (gst_ogg_mux_queue_pads), (gst_ogg_mux_get_headers), (gst_ogg_mux_set_header_on_caps), (gst_ogg_mux_send_headers), (gst_ogg_mux_collected), (gst_ogg_mux_change_state): Ported ogg muxer.
189 lines
6.5 KiB
Text
189 lines
6.5 KiB
Text
ogg demuxer
|
|
-----------
|
|
|
|
This ogg demuxer has two modes of operation, which both share a significant
|
|
amount of code. The first mode is the streaming mode which is automatically
|
|
selected when the demuxer is connected to a non-getrange based element. When
|
|
connected to a getrange based element the ogg demuxer can do full seeking
|
|
with great efficiency.
|
|
|
|
1) the streaming mode.
|
|
|
|
In this mode, the ogg demuxer receives buffers in the _chain() function which
|
|
are then simply submited to the ogg sync layer. Pages are then processed when the
|
|
sync layer detects them, pads are created for new chains and packets are sent to
|
|
the peer elements of the pads.
|
|
|
|
In this mode, no seeking is possible. This is the typical case when the stream is
|
|
read from a network source.
|
|
|
|
In this mode, no setup is done at startup, the pages are just read and decoded.
|
|
A new logical chain is detected when one of the pages has the BOS flag set. At this
|
|
point the existing pads are removed and new pads are created for all the logical
|
|
streams in this new chain.
|
|
|
|
|
|
2) the random access mode.
|
|
|
|
In this mode, the ogg file is first scanned to detect the position and length of
|
|
all chains. This scanning is performed using a recursive binary search algorithm
|
|
that is explained below.
|
|
|
|
find_chains(start, end)
|
|
{
|
|
ret1 = read_next_pages (start);
|
|
ret2 = read_prev_page (end);
|
|
|
|
if (WAS_HEADER (ret1)) {
|
|
}
|
|
else {
|
|
}
|
|
|
|
}
|
|
|
|
a) read first and last pages
|
|
|
|
start end
|
|
V V
|
|
+-----------------------+-------------+--------------------+
|
|
| 111 | 222 | 333 |
|
|
BOS BOS BOS EOS
|
|
|
|
|
|
after reading start, serial 111, BOS, chain[0] = 111
|
|
after reading end, serial 333, EOS
|
|
|
|
start serialno != end serialno, binary search start, (end-start)/2
|
|
|
|
start bisect end
|
|
V V V
|
|
+-----------------------+-------------+--------------------+
|
|
| 111 | 222 | 333 |
|
|
|
|
|
|
after reading start, serial 111, BOS, chain[0] = 111
|
|
after reading end, serial 222, EOS
|
|
|
|
while (
|
|
|
|
|
|
|
|
testcases
|
|
---------
|
|
|
|
a) stream without BOS
|
|
|
|
+----------------------------------------------------------+
|
|
111 |
|
|
EOS
|
|
|
|
b) chained stream, first chain without BOS
|
|
|
|
+-------------------+--------------------------------------+
|
|
111 | 222 |
|
|
BOS EOS
|
|
|
|
|
|
c) chained stream
|
|
|
|
+-------------------+--------------------------------------+
|
|
| 111 | 222 |
|
|
BOS BOS EOS
|
|
|
|
|
|
d) chained stream, second without BOS
|
|
|
|
+-------------------+--------------------------------------+
|
|
| 111 | 222 |
|
|
BOS EOS
|
|
|
|
|
|
|
|
ogg and the granulepos
|
|
----------------------
|
|
|
|
an ogg streams contains pages with a serial number and a granule pos. The granulepos
|
|
is a number that is codec specific and denotes the 'position' of the last sample in
|
|
the last packet in that page.
|
|
|
|
ogg has therefore no notion about time, it only knows about bytes and granule positions.
|
|
|
|
The granule position is just a number, it can contain gaps or can just be any random
|
|
number.
|
|
|
|
|
|
theora and the granulepos
|
|
-------------------------
|
|
|
|
the granulepos in theora consists of the framenumber of the last keyframe shifted some
|
|
amount of bits plus the number of p/b-frames.
|
|
|
|
This means that given a framenumber or a timestamp one cannot generate the granulepos
|
|
for that frame. eg frame 10 could have several valid granulepos values depending on if
|
|
the last keyframe was on frame 5 or 0. Given a granulepos we can, however, create a
|
|
unique correct timestamp and a framenumber.
|
|
|
|
in a raw theroa stream we use the granulepos as the offset field.
|
|
|
|
The granulepos of an ogg page is the framenumber of the last frame in the page.
|
|
|
|
|
|
vorbis and granulepos
|
|
---------------------
|
|
|
|
the granulepos in vorbis happens to be the same as the sample counter. conversion to and
|
|
from granulepos is therefore easy.
|
|
|
|
in a raw vorbis stream we use the granulepos as the offset field.
|
|
|
|
The granulepos of an ogg page is the sample number of the next page in the ogg stream.
|
|
|
|
|
|
What can ogg do?
|
|
----------------
|
|
|
|
An ogg demuxer can read pages and get the granuleposition from it. It can ask the decoder
|
|
elements to convert a granulepos to time.
|
|
|
|
An ogg demuxer can also get the granulepos of the first and the last page of a stream to
|
|
get the start and end timestamp of that stream. It can also get the length in bytes of
|
|
the stream (when the peer is seekable, that is).
|
|
|
|
An ogg demuxer is therefore basically able to seek to any byte position and timestamp.
|
|
When asked to seek to a given granulepos, the ogg demuxer should always convert the
|
|
value to a timestamp using the peer decoder element conversion function. It can then
|
|
binary search the file to eventually end up on the page with the given granule pos or
|
|
a granulepos with the same timestamp.
|
|
|
|
Seeking in ogg currently
|
|
------------------------
|
|
|
|
When seeking in an ogg, the decoders can choose to forward the seek event as a
|
|
granulepos or a timestamp to the ogg demuxer.
|
|
|
|
In the case of a granulepos, the ogg demuxer will seek back to the beginning of
|
|
the stream and skip pages until it finds one with the requested timestamp.
|
|
|
|
In the case of a timestamp, the ogg demuxer also seeks back to the beginning of
|
|
the stream. For each page it reads, it asks the decoder element to convert the
|
|
granulepos back to a timestamp. The ogg demuxer keeps on skipping pages until the
|
|
page has a timestamp bigger or equal to the requested one.
|
|
|
|
It is therefore important that the decoder elements in vorbis can convert a granulepos
|
|
into a timestamp or never seek on timestamp on the oggdemuxer.
|
|
|
|
The default format on the oggdemuxer source pads is currently defined as a the
|
|
granulepos of the packets, it is also the value of the OFFSET field in the GstBuffer.
|
|
|
|
|
|
Oggmux
|
|
------
|
|
|
|
The oggmuxer uses the offset fields to fill in the granulepos in the pages.
|
|
|
|
|
|
TODO
|
|
----
|
|
|
|
- use the OFFSET field in the GstBuffer to store/read the granulepos as
|
|
opposed to the OFFSET_END field.
|