[NUT-devel] [nut]: r230 - trunk/libnut/demuxer.c
ods15
subversion at mplayerhq.hu
Sat Nov 18 11:17:08 CET 2006
Author: ods15
Date: Sat Nov 18 11:17:08 2006
New Revision: 230
Modified:
trunk/libnut/demuxer.c
Log:
Make find_main_headers() search at 2^n positions and from EOF
Make first syncpoint be read right at the begginning
Modified: trunk/libnut/demuxer.c
==============================================================================
--- trunk/libnut/demuxer.c (original)
+++ trunk/libnut/demuxer.c Sat Nov 18 11:17:08 2006
@@ -553,7 +553,7 @@
CHECK(add_syncpoint(nut, s, pts, eor, &i));
nut->syncpoints.s[i - 1].seen_next = 1;
}
- } else if (!nut->syncpoints.len || nut->dopts.cache_syncpoints) {
+ } else if (nut->dopts.cache_syncpoints) { // we're seeking, we need syncpoint cache
int i;
CHECK(add_syncpoint(nut, s, NULL, NULL, &i));
if (!after_seek) nut->syncpoints.s[i - 1].seen_next = 1;
@@ -758,24 +758,54 @@
static int find_main_headers(nut_context_t * nut) {
int err = 0;
uint64_t tmp;
- off_t start = bctello(nut->i);
- if (start < strlen(ID_STRING) + 1) {
- int n = strlen(ID_STRING) + 1 - start;
- ERROR(ready_read_buf(nut->i, n) < n, buf_eof(nut->i));
- if (memcmp(get_buf(nut->i, start), ID_STRING + start, n)) nut->i->buf_ptr = nut->i->buf; // rewind
- else fprintf(stderr, "NUT file_id checks out\n");
- }
+ int read_data = 512*1024;
+
+ // don't waste cpu by running this check every damn time for EAGAIN
+ // Except for the first time, to not waste memory
+ if (!nut->seek_status && ready_read_buf(nut->i, read_data) < read_data && buf_eof(nut->i) == NUT_ERR_EAGAIN)
+ return NUT_ERR_EAGAIN;
CHECK(get_bytes(nut->i, 7, &tmp));
- ERROR(ready_read_buf(nut->i, 4096) < 4096, buf_eof(nut->i));
- while (bctello(nut->i) < 4096) {
+ read_data -= 7;
+ while (read_data--) {
+ ERROR(ready_read_buf(nut->i, 30) < 1, buf_eof(nut->i));
tmp = (tmp << 8) | *(nut->i->buf_ptr++);
if (tmp == MAIN_STARTCODE) break;
+ // give up if we reach a syncpoint, unless we're searching the file end
+ if (tmp == SYNCPOINT_STARTCODE && nut->seek_status != 18) break;
}
- ERROR(tmp != MAIN_STARTCODE, NUT_ERR_NO_HEADERS);
- nut->i->buf_ptr -= 8;
- nut->last_headers = bctello(nut->i);
- flush_buf(nut->i);
+ if (tmp == MAIN_STARTCODE) {
+ off_t pos = bctello(nut->i) - 8;
+ // load all headers into memory so they can be cleanly decoded without EAGAIN issues
+ // also check validity of the headers we just found
+ do {
+ if ((err = get_header(nut->i, NULL)) == NUT_ERR_EAGAIN) goto err_out;
+ if (err) { tmp = err = 0; break; } // bad
+
+ if ((err = get_bytes(nut->i, 8, &tmp)) == NUT_ERR_EAGAIN) goto err_out;
+ assert(!err || err == NUT_ERR_EOF); // the only possibilities
+ // EOF is a legal error here - when reading the last headers in file
+ if (err == NUT_ERR_EOF) { err = 0; tmp = SYNCPOINT_STARTCODE; }
+ } while (tmp != SYNCPOINT_STARTCODE);
+ if (tmp == SYNCPOINT_STARTCODE) { // success!
+ nut->last_headers = pos;
+ nut->i->buf_ptr = get_buf(nut->i, nut->last_headers);
+ flush_buf(nut->i);
+ return 0;
+ }
+ }
+
+ // failure
+ if (!nut->i->isc.seek) return NUT_ERR_NO_HEADERS;
+ if (!nut->seek_status) {
+ nut->seek_status = 18; // start search at 512kb
+ // but first, let's check EOF
+ seek_buf(nut->i, -512*1024, SEEK_END);
+ return find_main_headers(nut);
+ }
+ seek_buf(nut->i, 1 << ++nut->seek_status, SEEK_SET);
+ // evantually we'll hit EOF and give up
+ return find_main_headers(nut);
err_out:
return err;
}
@@ -841,8 +871,6 @@
int nut_read_next_packet(nut_context_t * nut, nut_packet_t * pd) {
int err = 0;
- ERROR(!nut->last_headers, NUT_ERR_NO_HEADERS); // paranoia, old API
-
if (nut->seek_status) { // in error mode!
syncpoint_t s;
CHECK(find_syncpoint(nut, 0, &s, 0));
@@ -874,15 +902,10 @@
int nut_read_headers(nut_context_t * nut, nut_stream_header_t * s [], nut_info_packet_t * info []) {
int i, err = 0;
uint64_t tmp;
+ syncpoint_t sp;
if (!nut->sc) { // we already have headers, we were called just for index
if (!nut->last_headers) CHECK(find_main_headers(nut));
- // load all headers into memory so they can be cleanly decoded without EAGAIN issues
- // FIXME deal with errors and such
- CHECK(skip_reserved_headers(nut, SYNCPOINT_STARTCODE));
-
- // rewind to where the headers were found
- nut->i->buf_ptr = get_buf(nut->i, nut->last_headers);
CHECK(get_headers(nut, !!info));
if (nut->dopts.read_index) { // check for index right after main headers
@@ -919,9 +942,17 @@
nut->before_seek = 0;
}
- if ((err = skip_reserved_headers(nut, SYNCPOINT_STARTCODE)) == NUT_ERR_EAGAIN) goto err_out;
- nut->seek_status = !!err; // enter error mode if we're not at a syncpoint
- err = 0;
+ // last step - find the first syncpoint in file
+ if (nut->last_headers > 1024 && !nut->seek_status) {
+ // the headers weren't found in begginning of file
+ assert(nut->i->isc.seek);
+ seek_buf(nut->i, 0, SEEK_SET);
+ nut->seek_status = 1;
+ }
+ CHECK(find_syncpoint(nut, 0, &sp, 0));
+ CHECK(add_syncpoint(nut, sp, NULL, NULL, NULL));
+ nut->i->buf_ptr = get_buf(nut->i, sp.pos); // rewind to the syncpoint, this is where playback starts...
+ nut->seek_status = 0;
SAFE_CALLOC(nut->alloc, *s, sizeof(nut_stream_header_t), nut->stream_count + 1);
for (i = 0; i < nut->stream_count; i++) (*s)[i] = nut->sc[i].sh;
@@ -958,14 +989,7 @@
syncpoint_list_t * sl = &nut->syncpoints;
syncpoint_t s;
- if (!sl->len) { // not even a single syncpoint, find first one.
- // the first syncpoint put in the cache is always always the BEGIN syncpoint
- if (!nut->seek_status) seek_buf(nut->i, 0, SEEK_SET);
- nut->seek_status = 1;
- CHECK(find_syncpoint(nut, 0, &s, 0));
- CHECK(add_syncpoint(nut, s, NULL, NULL, NULL));
- nut->seek_status = 0;
- }
+ assert(sl->len); // it is impossible for the first syncpoint to not have been read
// find last syncpoint if it's not already found
if (!sl->s[sl->len-1].seen_next) {
@@ -1008,8 +1032,7 @@
goto err_out;
}
if (i == 0) { // there isn't any syncpoint smaller than requested
- if (sl->s[0].pts) seek_buf(nut->i, sl->s[0].pos, SEEK_SET);
- else seek_buf(nut->i, nut->last_headers, SEEK_SET); // seeking to "begginning of file", the headers
+ seek_buf(nut->i, sl->s[0].pos, SEEK_SET); // seek to first syncpoint
clear_dts_cache(nut);
nut->last_syncpoint = 0;
goto err_out;
More information about the NUT-devel
mailing list