[theora-dev] further debugging of my ogg/theora decoder

Conrad Parker conrad at metadecks.org
Wed Nov 12 21:52:27 PST 2008

2008/11/13 salsaman <salsaman at gmail.com>:
> On Wed, Nov 12, 2008 at 6:36 PM, Ralph Giles <giles at xiph.org> wrote:
>> On Wed, Nov 12, 2008 at 1:13 PM, salsaman <salsaman at gmail.com> wrote:
>> > suppose I start decoding from a page with granulepos (kframe=x, frame
>> > =y)
>> > and I continue decoding in sequence until I reach the next page with a
>> > non-negative granulepos (kframe=a, frame=b). Is it possible that there
>> > could
>> > be another keyframe between x and a ? In other words, do "hidden"
>> > keyframes
>> > exist in the ogg stream, or is it safe to assume that every keyframe has
>> > at
>> > least one (non-negative) granulepos ?
>> It's possible, though unlikely.

(hence it is not safe to assume that every keyframe is represented by
a granulepos in the stream.)

>> > Let me give an example. Suppose I am seeking for frame 20. I find a
>> > granulepos of (18,22). Good, so I know that the keyframe is 18 + an
>> > offset
>> > of 2. So now I seek again to find the largest granulepos before 18. I
>> > find
>> > (10,12). Great.
>> > So I start decoding from (10,12) and I reach a keyframe. Can I assume
>> > this
>> > keyframe is 18, and then just decode two more frames ?
>> In this case, you know the answer, because if you know by counting
>> whether the keyframe you just found is frame 18, no? Or are you
>> worried about having the backpropagate the (10,12) to earlier packets
>> in that (10,12) page? You do have to do that, you can't assume there
>> isn't a 9,9 in there too.
> No, I am not worried about that. But the first keyframe I find could be 14
> instead of 18, for example. Then I count two frames, I would end up at 16
> instead of 20.

right -- when you found (10,12), the only info that gives you is that
a keyframe exists at frame 10, and interframes 11 and 12 depend on it.
You previously knew that keyframe 18 exists and interframes 19-22
depend on it. You don't yet know anything about the keyframes and
interframes between 13-17.

> The only way I can see to be sure is to decode right up to the (18,22) page
> and make sure there are no more keyframes until then.
> This would occur for example, if there were continuation packets up to frame
> 13, then on the same page 14 (keyframe in this example) begins and the
> packet continues until we get to 18, then 18 continues until 18,22.


> So what I really need to know, if a frame/packet completes on a page, and
> then another frame/packet begins on the same page, but continues, would the
> granulepos be for the completed frame, or would it be a continuation ?

for the completed frame; the granulepos (which is a field in the page
header) refers to the last completed packet on the page.

> If
> it's the former then I think I am OK because in case of a keyframe before
> 18, there should always be a completed frame (e.g. 17 with a granulepos of
> 14,17) before 18 starts, right ?

No, eg. your next example is possible:

> The other example I can think of is if 17 is a keyframe, and it completes on
> the same page as 18, also a keyframe, completes. I guess this might be
> possible for very small, rapidly changing frames, right ? In this case I
> would only need to decode to the end of the page where a keyframe first
> appears, and make sure I got the last keyframe on that page.
> I hope this makes some sense.

If you just want to identify keyframe packets, you can skip the full
decode and use theora_packet_is_keyframe(), which just probes the
packet data for the keyframe flag.

So in general, you can't make assumptions about keyframe existence
based on granulepos.

To find the keyframe for a frame you want to render, you should first
try to find the page with the largest granulepos less than the target
keyframe. Let's call that page G, and we'll call the last packet
finishing on it P; ie. packet P has G's granulepos. Once you've found
page G, then scan forwards through all the packets following P
(probing for keyframes, or just counting) until you've found your
target keyframe.

Note that the next packet after P may begin on G, so you can't just skip G.

So you need to start by pulling packets out of G, and once you see one
with the same granulepos as G you can start your counter. However if P
is continued on G (ie. it starts on an earlier page), and you just
feed G into ogg_stream_pagein(), then ogg_stream_packetout() will not
give you P, so you won't see any granulepos values and you won't be
able to initialize your counter. You can detect this condition using
libogg as follows (from ogg/src/framing.c):

/* NOTE:
If a page consists of a packet begun on a previous page, and a new
packet begun (but not completed) on this page, the return will be:
  ogg_page_packets(page)   ==1,
  ogg_page_continued(page) !=0

In that case you can assume that the first packet coming out of
ogg_stream_packetout() is P+1.


More information about the theora-dev mailing list