diff options
author | Sylvain Munaut <tnt@246tNt.com> | 2010-11-11 22:58:57 +0100 |
---|---|---|
committer | Sylvain Munaut <tnt@246tNt.com> | 2010-11-11 22:58:57 +0100 |
commit | 4604976a5facb2105bde3214b31ba609df65b939 (patch) | |
tree | 9e9db09a2c9bd4ca0879d4b174980f0484607a22 | |
parent | 456758c80826bc9f95f9418392fdaed35a81bd04 (diff) |
Add a real main method to does the job
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
-rw-r--r-- | src/main.c | 406 |
1 files changed, 405 insertions, 1 deletions
@@ -17,7 +17,411 @@ * along with gapk. If not, see <http://www.gnu.org/licenses/>. */ -int main(int argc, char *argv[]) +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <getopt.h> + +#include <gapk/codecs.h> +#include <gapk/formats.h> +#include <gapk/procqueue.h> + + +struct gapk_options +{ + const char *fname_in; + const struct format_desc *fmt_in; + + const char *fname_out; + const struct format_desc *fmt_out; +}; + +struct gapk_state +{ + struct gapk_options opts; + + struct pq *pq; + + FILE *fh_in; + FILE *fh_out; +}; + + +static void +print_help(char *progname) +{ + int i; + + /* Header */ + fprintf(stdout, "Usage: %s [options]\n", progname); + fprintf(stdout, "\n"); + fprintf(stdout, "Options:\n"); + fprintf(stdout, " -i, --input-file=FILE\t\tInput file\n"); + fprintf(stdout, " -o, --output-file=FILE\tOutput file\n"); + fprintf(stdout, " -f, --input-format=FMT\tInput format (see below)\n"); + fprintf(stdout, " -g, --output-format=FMT\tOutput format (see below)\n"); + fprintf(stdout, "\n"); + + /* Print all codecs */ + fprintf(stdout, "Supported codecs:\n"); + fprintf(stdout, " name\tfmt enc dec\tdescription\n"); + + for (i=CODEC_INVALID+1; i<_CODEC_MAX; i++) { + const struct codec_desc *codec = codec_get_from_type(i); + fprintf(stdout, " %s\t %c %c %c\t%s\n", + codec->name, + '*', + codec->codec_encode ? '*' : ' ', + codec->codec_decode ? '*' : ' ', + codec->description + ); + } + + fprintf(stdout, "\n"); + + /* Print all formats */ + fprintf(stdout, "Supported formats:\n"); + + for (i=FMT_INVALID+1; i<_FMT_MAX; i++) { + const struct format_desc *fmt = fmt_get_from_type(i); + fprintf(stdout, " %s%s%s\t%s\n", + fmt->name, + strlen(fmt->name) < 7 ? "\t" : "", + strlen(fmt->name) < 15 ? "\t" : "", + fmt->description + ); + } + + fprintf(stdout, "\n"); +} + +static int +parse_options(struct gapk_state *state, int argc, char *argv[]) +{ + const struct option long_options[] = { + {"input-file", 1, 0, 'i'}, + {"output-file", 1, 0, 'o'}, + {"input-format", 1, 0, 'f'}, + {"output-format", 1, 0, 'g'}, + {"help", 0, 0, 'h'}, + }; + const char *short_options = "i:o:f:g:h"; + + struct gapk_options *opt = &state->opts; + + /* Set some defaults */ + memset(opt, 0x00, sizeof(*opt)); + + /* Parse */ + while (1) { + int c; + int opt_idx; + + c = getopt_long( + argc, argv, short_options, long_options, &opt_idx); + if (c == -1) + break; + + switch (c) { + case 'i': + opt->fname_in = optarg; + break; + + case 'o': + opt->fname_out = optarg; + break; + + case 'f': + opt->fmt_in = fmt_get_from_name(optarg); + if (!opt->fmt_in) { + fprintf(stderr, "[!] Unsupported format: %s\n", optarg); + return -EINVAL; + } + break; + + case 'g': + opt->fmt_out = fmt_get_from_name(optarg); + if (!opt->fmt_out) { + fprintf(stderr, "[!] Unsupported format: %s\n", optarg); + return -EINVAL; + } + break; + + case 'h': + return 1; + + default: + fprintf(stderr, "[+] Unknown option\n"); + return -EINVAL; + + } + } + + return 0; +} + +static int +check_options(struct gapk_state *gs) { + /* Required formats */ + if (!gs->opts.fmt_in || !gs->opts.fmt_out) { + fprintf(stderr, "[!] Input and output formats are required arguments !\n"); + return -EINVAL; + } + + /* Transcoding */ + if (gs->opts.fmt_in->codec_type != gs->opts.fmt_out->codec_type) { + const struct codec_desc *codec; + + /* Check source codec */ + codec = codec_get_from_type(gs->opts.fmt_in->codec_type); + if (!codec) { + fprintf(stderr, "[!] Internal error: bad codec reference\n"); + return -EINVAL; + } + if ((codec->type != CODEC_PCM) && !codec->codec_decode) { + fprintf(stderr, "[!] Decoding from '%s' codec is unsupported\n", codec->name); + return -ENOTSUP; + } + + /* Check destination codec */ + codec = codec_get_from_type(gs->opts.fmt_out->codec_type); + if (!codec) { + fprintf(stderr, "[!] Internal error: bad codec reference\n"); + return -EINVAL; + } + if ((codec->type != CODEC_PCM) && !codec->codec_encode) { + fprintf(stderr, "[!] Encoding to '%s' codec is unsupported\n", codec->name); + return -ENOTSUP; + } + } + + return 0; +} + +static int +files_open(struct gapk_state *gs) +{ + if (gs->opts.fname_in) { + gs->fh_in = fopen(gs->opts.fname_in, "rb"); + if (!gs->fh_in) { + fprintf(stderr, "[!] Error while opening input file for reading\n"); + perror("fopen"); + return -errno; + } + } else + gs->fh_in = stdin; + + if (gs->opts.fname_out) { + gs->fh_out = fopen(gs->opts.fname_out, "wb"); + if (!gs->fh_out) { + fprintf(stderr, "[!] Error while opening output file for writing\n"); + perror("fopen"); + return -errno; + } + } else + gs->fh_out = stdout; + return 0; } + +static void +files_close(struct gapk_state *gs) +{ + if (gs->fh_in && gs->fh_in != stdin) + fclose(gs->fh_in); + if (gs->fh_out && gs->fh_out != stdout) + fclose(gs->fh_out); +} + +static int +handle_headers(struct gapk_state *gs) +{ + int rv; + unsigned int len; + + /* Input file header (remove & check it) */ + len = gs->opts.fmt_in->header_len; + if (len) { + uint8_t *buf; + + buf = malloc(len); + if (!buf) + return -ENOMEM; + + rv = fread(buf, len, 1, gs->fh_in); + if ((rv != 1) || + memcmp(buf, gs->opts.fmt_in->header, len)) + { + free(buf); + fprintf(stderr, "[!] Invalid header in input file"); + return -EINVAL; + } + + free(buf); + } + + /* Output file header (write it) */ + len = gs->opts.fmt_out->header_len; + if (len) { + rv = fwrite(gs->opts.fmt_out->header, len, 1, gs->fh_out); + if (rv != 1) + return -ENOSPC; + } + + return 0; +} + +static int +make_processing_chain(struct gapk_state *gs) +{ + const struct format_desc *fmt_in, *fmt_out; + const struct codec_desc *codec_in, *codec_out; + + int need_dec, need_enc; + + fmt_in = gs->opts.fmt_in; + fmt_out = gs->opts.fmt_out; + + codec_in = codec_get_from_type(fmt_in->codec_type); + codec_out = codec_get_from_type(fmt_out->codec_type); + + need_dec = (fmt_in->codec_type != CODEC_PCM) && + (fmt_in->codec_type != fmt_out->codec_type); + need_enc = (fmt_out->codec_type != CODEC_PCM) && + (fmt_out->codec_type != fmt_in->codec_type); + + /* File read */ + pq_queue_file_input(gs->pq, gs->fh_in, fmt_in->frame_len); + + /* Decoding to PCM ? */ + if (need_dec) + { + /* Convert input to decoder input fmt */ + if (fmt_in->type != codec_in->codec_dec_format_type) + { + const struct format_desc *fmt_dec; + + fmt_dec = fmt_get_from_type(codec_in->codec_dec_format_type); + if (!fmt_dec) + return -EINVAL; + + pq_queue_fmt_convert(gs->pq, fmt_in, 0); + pq_queue_fmt_convert(gs->pq, fmt_dec, 1); + } + + /* Do decoding */ + pq_queue_codec(gs->pq, codec_in, 0); + } + else if (fmt_in->type != fmt_out->type) + { + /* Convert input to canonical fmt */ + pq_queue_fmt_convert(gs->pq, fmt_in, 0); + } + + /* Encoding from PCM ? */ + if (need_enc) + { + /* Do encoding */ + pq_queue_codec(gs->pq, codec_out, 1); + + /* Convert encoder output to output fmt */ + if (fmt_out->type != codec_out->codec_enc_format_type) + { + const struct format_desc *fmt_enc; + + fmt_enc = fmt_get_from_type(codec_out->codec_enc_format_type); + if (!fmt_enc) + return -EINVAL; + + pq_queue_fmt_convert(gs->pq, fmt_enc, 0); + pq_queue_fmt_convert(gs->pq, fmt_out, 1); + } + } + else if (fmt_in->type != fmt_out->type) + { + /* Convert canonical to output fmt */ + pq_queue_fmt_convert(gs->pq, fmt_out, 1); + } + + /* File write */ + pq_queue_file_output(gs->pq, gs->fh_out, fmt_out->frame_len); + + return 0; +} + +static int +run(struct gapk_state *gs) +{ + int rv, frames; + + rv = pq_prepare(gs->pq); + if (rv) + return rv; + + for (frames=0; !(rv = pq_execute(gs->pq)); frames++); + + fprintf(stderr, "[+] Processed %d frames\n", frames); + + return frames > 0 ? 0 : rv; +} + +int main(int argc, char *argv[]) +{ + struct gapk_state _gs, *gs = &_gs; + int rv; + + /* Clear state */ + memset(gs, 0x00, sizeof(struct gapk_state)); + + /* Parse / check options */ + rv = parse_options(gs, argc, argv); + if (rv > 0) { + print_help(argv[0]); + return 0; + } + if (rv < 0) + return rv; + + /* Check request */ + rv = check_options(gs); + if (rv) + return rv; + + /* Create processing queue */ + gs->pq = pq_create(); + if (!gs->pq) { + rv = -ENOMEM; + goto error; + } + + /* Open source / destination files */ + rv = files_open(gs); + if (rv) + goto error; + + /* Handle input/output headers */ + rv = handle_headers(gs); + if (rv) + goto error; + + /* Make processing chain */ + rv = make_processing_chain(gs); + if (rv) + goto error; + + /* Run the processing queue */ + rv = run(gs); + +error: + /* Close source / destination files */ + files_close(gs); + + /* Release processing queue */ + pq_destroy(gs->pq); + + return rv; +} |