Conrad Parker
2008-Oct-29 00:50 UTC
[theora-dev] forcing eos on last theora packet (was Re: Theora 1.0 RC2)
2008/10/29 Romain Beauxis <toots at rastageeks.org>:> > I am currently implementing theora for our application. > In our model for generating ogg streams, we may want to stop > a stream while not providing a new YUV data buffer for encoding. > > Current API doesn't allow such thing, since the eos flag is set by the > packetout function only when the last_p parameter was passed *and* > there was some data available to output. > > Hence, I have written a function that forges this packet, along with NULL > data, which is allowed by the ogg specifications (and works with other > encoders, like speex).Hi, I think a simpler approach might be for you to directly set the eos flag on the last ogg page, after you have retrieved it from ogg_stream_pageout(). You can use a function like this (copied from oggz-chop.c, where it similarly cuts the end of a file): static void _ogg_page_set_eos (const ogg_page * og) { if (og == NULL) return; og->header[5] |= 0x04; ogg_page_checksum_set (og); }> Furthermore, since API claims that the 1-1 correspondance with YUV encoded > buffer and ogg packet might not remain in the futur, I believe such function > may be usefull in the case when 2, 3 or 4 buffers could be needed to fill a > new ogg packet.. > > Patch is attached. I didn't test it yet, but it is mainly packetout's code. I > believe it is correct, though I don't know if the granulepos and packetno > should be incremented in this case.As for these questions regarding your patch, packetno would need to be incremented. I think granulepos would probably be the same as that of the previous packet (ie. the last actual frame), but the spec doesn't define that such an empty packet is valid for theora. Just setting eos directly on the last page produced should avoid any of these issues. cheers, Conrad.
Romain Beauxis
2008-Oct-29 08:56 UTC
[theora-dev] forcing eos on last theora packet (was Re: Theora 1.0 RC2)
Le Wednesday 29 October 2008 01:50:25 Conrad Parker, vous avez ?crit?:> Hi,Hi !> I think a simpler approach might be for you to directly set the eos > flag on the last ogg page, after you have retrieved it from > ogg_stream_pageout(). You can use a function like this (copied from > oggz-chop.c, where it similarly cuts the end of a file): > > static void > _ogg_page_set_eos (const ogg_page * og) > { > ? if (og == NULL) return; > > ? og->header[5] |= 0x04; > ? ogg_page_checksum_set (og); > }I see this has a hack. Besides, it is exactly the same issue, since you need the last page, which is not my case. What I want to do is: "Terminal pages may be 'nil' pages, that is, pages containing no content but simply a page header with position information and the 'last page of bitstream' flag set in the page header." http://xiph.org/ogg/doc/oggstream.html I don't know how to forge a 'nil' page, since the structure is pretty opaque: typedef struct { unsigned char *header; long header_len; unsigned char *body; long body_len; } ogg_page; So the solution to generate a clean 'nil' page is to forge an empty eos packet, put it in the ogg stream, and flush the last page. This only needs packetno and serialno: typedef struct { unsigned char *packet; long bytes; long b_o_s; long e_o_s; ogg_int64_t granulepos; ogg_int64_t packetno; /* sequence number for decode; the framing knows where there's a hole in the data, but we need coupling so that the codec (which is in a seperate abstraction layer) also knows about the gap */ } ogg_packet;> > Furthermore, since API claims that the 1-1 correspondance with YUV > > encoded buffer and ogg packet might not remain in the futur, I believe > > such function may be usefull in the case when 2, 3 or 4 buffers could be > > needed to fill a new ogg packet.. > > > > Patch is attached. I didn't test it yet, but it is mainly packetout's > > code. I believe it is correct, though I don't know if the granulepos and > > packetno should be incremented in this case. > > As for these questions regarding your patch, packetno would need to be > incremented. I think granulepos would probably be the same as that of > the previous packet (ie. the last actual frame), but the spec doesn't > define that such an empty packet is valid for theora.At least ogg specs allows it. I will do more testings on my patch about packetno and granulepos. Another alternative would be to have the two variables used to generate then available, that is to say pi->CurrentFrame since granulepos is a member of the theora_state value. Romain