[xiph-commits] r3492 - liboggz/trunk/src/tools
conrad at svn.annodex.net
conrad at svn.annodex.net
Mon Feb 25 18:00:10 PST 2008
Author: conrad
Date: 2008-02-25 18:00:09 -0800 (Mon, 25 Feb 2008)
New Revision: 3492
Added:
liboggz/trunk/src/tools/oggz-chop.c
Modified:
liboggz/trunk/src/tools/Makefile.am
Log:
add first cut at oggz-chop: works on pages, copies headers and per-track data
from previous keyframe before chop. Does not yet attempt to add or rewrite
skeleton, but works for general vorbis+theora files without skeleton.
Modified: liboggz/trunk/src/tools/Makefile.am
===================================================================
--- liboggz/trunk/src/tools/Makefile.am 2008-02-24 08:00:00 UTC (rev 3491)
+++ liboggz/trunk/src/tools/Makefile.am 2008-02-26 02:00:09 UTC (rev 3492)
@@ -14,7 +14,7 @@
oggz_read_noinst_programs =
if OGGZ_CONFIG_WRITE
-oggz_rw_programs = oggzmerge oggzrip oggz-validate oggz-comment oggz-sort
+oggz_rw_programs = oggzmerge oggzrip oggz-chop oggz-validate oggz-comment oggz-sort
oggz_rw_noinst_programs = oggz-basetime
endif
@@ -29,6 +29,9 @@
oggzinfo_SOURCES = oggzinfo.c oggz_tools.c skeleton.c
oggzinfo_LDADD = $(OGGZ_LIBS) -lm
+oggz_chop_SOURCES = oggz-chop.c oggz_tools.c
+oggz_chop_LDADD = $(OGGZ_LIBS)
+
oggz_comment_SOURCES = oggz-comment.c oggz_tools.c
oggz_comment_LDADD = $(OGGZ_LIBS)
Added: liboggz/trunk/src/tools/oggz-chop.c
===================================================================
--- liboggz/trunk/src/tools/oggz-chop.c (rev 0)
+++ liboggz/trunk/src/tools/oggz-chop.c 2008-02-26 02:00:09 UTC (rev 3492)
@@ -0,0 +1,453 @@
+
+/*
+ Copyright (C) 2008 Annodex Association
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ - Neither the name of the Annodex Association nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ASSOCIATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+
+
+#include <oggz/oggz.h>
+
+static char * progname;
+
+static void
+usage (char * progname)
+{
+ printf ("Usage: %s [options] filename\n", progname);
+ printf ("Chop an Ogg file.\n");
+ printf ("\nOutput options\n");
+ printf (" -o filename, --output filename\n");
+ printf (" Specify output filename\n");
+ printf (" -s start_time, --start start_time\n");
+ printf (" Specify start time\n");
+ printf (" -e end_time, --end end_time\n");
+ printf (" Specify end time\n");
+ printf ("\nMiscellaneous options\n");
+ printf (" -h, --help Display this help and exit\n");
+ printf (" -v, --version Output version information and exit\n");
+ printf ("\n");
+ printf ("Please report bugs to <ogg-dev at xiph.org>\n");
+}
+
+/************************************************************
+ * OCState
+ */
+
+typedef struct _OCState {
+ OggzTable * tracks;
+ FILE * outfile;
+ double start;
+ double end;
+} OCState;
+
+/************************************************************
+ * OCTrackState
+ */
+
+typedef struct _OCTrackState {
+ OggzTable * page_accum;
+
+ int headers_remaining;
+
+ long start_granule;
+
+ /* Greatest previously inferred keyframe value */
+ ogg_int64_t prev_keyframe;
+
+} OCTrackState;
+
+static OCTrackState *
+track_state_new (void)
+{
+ OCTrackState * ts;
+
+ ts = (OCTrackState *) malloc (sizeof(*ts));
+
+ memset (ts, 0, sizeof(*ts));
+ ts->page_accum = oggz_table_new();
+
+ return ts;
+}
+
+static void
+track_state_delete (OCTrackState * ts)
+{
+ if (ts == NULL) return;
+
+ /* XXX: delete accumulated pages */
+ oggz_table_delete (ts->page_accum);
+
+ free (ts);
+
+ return;
+}
+
+/* Add a track to the overall state */
+static OCTrackState *
+track_state_add (OggzTable * state, long serialno)
+{
+ OCTrackState * ts;
+
+ ts = track_state_new ();
+ if (oggz_table_insert (state, serialno, ts) == ts) {
+ return ts;
+ } else {
+ track_state_delete (ts);
+ return NULL;
+ }
+}
+
+/************************************************************
+ * ogg_page helpers
+ */
+
+static ogg_page *
+_ogg_page_copy (const ogg_page * og)
+{
+ ogg_page * new_og;
+
+ new_og = malloc (sizeof (*og));
+ new_og->header = malloc (og->header_len);
+ new_og->header_len = og->header_len;
+ memcpy (new_og->header, og->header, og->header_len);
+ new_og->body = malloc (og->body_len);
+ new_og->body_len = og->body_len;
+ memcpy (new_og->body, og->body, og->body_len);
+
+ return new_og;
+}
+
+static void
+_ogg_page_free (const ogg_page * og)
+{
+ if (og == NULL) return;
+
+ free (og->header);
+ free (og->body);
+ free ((ogg_page *)og);
+}
+
+static void
+_ogg_page_set_eos (const ogg_page * og)
+{
+ if (og == NULL) return;
+
+ og->header[5] |= 0x04;
+ ogg_page_checksum_set (og);
+}
+
+static void
+fwrite_ogg_page (FILE * outfile, ogg_page * og)
+{
+ if (og == NULL) return;
+
+ fwrite (og->header, 1, og->header_len, outfile);
+ fwrite (og->body, 1, og->body_len, outfile);
+}
+
+/************************************************************
+ * chop
+ */
+
+/*
+ * OggzReadPageCallback read_plain
+ *
+ * A page reading callback for tracks without granuleshift.
+ */
+static int
+read_plain (OGGZ * oggz, const ogg_page * og, long serialno, void * user_data)
+{
+ OCState * state = (OCState *)user_data;
+ OCTrackState * ts;
+ double page_time;
+
+ ts = oggz_table_lookup (state->tracks, serialno);
+
+ page_time = oggz_tell_units (oggz) / 1000.0;
+
+#if 0
+ printf ("page_time: %g\tspan (%g, %g)\n", page_time, state->start, state->end);
+ printf ("\tpageno: %d, numheaders %d\n", ogg_page_pageno(og),
+ oggz_stream_get_numheaders (oggz, serialno));
+#endif
+
+ if (page_time >= state->start &&
+ (state->end == -1 || page_time <= state->end)) {
+ fwrite_ogg_page (state->outfile, og);
+ } else if (state->end != -1.0 && page_time > state->end) {
+ /* This is the first page past the end time; set EOS */
+ _ogg_page_set_eos (og);
+ fwrite_ogg_page (state->outfile, og);
+
+ /* Stop handling this track */
+ oggz_set_read_page (oggz, serialno, NULL, NULL);
+ }
+
+ return OGGZ_CONTINUE;
+}
+
+/*
+ * OggzReadPageCallback read_gs
+ *
+ * A page reading callback for tracks with granuleshift.
+ */
+static int
+read_gs (OGGZ * oggz, const ogg_page * og, long serialno, void * user_data)
+{
+ OCState * state = (OCState *)user_data;
+ OCTrackState * ts;
+ double page_time;
+ ogg_int64_t granulepos, keyframe;
+ int granuleshift, i, accum_size;
+ ogg_page * accum_og;
+
+ page_time = oggz_tell_units (oggz) / 1000.0;
+
+ ts = oggz_table_lookup (state->tracks, serialno);
+ accum_size = oggz_table_size (ts->page_accum);
+
+ if (page_time >= state->start) {
+ /* Write out accumulated pages */
+ for (i = 0; i < accum_size; i++) {
+ accum_og = (ogg_page *)oggz_table_lookup (ts->page_accum, i);
+ fwrite_ogg_page (state->outfile, accum_og);
+ _ogg_page_free (accum_og);
+ }
+ oggz_table_delete (ts->page_accum);
+ ts->page_accum = NULL;
+
+ /* Switch to the plain page reader */
+ oggz_set_read_page (oggz, serialno, read_plain, state);
+ return read_plain (oggz, og, serialno, user_data);
+ } /* else { ... */
+
+ granulepos = ogg_page_granulepos (og);
+ if (granulepos != -1) {
+ granuleshift = oggz_get_granuleshift (oggz, serialno);
+ keyframe = granulepos >> granuleshift;
+
+ if (keyframe != ts->prev_keyframe) {
+ /* Clear the page accumulator */
+ for (i = accum_size; i >= 0; i--) {
+ _ogg_page_free ((ogg_page *)oggz_table_lookup (ts->page_accum, i));
+ oggz_table_remove (ts->page_accum, (long)i);
+ }
+ accum_size = 0;
+
+ /* Record this as prev_keyframe */
+ ts->prev_keyframe = keyframe;
+ }
+ }
+
+ /* Add a copy of this to the page accumulator */
+ oggz_table_insert (ts->page_accum, accum_size, _ogg_page_copy (og));
+
+ return OGGZ_CONTINUE;
+}
+
+/*
+ * OggzReadPageCallback read_headers
+ *
+ * A page reading callback for header pages
+ */
+static int
+read_headers (OGGZ * oggz, const ogg_page * og, long serialno, void * user_data)
+{
+ OCState * state = (OCState *)user_data;
+ OCTrackState * ts;
+
+ fwrite_ogg_page (state->outfile, og);
+
+ ts = oggz_table_lookup (state->tracks, serialno);
+ ts->headers_remaining -= ogg_page_packets (og);
+
+ if (ts->headers_remaining <= 0) {
+ if (state->start == 0.0 || oggz_get_granuleshift (oggz, serialno) == 0) {
+ oggz_set_read_page (oggz, serialno, read_plain, state);
+ } else {
+ oggz_set_read_page (oggz, serialno, read_gs, state);
+ }
+ }
+
+ return OGGZ_CONTINUE;
+}
+
+static int
+read_bos (OGGZ * oggz, const ogg_page * og, long serialno, void * user_data)
+{
+ OCState * state = (OCState *)user_data;
+ OCTrackState * ts;
+ double page_time;
+
+ if (ogg_page_bos (og)) {
+ ts = track_state_add (state->tracks, serialno);
+ ts->headers_remaining = oggz_stream_get_numheaders (oggz, serialno);
+
+ oggz_set_read_page (oggz, serialno, read_headers, state);
+ read_headers (oggz, og, serialno, user_data);
+ } else {
+ /* Deregister the catch-all page reading callback */
+ oggz_set_read_page (oggz, -1, NULL, NULL);
+ }
+
+ return OGGZ_CONTINUE;
+}
+
+static int
+chop (char * infilename, char * outfilename, double start, double end)
+{
+ OCState state;
+ OGGZ * oggz;
+
+ state.tracks = oggz_table_new ();
+
+ if (strcmp (infilename, "-") == 0) {
+ oggz = oggz_open_stdio (stdin, OGGZ_READ|OGGZ_AUTO);
+ } else {
+ oggz = oggz_open (infilename, OGGZ_READ|OGGZ_AUTO);
+ }
+
+ if (outfilename == NULL) {
+ state.outfile = stdout;
+ } else {
+ state.outfile = fopen (outfilename, "wb");
+ if (state.outfile == NULL) {
+ fprintf (stderr, "%s: unable to open output file %s\n",
+ progname, outfilename);
+ return -1;
+ }
+ }
+
+ state.start = start;
+ state.end = end;
+
+ /* set up a demux filter */
+ oggz_set_read_page (oggz, -1, read_bos, &state);
+
+ oggz_run_set_blocksize (oggz, 1024*1024);
+ oggz_run (oggz);
+
+ oggz_close (oggz);
+
+ return 0;
+}
+
+int
+main (int argc, char * argv[])
+{
+ int show_version = 0;
+ int show_help = 0;
+ double start = 0.0, end = -1.0;
+ char * infilename = NULL, * outfilename = NULL;
+ int i;
+
+ progname = argv[0];
+
+ if (argc < 2) {
+ usage (progname);
+ return (1);
+ }
+
+ while (1) {
+ char * optstring = "s:e:o:hv";
+
+#ifdef HAVE_GETOPT_LONG
+ static struct option long_options[] = {
+ {"output", required_argument, 0, 'o'},
+ {"format", required_argument, 0, 'f'},
+ {"keyframe", no_argument, 0, 'k'},
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'v'},
+ {0,0,0,0}
+ };
+
+ i = getopt_long(argc, argv, optstring, long_options, NULL);
+#else
+ i = getopt (argc, argv, optstring);
+#endif
+ if (i == -1) break;
+ if (i == ':') {
+ usage (progname);
+ goto exit_err;
+ }
+
+ switch (i) {
+ case 's': /* start */
+ start = atof (optarg);
+ break;
+ case 'e': /* end */
+ end = atof (optarg);
+ break;
+ case 'h': /* help */
+ show_help = 1;
+ break;
+ case 'v': /* version */
+ show_version = 1;
+ break;
+ case 'o': /* output */
+ outfilename = optarg;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (show_version) {
+ printf ("%s version " VERSION "\n", progname);
+ }
+
+ if (show_help) {
+ usage (progname);
+ }
+
+ if (show_version || show_help) {
+ goto exit_ok;
+ }
+
+ if (optind >= argc) {
+ usage (progname);
+ goto exit_err;
+ }
+
+ infilename = argv[optind++];
+
+ return chop (infilename, outfilename, start, end);
+
+exit_ok:
+ return 0;
+
+exit_err:
+ return 1;
+}
More information about the commits
mailing list