⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pnmtoy4m.c

📁 Motion JPEG编解码器源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * pnmtoy4m.c:  Generate a YUV4MPEG2 stream from one or more PNM/PAM images. * *              Converts R'G'B' to ITU-Rec.601 Y'CbCr colorspace, and/or *               converts [0,255] grayscale to Rec.601 Y' luma. * * *  Copyright (C) 2004 Matthew J. Marjanovic <maddog@mir.com> * * *  This program is free software; you can redistribute it and/or *  modify it under the terms of the GNU General Public License *  as published by the Free Software Foundation; either version 2 *  of the License, or (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. * */#include <config.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <ctype.h>#include <errno.h>#include <fcntl.h>#include <assert.h>#include <yuv4mpeg.h>#include <mpegconsts.h>#include "colorspace.h"#ifndef O_BINARY# define O_BINARY 0#endif/* command-line parameters */typedef struct _cl_info {  y4m_ratio_t output_aspect;      y4m_ratio_t output_framerate;   int output_interlace;           int input_interlace;           int deinterleave;  int offset;  int framecount;  int repeatlast;  int verbosity;  int fdin;  int bgr;} cl_info_t;staticvoid usage(const char *progname){  fprintf(stdout, "\n");  fprintf(stdout, "usage:  %s [options] [pnm-file]\n", progname);  fprintf(stdout, "\n");  fprintf(stdout, "Reads RAW PNM/PAM image(s), and produces YUV4MPEG2 stream on stdout.\n");  fprintf(stdout, "Converts computer graphics R'G'B' colorspace to digital video Y'CbCr.\n");  fprintf(stdout, "\n");  fprintf(stdout, "If 'pnm-file' is not specified, reads from stdin.\n");  fprintf(stdout, "\n");  fprintf(stdout, " options:  (defaults specified in [])\n");  fprintf(stdout, "\n");  fprintf(stdout, "  -o n     frame offset (skip n input frames) [0]\n");  fprintf(stdout, "  -n n     frame count (output n frames; 0 == all of them) [0]\n");  fprintf(stdout, "  -r       repeat last input frame\n");  fprintf(stdout, "  -D x     treat PNM images as de-interleaved fields, with:\n");  fprintf(stdout, "             t = first-image-is-top-field\n");  fprintf(stdout, "             b = first-image-is-bottom-field\n");  fprintf(stdout, "  -F n:d   output framerate [30000:1001 = NTSC]\n");  fprintf(stdout, "  -A w:h   output pixel aspect ratio [1:1]\n");  fprintf(stdout, "  -I x     output interlacing [from -D, or p]\n");  fprintf(stdout, "             p = none/progressive\n");  fprintf(stdout, "             t = top-field-first\n");  fprintf(stdout, "             b = bottom-field-first\n");  fprintf(stdout, "  -v n     verbosity (0,1,2) [1]\n");  fprintf(stdout, "  -B       pixels are packed in BGR(A) format [RGB(A)]\n");}staticvoid parse_args(cl_info_t *cl, int argc, char **argv){  int c;  cl->offset = 0;  cl->framecount = 0;  cl->output_aspect = y4m_sar_SQUARE;  cl->output_interlace = Y4M_UNKNOWN;  cl->output_framerate = y4m_fps_NTSC;  cl->deinterleave = 0;  cl->input_interlace = Y4M_ILACE_NONE;  cl->repeatlast = 0;  cl->verbosity = 1;  cl->fdin = 0; /* default to stdin */  cl->bgr = 0;  while ((c = getopt(argc, argv, "A:F:I:D:o:n:rv:Bh")) != -1) {    switch (c) {    case 'A':      if (y4m_parse_ratio(&(cl->output_aspect), optarg) != Y4M_OK) {	mjpeg_error("Could not parse ratio:  '%s'", optarg);	goto ERROR_EXIT;      }      break;    case 'F':      if (y4m_parse_ratio(&(cl->output_framerate), optarg) != Y4M_OK) {	mjpeg_error("Could not parse ratio:  '%s'", optarg);	goto ERROR_EXIT;      }      break;    case 'I':      switch (optarg[0]) {      case 'p':  cl->output_interlace = Y4M_ILACE_NONE;  break;      case 't':  cl->output_interlace = Y4M_ILACE_TOP_FIRST;  break;      case 'b':  cl->output_interlace = Y4M_ILACE_BOTTOM_FIRST;  break;      default:	mjpeg_error("Unknown value for output interlace: '%c'", optarg[0]);	goto ERROR_EXIT;	break;      }      break;    case 'D':      cl->deinterleave = 1;      switch (optarg[0]) {      case 't':  cl->input_interlace = Y4M_ILACE_TOP_FIRST;  break;      case 'b':  cl->input_interlace = Y4M_ILACE_BOTTOM_FIRST;  break;      default:	mjpeg_error("Unknown value for input interlace: '%c'", optarg[0]);	goto ERROR_EXIT;	break;      }      break;    case 'o':      if ((cl->offset = atoi(optarg)) < 0)	mjpeg_error_exit1("Offset must be >= 0:  '%s'", optarg);      break;    case 'n':      if ((cl->framecount = atoi(optarg)) < 0)	mjpeg_error_exit1("Frame count must be >= 0:  '%s'", optarg);      break;    case 'r':      cl->repeatlast = 1;      break;    case 'v':      cl->verbosity = atoi(optarg);      if ((cl->verbosity < 0) || (cl->verbosity > 2))	mjpeg_error("Verbosity must be 0, 1, or 2:  '%s'", optarg);      break;    case 'h':      usage(argv[0]);      exit(0);      break;    case 'B':      cl->bgr = 1;      break;    case '?':    default:      goto ERROR_EXIT;      break;    }  }  /* optional remaining argument is a filename */  if (optind == (argc - 1)) {    if ((cl->fdin = open(argv[optind], O_RDONLY | O_BINARY)) == -1)      mjpeg_error_exit1("Failed to open '%s':  %s",			argv[optind], strerror(errno));  } else if (optind != argc)     goto ERROR_EXIT;  mjpeg_default_handler_verbosity(cl->verbosity);  /* output ilace defaults to match input (or none if input is interleaved) */  if (cl->output_interlace == Y4M_UNKNOWN) {    if (cl->deinterleave)      cl->output_interlace = cl->input_interlace;    else      cl->output_interlace = Y4M_ILACE_NONE;  }  mjpeg_info("Command-line Parameters:");  if (!cl->deinterleave) {    mjpeg_info("  input format:  interleaved");  } else {    mjpeg_info("  input format:  field-sequential, %s",               (cl->input_interlace == Y4M_ILACE_TOP_FIRST) ?               "first-image-is-top" :               "first-image-is-bottom");  }  mjpeg_info("    pixel packing:  %s", (cl->bgr?"BGR(A)":"RGB(A)"));   mjpeg_info(" output framerate:  %d:%d",	     cl->output_framerate.n, cl->output_framerate.d);  mjpeg_info("       output SAR:  %d:%d",	     cl->output_aspect.n, cl->output_aspect.d);  mjpeg_info(" output interlace:  %s",	     mpeg_interlace_code_definition(cl->output_interlace));  mjpeg_info("   starting frame:  %d", cl->offset);  if (cl->framecount == 0)    mjpeg_info("    # of frames:  all%s",	       (cl->repeatlast) ? ", repeat last frame forever" :	       ", until input exhausted");  else    mjpeg_info("    # of frames:  %d%s",	       cl->framecount,	       (cl->repeatlast) ? ", repeat last frame until done" :	       ", or until input exhausted");  /* DONE! */  return; ERROR_EXIT:  mjpeg_error("For usage hints, use option '-h'.  Please take a hint.");  exit(1);}/* the various PNM formats we handle */typedef enum {  FMT_PAM = 0,  FMT_PPM_RAW,  FMT_PGM_RAW,  FMT_PBM_RAW,  FMT_PPM_PLAIN,  FMT_PGM_PLAIN,  FMT_PBM_PLAIN,  FMT_UNKNOWN} pnm_format_t;#define FMT_FIRST FMT_PAM#define FMT_COUNT FMT_UNKNOWN/* 'magic numbers' of the PNM formats (corresponding to enum above) */const char *magics[FMT_COUNT+1] = {  "P7",  "P6",  "P5",  "P4",  "P3",  "P2",  "P1",  "*UNKNOWN*"};/* the various PAM "tupls" we handle */typedef enum {  TUPL_RGB = 0,  TUPL_GRAY,  TUPL_RGB_ALPHA,  TUPL_GRAY_ALPHA,  TUPL_BW,  TUPL_BW_ALPHA,  TUPL_UNKNOWN} pam_tupl_t;#define TUPL_FIRST TUPL_RGB#define TUPL_COUNT TUPL_UNKNOWNstruct tupl_info {  const char *tag;  int depth;};/* descriptions of the PAM tupls (corresponding to enum above) */const struct tupl_info tupls[TUPL_COUNT+1] = {  { "RGB",                  3 },  { "GRAYSCALE",            1 },  { "RGB_ALPHA",            4 },  { "GRAYSCALE_ALPHA",      2 },  { "BLACKANDWHITE",        1 },  { "BLACKANDWHITE_ALPHA",  2 },  { "*UNKNOWN*",            0 }};/* PNM image information */typedef struct _pnm_info {  pnm_format_t format;  int width;  int height;  int depth;  pam_tupl_t tupl;} pnm_info_t;staticint pnm_info_equal(pnm_info_t *a, pnm_info_t *b){  return ((a->format == b->format) &&          (a->width  == b->width)  &&          (a->height == b->height) &&          (a->depth  == b->depth) &&          (a->tupl   == b->tupl));}staticvoid pnm_info_copy(pnm_info_t *dst, pnm_info_t *src){  dst->format = src->format;  dst->width  = src->width;  dst->height = src->height;  dst->depth  = src->depth;  dst->tupl   = src->tupl;}staticchar *read_tag_and_value(int fd, char *line, int maxlen){  int found_end_of_tag = 0;  char *v = NULL;  int n;  while ( (maxlen > 0) &&          ((n = read(fd, line, 1)) == 1) &&          (*line != '\n') ) {    if (!found_end_of_tag) {      if (isspace(*line)) {        *line = '\0';        found_end_of_tag = 1;      }    } else if (v == NULL) {      if (!isspace(*line))        v = line;    }    line++;  }  if (maxlen <= 0) return NULL;  if (n != 1) return NULL;  *line = '\0';  if (v == NULL) return line;  return v;}staticint read_pam_header(int fd, pnm_info_t *pnm){  char line[128];  int done = 0;  int maxval = 0;  char *val;  pnm->width = 0;  pnm->height = 0;  pnm->depth = 0;  pnm->tupl = TUPL_UNKNOWN;  while (!done && ((val = read_tag_and_value(fd, line, 128)) != NULL)) {    if (!strcmp(line, "ENDHDR")) {      done = 1;    } else if (!strcmp(line, "HEIGHT")) {      pnm->height = atoi(val);    } else if (!strcmp(line, "WIDTH")) {      pnm->width = atoi(val);    } else if (!strcmp(line, "DEPTH")) {      pnm->depth = atoi(val);    } else if (!strcmp(line, "MAXVAL")) {      maxval = atoi(val);    } else if (!strcmp(line, "TUPLTYPE")) {      if (pnm->tupl != TUPL_UNKNOWN)         mjpeg_error_exit1("Too many PAM TUPLTYPE's: %s", val);      for (pnm->tupl = TUPL_FIRST;           pnm->tupl < TUPL_UNKNOWN;            (pnm->tupl)++) {        if (!(strcmp(val, tupls[pnm->tupl].tag))) break;      }      if (pnm->tupl == TUPL_UNKNOWN)        mjpeg_error_exit1("Unknown PAM TUPLTYPE: %s", val);    }  }  if ( (pnm->width == 0) || (pnm->height == 0) ||        (pnm->depth == 0) || (maxval == 0) )    mjpeg_error_exit1("Bad PAM header!\n");    if (pnm->tupl == TUPL_UNKNOWN) {    for (pnm->tupl = TUPL_FIRST;         pnm->tupl < TUPL_UNKNOWN;         (pnm->tupl)++) {      if (pnm->depth == tupls[pnm->tupl].depth) break;    }    if (pnm->tupl == TUPL_UNKNOWN)       mjpeg_error_exit1("No PAM TUPL for depth %d!", pnm->depth);  } else {    if (pnm->depth != tupls[pnm->tupl].depth)      mjpeg_error_exit1("PAM depth mismatch:  %d != %d for %s.",                        pnm->depth,                        tupls[pnm->tupl].depth, tupls[pnm->tupl].tag);  }  if (maxval != 255)    mjpeg_error_exit1("Expecting maxval == 255, not %d!", maxval);  return 0;}#define DO_READ_NUMBER(var)                                     \  do {                                                          \    if (!isdigit(s[0]))                                         \      mjpeg_error_exit1("PNM read error:  bad char  %d", s[0]); \    (var) = ((var) * 10) + (s[0] - '0');                        \  } while (((n = read(fd, s, 1)) == 1) && (!isspace(s[0])));    \  if (n <= 0) return -1;                                        #define DO_SKIP_WHITESPACE()                                     \  incomment = 0;                                                 \  while ( ((n = read(fd, s, 1)) == 1) &&                         \	  ((isspace(s[0])) || (s[0] == '#') || (incomment)) ) {  \    if (s[0] == '#') incomment = 1;                              \    if (s[0] == '\n') incomment = 0;                             \  }                                                              \  if (n <= 0) return -1;                                         /* * returns:  0 - success, got header *           1 - EOF, no new frame *          -1 - failure (actually, just errors out...) */staticint read_pnm_header(int fd, pnm_info_t *pnm){  char s[6];  int incomment;  int n;  int maxval = 0;    pnm->width = 0;  pnm->height = 0;  pnm->depth = 0;  /* look for MAGIC */  n = y4m_read(fd, s, 3);  if (n > 0)     return 1;  /* EOF */  if (n < 0)    mjpeg_error_exit1("Bad PNM header magic!");  for (pnm->format = FMT_FIRST;       pnm->format < FMT_UNKNOWN;        (pnm->format)++) {    if (!(strncmp(s, magics[pnm->format], 2))) break;  }  if ( (pnm->format == FMT_UNKNOWN) ||       (!isspace(s[2])) )    mjpeg_error_exit1("Bad PNM magic!");  if (pnm->format == FMT_PAM) {    if (s[2] != '\n')      mjpeg_error_exit1("Bad PAM magic!");    return read_pam_header(fd, pnm);  } else {    pnm->tupl = TUPL_UNKNOWN;    incomment = 0;    DO_SKIP_WHITESPACE();    DO_READ_NUMBER(pnm->width);    DO_SKIP_WHITESPACE();    DO_READ_NUMBER(pnm->height);    if ((pnm->format != FMT_PBM_RAW) && (pnm->format != FMT_PBM_PLAIN)) {      DO_SKIP_WHITESPACE();      DO_READ_NUMBER(maxval);      if (maxval != 255)        mjpeg_error_exit1("Expecting maxval == 255, not %d!", maxval);    }    switch (pnm->format) {    case FMT_PPM_RAW:     case FMT_PPM_PLAIN:      pnm->depth = 3;      break;    case FMT_PGM_RAW:    case FMT_PBM_RAW:    case FMT_PGM_PLAIN:    case FMT_PBM_PLAIN:      pnm->depth = 1;      break;    default:      assert(0);      break;    }  }  return 0;}staticvoid alloc_buffers(uint8_t *buffers[], int width, int height, int depth){  mjpeg_debug("Alloc'ing buffers");  buffers[0] = malloc(width * height * sizeof(buffers[0][0]));  if (depth > 1) {    buffers[1] = malloc(width * height * sizeof(buffers[1][0]));    buffers[2] = malloc(width * height * sizeof(buffers[2][0]));  }  if (depth > 3)     buffers[3] = malloc(width * height * sizeof(buffers[3][0]));}staticvoid read_rgba_raw(int fd, uint8_t *buffers[],                   uint8_t *rowbuffer, int width, int height, int bgra) {  int x, y;  uint8_t *pixels;  uint8_t *R = buffers[0];  uint8_t *G = buffers[1];  uint8_t *B = buffers[2];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -