Commit 6e924a13 authored by chris's avatar chris Committed by conrad

Add ability to limit seeks to only search inside a specified byte range.

Adds oggz_bounded_seek_set() public API call.
parent 6b01b2a7
...@@ -475,4 +475,23 @@ int oggz_set_data_start (OGGZ * oggz, oggz_off_t offset); ...@@ -475,4 +475,23 @@ int oggz_set_data_start (OGGZ * oggz, oggz_off_t offset);
/** \} /** \}
*/ */
/**
* Seeks Oggz to time unit_target, but with the bounds of the offset range
* [offset_begin, offset_end]. This is useful when seeking in network streams
* where only parts of a media are buffered, and retrieving unbuffered
* parts is expensive.
* \param oggz An OGGZ handle previously opened for reading
* \param unit_target The seek target, in milliseconds, or custom units
* \param offset_begin Start of offset range to seek inside, in bytes
* \param offset_end End of offset range to seek inside, in bytes,
pass -1 for end of media
* \returns The new position, in milliseconds or custom units
* \retval -1 on failure (unit_target is not within range)
*/
ogg_int64_t
oggz_bounded_seek_set (OGGZ * oggz,
ogg_int64_t unit_target,
ogg_int64_t offset_begin,
ogg_int64_t offset_end);
#endif /* __OGGZ_SEEK_H__ */ #endif /* __OGGZ_SEEK_H__ */
...@@ -609,14 +609,17 @@ oggz_offset_end (OGGZ * oggz) ...@@ -609,14 +609,17 @@ oggz_offset_end (OGGZ * oggz)
return offset_end; return offset_end;
} }
static ogg_int64_t ogg_int64_t
oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target) oggz_bounded_seek_set (OGGZ * oggz,
ogg_int64_t unit_target,
ogg_int64_t offset_begin,
ogg_int64_t offset_end)
{ {
OggzReader * reader; OggzReader * reader;
oggz_off_t offset_orig, offset_at, offset_guess; oggz_off_t offset_orig, offset_at, offset_guess;
oggz_off_t offset_begin, offset_end = -1, offset_next; oggz_off_t offset_next;
ogg_int64_t granule_at; ogg_int64_t granule_at;
ogg_int64_t unit_at, unit_begin = 0, unit_end = -1, unit_last_iter = -1; ogg_int64_t unit_at, unit_begin = -1, unit_end = -1, unit_last_iter = -1;
long serialno; long serialno;
ogg_page * og; ogg_page * og;
int hit_eof = 0; int hit_eof = 0;
...@@ -627,14 +630,14 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target) ...@@ -627,14 +630,14 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target)
if (unit_target > 0 && !oggz_has_metrics (oggz)) { if (unit_target > 0 && !oggz_has_metrics (oggz)) {
#ifdef DEBUG #ifdef DEBUG
printf ("oggz_seek_set: No metric defined, FAIL\n"); printf ("oggz_bounded_seek_set: No metric defined, FAIL\n");
#endif #endif
return -1; return -1;
} }
if ((offset_end = oggz_offset_end (oggz)) == -1) { if (offset_end == -1 && (offset_end = oggz_offset_end (oggz)) == -1) {
#ifdef DEBUG #ifdef DEBUG
printf ("oggz_seek_set: oggz_offset_end == -1, FAIL\n"); printf ("oggz_bounded_seek_set: oggz_offset_end == -1, FAIL\n");
#endif #endif
return -1; return -1;
} }
...@@ -643,7 +646,7 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target) ...@@ -643,7 +646,7 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target)
if (unit_target == reader->current_unit) { if (unit_target == reader->current_unit) {
#ifdef DEBUG #ifdef DEBUG
printf ("oggz_seek_set: unit_target == reader->current_unit, SKIP\n"); printf ("oggz_bounded_seek_set: unit_target == reader->current_unit, SKIP\n");
#endif #endif
return (long)reader->current_unit; return (long)reader->current_unit;
} }
...@@ -659,14 +662,11 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target) ...@@ -659,14 +662,11 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target)
offset_orig = oggz->offset; offset_orig = oggz->offset;
offset_begin = 0;
unit_at = reader->current_unit; unit_at = reader->current_unit;
unit_begin = 0;
og = &oggz->current_page; og = &oggz->current_page;
if (oggz_seek_raw (oggz, 0, SEEK_END) >= 0) { if (unit_end == -1 && oggz_seek_raw (oggz, offset_end, SEEK_SET) >= 0) {
ogg_int64_t granulepos; ogg_int64_t granulepos;
if (oggz_get_prev_start_page (oggz, og, &granulepos, &serialno) >= 0) { if (oggz_get_prev_start_page (oggz, og, &granulepos, &serialno) >= 0) {
...@@ -674,6 +674,30 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target) ...@@ -674,6 +674,30 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target)
} }
} }
if (unit_begin == -1 && oggz_seek_raw (oggz, offset_begin, SEEK_SET) >= 0) {
ogg_int64_t granulepos;
if (oggz_get_next_start_page (oggz, og) >= 0) {
serialno = ogg_page_serialno (og);
granulepos = ogg_page_granulepos (og);
unit_begin = oggz_get_unit (oggz, serialno, granulepos);
}
}
/* Fail if target isn't in specified range. */
if (unit_target < unit_begin || unit_target > unit_end)
return -1;
/* Reduce the search range if possible using read cursor position. */
if (unit_at > unit_begin && unit_at < unit_end) {
if (unit_target < unit_at) {
unit_end = unit_at;
offset_end = offset_at;
} else {
unit_begin = unit_at;
offset_begin = offset_at;
}
}
og = &oggz->current_page; og = &oggz->current_page;
for ( ; ; ) { for ( ; ; ) {
...@@ -682,7 +706,7 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target) ...@@ -682,7 +706,7 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target)
hit_eof = 0; hit_eof = 0;
#ifdef DEBUG #ifdef DEBUG
printf ("oggz_seek_set: [A] want u%lld: (u%lld - u%lld) [@%" PRI_OGGZ_OFF_T "d - @%" PRI_OGGZ_OFF_T "d]\n", printf ("oggz_bounded_seek_set: [A] want u%lld: (u%lld - u%lld) [@%" PRI_OGGZ_OFF_T "d - @%" PRI_OGGZ_OFF_T "d]\n",
unit_target, unit_begin, unit_end, offset_begin, offset_end); unit_target, unit_begin, unit_end, offset_begin, offset_end);
#endif #endif
...@@ -699,61 +723,24 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target) ...@@ -699,61 +723,24 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target)
if (offset_guess > offset_end) { if (offset_guess > offset_end) {
offset_guess = offset_end; offset_guess = offset_end;
} offset_at = oggz_seek_raw (oggz, offset_guess, SEEK_SET);
offset_next = oggz_get_prev_start_page (oggz, og, &granule_at, &serialno);
offset_at = oggz_seek_raw (oggz, offset_guess, SEEK_SET); } else {
if (offset_at == -1) { offset_at = oggz_seek_raw (oggz, offset_guess, SEEK_SET);
goto notfound; offset_next = oggz_get_next_start_page (oggz, og);
}
offset_next = oggz_get_next_start_page (oggz, og);
#ifdef DEBUG
printf ("oggz_seek_set: offset_next %" PRI_OGGZ_OFF_T "d\n", offset_next);
#endif
if (/*unit_end == -1 &&*/ offset_next == -2) { /* reached eof, backtrack */
hit_eof = 1;
offset_next = oggz_get_prev_start_page (oggz, og, &granule_at,
&serialno);
unit_end = oggz_get_unit (oggz, serialno, granule_at);
#ifdef DEBUG
printf ("oggz_seek_set: [C] offset_next @%" PRI_OGGZ_OFF_T "d, g%lld, (s%ld)\n",
offset_next, granule_at, serialno);
printf ("oggz_seek_set: [c] u%lld\n",
oggz_get_unit (oggz, serialno, granule_at));
#endif
} else if (offset_next >= 0) {
serialno = ogg_page_serialno (og);
granule_at = ogg_page_granulepos (og);
}
if (offset_next < 0) {
goto notfound;
}
if (hit_eof || offset_next > offset_end) {
offset_next =
oggz_scan_for_page (oggz, og, unit_target, offset_begin, offset_end);
if (offset_next < 0) goto notfound;
offset_at = offset_next;
serialno = ogg_page_serialno (og); serialno = ogg_page_serialno (og);
granule_at = ogg_page_granulepos (og); granule_at = ogg_page_granulepos (og);
unit_at = oggz_get_unit (oggz, serialno, granule_at);
goto found;
} }
offset_at = offset_next;
unit_at = oggz_get_unit (oggz, serialno, granule_at); unit_at = oggz_get_unit (oggz, serialno, granule_at);
#ifdef DEBUG
printf ("oggz_bounded_seek_set: offset_next %" PRI_OGGZ_OFF_T "d\n", offset_next);
#endif
if (unit_at == unit_last_iter) break; if (unit_at == unit_last_iter) break;
#ifdef DEBUG #ifdef DEBUG
printf ("oggz_seek_set: [D] want u%lld, got page u%lld @%" PRI_OGGZ_OFF_T "d g%lld\n", printf ("oggz_bounded_seek_set: [D] want u%lld, got page u%lld @%" PRI_OGGZ_OFF_T "d g%lld\n",
unit_target, unit_at, offset_at, granule_at); unit_target, unit_at, offset_at, granule_at);
#endif #endif
...@@ -770,7 +757,6 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target) ...@@ -770,7 +757,6 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target)
} }
} }
found:
do { do {
offset_at = oggz_get_prev_start_page (oggz, og, &granule_at, &serialno); offset_at = oggz_get_prev_start_page (oggz, og, &granule_at, &serialno);
unit_at = oggz_get_unit (oggz, serialno, granule_at); unit_at = oggz_get_unit (oggz, serialno, granule_at);
...@@ -785,19 +771,10 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target) ...@@ -785,19 +771,10 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t unit_target)
if (offset_at == -1) return -1; if (offset_at == -1) return -1;
#ifdef DEBUG #ifdef DEBUG
printf ("oggz_seek_set: FOUND (%lld)\n", unit_at); printf ("oggz_bounded_seek_set: FOUND (%lld)\n", unit_at);
#endif #endif
return (long)reader->current_unit; return (long)reader->current_unit;
notfound:
#ifdef DEBUG
printf ("oggz_seek_set: NOT FOUND\n");
#endif
oggz_reset (oggz, offset_orig, -1, SEEK_SET);
return -1;
} }
static ogg_int64_t static ogg_int64_t
...@@ -830,7 +807,7 @@ oggz_seek_end (OGGZ * oggz, ogg_int64_t unit_offset) ...@@ -830,7 +807,7 @@ oggz_seek_end (OGGZ * oggz, ogg_int64_t unit_offset)
unit_end, offset_end, granulepos); unit_end, offset_end, granulepos);
#endif #endif
return oggz_seek_set (oggz, unit_end + unit_offset); return oggz_bounded_seek_set (oggz, unit_end + unit_offset, 0, -1);
} }
off_t off_t
...@@ -889,11 +866,11 @@ oggz_seek_units (OGGZ * oggz, ogg_int64_t units, int whence) ...@@ -889,11 +866,11 @@ oggz_seek_units (OGGZ * oggz, ogg_int64_t units, int whence)
switch (whence) { switch (whence) {
case SEEK_SET: case SEEK_SET:
r = oggz_seek_set (oggz, units); r = oggz_bounded_seek_set (oggz, units, 0, -1);
break; break;
case SEEK_CUR: case SEEK_CUR:
units += reader->current_unit; units += reader->current_unit;
r = oggz_seek_set (oggz, units); r = oggz_bounded_seek_set (oggz, units, 0, -1);
break; break;
case SEEK_END: case SEEK_END:
r = oggz_seek_end (oggz, units); r = oggz_seek_end (oggz, units);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment