[Vorbis-dev] Continued:How can I seek in Ogg Vorbis file, but not using Vorbisfile library?

Ian Malone ibmalone at gmail.com
Wed Aug 30 04:00:16 PDT 2006


On 30/08/06, 隽 徐 <china_xujun at yahoo.com.cn> wrote:
>
> Hello, All.
>
> First, I want to thank Ian Malone and Ralph Giles, thanks for your kind
> replies. But I still have problems about seek.
>
> As you suggested, I could use ov_open_callbacks() to supply my own
> read/write/seek functions. So, can you give me an example? I'm sorry for my
> ignorance, because I haven't used callbacks before.
>

Have a look at how ov_open is implemented by calling ov_open_callbacks
in vorbisfile.c and at the comments for ov_callbacks in vorbisfile.h:
/* The function prototypes for the callbacks are basically the same as for
 * the stdio functions fread, fseek, fclose, ftell.
 * The one difference is that the FILE * arguments have been replaced with
 * a void * - this is to be used as a pointer to whatever internal data these
 * functions might need. In the stdio case, it's just a FILE * cast to a void *
 *
 * If you use other functions, check the docs for these functions and return
 * the right values. For seek_func(), you *MUST* return -1 if the stream is
 * unseekable
 */

What I'd do would be to make my own struct containing the buffer, it's
length and current read position (either as a pointer or an offset), then
check the documentation for fread, fseek, fclose and ftell and implement
functions to do equivalent things to the buffer.  The simplest one is
my_tell:

long my_tell(struct my_struct_t *my_struct) {
    /* Assuming that current and start are both type char * and doing the
       obvious. If you were storing length you'd just return that. */
    return (long) (my_struct->current - my_struct->start);
}

I think strictly it would be better to define it as taking void *datasource
(which is what it will be given) and casting it to my_struct_t.  In any
case be sure to replicate the documented functionality of the f*
functions (including the above fseek return -1 if not seekable).
_get_data may need you to set errno with my_read, I'm not sure
how good an idea that is.

Then add them to the callbacks list either altogether as done in
ov_open or one at a time like:
struct ov_callbacks callbacks;
callbacks.tell_func = my_tell;
callbacks.read_func = my_read;

etc.
As far as I can tell the next two questions relate to going down the
do it yourself route?

> I analyzed the vorbisfile.c in Tremor, and I think I need more specific
> information about the seek algorithm. As far as I know, I could use
> ogg_sync_pageseek() function to find the next page; if it returns 0, that
> means I need to read more data; if it returns n, that means the page was
> synced at the current location with a page length of n bytes, so the
> location is where the "Oggs" is, am I right? And if it returns -n, does it
> mean I already skipped n bytes from the start point or I need to skip back n
> bytes to get the sync page?

As far as I can tell from the documentation -n is the amount you've skipped
from the last submitted block of data to the current one. n indicates you've
got a page length n, so you've submitted all the data for that page (and
possibly some for the next one, the only way to know the difference is
to submit a byte at a time).

>
> Also, if I find the sync page, I must update the decode engine, the
> structures, like ogg_page, ogg_packet, etc need to get a new value, is that
> right? Then, there is another problem. I might have passed several segments
> of a packet, but the packet is not finished, so the next page starts with
> segments of the last packet. Can these segments be decoded? Or I must find
> the next packet? If so, how can I do it? I think granulepos is not very
> helpful in this case.
>

I'm not quite sure of the answer offhand, ov_raw_seek looks enlightening.
What I can tell you is that you have a page, you can now do the
ogg_stream_pagein/ogg_stream_packetout cycle until you get the next
packet, any segments from a previous packet running over page boundaries
will be dropped. To get the previous packet you'd have to go backwards to
get to the page it started on (with Vorbis that will probably be the previous
page).

-- 
imalone


More information about the Vorbis-dev mailing list