|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
|
Packit |
a38265 |
Organisation (CSIRO) Australia
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
Redistribution and use in source and binary forms, with or without
|
|
Packit |
a38265 |
modification, are permitted provided that the following conditions
|
|
Packit |
a38265 |
are met:
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
- Redistributions of source code must retain the above copyright
|
|
Packit |
a38265 |
notice, this list of conditions and the following disclaimer.
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
- Redistributions in binary form must reproduce the above copyright
|
|
Packit |
a38265 |
notice, this list of conditions and the following disclaimer in the
|
|
Packit |
a38265 |
documentation and/or other materials provided with the distribution.
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
- Neither the name of CSIRO Australia nor the names of its
|
|
Packit |
a38265 |
contributors may be used to endorse or promote products derived from
|
|
Packit |
a38265 |
this software without specific prior written permission.
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
Packit |
a38265 |
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
Packit |
a38265 |
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
Packit |
a38265 |
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ORGANISATION OR
|
|
Packit |
a38265 |
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
Packit |
a38265 |
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
Packit |
a38265 |
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
Packit |
a38265 |
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
Packit |
a38265 |
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
Packit |
a38265 |
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
Packit |
a38265 |
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include "config.h"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include <stdio.h>
|
|
Packit |
a38265 |
#include <stdlib.h>
|
|
Packit |
a38265 |
#include <string.h>
|
|
Packit |
a38265 |
#include <getopt.h>
|
|
Packit |
a38265 |
#include <errno.h>
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef HAVE_INTTYPES_H
|
|
Packit |
a38265 |
# include <inttypes.h>
|
|
Packit |
a38265 |
#else
|
|
Packit |
a38265 |
# define PRId64 "I64d"
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include "oggz/oggz.h"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include "oggz_tools.h"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#define MAX_ERRORS 10
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#define SUBSECONDS 1000.0
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* #define DEBUG */
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
typedef ogg_int64_t timestamp_t;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
typedef struct _OVData {
|
|
Packit |
a38265 |
OGGZ * writer;
|
|
Packit |
a38265 |
OggzTable * missing_eos;
|
|
Packit |
a38265 |
OggzTable * packetno;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int theora_count;
|
|
Packit |
a38265 |
int audio_count;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int chain_ended;
|
|
Packit |
a38265 |
} OVData;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
typedef struct {
|
|
Packit |
a38265 |
int error;
|
|
Packit |
a38265 |
char * description;
|
|
Packit |
a38265 |
} error_text;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static error_text errors[] = {
|
|
Packit |
a38265 |
{-20, "Packet belongs to unknown serialno"},
|
|
Packit |
a38265 |
{-24, "Granulepos decreasing within track"},
|
|
Packit |
a38265 |
{-5, "Multiple bos pages"},
|
|
Packit |
a38265 |
{-6, "Multiple eos pages"},
|
|
Packit |
a38265 |
{0, NULL}
|
|
Packit |
a38265 |
};
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static char * progname;
|
|
Packit |
a38265 |
static int max_errors = MAX_ERRORS;
|
|
Packit |
a38265 |
static int multifile = 0;
|
|
Packit |
a38265 |
static char * current_filename = NULL;
|
|
Packit |
a38265 |
static timestamp_t current_timestamp = 0;
|
|
Packit |
a38265 |
static int exit_status = 0;
|
|
Packit |
a38265 |
static int nr_errors = 0;
|
|
Packit |
a38265 |
static int prefix = 0, suffix = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static void
|
|
Packit |
a38265 |
list_errors (void)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
int i = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
printf (" File contains no Ogg packets\n");
|
|
Packit |
a38265 |
printf (" Packets out of order\n");
|
|
Packit |
a38265 |
for (i = 0; errors[i].error; i++) {
|
|
Packit |
a38265 |
printf (" %s\n", errors[i].description);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
printf (" eos marked but no bos\n");
|
|
Packit |
a38265 |
printf (" Missing eos pages\n");
|
|
Packit |
a38265 |
printf (" eos marked on page with no completed packets\n");
|
|
Packit |
a38265 |
printf (" Granulepos on page with no completed packets\n");
|
|
Packit |
a38265 |
printf (" Theora video bos page after audio bos page\n");
|
|
Packit |
a38265 |
printf (" Terminal header page has non-zero granulepos\n");
|
|
Packit |
a38265 |
printf (" Terminal header page contains non-header packet\n");
|
|
Packit |
a38265 |
printf (" Terminal header page contains non-header segment\n");
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static void
|
|
Packit |
a38265 |
usage (char * progname)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
printf ("Usage: %s [options] filename ...\n", progname);
|
|
Packit |
a38265 |
printf ("Validate the Ogg framing of one or more files\n");
|
|
Packit |
a38265 |
printf ("\n%s detects the following errors in Ogg framing:\n", progname);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
list_errors ();
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
printf ("\nError reporting options\n");
|
|
Packit |
a38265 |
printf (" -M num, --max-errors num\n");
|
|
Packit |
a38265 |
printf (" Exit after the specified number of errors.\n");
|
|
Packit |
a38265 |
printf (" A value of 0 specifies no maximum. Default: %d\n", MAX_ERRORS);
|
|
Packit |
a38265 |
printf (" -p, --prefix Treat input as the prefix of a stream; suppress\n");
|
|
Packit |
a38265 |
printf (" warnings about missing end-of-stream markers\n");
|
|
Packit |
a38265 |
printf (" -s, --suffix Treat input as the suffix of a stream; suppress\n");
|
|
Packit |
a38265 |
printf (" warnings about missing beginning-of-stream markers\n");
|
|
Packit |
a38265 |
printf (" on the first chain\n");
|
|
Packit |
a38265 |
printf (" -P, --partial Treat input as a the middle portion of a stream;\n");
|
|
Packit |
a38265 |
printf (" equivalent to both --prefix and --suffix\n");
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
printf ("\nMiscellaneous options\n");
|
|
Packit |
a38265 |
printf (" -h, --help Display this help and exit\n");
|
|
Packit |
a38265 |
printf (" -E, --help-errors List known types of error and exit\n");
|
|
Packit |
a38265 |
printf (" -v, --version Output version information and exit\n");
|
|
Packit |
a38265 |
printf ("\n");
|
|
Packit |
a38265 |
printf ("Exit status is 0 if all input files are valid, 1 otherwise.\n\n");
|
|
Packit |
a38265 |
printf ("Please report bugs to <ogg-dev@xiph.org>\n");
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static void
|
|
Packit |
a38265 |
exit_out_of_memory (void)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
fprintf (stderr, "%s: Out of memory\n", progname);
|
|
Packit |
a38265 |
exit (1);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
log_error (void)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
if (multifile && nr_errors == 0) {
|
|
Packit |
a38265 |
fprintf (stderr, "%s: Error:\n", current_filename);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
exit_status = 1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
nr_errors++;
|
|
Packit |
a38265 |
if (max_errors && nr_errors > max_errors)
|
|
Packit |
a38265 |
return OGGZ_STOP_ERR;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return OGGZ_STOP_OK;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static ogg_int64_t
|
|
Packit |
a38265 |
gp_to_granule (OGGZ * oggz, long serialno, ogg_int64_t granulepos)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
int granuleshift;
|
|
Packit |
a38265 |
ogg_int64_t iframe, pframe, granule;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
granuleshift = oggz_get_granuleshift (oggz, serialno);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
iframe = granulepos >> granuleshift;
|
|
Packit |
a38265 |
pframe = granulepos - (iframe << granuleshift);
|
|
Packit |
a38265 |
granule = iframe+pframe;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz_stream_get_content (oggz, serialno) == OGGZ_CONTENT_DIRAC)
|
|
Packit |
a38265 |
granule >>= 9;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return granule;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static timestamp_t
|
|
Packit |
a38265 |
gp_to_time (OGGZ * oggz, long serialno, ogg_int64_t granulepos)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
ogg_int64_t gr_n, gr_d;
|
|
Packit |
a38265 |
ogg_int64_t granule;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (granulepos == -1) return -1.0;
|
|
Packit |
a38265 |
if (oggz_get_granulerate (oggz, serialno, &gr_n, &gr_d) != 0) return -1.0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
granule = gp_to_granule (oggz, serialno, granulepos);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return (timestamp_t)((double)(SUBSECONDS * granule * gr_d) / (double)gr_n);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static void
|
|
Packit |
a38265 |
ovdata_init (OVData * ovdata)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
int flags;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
current_timestamp = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
flags = OGGZ_WRITE|OGGZ_AUTO;
|
|
Packit |
a38265 |
if (prefix) flags |= OGGZ_PREFIX;
|
|
Packit |
a38265 |
if (suffix) flags |= OGGZ_SUFFIX;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if ((ovdata->writer = oggz_new (flags)) == NULL) {
|
|
Packit |
a38265 |
fprintf (stderr, "oggz-validate: unable to create new writer\n");
|
|
Packit |
a38265 |
exit (1);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if ((ovdata->missing_eos = oggz_table_new ()) == NULL)
|
|
Packit |
a38265 |
exit_out_of_memory();
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if ((ovdata->packetno = oggz_table_new ()) == NULL)
|
|
Packit |
a38265 |
exit_out_of_memory();
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
ovdata->theora_count = 0;
|
|
Packit |
a38265 |
ovdata->audio_count = 0;
|
|
Packit |
a38265 |
ovdata->chain_ended = 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static void
|
|
Packit |
a38265 |
ovdata_clear (OVData * ovdata)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
long serialno;
|
|
Packit |
a38265 |
int i, nr_missing_eos = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_close (ovdata->writer);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (!prefix && (max_errors == 0 || nr_errors <= max_errors)) {
|
|
Packit |
a38265 |
nr_missing_eos = oggz_table_size (ovdata->missing_eos);
|
|
Packit |
a38265 |
for (i = 0; i < nr_missing_eos; i++) {
|
|
Packit |
a38265 |
log_error ();
|
|
Packit |
a38265 |
oggz_table_nth (ovdata->missing_eos, i, &serialno);
|
|
Packit |
a38265 |
fprintf (stderr, "serialno %010lu: missing *** eos\n", serialno);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_table_delete (ovdata->missing_eos);
|
|
Packit |
a38265 |
oggz_table_delete (ovdata->packetno);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
read_page (OGGZ * oggz, const ogg_page * og, long serialno, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
OVData * ovdata = (OVData *)user_data;
|
|
Packit |
a38265 |
ogg_int64_t gpos = ogg_page_granulepos((ogg_page *)og);
|
|
Packit |
a38265 |
OggzStreamContent content_type;
|
|
Packit |
a38265 |
int packets, packetno, headers, ret = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (ovdata->chain_ended) {
|
|
Packit |
a38265 |
ovdata_clear (ovdata);
|
|
Packit |
a38265 |
ovdata_init (ovdata);
|
|
Packit |
a38265 |
suffix = 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (ogg_page_bos ((ogg_page *)og)) {
|
|
Packit |
a38265 |
/* Register this serialno as needing eos */
|
|
Packit |
a38265 |
if (oggz_table_insert (ovdata->missing_eos, serialno, (void *)0x1) == NULL)
|
|
Packit |
a38265 |
exit_out_of_memory();
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Handle ordering of Theora vs. audio packets */
|
|
Packit |
a38265 |
content_type = oggz_stream_get_content (oggz, serialno);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
switch (content_type) {
|
|
Packit |
a38265 |
case OGGZ_CONTENT_THEORA:
|
|
Packit |
a38265 |
ovdata->theora_count++;
|
|
Packit |
a38265 |
if (ovdata->audio_count > 0) {
|
|
Packit |
a38265 |
log_error ();
|
|
Packit |
a38265 |
fprintf (stderr, "serialno %010lu: Theora video bos page after audio bos page\n", serialno);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case OGGZ_CONTENT_VORBIS:
|
|
Packit |
a38265 |
case OGGZ_CONTENT_SPEEX:
|
|
Packit |
a38265 |
case OGGZ_CONTENT_PCM:
|
|
Packit |
a38265 |
case OGGZ_CONTENT_FLAC0:
|
|
Packit |
a38265 |
case OGGZ_CONTENT_FLAC:
|
|
Packit |
a38265 |
case OGGZ_CONTENT_CELT:
|
|
Packit |
a38265 |
ovdata->audio_count++;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
default:
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
packets = ogg_page_packets ((ogg_page *)og);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Check header constraints */
|
|
Packit |
a38265 |
if (!suffix) {
|
|
Packit |
a38265 |
if (oggz_table_lookup (ovdata->missing_eos, serialno) == NULL) {
|
|
Packit |
a38265 |
ret = log_error ();
|
|
Packit |
a38265 |
fprintf (stderr, "serialno %010lu: missing *** bos\n", serialno);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
packetno = (int)oggz_table_lookup (ovdata->packetno, serialno);
|
|
Packit |
a38265 |
headers = oggz_stream_get_numheaders (oggz, serialno);
|
|
Packit |
a38265 |
if (packetno < headers-1) {
|
|
Packit |
a38265 |
/* The previous page was headers, and more are expected */
|
|
Packit |
a38265 |
packetno += packets;
|
|
Packit |
a38265 |
if (oggz_table_insert (ovdata->packetno, serialno, (void *)packetno) == NULL)
|
|
Packit |
a38265 |
exit_out_of_memory();
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (packetno == headers && gpos != 0) {
|
|
Packit |
a38265 |
ret = log_error ();
|
|
Packit |
a38265 |
fprintf (stderr, "serialno %010lu: Terminal header page has non-zero granulepos\n", serialno);
|
|
Packit |
a38265 |
} else if (packetno > headers) {
|
|
Packit |
a38265 |
ret = log_error ();
|
|
Packit |
a38265 |
fprintf (stderr, "serialno %010lu: Terminal header page contains non-header packet\n", serialno);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
} else if (packetno == headers) {
|
|
Packit |
a38265 |
/* This is the next page after the page on which the last header finished */
|
|
Packit |
a38265 |
if (ogg_page_continued (og)) {
|
|
Packit |
a38265 |
ret = log_error ();
|
|
Packit |
a38265 |
fprintf (stderr, "serialno %010lu: Terminal header page contains non-header segment\n", serialno);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Mark packetno as greater than headers to avoid these checks for this serialno */
|
|
Packit |
a38265 |
if (oggz_table_insert (ovdata->packetno, serialno, (void *)(headers+1)) == NULL)
|
|
Packit |
a38265 |
exit_out_of_memory();
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Check EOS */
|
|
Packit |
a38265 |
if (ogg_page_eos((ogg_page *)og)) {
|
|
Packit |
a38265 |
int removed = oggz_table_remove (ovdata->missing_eos, serialno);
|
|
Packit |
a38265 |
if (!suffix && removed == -1) {
|
|
Packit |
a38265 |
ret = log_error ();
|
|
Packit |
a38265 |
fprintf (stderr, "serialno %010lu: *** eos marked but no bos\n",
|
|
Packit |
a38265 |
serialno);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (packets == 0) {
|
|
Packit |
a38265 |
ret = log_error ();
|
|
Packit |
a38265 |
fprintf (stderr, "serialno %010lu: *** eos marked on page with no completed packets\n",
|
|
Packit |
a38265 |
serialno);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (oggz_table_size (ovdata->missing_eos) == 0) {
|
|
Packit |
a38265 |
ovdata->chain_ended = 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if(gpos != -1 && packets == 0) {
|
|
Packit |
a38265 |
ret = log_error ();
|
|
Packit |
a38265 |
fprintf (stderr, "serialno %010lu: granulepos %" PRId64 " on page with no completed packets, must be -1\n", serialno, gpos);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return ret;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
read_packet (OGGZ * oggz, oggz_packet * zp, long serialno, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
OVData * ovdata = (OVData *)user_data;
|
|
Packit |
a38265 |
ogg_packet * op = &zp->op;
|
|
Packit |
a38265 |
timestamp_t timestamp;
|
|
Packit |
a38265 |
int flush;
|
|
Packit |
a38265 |
int ret = 0, feed_err = 0, i;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
timestamp = gp_to_time (oggz, serialno, op->granulepos);
|
|
Packit |
a38265 |
if (timestamp != -1.0 && oggz_stream_get_content (oggz, serialno) != OGGZ_CONTENT_DIRAC) {
|
|
Packit |
a38265 |
if (timestamp < current_timestamp) {
|
|
Packit |
a38265 |
ret = log_error();
|
|
Packit |
a38265 |
ot_fprint_time (stderr, (double)timestamp/SUBSECONDS);
|
|
Packit |
a38265 |
fprintf (stderr, ": serialno %010lu: Packet out of order (previous ",
|
|
Packit |
a38265 |
serialno);
|
|
Packit |
a38265 |
ot_fprint_time (stderr, (double)current_timestamp/SUBSECONDS);
|
|
Packit |
a38265 |
fprintf (stderr, ")\n");
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
current_timestamp = timestamp;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (op->granulepos == -1) {
|
|
Packit |
a38265 |
flush = 0;
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
flush = OGGZ_FLUSH_AFTER;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if ((feed_err = oggz_write_feed (ovdata->writer, op, serialno, flush, NULL)) != 0) {
|
|
Packit |
a38265 |
ret = log_error ();
|
|
Packit |
a38265 |
if (timestamp == -1.0) {
|
|
Packit |
a38265 |
fprintf (stderr, "%" PRId64 , oggz_tell (oggz));
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
ot_fprint_time (stderr, (double)timestamp/SUBSECONDS);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
fprintf (stderr, ": serialno %010lu: ", serialno);
|
|
Packit |
a38265 |
for (i = 0; errors[i].error; i++) {
|
|
Packit |
a38265 |
if (errors[i].error == feed_err) {
|
|
Packit |
a38265 |
fprintf (stderr, "%s\n", errors[i].description);
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
if (errors[i].error == 0) {
|
|
Packit |
a38265 |
fprintf (stderr,
|
|
Packit |
a38265 |
"Packet violates Ogg framing constraints: %d\n",
|
|
Packit |
a38265 |
feed_err);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return ret;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
validate (char * filename)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
OGGZ * reader;
|
|
Packit |
a38265 |
OVData ovdata;
|
|
Packit |
a38265 |
unsigned char buf[1024];
|
|
Packit |
a38265 |
long n, nout = 0, bytes_written = 0;
|
|
Packit |
a38265 |
int active = 1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
current_filename = filename;
|
|
Packit |
a38265 |
current_timestamp = 0;
|
|
Packit |
a38265 |
nr_errors = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/*printf ("oggz-validate: %s\n", filename);*/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (!strncmp (filename, "-", 2)) {
|
|
Packit |
a38265 |
if ((reader = oggz_open_stdio (stdin, OGGZ_READ|OGGZ_AUTO)) == NULL) {
|
|
Packit |
a38265 |
fprintf (stderr, "oggz-validate: unable to open stdin\n");
|
|
Packit |
a38265 |
return -1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
} else if ((reader = oggz_open (filename, OGGZ_READ|OGGZ_AUTO)) == NULL) {
|
|
Packit |
a38265 |
fprintf (stderr, "oggz-validate: unable to open file %s\n", filename);
|
|
Packit |
a38265 |
return -1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
ovdata_init (&ovdata);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_set_read_callback (reader, -1, read_packet, &ovdata);
|
|
Packit |
a38265 |
oggz_set_read_page (reader, -1, read_page, &ovdata);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
while (active && (n = oggz_read (reader, 1024)) != 0) {
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
fprintf (stderr, "validate: read %ld bytes\n", n);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (max_errors && nr_errors > max_errors) {
|
|
Packit |
a38265 |
fprintf (stderr,
|
|
Packit |
a38265 |
"oggz-validate --max-errors %d: maximum error count reached, bailing out ...\n",
|
|
Packit |
a38265 |
max_errors);
|
|
Packit |
a38265 |
active = 0;
|
|
Packit |
a38265 |
} else while ((nout = oggz_write_output (ovdata.writer, buf, n)) > 0) {
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
fprintf (stderr, "validate: wrote %ld bytes\n", nout);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
bytes_written += nout;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_close (reader);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (bytes_written == 0) {
|
|
Packit |
a38265 |
log_error ();
|
|
Packit |
a38265 |
fprintf (stderr, "File contains no Ogg packets\n");
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
ovdata_clear (&ovdata);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return active ? 0 : -1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
main (int argc, char ** argv)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
int show_version = 0;
|
|
Packit |
a38265 |
int show_help = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* Cache the --prefix, --suffix options and reset before validating
|
|
Packit |
a38265 |
* each input file */
|
|
Packit |
a38265 |
int opt_prefix = 0;
|
|
Packit |
a38265 |
int opt_suffix = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
char * filename;
|
|
Packit |
a38265 |
int i = 1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
char * optstring = "M:psPhvE";
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef HAVE_GETOPT_LONG
|
|
Packit |
a38265 |
static struct option long_options[] = {
|
|
Packit |
a38265 |
{"max-errors", required_argument, 0, 'M'},
|
|
Packit |
a38265 |
{"prefix", no_argument, 0, 'p'},
|
|
Packit |
a38265 |
{"suffix", no_argument, 0, 's'},
|
|
Packit |
a38265 |
{"partial", no_argument, 0, 'P'},
|
|
Packit |
a38265 |
{"help", no_argument, 0, 'h'},
|
|
Packit |
a38265 |
{"help-errors", no_argument, 0, 'E'},
|
|
Packit |
a38265 |
{"version", no_argument, 0, 'v'},
|
|
Packit |
a38265 |
{0,0,0,0}
|
|
Packit |
a38265 |
};
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
ot_init();
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
progname = argv[0];
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (argc < 2) {
|
|
Packit |
a38265 |
usage (progname);
|
|
Packit |
a38265 |
return (1);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (!strncmp (argv[1], "-?", 2)) {
|
|
Packit |
a38265 |
#ifdef HAVE_GETOPT_LONG
|
|
Packit |
a38265 |
ot_print_options (long_options, optstring);
|
|
Packit |
a38265 |
#else
|
|
Packit |
a38265 |
ot_print_short_options (optstring);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
exit (0);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
while (1) {
|
|
Packit |
a38265 |
#ifdef HAVE_GETOPT_LONG
|
|
Packit |
a38265 |
i = getopt_long(argc, argv, optstring, long_options, NULL);
|
|
Packit |
a38265 |
#else
|
|
Packit |
a38265 |
i = getopt (argc, argv, optstring);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
if (i == -1) {
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
if (i == ':') {
|
|
Packit |
a38265 |
usage (progname);
|
|
Packit |
a38265 |
goto exit_err;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
switch (i) {
|
|
Packit |
a38265 |
case 'M': /* max-errors */
|
|
Packit |
a38265 |
max_errors = atoi (optarg);
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 'p': /* prefix */
|
|
Packit |
a38265 |
opt_prefix = 1;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 's': /* suffix */
|
|
Packit |
a38265 |
opt_suffix = 1;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 'P': /* partial */
|
|
Packit |
a38265 |
opt_prefix = 1;
|
|
Packit |
a38265 |
opt_suffix = 1;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 'h': /* help */
|
|
Packit |
a38265 |
show_help = 1;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 'v': /* version */
|
|
Packit |
a38265 |
show_version = 1;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
case 'E': /* list errors */
|
|
Packit |
a38265 |
show_help = 2;
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
default:
|
|
Packit |
a38265 |
break;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (show_version) {
|
|
Packit |
a38265 |
printf ("%s version " VERSION "\n", progname);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (show_help == 1) {
|
|
Packit |
a38265 |
usage (progname);
|
|
Packit |
a38265 |
} else if (show_help == 2) {
|
|
Packit |
a38265 |
list_errors ();
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (show_version || show_help) {
|
|
Packit |
a38265 |
goto exit_out;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (max_errors < 0) {
|
|
Packit |
a38265 |
printf ("%s: Error: [-M num, --max-errors num] option must be non-negative\n", progname);
|
|
Packit |
a38265 |
goto exit_err;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (optind >= argc) {
|
|
Packit |
a38265 |
usage (progname);
|
|
Packit |
a38265 |
goto exit_err;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (argc-i > 2) multifile = 1;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
for (i = optind; i < argc; i++) {
|
|
Packit |
a38265 |
filename = argv[i];
|
|
Packit |
a38265 |
prefix = opt_prefix;
|
|
Packit |
a38265 |
suffix = opt_suffix;
|
|
Packit |
a38265 |
if (validate (filename) == -1)
|
|
Packit |
a38265 |
exit_status = 1;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
exit_out:
|
|
Packit |
a38265 |
exit (exit_status);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
exit_err:
|
|
Packit |
a38265 |
exit (1);
|
|
Packit |
a38265 |
}
|