[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