[xiph-cvs] cvs commit: ogg-tools/oggmerge mng.c

Ralph Giles giles at xiph.org
Sun Jun 22 14:39:10 PDT 2003



giles       03/06/22 17:39:10

  Modified:    oggmerge mng.c
  Log:
  Work to complete mng import module for oggmerge. Mostly works now.

Revision  Changes    Path
1.2       +187 -72   ogg-tools/oggmerge/mng.c

Index: mng.c
===================================================================
RCS file: /usr/local/cvsroot/ogg-tools/oggmerge/mng.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- mng.c	15 Oct 2001 07:10:02 -0000	1.1
+++ mng.c	22 Jun 2003 21:39:10 -0000	1.2
@@ -5,15 +5,15 @@
         mng.c
         oggmerge mng module
 
-	Copyright 2001 Ralph Giles <Ralph_Giles at telus.net>
+	Copyright 2001-2003 Ralph Giles <giles at xiph.org>
 
         Distributed under the GPL
         see the file COPYING for details
         or visit http://www.gnu.org/copyleft/gpl.html
 */
 
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 
@@ -31,11 +31,39 @@
 #define MNG_UINT_MHDR 0x4d484452L
 #define MNG_UINT_MEND 0x4d454e44L
 
+#define MIN(x,y) (((x)<(y)) ? (x) : (y))
+#define MAX(x,y) (((x)>(y)) ? (x) : (y))
+
+/* chunk access functions */
+ogg_uint32_t mngchunk_length(const unsigned char *chunk)
+{
+	int length;
+
+	length = ( ((chunk)[0]&0xFF) << 24 |
+                   ((chunk)[1]&0xFF) << 16 |
+                   ((chunk)[2]&0xFF) << 8 |
+                   ((chunk)[3]&0xFF) );
+
+	return length;
+}
+ogg_uint32_t mngchunk_type(const unsigned char *chunk)
+{
+	ogg_uint32_t type;
+
+	type = ( ((chunk)[4]&0xFF) << 24 |
+                 ((chunk)[5]&0xFF) << 16 |
+                 ((chunk)[6]&0xFF) << 8 |
+                 ((chunk)[7]&0xFF) );
+
+	return type;
+}
+
 typedef struct {
         ogg_stream_state	*os;
         int			serialno;
         u_int64_t		packetno;
         unsigned char		*chunk;
+	unsigned long		length;
 } mng_state_t;
 
 /* allocates and initializes local storage for a particular
@@ -60,7 +88,8 @@
                 local->serialno = serialno;
                 local->packetno = 0;	/* number of 'next' packet */
                 local->chunk = NULL;
-
+		local->length = 0;
+		
                 /* save our local data inside the oggmerge state */
                 state->private = local;
 
@@ -93,6 +122,39 @@
         return 0;	/* success */
 }
 
+/* read out a chunk type from a buffer into a string */
+static int mngchunk_type2string(char *name, ogg_uint32_t type)
+{
+	/* parse the chunk type code */
+	name[0] = (char)((type >> 24) & 0xFF);
+	name[1] = (char)((type >> 16) & 0xFF);
+	name[2] = (char)((type >>  8) & 0xFF);
+	name[3] = (char)((type      ) & 0xFF);
+	name[4] = '\0';
+	
+	return 0;
+}
+
+/* copy a mng chunk into an ogg bitstream packet */
+int mngchunk_packet(ogg_packet *op, unsigned char *chunk)
+{
+	ogg_int32_t length,type,crc;
+	char name[5];
+
+	length = mngchunk_length(chunk);
+	type = mngchunk_type(chunk);
+	mngchunk_type2string(name, type);
+	fprintf(stderr, "  processing '%s' chunk (%d bytes)\n",
+		name, length);
+
+	op->packet = chunk;
+	op->bytes = 12 + length;
+	op->b_o_s = (type == MNG_UINT_MHDR) ? 1 : 0;
+	op->e_o_s = (type == MNG_UINT_MEND) ? 1 : 0;
+
+	return 0;
+}
+
 /* accepts a buffer of input data (raw mng bytestream)
  * the buffer must be completely consumed before returning
  *
@@ -103,86 +165,148 @@
         mng_state_t	*mngstate;
         ogg_packet	op;
 
-	if (state == NULL || buffer == NULL || size <= 0) return;
-
+	if (state == NULL || buffer == NULL) return;
         mngstate = (mng_state_t*)state->private;
         
-	/* are we looking for the signature? */
+	/* are we looking for the header? */
         if (mngstate->packetno == 0) {
-		char	sig[9];
-
+		int length, type;
+		
+		/* check the signature */
                 if (size < 8) {
                         fprintf(stderr, "oggmng: mng_data_in() must get at least 8 bytes on the first submission to check the signature.\n");
                         exit(1);
                 }
-		memcpy(sig, buffer, 8);
-		sig[8] = '\0';
-		if (strncmp((const char *)sig, MNG_SIGNATURE, 8) != 0) {
+		if (memcmp(buffer, MNG_SIGNATURE, 8)) {
+			fprintf(stderr, "oggmng: file signature didn't match!\n");
                         return EBADHEADER;
                 }
-		
                 fprintf(stderr, "oggmng: found mng signature\n");
                 
-		/* the first packet is always just the mng signature */
+		/* check the MHDR -- TODO: should buffer instead */
+		if (size < 8 + 12 + 28) {
+			fprintf(stderr, "oggmng: mng_data_in() must get at least the complete MHDR chunk in the first submission.\n");
+			exit(1);
+		}
+		length = mngchunk_length(buffer + 8);
+		type = mngchunk_type(buffer + 8);
+		if (type != MNG_UINT_MHDR) {
+			return EBADHEADER;
+		}
+		if (length != 28) {
+			fprintf(stderr, "oggmng: MHDR length doesn't match spec!\n");
+			return EBADHEADER;
+		}
+		fprintf(stderr, "oggmng: found MHDR\n");
+		
+		/* the first packet is always the mng signature and MHDR chunk */
                 op.packet = buffer;
-		op.bytes = 8;
+		op.bytes = 8 + 12 + length;
                 op.b_o_s = 1;
                 op.e_o_s = 0;
                 op.packetno = 0;
-		/* submit it */
                 ogg_stream_packetin(mngstate->os, &op);
                 mngstate->packetno++;
-		buffer += 8;
-		size -= 8;
+		buffer += 8 + 12 + length;
+		size -= 8 + 12 + length;
         }
 
         /* are we continuing a previous chunk? */
         if (mngstate->chunk != NULL) {
-		fprintf(stderr, "sorry, unimplemented section\n");
-		return EBADEVENT;
+		unsigned char *chunk = mngstate->chunk;
+		int length = mngstate->length;
+		int needed = mngchunk_length(chunk) + 12 - length;
+		int copybytes = MIN(needed,size);
+		fprintf(stderr, "adding %d bytes to chunk buffer\n", copybytes);
+		fprintf(stderr, "  buffer offset %d and %d bytes needed\n",
+			length, needed);
+		memcpy(chunk + length, buffer, copybytes);
+		if (copybytes == needed) {
+			mngchunk_packet(&op, chunk);
+			op.packetno = mngstate->packetno++;
+			ogg_stream_packetin(mngstate->os, &op);
+			mngstate->chunk = NULL; /* ogg takes ownership */
+			mngstate->length = 0;
+		}
+		buffer += copybytes;
+		size -= copybytes;
         }
 
         /* data should be pointing to the beginning of a chunk */
         while (size > 0) {
-		char    lenb[4],typeb[4],crcb[4];
                 char    name[5];
                 int     length,type,crc;
                 int	copybytes;
 
-		/* read the get the length and type */
-		length = (buffer[0]&0xFF) << 24 | 
-                        (buffer[1]&0xFF) << 16 |
-                        (buffer[2]&0xFF) << 8 |
-                        (buffer[3]&0xFF);
-		memcpy(name, buffer+4, 4);
-		name[4] = '\0';
-
-		/* should check crc here */
-
-		fprintf(stderr, "oggmng: found '%s' chunk (%d bytes)\n", name, length);
-
-		/* copy the chunk into an ogg packet */
-		op.bytes = length + 12;
-		op.packet = (unsigned char *)malloc(op.bytes);
-		if (op.packet == NULL) return EMALLOC;
-		op.b_o_s = 0;	/* should be the second packet in the header page */
-		op.e_o_s = ( (unsigned int)*(buffer+4) == MNG_UINT_MEND) ? 1 : 0;
-		copybytes = (length + 12 < size) ? length + 12 : size;
-		memcpy(op.packet, buffer, copybytes);
+		if (size < 8) {	/* partial chunk header */
+			fprintf(stderr, "sorry, unimplemented section\n");
+			return EBADEVENT;
+		}
+		
+		/* get the length and type */
+		length = mngchunk_length(buffer);
+		type = mngchunk_type(buffer);
+		mngchunk_type2string(name, type);
+		/* allocate storage for the next chunk */
+		fprintf(stderr, "allocating storage for '%s' chunk (%d bytes)\n",
+			name, length + 12);
+		mngstate->chunk = malloc(length + 12);
+		if (mngstate->chunk == NULL) {
+			fprintf(stderr, "oggmng: failed to allocate chunk storage!\n");
+			return EBADEVENT;
+		}
+		copybytes = MIN(size, length + 12);
+		memcpy(mngstate->chunk, buffer, copybytes);
+		mngstate->length = copybytes;
+		size -= copybytes;
                 buffer += copybytes;
-		if (size < length + 12) {
-			/* save state here */
+		fprintf(stderr, "copied %d bytes to the chunk buffer\n", copybytes);
+
+		if (copybytes == length + 12) {
+			/* should check crc here */
+			/* submit */
+			fprintf(stderr, "submitting chunk for packetization (packet %d)\n", mngstate->packetno);
+			mngchunk_packet(&op, mngstate->chunk);
+			op.packetno = mngstate->packetno++;
+			ogg_stream_packetin(mngstate->os, &op);
+			mngstate->length = 0;
+			free(mngstate->chunk);
+			mngstate->chunk = NULL;
+		} else {
                         return EMOREDATA;
                 }
-		size -= copybytes;
-		/* submit */
-		op.packetno = mngstate->packetno++;
-		ogg_stream_packetin(mngstate->os, &op);
+
         }
 
         return 0;	/* success */
 }
 
+static ogg_page *_copy_ogg_page(ogg_page *og)
+{
+        ogg_page *page;
+ 
+        page = (ogg_page *)malloc(sizeof(ogg_page));
+        if (page == NULL) return NULL;
+ 
+        page->header_len = og->header_len;
+        page->body_len = og->body_len;
+        page->header = (unsigned char *)malloc(page->header_len);
+        if (page->header == NULL) {
+                free(page);
+                return NULL;
+        }
+        memcpy(page->header, og->header, page->header_len);
+        page->body = (unsigned char *)malloc(page->body_len);
+        if (page->body == NULL) {
+                free(page->header);
+                free(page);
+                return NULL;
+        }
+        memcpy(page->body, og->body, page->body_len);
+
+        return page;
+}
+
 /* returns an completed oggmerge_page created from the data previously
  * passed through mng_data_in()
  *
@@ -190,32 +314,23 @@
  */
 oggmerge_page_t *mng_page_out(oggmerge_state_t *state)
 {
-	return NULL;
-}
-
-/* copy a mng chunk into an ogg bitstream packet */
-ogg_packet *mngchunk_ogg(char *chunk)
-{
-	ogg_packet *packet = NULL;
-	int32_t chunktype;
-	int32_t length,crc;
-	char chunkname[5];
+	mng_state_t *mngstate;
+	ogg_page og;
+	oggmerge_page_t *om;
 
-	/* parse the chunk type code */
-	chunkname[0] = (char)((chunktype >> 24) & 0xFF);
-	chunkname[1] = (char)((chunktype >> 16) & 0xFF);
-	chunkname[2] = (char)((chunktype >>  8) & 0xFF);
-	chunkname[3] = (char)((chunktype      ) & 0xFF);
-	chunkname[4] = '\0';
-
-	fprintf(stderr, "  processing '%s' chunk\n", chunkname);
-
-	packet = (ogg_packet*)malloc(sizeof(ogg_packet));
-	packet->packet = chunk;
-
-	packet->b_o_s = (chunktype == MNG_UINT_MHDR) ? 1 : 0;
-	packet->e_o_s = (chunktype == MNG_UINT_MEND) ? 1 : 0;
+	if (state == NULL) return;
+	mngstate = (mng_state_t*)state->private;
 
-	return packet;
+	om = malloc(sizeof(oggmerge_page_t));
+	om->og = malloc(sizeof(ogg_page));
+	if(ogg_stream_pageout(mngstate->os, &og)==0) {
+		free(om);
+		om = NULL;
+	} else {
+		om->og = _copy_ogg_page(&og);
+		om->timestamp = mngstate->packetno;
+		fprintf(stderr, "oggmng: returning page with timestamp %ld\n",om->timestamp);
+	}
+	
+	return om;
 }
-

<p><p>--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list