[xiph-commits] r14548 - trunk/vorbis-tools/vcut

ivo at svn.xiph.org ivo at svn.xiph.org
Sat Mar 1 11:14:04 PST 2008


Author: ivo
Date: 2008-03-01 11:14:03 -0800 (Sat, 01 Mar 2008)
New Revision: 14548

Modified:
   trunk/vorbis-tools/vcut/vcut.c
   trunk/vorbis-tools/vcut/vcut.h
Log:
Committing large patch by Michael Gold.  It fixes three issues pointed out in http://article.gmane.org/gmane.comp.multimedia.ogg.vorbis.devel/4293

Modified: trunk/vorbis-tools/vcut/vcut.c
===================================================================
--- trunk/vorbis-tools/vcut/vcut.c	2008-02-29 07:58:43 UTC (rev 14547)
+++ trunk/vorbis-tools/vcut/vcut.c	2008-03-01 19:14:03 UTC (rev 14548)
@@ -125,7 +125,7 @@
 	int eos=0;
 	ogg_page page;
 	ogg_packet packet;
-	ogg_int64_t granpos, prevgranpos;
+	ogg_int64_t granpos, prevgranpos = -1;
 	int result;
 
 	while(!eos)
@@ -154,6 +154,9 @@
 							fprintf(stderr, _("Bitstream error, continuing\n"));
 						else
 						{
+							if(packet.e_o_s)
+								s->e_o_s=1;
+
 							/* We need to save the last packet in the first
 							 * stream - but we don't know when we're going
 							 * to get there. So we have to keep every packet
@@ -164,7 +167,19 @@
 							s->packets[0] = save_packet(&packet);
 
 							ogg_stream_packetin(stream, &packet);
-							if(write_pages_to_file(stream, f,0))
+
+							/* Flush the stream after the second audio
+							 * packet, which is necessary if we need the
+							 * decoder to discard some samples from the
+							 * beginning of this packet.
+							 */
+							if(packet.packetno == 4
+									&& packet.granulepos != -1)
+							{
+								if(write_pages_to_file(stream, f,1))
+									return -1;
+							}
+							else if(write_pages_to_file(stream, f,0))
 								return -1;
 						}
 					}
@@ -174,7 +189,7 @@
 					eos=1; /* First stream ends somewhere in this page.
 							  We break of out this loop here. */
 
-				if(ogg_page_eos(&page))
+				if(ogg_page_eos(&page) && !eos)
 				{
 					fprintf(stderr, _("Found EOS before cut point.\n"));
 					eos=1;
@@ -204,11 +219,30 @@
 	while((result = ogg_stream_packetout(s->stream_in, &packet))!=0)
 	{
 		int bs;
-		
+
+		if(packet.e_o_s)
+			s->e_o_s=1;
 		bs = get_blocksize(s, s->vi, &packet);
-		prevgranpos += bs;
+		if(prevgranpos == -1)
+		{
+			/* this is the first audio packet; the second one normally
+			 * starts at position 0 */
+			prevgranpos = 0;
+		}
+		else if(prevgranpos == 0 && !packet.e_o_s)
+		{
+			/* the second packet; if our calculated granule position is
+			 * greater than granpos, it means some audio samples must be
+			 * discarded from the beginning when decoding (in this case,
+			 * the Vorbis I spec. requires that this is the last packet
+			 * on its page) */
+			prevgranpos = bs;
+			if(prevgranpos > granpos)
+				prevgranpos = granpos;
+		}
+		else prevgranpos += bs;
 
-		if(prevgranpos > s->cutpoint)
+		if(prevgranpos >= s->cutpoint && s->packets[0])
 		{
 			s->packets[1] = save_packet(&packet);
 			packet.granulepos = s->cutpoint; /* Set it! This 'truncates' the 
@@ -235,6 +269,7 @@
 	if(write_pages_to_file(stream,f, 0))
 		return -1;
 
+	s->pagegranpos = granpos;
 	/* Remaining samples in first packet */
 	s->initialgranpos = prevgranpos - s->cutpoint; 
 
@@ -254,7 +289,7 @@
 {
 	ogg_packet packet;
 	ogg_page page;
-	int eos=0;
+	int eos=s->e_o_s;
 	int result;
 	ogg_int64_t page_granpos, current_granpos=s->initialgranpos;
 	ogg_int64_t packetnum=0; /* Should this start from 0 or 3 ? */
@@ -262,19 +297,35 @@
 	packet.bytes = s->packets[0]->length;
 	packet.packet = s->packets[0]->packet;
 	packet.b_o_s = 0;
-	packet.e_o_s = 0;
+	packet.e_o_s = eos;
 	packet.granulepos = 0;
 	packet.packetno = packetnum++; 
 	ogg_stream_packetin(stream,&packet);
 
-	packet.bytes = s->packets[1]->length;
-	packet.packet = s->packets[1]->packet;
-	packet.b_o_s = 0;
-	packet.e_o_s = 0;
-	packet.granulepos = s->initialgranpos;
-	packet.packetno = packetnum++;
-	ogg_stream_packetin(stream,&packet);
+	if(eos)
+	{
+		/* Don't write the second file. Normally, we set the granulepos
+		 * of its second audio packet so audio samples will be discarded
+		 * from the beginning when decoding; but if that's also the last
+		 * packet, the samples will be discarded from the end instead,
+		 * which would corrupt the audio. */
 
+		/* We'll still consider this a success; even if we could create
+		 * such a short file, it would probably be useless. */
+		fprintf(stderr, _("Cutpoint too close to end of file."
+				" Second file will be empty.\n"));
+	}
+	else
+	{
+		packet.bytes = s->packets[1]->length;
+		packet.packet = s->packets[1]->packet;
+		packet.b_o_s = 0;
+		packet.e_o_s = 0;
+		packet.granulepos = s->initialgranpos;
+		packet.packetno = packetnum++;
+		ogg_stream_packetin(stream,&packet);
+	}
+
 	if(ogg_stream_flush(stream, &page)!=0)
 	{
 		fwrite(page.header,1,page.header_len,f);
@@ -293,54 +344,55 @@
 		fwrite(page.body,1,page.body_len,f);
 	}
 
+	page_granpos = s->pagegranpos - s->cutpoint;
 	while(!eos)
 	{
-		while(!eos)
+		result = ogg_stream_packetout(s->stream_in, &packet);
+		if(result==0)  /* another page is needed */
 		{
-			result=ogg_sync_pageout(s->sync_in, &page);
-			if(result==0) break;
-			else if(result==-1)
-				fprintf(stderr, _("Recoverable bitstream error\n"));
-			else
+			while(!eos)
 			{
-				page_granpos = ogg_page_granulepos(&page) - s->cutpoint;
-				if(ogg_page_eos(&page))eos=1;
-				ogg_stream_pagein(s->stream_in, &page);
-				while(1)
+				result=ogg_sync_pageout(s->sync_in, &page);
+				if(result==0)  /* need more data */
 				{
-					result = ogg_stream_packetout(s->stream_in, &packet);
-					if(result==0) break;
-					else if(result==-1) fprintf(stderr, _("Bitstream error\n"));
-					else
+					if(update_sync(s, in)==0)
 					{
-						int bs = get_blocksize(s, s->vi, &packet);
-						current_granpos += bs;
-						if(current_granpos > page_granpos)
-						{
-							current_granpos = page_granpos;
-						}
-
-						packet.granulepos = current_granpos;
-						packet.packetno = packetnum++;
-						ogg_stream_packetin(stream, &packet);
-						if(write_pages_to_file(stream,f, 0))
-							return -1;
+						fprintf(stderr,
+							_("Update sync returned 0, setting eos\n"));
+						eos=1;
 					}
 				}
+				else if(result==-1)
+					fprintf(stderr, _("Recoverable bitstream error\n"));
+				else  /* got a page */
+				{
+					ogg_stream_pagein(s->stream_in, &page);
+					page_granpos = ogg_page_granulepos(&page)-s->cutpoint;
+					break;
+				}
 			}
 		}
-		if(!eos)
+		else if(result==-1) fprintf(stderr, _("Bitstream error\n"));
+		else  /* got a packet */
 		{
-			if(update_sync(s, in)==0)
+			int bs = get_blocksize(s, s->vi, &packet);
+			current_granpos += bs;
+			if(current_granpos > page_granpos)
 			{
-				fprintf(stderr, _("Update sync returned 0, setting eos\n"));
-				eos=1;
+				current_granpos = page_granpos;
 			}
+
+			if(packet.e_o_s) eos=1;
+			packet.granulepos = current_granpos;
+			packet.packetno = packetnum++;
+			ogg_stream_packetin(stream, &packet);
+			if(write_pages_to_file(stream,f, 0))
+				return -1;
 		}
 	}
 
 	return 0;
-}			
+}
 
 static void submit_headers_to_stream(ogg_stream_state *stream, vcut_state *s) 
 {
@@ -357,7 +409,7 @@
 		ogg_stream_packetin(stream, &p);
 	}
 }
-									
+
 /* Pull out and save the 3 header packets from the input file.
  * If the cutpoint arg was given as seconds, find the number
  * of samples.

Modified: trunk/vorbis-tools/vcut/vcut.h
===================================================================
--- trunk/vorbis-tools/vcut/vcut.h	2008-02-29 07:58:43 UTC (rev 14547)
+++ trunk/vorbis-tools/vcut/vcut.h	2008-03-01 19:14:03 UTC (rev 14548)
@@ -18,6 +18,8 @@
 	vorbis_info *vi;
 	int prevW;
 	ogg_int64_t initialgranpos;
+	ogg_int64_t pagegranpos;
+	int e_o_s;
 	int time;
 	ogg_int64_t cutpoint;
 	unsigned int serial;



More information about the commits mailing list