[xiph-commits] r15518 - in trunk/vorbis-tools: . vcut
ivo at svn.xiph.org
ivo at svn.xiph.org
Mon Nov 10 14:10:02 PST 2008
Author: ivo
Date: 2008-11-10 14:10:00 -0800 (Mon, 10 Nov 2008)
New Revision: 15518
Modified:
trunk/vorbis-tools/AUTHORS
trunk/vorbis-tools/vcut/vcut.c
trunk/vorbis-tools/vcut/vcut.h
Log:
Flush stream after the third header packet, and delay the writing of the reference packet to avoid writing out a stream and ending it on granulepos 0. Patches for vcut by Michael Gold.
Modified: trunk/vorbis-tools/AUTHORS
===================================================================
--- trunk/vorbis-tools/AUTHORS 2008-11-10 17:40:17 UTC (rev 15517)
+++ trunk/vorbis-tools/AUTHORS 2008-11-10 22:10:00 UTC (rev 15518)
@@ -14,8 +14,9 @@
vcut:
Michael Smith <msmith at xiph.org>
+Michael Gold <mgold at ncf.ca>
vorbiscomment:
Michael Smith <msmith at xiph.org>
-and the rest of the Xiph.Org Foundation.
+and the rest of the Xiph.Org Foundation and its contributors.
\ No newline at end of file
Modified: trunk/vorbis-tools/vcut/vcut.c
===================================================================
--- trunk/vorbis-tools/vcut/vcut.c 2008-11-10 17:40:17 UTC (rev 15517)
+++ trunk/vorbis-tools/vcut/vcut.c 2008-11-10 22:10:00 UTC (rev 15518)
@@ -2,6 +2,7 @@
* a copy of which is included with this program.
*
* (c) 2000-2001 Michael Smith <msmith at xiph.org>
+ * (c) 2008 Michael Gold <mgold at ncf.ca>
*
*
* Simple application to cut an ogg at a specified frame, and produce two
@@ -158,46 +159,49 @@
return -1;
s->out = NULL;
- if(!s->drop_output && fclose(out) != 0)
+ if(out && fclose(out) != 0)
{
fprintf(stderr, _("Couldn't close output file\n"));
return -1;
}
+ s->output_filename = NULL;
s->drop_output = 0;
return 0;
}
-static void submit_headers_to_stream(vcut_state *s)
+/* Write out the header packets and reference audio packet. */
+static int submit_headers_to_stream(vcut_state *s)
{
vcut_vorbis_stream *vs = &s->vorbis_stream;
int i;
- for(i=0;i<3;i++)
+ for(i=0;i<4;i++)
{
ogg_packet p;
- p.bytes = vs->headers[i].length;
- p.packet = vs->headers[i].packet;
+ if(i < 4) /* a header packet */
+ {
+ p.bytes = vs->headers[i].length;
+ p.packet = vs->headers[i].packet;
+ }
+ else /* the reference audio packet */
+ {
+ if (!vs->last_packet.packet) break;
+ p.bytes = vs->last_packet.length;
+ p.packet = vs->last_packet.packet;
+ }
+
assert(p.packet);
p.b_o_s = ((i==0)?1:0);
p.e_o_s = 0;
- p.granulepos=0;
+ p.granulepos = 0;
+ p.packetno = i;
- ogg_stream_packetin(&s->stream_out, &p);
+ if (write_packet(s, &p) != 0)
+ return -1;
}
+ return 0;
}
-/* Writes the header packets to the output stream. These 3 packets must
- * already be stored in s->vorbis_stream->headers. */
-static void open_output_stream(vcut_state *s)
-{
- /* ogg_stream_init should only fail if stream_out is null */
- int rv = ogg_stream_init(&s->stream_out, ++s->serial_out);
- assert(rv == 0);
-
- submit_headers_to_stream(s);
- s->output_stream_open = 1;
-}
-
/* Opens the given output file; or sets s->drop_output if the filename is ".".
* Returns 0 for success, or -1 on failure. */
static int open_output_file(vcut_state *s, char *filename)
@@ -224,24 +228,20 @@
/* Opens an output stream; if necessary, opens the next output file first.
* Returns 0 for success, or -1 on failure. */
-static int open_next_output_stream(vcut_state *s)
+static int open_output_stream(vcut_state *s)
{
if(!s->out && !s->drop_output)
{
- char *outname;
- vcut_segment *segment = s->next_segment;
- if(!segment) return 0;
-
- outname = segment->filename;
- s->next_segment = segment->next;
- free(segment);
-
- if(open_output_file(s,outname)!=0)
+ if(open_output_file(s, s->output_filename)!=0)
return -1;
- }
-
- open_output_stream(s);
- return 0;
+ }
+
+ /* ogg_stream_init should only fail if stream_out is null */
+ int rv = ogg_stream_init(&s->stream_out, ++s->serial_out);
+ assert(rv == 0);
+
+ s->output_stream_open = 1;
+ return submit_headers_to_stream(s);
}
@@ -271,21 +271,14 @@
exit(1);
}
+ state.output_filename = argv[2];
seg = vcut_malloc(sizeof(vcut_segment));
if(!seg)
exit(1);
seg->cuttime = -1;
- seg->cutpoint = -1;
- seg->filename = argv[2];
- state.next_segment = seg;
- seg->next = vcut_malloc(sizeof(vcut_segment));
-
- seg = seg->next;
- if(!seg)
- exit(1);
- seg->cuttime = -1;
seg->filename = argv[3];
seg->next = NULL;
+ state.next_segment = seg;
if(strchr(argv[4], '+') != NULL) {
if(sscanf(argv[4], "%lf", &seg->cuttime) != 1) {
@@ -327,6 +320,7 @@
{
int bs = get_blocksize(vs, packet);
long cut_on_eos = 0;
+ int packet_done = 0;
ogg_int64_t packet_start_granpos = vs->granulepos;
ogg_int64_t gp_to_global_sample_adj;
@@ -363,6 +357,9 @@
* will start at granulepos 0, or will be the last packet
* on its page (as mentioned above). */
vs->granulepos = 0;
+
+ /* Don't look for a cutpoint in this packet. */
+ packet_done = 1;
}
else
{
@@ -370,12 +367,13 @@
}
gp_to_global_sample_adj = s->prevstream_samples - vs->initial_granpos;
- while(1)
+ while(!packet_done)
{
ogg_int64_t rel_cutpoint, rel_sample;
- if(!s->next_segment) break;
+ vcut_segment *segment = s->next_segment;
+ if(!segment) break;
- if(s->next_segment->cuttime >= 0)
+ if(segment->cuttime >= 0)
{
/* convert cuttime to cutpoint (a sample number) */
rel_cutpoint = vs->vi.rate * (s->next_segment->cuttime
@@ -383,14 +381,11 @@
}
else
{
- if(s->next_segment->cutpoint == -1)
- break;
- rel_cutpoint = (s->next_segment->cutpoint
- - s->prevstream_samples);
+ rel_cutpoint = (segment->cutpoint - s->prevstream_samples);
}
rel_sample = vs->granulepos - vs->initial_granpos;
- if(rel_sample <= rel_cutpoint)
+ if(rel_sample < rel_cutpoint)
break;
/* reached the cutpoint */
@@ -419,44 +414,37 @@
packet->granulepos = rel_cutpoint;
cut_on_eos = packet->e_o_s;
packet->e_o_s = 1;
- if(write_packet(s, packet) != 0)
- return -1;
+ if(rel_cutpoint > 0)
+ {
+ if(write_packet(s, packet) != 0)
+ return -1;
+ }
if(close_output_file(s) != 0)
return -1;
- packet->granulepos = vs->granulepos - rel_cutpoint;
vs->samples_cut = rel_cutpoint;
packet->e_o_s = cut_on_eos;
- if(vs->last_packet.packet && vs->granulepos != rel_cutpoint)
+ s->output_filename = segment->filename;
+ s->next_segment = segment->next;
+ free(segment);
+ segment = NULL;
+
+ if(rel_cutpoint == rel_sample)
{
- ogg_packet ref_packet;
- ref_packet.bytes = vs->last_packet.length;
- ref_packet.packet = vs->last_packet.packet;
- ref_packet.b_o_s = 0;
- ref_packet.e_o_s = 0;
- ref_packet.granulepos = 0;
-
- if(write_packet(s, &ref_packet) != 0)
- return -1;
+ /* There's no unwritten data left in this packet. */
+ packet_done = 1;
}
- else break;
}
- /* 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
- * just in case. */
- if(save_packet(packet, &vs->last_packet) != 0)
- return -1;
-
-
- /* write the packet (header or audio) to the output stream */
- if(vs->granulepos > 0)
+ /* Write the audio packet to the output stream, unless it's the
+ * reference packet or we cut it at the last sample. */
+ if(!packet_done)
{
packet->granulepos = vs->granulepos
- vs->initial_granpos - vs->samples_cut;
- if(packet->granulepos < bs && cut_on_eos && !s->drop_output)
+ if(packet->granulepos < bs && cut_on_eos
+ && strcmp(s->output_filename, ".") != 0)
{
fprintf(stderr, _("Can't produce a file starting between sample"
" positions " FORMAT_INT64 " and " FORMAT_INT64 ".\n"),
@@ -466,8 +454,18 @@
" to suppress this error.\n"));
return -1;
}
+ if(write_packet(s, packet) != 0)
+ return -1;
}
- return write_packet(s, packet);
+
+ /* 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
+ * just in case. */
+ if(save_packet(packet, &vs->last_packet) != 0)
+ return -1;
+
+ return 0;
}
/* Writes a packet, opening an output stream/file if necessary.
@@ -475,11 +473,17 @@
int write_packet(vcut_state *s, ogg_packet *packet)
{
int flush;
- if(!s->output_stream_open && open_next_output_stream(s) != 0)
+ if(!s->output_stream_open && open_output_stream(s) != 0)
return -1;
- flush = (s->stream_out.packetno == 4 && packet->granulepos != -1)
- || packet->e_o_s;
+ /* According to the Vorbis I spec, we need to flush the stream after:
+ * - the first (BOS) header packet
+ * - the last header packet (packet #2)
+ * - the second audio packet (packet #4), if the stream starts at
+ * a non-zero granulepos */
+ flush = (s->stream_out.packetno == 2)
+ || (s->stream_out.packetno == 4 && packet->granulepos != -1)
+ || packet->b_o_s || packet->e_o_s;
ogg_stream_packetin(&s->stream_out, packet);
if(write_pages_to_file(&s->stream_out, s->out, flush) != 0)
Modified: trunk/vorbis-tools/vcut/vcut.h
===================================================================
--- trunk/vorbis-tools/vcut/vcut.h 2008-11-10 17:40:17 UTC (rev 15517)
+++ trunk/vorbis-tools/vcut/vcut.h 2008-11-10 22:10:00 UTC (rev 15518)
@@ -47,8 +47,7 @@
} vcut_segment;
typedef struct {
- /* pointer to a linked list of segments/cutpoints; the first element has
- cuttime == cutpoint == -1 and represents the data before any cutpoint */
+ /* pointer to a linked list of segments/cutpoints */
vcut_segment *next_segment;
/* the input file may have multiple chained streams; these variables store
@@ -64,6 +63,7 @@
vcut_vorbis_stream vorbis_stream;
FILE *out;
+ char *output_filename;
int drop_output; /* 1 if we don't want any output */
int output_stream_open; /* 1 if stream_out initialized */
ogg_stream_state stream_out;
More information about the commits
mailing list