PageRenderTime 110ms CodeModel.GetById 76ms app.highlight 28ms RepoModel.GetById 1ms app.codeStats 1ms

/src/flvmeta.c

https://code.google.com/
C | 404 lines | 321 code | 22 blank | 61 comment | 56 complexity | 5d97fada5d7f1ff7a6abbbc2c7ffa120 MD5 | raw file
  1/*
  2    $Id: flvmeta.c 231 2011-06-27 13:46:19Z marc.noirot $
  3
  4    FLV Metadata updater
  5
  6    Copyright (C) 2007-2012 Marc Noirot <marc.noirot AT gmail.com>
  7
  8    This file is part of FLVMeta.
  9
 10    FLVMeta is free software; you can redistribute it and/or modify
 11    it under the terms of the GNU General Public License as published by
 12    the Free Software Foundation; either version 2 of the License, or
 13    (at your option) any later version.
 14
 15    FLVMeta is distributed in the hope that it will be useful,
 16    but WITHOUT ANY WARRANTY; without even the implied warranty of
 17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18    GNU General Public License for more details.
 19
 20    You should have received a copy of the GNU General Public License
 21    along with FLVMeta; if not, write to the Free Software
 22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 23*/
 24#include <getopt.h>
 25#include <stdio.h>
 26#include <stdlib.h>
 27#include <string.h>
 28
 29#include "flvmeta.h"
 30#include "check.h"
 31#include "dump.h"
 32#include "update.h"
 33
 34/*
 35    Command-line options
 36*/
 37static struct option long_options[] = {
 38    { "dump",               no_argument,        NULL, 'D'},
 39    { "full-dump",          no_argument,        NULL, 'F'},
 40    { "check",              no_argument,        NULL, 'C'},
 41    { "update",             no_argument,        NULL, 'U'},
 42    { "dump-format",        required_argument,  NULL, 'd'},
 43    { "json",               no_argument,        NULL, 'j'},
 44    { "raw",                no_argument,        NULL, 'r'},
 45    { "xml",                no_argument,        NULL, 'x'},
 46    { "yaml",               no_argument,        NULL, 'y'},
 47    { "event",              required_argument,  NULL, 'e'},
 48    { "level",              required_argument,  NULL, 'l'},
 49    { "quiet",              no_argument,        NULL, 'q'},
 50    { "print-metadata",     no_argument,        NULL, 'm'},
 51    { "add",                required_argument,  NULL, 'a'},
 52    { "no-lastsecond",      no_argument,        NULL, 's'},
 53    { "preserve",           no_argument,        NULL, 'p'},
 54    { "fix",                no_argument,        NULL, 'f'},
 55    { "ignore",             no_argument,        NULL, 'i'},
 56    { "reset-timestamps",   no_argument,        NULL, 't'},
 57    { "all-keyframes",      no_argument,        NULL, 'k'},
 58    { "verbose",            no_argument,        NULL, 'v'},
 59    { "version",            no_argument,        NULL, 'V'},
 60    { "help",               no_argument,        NULL, 'h'},
 61    { 0, 0, 0, 0 }
 62};
 63
 64/* short options */
 65#define DUMP_COMMAND                "D"
 66#define FULL_DUMP_COMMAND           "F"
 67#define CHECK_COMMAND               "C"
 68#define UPDATE_COMMAND              "U"
 69#define DUMP_FORMAT_OPTION          "d:"
 70#define JSON_OPTION                 "j"
 71#define RAW_OPTION                  "r"
 72#define XML_OPTION                  "x"
 73#define YAML_OPTION                 "y"
 74#define EVENT_OPTION                "e:"
 75#define LEVEL_OPTION                "l:"
 76#define QUIET_OPTION                "q"
 77#define PRINT_METADATA_OPTION       "m"
 78#define ADD_OPTION                  "a:"
 79#define NO_LASTSECOND_OPTION        "s"
 80#define PRESERVE_OPTION             "p"
 81#define FIX_OPTION                  "f"
 82#define IGNORE_OPTION               "i"
 83#define RESET_TIMESTAMPS_OPTION     "t"
 84#define ALL_KEYFRAMES_OPTION        "k"
 85#define VERBOSE_OPTION              "v"
 86#define VERSION_OPTION              "V"
 87#define HELP_OPTION                 "h"
 88
 89static void version(void) {
 90    printf("%s\n\n", PACKAGE_STRING);
 91    printf("%s\n", COPYRIGHT_STR);
 92    printf("This is free software; see the source for copying conditions. There is NO\n"
 93           "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
 94}
 95
 96static void usage(const char * name) {
 97    fprintf(stderr, "Usage: %s [COMMAND] [OPTIONS] INPUT_FILE [OUTPUT_FILE]\n", name);
 98    fprintf(stderr, "Try `%s --help' for more information.\n", name);
 99}
100
101static void help(const char * name) {
102    printf("Usage: %s [COMMAND] [OPTIONS] INPUT_FILE [OUTPUT_FILE]\n", name);
103    printf("\nIf OUTPUT_FILE is omitted for commands expecting it, INPUT_FILE will be overwritten instead.\n"
104           "\nCommands:\n"
105           "  -D, --dump                dump onMetaData tag (default without output file)\n"
106           "  -F, --full-dump           dump all tags\n"
107           "  -C, --check               check the validity of INPUT_FILE, returning 0 if\n"
108           "                            the file is valid, or 10 if it contains errors\n"
109           "  -U, --update              update computed onMetaData tag from INPUT_FILE\n"
110           "                            into OUTPUT_FILE (default with output file)\n"
111           /*    "  -A, --extract-audio       extract raw audio data into OUTPUT_FILE\n"*/
112           /*    "  -E, --extract-video       extract raw video data into OUTPUT_FILE\n"*/
113           "\nDump options:\n"
114           "  -d, --dump-format=TYPE    dump format is of type TYPE\n"
115           "                            TYPE is 'xml' (default), 'json', 'raw', or 'yaml'\n"
116           "  -j, --json                equivalent to --dump-format=json\n"
117           "  -r, --raw                 equivalent to --dump-format=raw\n"
118           "  -x, --xml                 equivalent to --dump-format=xml\n"
119           "  -y, --yaml                equivalent to --dump-format=yaml\n"
120           "  -e, --event=EVENT         specify the event to be dumped instead of 'onMetadata'\n"
121           "\nCheck options:\n"
122           "  -l, --level=LEVEL         print only messages where level is at least LEVEL\n"
123           "                            LEVEL is 'info', 'warning' (default), 'error', or 'fatal'\n"
124           "  -q, --quiet               do not print messages, only return the status code\n"
125           "  -x, --xml                 generate an XML report\n"
126           "\nUpdate options:\n"
127           "  -m, --print-metadata      print metadata to stdout after update using\n"
128           "                            the specified format\n"
129           "  -a, --add=NAME=VALUE      add a metadata string value to the output file\n"
130           "  -s, --no-lastsecond       do not create the onLastSecond tag\n"
131           "  -p, --preserve            preserve input file existing onMetadata tags\n"
132           "  -f, --fix                 fix invalid tags from the input file\n"
133           "  -i, --ignore              ignore invalid tags from the input file\n"
134           "                            (the default is to stop with an error)\n"
135           "  -t, --reset-timestamps    reset timestamps so OUTPUT_FILE starts at zero\n"
136           "  -k, --all-keyframes       index all keyframe tags, including duplicate timestamps\n"
137           "\nCommon options:\n"
138           "  -v, --verbose             display informative messages\n"
139           "\nMiscellaneous:\n"
140           "  -V, --version             print version information and exit\n"
141           "  -h, --help                display this information and exit\n");
142    printf("\nPlease report bugs to <%s>\n", PACKAGE_BUGREPORT);
143}
144
145static int parse_command_line(int argc, char ** argv, flvmeta_opts * options) {
146    int option, option_index;
147
148    option_index = 0;
149    do {
150        option = getopt_long(argc, argv, 
151            DUMP_COMMAND
152            FULL_DUMP_COMMAND
153            CHECK_COMMAND
154            UPDATE_COMMAND
155            DUMP_FORMAT_OPTION
156            JSON_OPTION
157            RAW_OPTION
158            XML_OPTION
159            YAML_OPTION
160            EVENT_OPTION
161            LEVEL_OPTION
162            QUIET_OPTION
163            PRINT_METADATA_OPTION
164            ADD_OPTION
165            NO_LASTSECOND_OPTION
166            PRESERVE_OPTION
167            FIX_OPTION
168            IGNORE_OPTION
169            RESET_TIMESTAMPS_OPTION
170            ALL_KEYFRAMES_OPTION
171            VERBOSE_OPTION
172            VERSION_OPTION
173            HELP_OPTION,
174            long_options, &option_index);
175        switch (option) {
176            /*
177                commands
178            */
179            case 'D':
180                if (options->command != FLVMETA_DEFAULT_COMMAND) {
181                    fprintf(stderr, "%s: only one command can be specified -- %s\n", argv[0], argv[optind]);
182                    return EXIT_FAILURE;
183                }
184                options->command = FLVMETA_DUMP_COMMAND;
185                break;
186            case 'F':
187                if (options->command != FLVMETA_DEFAULT_COMMAND) {
188                    fprintf(stderr, "%s: only one command can be specified -- %s\n", argv[0], argv[optind]);
189                    return EXIT_FAILURE;
190                }
191                options->command = FLVMETA_FULL_DUMP_COMMAND;
192                break;
193            case 'C':
194                if (options->command != FLVMETA_DEFAULT_COMMAND) {
195                    fprintf(stderr, "%s: only one command can be specified -- %s\n", argv[0], argv[optind]);
196                    return EXIT_FAILURE;
197                }
198                options->command = FLVMETA_CHECK_COMMAND;
199                break;
200            case 'U':
201                if (options->command != FLVMETA_DEFAULT_COMMAND) {
202                    fprintf(stderr, "%s: only one command can be specified -- %s\n", argv[0], argv[optind]);
203                    return EXIT_FAILURE;
204                }
205                options->command = FLVMETA_UPDATE_COMMAND;
206                break;
207            /*
208                options
209            */
210            /* check options */
211            case 'l':
212                if (!strcmp(optarg, "info")) {
213                    options->check_level = FLVMETA_CHECK_LEVEL_INFO;
214                }
215                else if (!strcmp(optarg, "warning")) {
216                    options->check_level = FLVMETA_CHECK_LEVEL_WARNING;
217                }
218                else if (!strcmp(optarg, "error")) {
219                    options->check_level = FLVMETA_CHECK_LEVEL_ERROR;
220                }
221                else if (!strcmp(optarg, "fatal")) {
222                    options->check_level = FLVMETA_CHECK_LEVEL_FATAL;
223                }
224                else {
225                    fprintf(stderr, "%s: invalid message level -- %s\n", argv[0], optarg);
226                    usage(argv[0]);
227                    return EXIT_FAILURE;
228                }
229                break;
230            case 'q': options->quiet = 1; break;
231            /* dump options */
232            case 'd':
233                if (!strcmp(optarg, "xml")) {
234                    options->dump_format = FLVMETA_FORMAT_XML;
235                }
236                if (!strcmp(optarg, "raw")) {
237                    options->dump_format = FLVMETA_FORMAT_RAW;
238                }
239                else if (!strcmp(optarg, "json")) {
240                    options->dump_format = FLVMETA_FORMAT_JSON;
241                }
242                else if (!strcmp(optarg, "yaml")) {
243                    options->dump_format = FLVMETA_FORMAT_YAML;
244                }
245                else {
246                    fprintf(stderr, "%s: invalid output format -- %s\n", argv[0], optarg);
247                    usage(argv[0]);
248                    return EXIT_FAILURE;
249                }
250                break;
251            case 'j': options->dump_format = FLVMETA_FORMAT_JSON;    break;
252            case 'r': options->dump_format = FLVMETA_FORMAT_RAW;     break;
253            case 'x':
254                /* xml dump format, or generation of xml report */
255                options->dump_format = FLVMETA_FORMAT_XML;
256                options->check_xml_report = 1;
257                break;
258            case 'y': options->dump_format = FLVMETA_FORMAT_YAML;    break;
259            case 'e': options->metadata_event = optarg;              break;
260            /* update options */
261            case 'm': options->dump_metadata = 1;                    break;
262            case 'a':
263                {
264                    char * eq_pos;
265                    eq_pos = strchr(optarg, '=');
266                    if (eq_pos != NULL) {
267                        *eq_pos = 0;
268                        if (options->metadata == NULL) {
269                            options->metadata = amf_associative_array_new();
270                        }
271                        amf_associative_array_add(options->metadata, optarg, amf_str(eq_pos + 1));
272                    }
273                    else {
274                        fprintf(stderr, "%s: invalid metadata format -- %s\n", argv[0], optarg);
275                        usage(argv[0]);
276                        return EXIT_FAILURE;
277                    }
278                } break;
279            case 's': options->insert_onlastsecond = 0;                  break;
280            case 'p': options->preserve_metadata = 1;                    break;
281            case 'f': options->error_handling = FLVMETA_FIX_ERRORS;      break;
282            case 'i': options->error_handling = FLVMETA_IGNORE_ERRORS;   break;
283            case 't': options->reset_timestamps = 1;                     break;
284            case 'k': options->all_keyframes = 1;                        break;
285            
286            /*
287                common options
288            */
289            case 'v': options->verbose = 1;  break;
290            /*
291                Miscellaneous
292            */
293            case 'V':
294                options->command = FLVMETA_VERSION_COMMAND;
295                return OK;
296                break;
297            case 'h':
298                options->command = FLVMETA_HELP_COMMAND;
299                return OK;
300                break;
301            /* last option */
302            case EOF: break;
303            /*
304                error cases
305            */
306            /* unknown option */
307            case '?':
308            /* missing argument */
309            case ':':
310            /* we should not be here */
311            default:
312                usage(argv[0]);
313                return EXIT_FAILURE;
314        }
315    } while (option != EOF);
316
317    /* input filename */
318    if (optind > 0 && optind < argc) {
319        options->input_file = argv[optind];
320    }
321    else {
322        fprintf(stderr, "%s: no input file\n", argv[0]);
323        usage(argv[0]);
324        return EXIT_FAILURE;
325    }
326
327    /* output filename */
328    if (++optind < argc) {
329        options->output_file = argv[optind];
330    }
331
332    /* determine command if default */
333    if (options->command == FLVMETA_DEFAULT_COMMAND && options->output_file != NULL) {
334        options->command = FLVMETA_UPDATE_COMMAND;
335    }
336    else if (options->command == FLVMETA_DEFAULT_COMMAND && options->output_file == NULL) {
337        options->command = FLVMETA_DUMP_COMMAND;
338    }
339
340    /* output file is input file if not specified */
341    if (options->output_file == NULL) {
342        options->output_file = options->input_file;
343    }
344
345    return OK;
346}
347
348int main(int argc, char ** argv) {
349    int errcode;
350
351    /* flvmeta default options */
352    static flvmeta_opts options;
353    options.command = FLVMETA_DEFAULT_COMMAND;
354    options.input_file = NULL;
355    options.output_file = NULL;
356    options.metadata = NULL;
357    options.check_level = FLVMETA_CHECK_LEVEL_WARNING;
358    options.quiet = 0;
359    options.check_xml_report = 0;
360    options.dump_metadata = 0;
361    options.insert_onlastsecond = 1;
362    options.reset_timestamps = 0;
363    options.all_keyframes = 0;
364    options.preserve_metadata = 0;
365    options.error_handling = FLVMETA_EXIT_ON_ERROR;
366    options.dump_format = FLVMETA_FORMAT_XML;
367    options.verbose = 0;
368    options.metadata_event = NULL;
369
370
371    /* Command-line parsing */
372    errcode = parse_command_line(argc, argv, &options);
373
374    /* free metadata if necessary */
375    if ((errcode != OK || options.command != FLVMETA_UPDATE_COMMAND) && options.metadata != NULL) {
376        amf_data_free(options.metadata);
377    }
378
379    if (errcode == OK) {
380        /* execute command */
381        switch (options.command) {
382            case FLVMETA_DUMP_COMMAND: errcode = dump_metadata(&options); break;
383            case FLVMETA_FULL_DUMP_COMMAND: errcode = dump_flv_file(&options); break;
384            case FLVMETA_CHECK_COMMAND: errcode = check_flv_file(&options); break;
385            case FLVMETA_UPDATE_COMMAND: errcode = update_metadata(&options); break;
386            case FLVMETA_VERSION_COMMAND: version(); break;
387            case FLVMETA_HELP_COMMAND: help(argv[0]); break;
388        }
389
390        /* error report */
391        switch (errcode) {
392            case ERROR_OPEN_READ: fprintf(stderr, "%s: cannot open %s for reading\n", argv[0], options.input_file); break;
393            case ERROR_NO_FLV: fprintf(stderr, "%s: %s is not a valid FLV file\n", argv[0], options.input_file); break;
394            case ERROR_EOF: fprintf(stderr, "%s: unexpected end of file\n", argv[0]); break;
395            case ERROR_MEMORY: fprintf(stderr, "%s: memory allocation error\n", argv[0]); break;
396            case ERROR_EMPTY_TAG: fprintf(stderr, "%s: empty FLV tag\n", argv[0]); break;
397            case ERROR_OPEN_WRITE: fprintf(stderr, "%s: cannot open %s for writing\n", argv[0], options.output_file); break;
398            case ERROR_INVALID_TAG: fprintf(stderr, "%s: invalid FLV tag\n", argv[0]); break;
399            case ERROR_WRITE: fprintf(stderr, "%s: unable to write to %s\n", argv[0], options.output_file); break;
400        }
401    }
402
403    return errcode;
404}