mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 21:31:04 +00:00
Bug 501031 - Make media seeking faster over HTTP by adding 'fuzz' factor to liboggz seek, and fixing its bisection search. r=doublec
This commit is contained in:
parent
8a38b2de30
commit
8d783e47e7
@ -1268,19 +1268,6 @@ static void GetBufferedBytes(nsMediaStream* aStream, nsTArray<ByteRange>& aRange
|
||||
nsresult nsOggDecodeStateMachine::Seek(float aTime, nsChannelReader* aReader)
|
||||
{
|
||||
LOG(PR_LOG_DEBUG, ("About to seek OggPlay to %fms", aTime));
|
||||
|
||||
// Get active tracks.
|
||||
PRInt32 numTracks = 0;
|
||||
PRInt32 tracks[2];
|
||||
if (mVideoTrack != -1) {
|
||||
tracks[numTracks] = mVideoTrack;
|
||||
numTracks++;
|
||||
}
|
||||
if (mAudioTrack != -1) {
|
||||
tracks[numTracks] = mAudioTrack;
|
||||
numTracks++;
|
||||
}
|
||||
|
||||
nsMediaStream* stream = aReader->Stream();
|
||||
nsAutoTArray<ByteRange, 16> ranges;
|
||||
stream->Pin();
|
||||
@ -1288,8 +1275,6 @@ nsresult nsOggDecodeStateMachine::Seek(float aTime, nsChannelReader* aReader)
|
||||
PRInt64 rv = -1;
|
||||
for (PRUint32 i = 0; rv < 0 && i < ranges.Length(); i++) {
|
||||
rv = oggplay_seek_to_keyframe(mPlayer,
|
||||
tracks,
|
||||
numTracks,
|
||||
ogg_int64_t(aTime * 1000),
|
||||
ranges[i].mStart,
|
||||
ranges[i].mEnd);
|
||||
@ -1300,8 +1285,6 @@ nsresult nsOggDecodeStateMachine::Seek(float aTime, nsChannelReader* aReader)
|
||||
// Could not seek in a buffered range, fall back to seeking over the
|
||||
// entire media.
|
||||
rv = oggplay_seek_to_keyframe(mPlayer,
|
||||
tracks,
|
||||
numTracks,
|
||||
ogg_int64_t(aTime * 1000),
|
||||
0,
|
||||
stream->GetLength());
|
||||
|
@ -46,4 +46,4 @@ oggplay_os2.patch: Bug 448918 - add OS/2 support (this patch should be
|
||||
bug498815.patch: Fix for bug 498815.
|
||||
bug498824.patch: Fix for bug 498824.
|
||||
bug500311.patch: Fix crash during decoder initialization.
|
||||
|
||||
faster_seek.patch: Fix for bug 501031, make seeking faster over HTTP.
|
||||
|
78
media/liboggplay/faster_seek.patch
Normal file
78
media/liboggplay/faster_seek.patch
Normal file
@ -0,0 +1,78 @@
|
||||
diff --git a/media/liboggplay/include/oggplay/oggplay_seek.h b/media/liboggplay/include/oggplay/oggplay_seek.h
|
||||
--- a/media/liboggplay/include/oggplay/oggplay_seek.h
|
||||
+++ b/media/liboggplay/include/oggplay/oggplay_seek.h
|
||||
@@ -42,15 +42,13 @@
|
||||
OggPlayErrorCode
|
||||
oggplay_seek(OggPlay *me, ogg_int64_t milliseconds);
|
||||
|
||||
/**
|
||||
* Seeks to key frame before |milliseconds|.
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_seek_to_keyframe(OggPlay *me,
|
||||
- int* tracks,
|
||||
- int num_tracks,
|
||||
ogg_int64_t milliseconds,
|
||||
ogg_int64_t offset_begin,
|
||||
ogg_int64_t offset_end);
|
||||
|
||||
#endif
|
||||
diff --git a/media/liboggplay/src/liboggplay/oggplay_seek.c b/media/liboggplay/src/liboggplay/oggplay_seek.c
|
||||
--- a/media/liboggplay/src/liboggplay/oggplay_seek.c
|
||||
+++ b/media/liboggplay/src/liboggplay/oggplay_seek.c
|
||||
@@ -75,54 +75,38 @@ oggplay_seek(OggPlay *me, ogg_int64_t mi
|
||||
oggplay_seek_cleanup(me, milliseconds);
|
||||
|
||||
return E_OGGPLAY_OK;
|
||||
|
||||
}
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_seek_to_keyframe(OggPlay *me,
|
||||
- int* tracks,
|
||||
- int num_tracks,
|
||||
ogg_int64_t milliseconds,
|
||||
ogg_int64_t offset_begin,
|
||||
ogg_int64_t offset_end)
|
||||
{
|
||||
- long *serial_nos;
|
||||
- int i;
|
||||
ogg_int64_t eof, time;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
- if (num_tracks > me->num_tracks || milliseconds < 0)
|
||||
+ if (milliseconds < 0)
|
||||
return E_OGGPLAY_CANT_SEEK;
|
||||
|
||||
eof = oggplay_get_duration(me);
|
||||
if (eof > -1 && milliseconds > eof) {
|
||||
return E_OGGPLAY_CANT_SEEK;
|
||||
}
|
||||
|
||||
- // Get the serialnos for the tracks we're seeking.
|
||||
- serial_nos = (long*)oggplay_malloc(sizeof(long)*num_tracks);
|
||||
- if (!serial_nos) {
|
||||
- return E_OGGPLAY_CANT_SEEK;
|
||||
- }
|
||||
- for (i=0; i<num_tracks; i++) {
|
||||
- serial_nos[i] = me->decode_data[tracks[i]]->serialno;
|
||||
- }
|
||||
-
|
||||
time = oggz_keyframe_seek_set(me->oggz,
|
||||
- serial_nos,
|
||||
- num_tracks,
|
||||
milliseconds,
|
||||
offset_begin,
|
||||
offset_end);
|
||||
- oggplay_free(serial_nos);
|
||||
|
||||
if (time == -1) {
|
||||
return E_OGGPLAY_CANT_SEEK;
|
||||
}
|
||||
|
||||
oggplay_seek_cleanup(me, time);
|
||||
|
||||
return E_OGGPLAY_OK;
|
@ -47,8 +47,6 @@ oggplay_seek(OggPlay *me, ogg_int64_t milliseconds);
|
||||
*/
|
||||
OggPlayErrorCode
|
||||
oggplay_seek_to_keyframe(OggPlay *me,
|
||||
int* tracks,
|
||||
int num_tracks,
|
||||
ogg_int64_t milliseconds,
|
||||
ogg_int64_t offset_begin,
|
||||
ogg_int64_t offset_end);
|
||||
|
@ -80,21 +80,17 @@ oggplay_seek(OggPlay *me, ogg_int64_t milliseconds) {
|
||||
|
||||
OggPlayErrorCode
|
||||
oggplay_seek_to_keyframe(OggPlay *me,
|
||||
int* tracks,
|
||||
int num_tracks,
|
||||
ogg_int64_t milliseconds,
|
||||
ogg_int64_t offset_begin,
|
||||
ogg_int64_t offset_end)
|
||||
{
|
||||
long *serial_nos;
|
||||
int i;
|
||||
ogg_int64_t eof, time;
|
||||
|
||||
if (me == NULL) {
|
||||
return E_OGGPLAY_BAD_OGGPLAY;
|
||||
}
|
||||
|
||||
if (num_tracks > me->num_tracks || milliseconds < 0)
|
||||
if (milliseconds < 0)
|
||||
return E_OGGPLAY_CANT_SEEK;
|
||||
|
||||
eof = oggplay_get_duration(me);
|
||||
@ -102,22 +98,10 @@ oggplay_seek_to_keyframe(OggPlay *me,
|
||||
return E_OGGPLAY_CANT_SEEK;
|
||||
}
|
||||
|
||||
// Get the serialnos for the tracks we're seeking.
|
||||
serial_nos = (long*)oggplay_malloc(sizeof(long)*num_tracks);
|
||||
if (!serial_nos) {
|
||||
return E_OGGPLAY_CANT_SEEK;
|
||||
}
|
||||
for (i=0; i<num_tracks; i++) {
|
||||
serial_nos[i] = me->decode_data[tracks[i]]->serialno;
|
||||
}
|
||||
|
||||
time = oggz_keyframe_seek_set(me->oggz,
|
||||
serial_nos,
|
||||
num_tracks,
|
||||
milliseconds,
|
||||
offset_begin,
|
||||
offset_end);
|
||||
oggplay_free(serial_nos);
|
||||
|
||||
if (time == -1) {
|
||||
return E_OGGPLAY_CANT_SEEK;
|
||||
|
@ -65,3 +65,4 @@ patch -p3 < bug498824.patch
|
||||
patch -p3 < bug496529.patch
|
||||
patch -p3 < bug499519.patch
|
||||
patch -p3 < bug500311.patch
|
||||
patch -p3 < faster_seek.patch
|
||||
|
@ -23,3 +23,4 @@ bug496063.patch: Fix for infinite loop during seek while shutting down.
|
||||
oggz_os2.patch: Bug 448918 - add OS/2 support (this patch should be
|
||||
removed when OS/2 support is added upstream)
|
||||
|
||||
faster_seek.patch: Fix for bug 501031, make seeking faster over HTTP.
|
||||
|
481
media/liboggz/faster_seek.patch
Normal file
481
media/liboggz/faster_seek.patch
Normal file
@ -0,0 +1,481 @@
|
||||
diff --git a/media/liboggz/include/oggz/oggz_seek.h b/media/liboggz/include/oggz/oggz_seek.h
|
||||
--- a/media/liboggz/include/oggz/oggz_seek.h
|
||||
+++ b/media/liboggz/include/oggz/oggz_seek.h
|
||||
@@ -471,40 +471,40 @@ long oggz_seek_byorder (OGGZ * oggz, voi
|
||||
* \param offset The offset of the start of data
|
||||
* \returns 0 on success, -1 on failure.
|
||||
*/
|
||||
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.
|
||||
+ * Seeks to within fuzz_margin milliseconds of time unit_target, within 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
|
||||
+ * \param fuzz_margin The seek stops when it's within this many milliseconds
|
||||
+ of unit_target
|
||||
* \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);
|
||||
+ ogg_int64_t offset_end,
|
||||
+ int fuzz_margin);
|
||||
|
||||
/**
|
||||
- * Seeks to the first key frame before unit_target, in the range
|
||||
- * [offset_begin, offset_end]. serial_nos contains an array of size serial_nos
|
||||
- * of serialnos of the streams which need to be seeked.
|
||||
+ * Seeks to before the first key frame before unit_target, in the range
|
||||
+ * [offset_begin, offset_end].
|
||||
*/
|
||||
ogg_int64_t
|
||||
oggz_keyframe_seek_set(OGGZ * oggz,
|
||||
- long* serial_nos,
|
||||
- int num_serialno,
|
||||
ogg_int64_t unit_target,
|
||||
ogg_int64_t offset_begin,
|
||||
ogg_int64_t offset_end);
|
||||
|
||||
#endif /* __OGGZ_SEEK_H__ */
|
||||
diff --git a/media/liboggz/src/liboggz/oggz_seek.c b/media/liboggz/src/liboggz/oggz_seek.c
|
||||
--- a/media/liboggz/src/liboggz/oggz_seek.c
|
||||
+++ b/media/liboggz/src/liboggz/oggz_seek.c
|
||||
@@ -491,65 +491,61 @@ oggz_scan_for_page (OGGZ * oggz, ogg_pag
|
||||
}
|
||||
}
|
||||
|
||||
return offset_at;
|
||||
}
|
||||
|
||||
#define GUESS_MULTIPLIER (1<<16)
|
||||
|
||||
-static oggz_off_t
|
||||
+static ogg_int64_t
|
||||
guess (ogg_int64_t unit_at, ogg_int64_t unit_target,
|
||||
ogg_int64_t unit_begin, ogg_int64_t unit_end,
|
||||
- oggz_off_t offset_begin, oggz_off_t offset_end)
|
||||
+ ogg_int64_t offset_begin, ogg_int64_t offset_end)
|
||||
{
|
||||
ogg_int64_t guess_ratio;
|
||||
- oggz_off_t offset_guess;
|
||||
-
|
||||
- if (unit_at == unit_begin) return offset_begin;
|
||||
+ ogg_int64_t offset_guess;
|
||||
|
||||
if (unit_end != -1) {
|
||||
guess_ratio =
|
||||
GUESS_MULTIPLIER * (unit_target - unit_begin) /
|
||||
(unit_end - unit_begin);
|
||||
} else {
|
||||
guess_ratio =
|
||||
GUESS_MULTIPLIER * (unit_target - unit_begin) /
|
||||
(unit_at - unit_begin);
|
||||
}
|
||||
|
||||
+ offset_guess = offset_begin +
|
||||
+ (((offset_end - offset_begin) * guess_ratio) /
|
||||
+ GUESS_MULTIPLIER);
|
||||
+
|
||||
#ifdef DEBUG
|
||||
- printf ("oggz_seek::guess: guess_ratio %lld = (%lld - %lld) / (%lld - %lld)\n",
|
||||
- guess_ratio, unit_target, unit_begin, unit_at, unit_begin);
|
||||
+ printf("guess: [o=%lld t=%lld]-[o=%lld t=%lld] guess_ratio=%lf offset_guess=%lu\n",
|
||||
+ offset_begin, unit_begin, offset_end, unit_end,
|
||||
+ ((double)guess_ratio / (double)GUESS_MULTIPLIER), offset_guess);
|
||||
#endif
|
||||
-
|
||||
- offset_guess = offset_begin +
|
||||
- (oggz_off_t)(((offset_end - offset_begin) * guess_ratio) /
|
||||
- GUESS_MULTIPLIER);
|
||||
-
|
||||
+
|
||||
return offset_guess;
|
||||
}
|
||||
|
||||
-static oggz_off_t
|
||||
-oggz_seek_guess (ogg_int64_t unit_at, ogg_int64_t unit_target,
|
||||
- ogg_int64_t unit_begin, ogg_int64_t unit_end,
|
||||
- oggz_off_t offset_at,
|
||||
- oggz_off_t offset_begin, oggz_off_t offset_end)
|
||||
+static ogg_int64_t
|
||||
+oggz_seek_guess (ogg_int64_t unit_at,
|
||||
+ ogg_int64_t unit_target,
|
||||
+ ogg_int64_t unit_begin,
|
||||
+ ogg_int64_t unit_end,
|
||||
+ oggz_off_t offset_at,
|
||||
+ oggz_off_t offset_begin,
|
||||
+ oggz_off_t offset_end)
|
||||
{
|
||||
oggz_off_t offset_guess;
|
||||
-
|
||||
- if (unit_at == unit_begin) {
|
||||
- offset_guess = offset_begin + (offset_end - offset_begin)/2;
|
||||
- } else if (unit_end == -1) {
|
||||
+ if (unit_end == -1) {
|
||||
offset_guess = guess (unit_at, unit_target, unit_begin, unit_end,
|
||||
offset_begin, offset_at);
|
||||
} else if (unit_end <= unit_begin) {
|
||||
-#ifdef DEBUG
|
||||
- printf ("oggz_seek_guess: unit_end <= unit_begin (ERROR)\n");
|
||||
-#endif
|
||||
offset_guess = -1;
|
||||
} else {
|
||||
offset_guess = guess (unit_at, unit_target, unit_begin, unit_end,
|
||||
offset_begin, offset_end);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("oggz_seek_guess: guessed %" PRI_OGGZ_OFF_T "d\n", offset_guess);
|
||||
@@ -617,21 +613,22 @@ oggz_offset_end (OGGZ * oggz)
|
||||
|
||||
return offset_end;
|
||||
}
|
||||
|
||||
ogg_int64_t
|
||||
oggz_bounded_seek_set (OGGZ * oggz,
|
||||
ogg_int64_t unit_target,
|
||||
ogg_int64_t offset_begin,
|
||||
- ogg_int64_t offset_end)
|
||||
+ ogg_int64_t offset_end,
|
||||
+ int fuzz_margin)
|
||||
{
|
||||
OggzReader * reader;
|
||||
- oggz_off_t offset_orig, offset_at, offset_guess;
|
||||
- oggz_off_t offset_next;
|
||||
+ ogg_int64_t offset_orig, offset_at, offset_guess;
|
||||
+ ogg_int64_t offset_next;
|
||||
ogg_int64_t granule_at;
|
||||
ogg_int64_t unit_at, unit_begin = -1, unit_end = -1, unit_last_iter = -1;
|
||||
long serialno;
|
||||
ogg_page * og;
|
||||
int hit_eof = 0;
|
||||
|
||||
if (oggz == NULL) {
|
||||
return -1;
|
||||
@@ -679,27 +676,30 @@ oggz_bounded_seek_set (OGGZ * oggz,
|
||||
ogg_int64_t granulepos;
|
||||
|
||||
if (oggz_get_prev_start_page (oggz, og, &granulepos, &serialno) >= 0) {
|
||||
unit_end = oggz_get_unit (oggz, serialno, granulepos);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
+ ogg_int64_t granulepos = 0;
|
||||
+ unit_begin = 0;
|
||||
+ // Start time needs to be the end time of the first non-header page.
|
||||
+ while (oggz_get_next_start_page (oggz, og) >= 0 && unit_begin <= 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)
|
||||
+ 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;
|
||||
@@ -738,16 +738,21 @@ oggz_bounded_seek_set (OGGZ * oggz,
|
||||
offset_at = oggz_seek_raw (oggz, offset_guess, SEEK_SET);
|
||||
offset_next = oggz_get_next_start_page (oggz, og);
|
||||
serialno = ogg_page_serialno (og);
|
||||
granule_at = ogg_page_granulepos (og);
|
||||
}
|
||||
|
||||
unit_at = oggz_get_unit (oggz, serialno, granule_at);
|
||||
|
||||
+ if (abs(unit_at - unit_target) < fuzz_margin) {
|
||||
+ // Within fuzz_margin of target, stop.
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
#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;
|
||||
|
||||
#ifdef DEBUG
|
||||
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);
|
||||
@@ -761,34 +766,17 @@ oggz_bounded_seek_set (OGGZ * oggz,
|
||||
offset_end = offset_at-1;
|
||||
unit_end = unit_at;
|
||||
if (unit_end == unit_begin) break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- do {
|
||||
- offset_at = oggz_get_prev_start_page (oggz, og, &granule_at, &serialno);
|
||||
- if (offset_at < 0)
|
||||
- break;
|
||||
- unit_at = oggz_get_unit (oggz, serialno, granule_at);
|
||||
- } while (unit_at > unit_target);
|
||||
-
|
||||
- if (offset_at < 0) {
|
||||
- oggz_reset (oggz, offset_orig, -1, SEEK_SET);
|
||||
- return -1;
|
||||
- }
|
||||
-
|
||||
- offset_at = oggz_reset (oggz, offset_at, unit_at, SEEK_SET);
|
||||
- if (offset_at == -1) return -1;
|
||||
-
|
||||
-#ifdef DEBUG
|
||||
- printf ("oggz_bounded_seek_set: FOUND (%lld)\n", unit_at);
|
||||
-#endif
|
||||
+ /* Reader is now approximately at the seek target. */
|
||||
|
||||
return (long)reader->current_unit;
|
||||
}
|
||||
|
||||
static ogg_int64_t
|
||||
oggz_seek_end (OGGZ * oggz, ogg_int64_t unit_offset)
|
||||
{
|
||||
oggz_off_t offset_orig, offset_at, offset_end;
|
||||
@@ -813,17 +801,17 @@ oggz_seek_end (OGGZ * oggz, ogg_int64_t
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("*** oggz_seek_end: found packet (%lld) at @%" PRI_OGGZ_OFF_T "d [%lld]\n",
|
||||
unit_end, offset_end, granulepos);
|
||||
#endif
|
||||
|
||||
- return oggz_bounded_seek_set (oggz, unit_end + unit_offset, 0, -1);
|
||||
+ return oggz_bounded_seek_set (oggz, unit_end + unit_offset, 0, -1, 0);
|
||||
}
|
||||
|
||||
off_t
|
||||
oggz_seek (OGGZ * oggz, oggz_off_t offset, int whence)
|
||||
{
|
||||
OggzReader * reader;
|
||||
ogg_int64_t units = -1;
|
||||
|
||||
@@ -872,21 +860,21 @@ oggz_seek_units (OGGZ * oggz, ogg_int64_
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
reader = &oggz->x.reader;
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
- r = oggz_bounded_seek_set (oggz, units, 0, -1);
|
||||
+ r = oggz_bounded_seek_set (oggz, units, 0, -1, 0);
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
units += reader->current_unit;
|
||||
- r = oggz_bounded_seek_set (oggz, units, 0, -1);
|
||||
+ r = oggz_bounded_seek_set (oggz, units, 0, -1, 0);
|
||||
break;
|
||||
case SEEK_END:
|
||||
r = oggz_seek_end (oggz, units);
|
||||
break;
|
||||
default:
|
||||
/*oggz_set_error (oggz, OGGZ_EINVALID);*/
|
||||
r = -1;
|
||||
break;
|
||||
@@ -934,130 +922,70 @@ oggz_seek_byorder (OGGZ * oggz, void * t
|
||||
long
|
||||
oggz_seek_packets (OGGZ * oggz, long serialno, long packets, int whence)
|
||||
{
|
||||
return OGGZ_ERR_DISABLED;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
-// Returns 1 if any of the elements of array |a|, which is of length |n|,
|
||||
-// contain the value |val|. Otherwise returns 0.
|
||||
-static int
|
||||
-is_any(ogg_int64_t* a, int n, ogg_int64_t val)
|
||||
-{
|
||||
- int i;
|
||||
- for (i=0; i<n; i++) {
|
||||
- if (a[i] == val) {
|
||||
- return 1;
|
||||
- }
|
||||
- }
|
||||
- return 0;
|
||||
+// Returns the maximum time in milliseconds by which a key frame could be
|
||||
+// offset for a given stream. Ogg granulepos encode time as:
|
||||
+// ((key_frame_number << granule_shift) + frame_offset).
|
||||
+// Therefore the maximum possible time by which any frame could be offset
|
||||
+// from a keyframe is the duration of (1 << granule_shift) - 1) frames.
|
||||
+static ogg_int64_t
|
||||
+get_keyframe_offset(oggz_stream_t* stream) {
|
||||
+ ogg_int64_t frame_duration;
|
||||
+ ogg_int64_t keyframe_diff;
|
||||
+
|
||||
+ if (stream->granuleshift == 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ // Max number of frames keyframe could possibly be offset.
|
||||
+ keyframe_diff = (1 << stream->granuleshift) - 1;
|
||||
+
|
||||
+ // Length of frame in ms.
|
||||
+ frame_duration = stream->granulerate_d / stream->granulerate_n;
|
||||
+
|
||||
+ return frame_duration * keyframe_diff;
|
||||
}
|
||||
|
||||
-// Returns the index of the element in array |a|, which is of length |n|,
|
||||
-// which contains the value |val|, or -1 of it's not present.
|
||||
-static int
|
||||
-find(long* a, int n, ogg_int64_t val)
|
||||
-{
|
||||
- int i;
|
||||
- for (i=0; i<n; i++) {
|
||||
- if (a[i] == val) {
|
||||
- return i;
|
||||
- }
|
||||
+// Returns the maximum possible time by which a keyframe could be offset in
|
||||
+// milliseconds, for all streams in the media.
|
||||
+static ogg_int64_t
|
||||
+get_max_keyframe_offset(OGGZ* oggz) {
|
||||
+ int i=0, size = 0, max_gshift = 0;
|
||||
+ ogg_int64_t max = 0, x;
|
||||
+ oggz_stream_t* stream = 0;
|
||||
+ size = oggz_vector_size (oggz->streams);
|
||||
+ for (i = 0; i < size; i++) {
|
||||
+ stream = (oggz_stream_t *)oggz_vector_nth_p (oggz->streams, i);
|
||||
+ if (!stream) continue;
|
||||
+ x = get_keyframe_offset(stream);
|
||||
+ if (x > max)
|
||||
+ max = x;
|
||||
}
|
||||
- return -1;
|
||||
-}
|
||||
-
|
||||
-// Returns the element with the smallest value in array |a|, which is
|
||||
-// of length |n|.
|
||||
-static ogg_int64_t
|
||||
-minimum(ogg_int64_t* a, int n) {
|
||||
- ogg_int64_t m = 0x7FFFFFFFFFFFFFFF;
|
||||
- int i;
|
||||
- for (i=0; i<n; i++) {
|
||||
- if (a[i] < m) {
|
||||
- m = a[i];
|
||||
- }
|
||||
- }
|
||||
- return m;
|
||||
+ return max;
|
||||
}
|
||||
|
||||
ogg_int64_t
|
||||
oggz_keyframe_seek_set(OGGZ * oggz,
|
||||
- long* serial_nos,
|
||||
- int num_serialno,
|
||||
ogg_int64_t unit_target,
|
||||
ogg_int64_t offset_begin,
|
||||
ogg_int64_t offset_end)
|
||||
{
|
||||
- oggz_off_t offset_at;
|
||||
- oggz_off_t offset_next;
|
||||
- ogg_int64_t granule_at;
|
||||
ogg_int64_t unit_at;
|
||||
- ogg_int64_t key_granule_at, key_unit_at;
|
||||
- long serialno;
|
||||
- ogg_page * og;
|
||||
- int granule_shift = 0, idx;
|
||||
- ogg_int64_t* key_frames = 0;
|
||||
-
|
||||
+ ogg_int64_t max_keyframe_offset;
|
||||
+ const ogg_int64_t fuzz = 500;
|
||||
+ ogg_int64_t keyframe_unit_target;
|
||||
+
|
||||
+ max_keyframe_offset = get_max_keyframe_offset(oggz);
|
||||
+
|
||||
+ keyframe_unit_target = MAX(0, unit_target - max_keyframe_offset - fuzz);
|
||||
+
|
||||
unit_at = oggz_bounded_seek_set(oggz,
|
||||
- unit_target,
|
||||
+ keyframe_unit_target,
|
||||
offset_begin,
|
||||
- offset_end);
|
||||
- // Time isn't in the specified offset range, fail.
|
||||
- if (unit_at == -1)
|
||||
- return -1;
|
||||
-
|
||||
- // We've seeked to beginning, we're at a key frame.
|
||||
- if (unit_at == 0)
|
||||
- return 0;
|
||||
-
|
||||
- // Backup this, in case we need to fail.
|
||||
- offset_at = oggz->offset;
|
||||
-
|
||||
- key_frames = oggz_malloc(sizeof(ogg_int64_t) * num_serialno);
|
||||
- if (!key_frames) {
|
||||
- // Malloc failure. We can still exit with the seek finishing at a non
|
||||
- // key frame.
|
||||
- return unit_at;
|
||||
- }
|
||||
- memset(key_frames, -1, sizeof(ogg_int64_t) * num_serialno);
|
||||
-
|
||||
- // Find the key frame offset for every stream.
|
||||
- og = &oggz->current_page;
|
||||
- while (is_any(key_frames, num_serialno, -1)) {
|
||||
- do {
|
||||
- offset_next = oggz_get_prev_start_page (oggz, og, &granule_at, &serialno);
|
||||
- if (offset_next <= 0 || granule_at == 0) {
|
||||
- // At beginning of file, or some other failure. Return with
|
||||
- // non-key frame seek if possible.
|
||||
- oggz_free(key_frames);
|
||||
- offset_at = oggz_reset (oggz, offset_at, unit_at, SEEK_SET);
|
||||
- return (offset_at == -1) ? -1 : unit_at;
|
||||
- }
|
||||
- } while (granule_at < 0);
|
||||
-
|
||||
- idx = find(serial_nos, num_serialno, serialno);
|
||||
- if (idx == -1 || key_frames[idx] != -1)
|
||||
- continue;
|
||||
-
|
||||
- granule_shift = oggz_get_granuleshift(oggz, serialno);
|
||||
- key_granule_at = (granule_at >> granule_shift) << granule_shift;
|
||||
- key_unit_at = oggz_get_unit(oggz, serialno, key_granule_at);
|
||||
-
|
||||
- if (key_unit_at < unit_target)
|
||||
- key_frames[idx] = key_unit_at;
|
||||
- }
|
||||
-
|
||||
- // Seek to 100ms before the earliest of all the streams' key frames.
|
||||
- // This is so that after the seek, the decoder will defintately return frames
|
||||
- // at or before get the key frame. Without this, some decoders will return
|
||||
- // frames which start after the specified time - after the key frame.
|
||||
- key_unit_at = minimum(key_frames, num_serialno);
|
||||
- unit_at = oggz_bounded_seek_set(oggz,
|
||||
- MAX((key_unit_at - 100), 0),
|
||||
- offset_begin,
|
||||
- offset_end);
|
||||
- oggz_free(key_frames);
|
||||
-
|
||||
+ offset_end,
|
||||
+ fuzz);
|
||||
return unit_at;
|
||||
}
|
@ -476,15 +476,17 @@ 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.
|
||||
* Seeks to within fuzz_margin milliseconds of time unit_target, within 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
|
||||
* \param fuzz_margin The seek stops when it's within this many milliseconds
|
||||
of unit_target
|
||||
* \returns The new position, in milliseconds or custom units
|
||||
* \retval -1 on failure (unit_target is not within range)
|
||||
*/
|
||||
@ -492,17 +494,15 @@ ogg_int64_t
|
||||
oggz_bounded_seek_set (OGGZ * oggz,
|
||||
ogg_int64_t unit_target,
|
||||
ogg_int64_t offset_begin,
|
||||
ogg_int64_t offset_end);
|
||||
ogg_int64_t offset_end,
|
||||
int fuzz_margin);
|
||||
|
||||
/**
|
||||
* Seeks to the first key frame before unit_target, in the range
|
||||
* [offset_begin, offset_end]. serial_nos contains an array of size serial_nos
|
||||
* of serialnos of the streams which need to be seeked.
|
||||
* Seeks to before the first key frame before unit_target, in the range
|
||||
* [offset_begin, offset_end].
|
||||
*/
|
||||
ogg_int64_t
|
||||
oggz_keyframe_seek_set(OGGZ * oggz,
|
||||
long* serial_nos,
|
||||
int num_serialno,
|
||||
ogg_int64_t unit_target,
|
||||
ogg_int64_t offset_begin,
|
||||
ogg_int64_t offset_end);
|
||||
|
@ -496,15 +496,13 @@ oggz_scan_for_page (OGGZ * oggz, ogg_page * og, ogg_int64_t unit_target,
|
||||
|
||||
#define GUESS_MULTIPLIER (1<<16)
|
||||
|
||||
static oggz_off_t
|
||||
static ogg_int64_t
|
||||
guess (ogg_int64_t unit_at, ogg_int64_t unit_target,
|
||||
ogg_int64_t unit_begin, ogg_int64_t unit_end,
|
||||
oggz_off_t offset_begin, oggz_off_t offset_end)
|
||||
ogg_int64_t offset_begin, ogg_int64_t offset_end)
|
||||
{
|
||||
ogg_int64_t guess_ratio;
|
||||
oggz_off_t offset_guess;
|
||||
|
||||
if (unit_at == unit_begin) return offset_begin;
|
||||
ogg_int64_t offset_guess;
|
||||
|
||||
if (unit_end != -1) {
|
||||
guess_ratio =
|
||||
@ -516,35 +514,33 @@ guess (ogg_int64_t unit_at, ogg_int64_t unit_target,
|
||||
(unit_at - unit_begin);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("oggz_seek::guess: guess_ratio %lld = (%lld - %lld) / (%lld - %lld)\n",
|
||||
guess_ratio, unit_target, unit_begin, unit_at, unit_begin);
|
||||
#endif
|
||||
|
||||
offset_guess = offset_begin +
|
||||
(oggz_off_t)(((offset_end - offset_begin) * guess_ratio) /
|
||||
(((offset_end - offset_begin) * guess_ratio) /
|
||||
GUESS_MULTIPLIER);
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("guess: [o=%lld t=%lld]-[o=%lld t=%lld] guess_ratio=%lf offset_guess=%lu\n",
|
||||
offset_begin, unit_begin, offset_end, unit_end,
|
||||
((double)guess_ratio / (double)GUESS_MULTIPLIER), offset_guess);
|
||||
#endif
|
||||
|
||||
return offset_guess;
|
||||
}
|
||||
|
||||
static oggz_off_t
|
||||
oggz_seek_guess (ogg_int64_t unit_at, ogg_int64_t unit_target,
|
||||
ogg_int64_t unit_begin, ogg_int64_t unit_end,
|
||||
oggz_off_t offset_at,
|
||||
oggz_off_t offset_begin, oggz_off_t offset_end)
|
||||
static ogg_int64_t
|
||||
oggz_seek_guess (ogg_int64_t unit_at,
|
||||
ogg_int64_t unit_target,
|
||||
ogg_int64_t unit_begin,
|
||||
ogg_int64_t unit_end,
|
||||
oggz_off_t offset_at,
|
||||
oggz_off_t offset_begin,
|
||||
oggz_off_t offset_end)
|
||||
{
|
||||
oggz_off_t offset_guess;
|
||||
|
||||
if (unit_at == unit_begin) {
|
||||
offset_guess = offset_begin + (offset_end - offset_begin)/2;
|
||||
} else if (unit_end == -1) {
|
||||
if (unit_end == -1) {
|
||||
offset_guess = guess (unit_at, unit_target, unit_begin, unit_end,
|
||||
offset_begin, offset_at);
|
||||
} else if (unit_end <= unit_begin) {
|
||||
#ifdef DEBUG
|
||||
printf ("oggz_seek_guess: unit_end <= unit_begin (ERROR)\n");
|
||||
#endif
|
||||
offset_guess = -1;
|
||||
} else {
|
||||
offset_guess = guess (unit_at, unit_target, unit_begin, unit_end,
|
||||
@ -622,11 +618,12 @@ ogg_int64_t
|
||||
oggz_bounded_seek_set (OGGZ * oggz,
|
||||
ogg_int64_t unit_target,
|
||||
ogg_int64_t offset_begin,
|
||||
ogg_int64_t offset_end)
|
||||
ogg_int64_t offset_end,
|
||||
int fuzz_margin)
|
||||
{
|
||||
OggzReader * reader;
|
||||
oggz_off_t offset_orig, offset_at, offset_guess;
|
||||
oggz_off_t offset_next;
|
||||
ogg_int64_t offset_orig, offset_at, offset_guess;
|
||||
ogg_int64_t offset_next;
|
||||
ogg_int64_t granule_at;
|
||||
ogg_int64_t unit_at, unit_begin = -1, unit_end = -1, unit_last_iter = -1;
|
||||
long serialno;
|
||||
@ -684,8 +681,10 @@ oggz_bounded_seek_set (OGGZ * oggz,
|
||||
}
|
||||
|
||||
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) {
|
||||
ogg_int64_t granulepos = 0;
|
||||
unit_begin = 0;
|
||||
// Start time needs to be the end time of the first non-header page.
|
||||
while (oggz_get_next_start_page (oggz, og) >= 0 && unit_begin <= 0) {
|
||||
serialno = ogg_page_serialno (og);
|
||||
granulepos = ogg_page_granulepos (og);
|
||||
unit_begin = oggz_get_unit (oggz, serialno, granulepos);
|
||||
@ -693,8 +692,9 @@ oggz_bounded_seek_set (OGGZ * oggz,
|
||||
}
|
||||
|
||||
/* Fail if target isn't in specified range. */
|
||||
if (unit_target < unit_begin || unit_target > unit_end)
|
||||
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) {
|
||||
@ -743,6 +743,11 @@ oggz_bounded_seek_set (OGGZ * oggz,
|
||||
|
||||
unit_at = oggz_get_unit (oggz, serialno, granule_at);
|
||||
|
||||
if (abs(unit_at - unit_target) < fuzz_margin) {
|
||||
// Within fuzz_margin of target, stop.
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("oggz_bounded_seek_set: offset_next %" PRI_OGGZ_OFF_T "d\n", offset_next);
|
||||
#endif
|
||||
@ -766,24 +771,7 @@ oggz_bounded_seek_set (OGGZ * oggz,
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
offset_at = oggz_get_prev_start_page (oggz, og, &granule_at, &serialno);
|
||||
if (offset_at < 0)
|
||||
break;
|
||||
unit_at = oggz_get_unit (oggz, serialno, granule_at);
|
||||
} while (unit_at > unit_target);
|
||||
|
||||
if (offset_at < 0) {
|
||||
oggz_reset (oggz, offset_orig, -1, SEEK_SET);
|
||||
return -1;
|
||||
}
|
||||
|
||||
offset_at = oggz_reset (oggz, offset_at, unit_at, SEEK_SET);
|
||||
if (offset_at == -1) return -1;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf ("oggz_bounded_seek_set: FOUND (%lld)\n", unit_at);
|
||||
#endif
|
||||
/* Reader is now approximately at the seek target. */
|
||||
|
||||
return (long)reader->current_unit;
|
||||
}
|
||||
@ -818,7 +806,7 @@ oggz_seek_end (OGGZ * oggz, ogg_int64_t unit_offset)
|
||||
unit_end, offset_end, granulepos);
|
||||
#endif
|
||||
|
||||
return oggz_bounded_seek_set (oggz, unit_end + unit_offset, 0, -1);
|
||||
return oggz_bounded_seek_set (oggz, unit_end + unit_offset, 0, -1, 0);
|
||||
}
|
||||
|
||||
off_t
|
||||
@ -877,11 +865,11 @@ oggz_seek_units (OGGZ * oggz, ogg_int64_t units, int whence)
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
r = oggz_bounded_seek_set (oggz, units, 0, -1);
|
||||
r = oggz_bounded_seek_set (oggz, units, 0, -1, 0);
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
units += reader->current_unit;
|
||||
r = oggz_bounded_seek_set (oggz, units, 0, -1);
|
||||
r = oggz_bounded_seek_set (oggz, units, 0, -1, 0);
|
||||
break;
|
||||
case SEEK_END:
|
||||
r = oggz_seek_end (oggz, units);
|
||||
@ -939,125 +927,65 @@ oggz_seek_packets (OGGZ * oggz, long serialno, long packets, int whence)
|
||||
|
||||
#endif
|
||||
|
||||
// Returns 1 if any of the elements of array |a|, which is of length |n|,
|
||||
// contain the value |val|. Otherwise returns 0.
|
||||
static int
|
||||
is_any(ogg_int64_t* a, int n, ogg_int64_t val)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<n; i++) {
|
||||
if (a[i] == val) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns the index of the element in array |a|, which is of length |n|,
|
||||
// which contains the value |val|, or -1 of it's not present.
|
||||
static int
|
||||
find(long* a, int n, ogg_int64_t val)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<n; i++) {
|
||||
if (a[i] == val) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Returns the element with the smallest value in array |a|, which is
|
||||
// of length |n|.
|
||||
// Returns the maximum time in milliseconds by which a key frame could be
|
||||
// offset for a given stream. Ogg granulepos encode time as:
|
||||
// ((key_frame_number << granule_shift) + frame_offset).
|
||||
// Therefore the maximum possible time by which any frame could be offset
|
||||
// from a keyframe is the duration of (1 << granule_shift) - 1) frames.
|
||||
static ogg_int64_t
|
||||
minimum(ogg_int64_t* a, int n) {
|
||||
ogg_int64_t m = 0x7FFFFFFFFFFFFFFF;
|
||||
int i;
|
||||
for (i=0; i<n; i++) {
|
||||
if (a[i] < m) {
|
||||
m = a[i];
|
||||
}
|
||||
get_keyframe_offset(oggz_stream_t* stream) {
|
||||
ogg_int64_t frame_duration;
|
||||
ogg_int64_t keyframe_diff;
|
||||
|
||||
if (stream->granuleshift == 0)
|
||||
return 0;
|
||||
|
||||
// Max number of frames keyframe could possibly be offset.
|
||||
keyframe_diff = (1 << stream->granuleshift) - 1;
|
||||
|
||||
// Length of frame in ms.
|
||||
frame_duration = stream->granulerate_d / stream->granulerate_n;
|
||||
|
||||
return frame_duration * keyframe_diff;
|
||||
}
|
||||
|
||||
// Returns the maximum possible time by which a keyframe could be offset in
|
||||
// milliseconds, for all streams in the media.
|
||||
static ogg_int64_t
|
||||
get_max_keyframe_offset(OGGZ* oggz) {
|
||||
int i=0, size = 0, max_gshift = 0;
|
||||
ogg_int64_t max = 0, x;
|
||||
oggz_stream_t* stream = 0;
|
||||
size = oggz_vector_size (oggz->streams);
|
||||
for (i = 0; i < size; i++) {
|
||||
stream = (oggz_stream_t *)oggz_vector_nth_p (oggz->streams, i);
|
||||
if (!stream) continue;
|
||||
x = get_keyframe_offset(stream);
|
||||
if (x > max)
|
||||
max = x;
|
||||
}
|
||||
return m;
|
||||
return max;
|
||||
}
|
||||
|
||||
ogg_int64_t
|
||||
oggz_keyframe_seek_set(OGGZ * oggz,
|
||||
long* serial_nos,
|
||||
int num_serialno,
|
||||
ogg_int64_t unit_target,
|
||||
ogg_int64_t offset_begin,
|
||||
ogg_int64_t offset_end)
|
||||
{
|
||||
oggz_off_t offset_at;
|
||||
oggz_off_t offset_next;
|
||||
ogg_int64_t granule_at;
|
||||
ogg_int64_t unit_at;
|
||||
ogg_int64_t key_granule_at, key_unit_at;
|
||||
long serialno;
|
||||
ogg_page * og;
|
||||
int granule_shift = 0, idx;
|
||||
ogg_int64_t* key_frames = 0;
|
||||
|
||||
ogg_int64_t max_keyframe_offset;
|
||||
const ogg_int64_t fuzz = 500;
|
||||
ogg_int64_t keyframe_unit_target;
|
||||
|
||||
max_keyframe_offset = get_max_keyframe_offset(oggz);
|
||||
|
||||
keyframe_unit_target = MAX(0, unit_target - max_keyframe_offset - fuzz);
|
||||
|
||||
unit_at = oggz_bounded_seek_set(oggz,
|
||||
unit_target,
|
||||
keyframe_unit_target,
|
||||
offset_begin,
|
||||
offset_end);
|
||||
// Time isn't in the specified offset range, fail.
|
||||
if (unit_at == -1)
|
||||
return -1;
|
||||
|
||||
// We've seeked to beginning, we're at a key frame.
|
||||
if (unit_at == 0)
|
||||
return 0;
|
||||
|
||||
// Backup this, in case we need to fail.
|
||||
offset_at = oggz->offset;
|
||||
|
||||
key_frames = oggz_malloc(sizeof(ogg_int64_t) * num_serialno);
|
||||
if (!key_frames) {
|
||||
// Malloc failure. We can still exit with the seek finishing at a non
|
||||
// key frame.
|
||||
return unit_at;
|
||||
}
|
||||
memset(key_frames, -1, sizeof(ogg_int64_t) * num_serialno);
|
||||
|
||||
// Find the key frame offset for every stream.
|
||||
og = &oggz->current_page;
|
||||
while (is_any(key_frames, num_serialno, -1)) {
|
||||
do {
|
||||
offset_next = oggz_get_prev_start_page (oggz, og, &granule_at, &serialno);
|
||||
if (offset_next <= 0 || granule_at == 0) {
|
||||
// At beginning of file, or some other failure. Return with
|
||||
// non-key frame seek if possible.
|
||||
oggz_free(key_frames);
|
||||
offset_at = oggz_reset (oggz, offset_at, unit_at, SEEK_SET);
|
||||
return (offset_at == -1) ? -1 : unit_at;
|
||||
}
|
||||
} while (granule_at < 0);
|
||||
|
||||
idx = find(serial_nos, num_serialno, serialno);
|
||||
if (idx == -1 || key_frames[idx] != -1)
|
||||
continue;
|
||||
|
||||
granule_shift = oggz_get_granuleshift(oggz, serialno);
|
||||
key_granule_at = (granule_at >> granule_shift) << granule_shift;
|
||||
key_unit_at = oggz_get_unit(oggz, serialno, key_granule_at);
|
||||
|
||||
if (key_unit_at < unit_target)
|
||||
key_frames[idx] = key_unit_at;
|
||||
}
|
||||
|
||||
// Seek to 100ms before the earliest of all the streams' key frames.
|
||||
// This is so that after the seek, the decoder will defintately return frames
|
||||
// at or before get the key frame. Without this, some decoders will return
|
||||
// frames which start after the specified time - after the key frame.
|
||||
key_unit_at = minimum(key_frames, num_serialno);
|
||||
unit_at = oggz_bounded_seek_set(oggz,
|
||||
MAX((key_unit_at - 100), 0),
|
||||
offset_begin,
|
||||
offset_end);
|
||||
oggz_free(key_frames);
|
||||
|
||||
offset_end,
|
||||
fuzz);
|
||||
return unit_at;
|
||||
}
|
||||
|
@ -57,3 +57,4 @@ patch -p3 <offset_next.patch
|
||||
patch -p3 <bug487519.patch
|
||||
patch -p3 <bug496063.patch
|
||||
patch -p3 <oggz_os2.patch
|
||||
patch -p3 <faster_seek.patch
|
||||
|
Loading…
Reference in New Issue
Block a user