📄 pgmtoy4m.c
字号:
/* * $Id: pgmtoy4m.c,v 1.15 2004/05/07 04:19:45 sms00 Exp $ * * pgmtoy4m converts the PGM output of "mpeg2dec -o pgmpipe" to YUV4MPEG2 on * stdout. * * Note: mpeg2dec uses a rather interesting variation of the PGM format - the * output is not actually traditional "Grey Maps" but rather a catenation of * the Y'CrCb planes. From the libmpeg2 project's video_out_pgm.c: * * Layout of the Y, U, and V buffers in our pgm image * * YY YY YY * 420: YY 422: YY 444: YY * UV UV UUVV * UV UUVV * * The PGM type is P5 ("raw") and the number of rows is really the * total of the Y', Cb and Cr heights. The Cb and Cr data is "joined" * together. * * NOTE: You MAY need to know the field order (top or bottom field first), * sample aspect ratio and frame rate because the PGM format makes * none of that information available! There are defaults provided * that hopefully will do the right thing in the common cases. * * The defaults provided are: 4:2:0, top field first, NTSC rate of * 30000/1001 frames/second, and a sample aspect of 10:11. * * If the incoming chroma space is not 4:2:0 then you MUST specify the * "-x chroma_tag" option or chaos and/or a program crash will occur.*/#if defined(HAVE_CONFIG_H)#include "config.h"#endif#include <stdio.h>#include <sys/types.h>#include <ctype.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include "yuv4mpeg.h"static void usage(char *progname);static void chroma_usage(char *progname);static int getint(int);#define P5MAGIC (('P' * 256) + '5')static intgetmagicnumber(int fd) { char ch1 = -1, ch2 = -1; read(fd, &ch1, 1); read(fd, &ch2, 1); return((ch1 * 256) + ch2); }static intpiperead(int fd, u_char *buf, int len) { int n = 0; int r = 0; while (r < len) { n = read (fd, buf + r, len - r); if (n <= 0) return(r); r += n; } return(r); }intmain(int argc, char **argv) { int width, height, uvlen, verbose = 1, fdout, fdin, c, i; int columns, rows, maxval, magicn, frameno; int ss_h, ss_v, chroma_height, chroma_width; int chroma_mode = Y4M_UNKNOWN; u_char *yuv[3]; char junkbuffer[16384]; y4m_ratio_t rate_ratio = y4m_fps_UNKNOWN; y4m_ratio_t aspect_ratio = y4m_sar_UNKNOWN; char ilace = Y4M_ILACE_TOP_FIRST; y4m_frame_info_t oframe; y4m_stream_info_t ostream; fdin = fileno(stdin); fdout = fileno(stdout); y4m_accept_extensions(1); opterr = 0; while ((c = getopt(argc, argv, "i:a:r:hv:x:")) != EOF) { switch (c) { case 'i': switch (optarg[0]) { case 'p': ilace = Y4M_ILACE_NONE; break; case 't': ilace = Y4M_ILACE_TOP_FIRST; break; case 'b': ilace = Y4M_ILACE_BOTTOM_FIRST; break; default: usage(argv[0]); } break; case 'v': verbose = atoi(optarg); if (verbose < 0 || verbose > 3) mjpeg_error_exit1("Verbosity [0..2]"); break; case 'a': i = y4m_parse_ratio(&aspect_ratio, optarg); if (i != Y4M_OK) mjpeg_error_exit1("Invalid aspect: %s", optarg); break; case 'r': i = y4m_parse_ratio(&rate_ratio, optarg); if (i != Y4M_OK) mjpeg_error_exit1("Invalid rate: %s", optarg); break; case 'x': chroma_mode = y4m_chroma_parse_keyword(optarg); if (chroma_mode == Y4M_UNKNOWN) { if (strcmp(optarg, "help") == 0) chroma_usage(argv[0]); mjpeg_error_exit1("bad chroma arg"); } break; case 'h': case '?': default: usage(argv[0]); /* NOTREACHED */ } } if (chroma_mode == Y4M_UNKNOWN) chroma_mode = Y4M_CHROMA_420MPEG2; if (isatty(fdout)) mjpeg_error_exit1("stdout must not be a terminal"); mjpeg_default_handler_verbosity(verbose);/* * Check that the input stream is really a P5 (rawbits PGM) stream, then if it * is retrieve the "rows" and "columns" (width and height) and the maxval. * The maxval will be 255 if the data was generated from mpeg2dec!*/ magicn = getmagicnumber(fdin); if (magicn != P5MAGIC) mjpeg_error_exit1("Input not P5 PGM data, got %x", magicn); columns = getint(fdin); rows = getint(fdin); maxval = getint(fdin); mjpeg_log(LOG_INFO, "P5 cols: %d rows: %d maxval: %d", columns, rows, maxval); if (maxval != 255) mjpeg_error_exit1("Maxval (%d) != 255, not mpeg2dec output?", maxval);/* * Put some sanity checks on the sizes - handling up to 4096x4096 should be * enough for now :)*/ if (columns < 0 || columns > 4096 || rows < 0 || rows > 4096) mjpeg_error_exit1("columns (%d) or rows(%d) < 0 or > 4096", columns, rows); y4m_init_frame_info(&oframe); y4m_init_stream_info(&ostream); y4m_si_set_chroma(&ostream, chroma_mode); if (y4m_si_get_plane_count(&ostream) != 3) mjpeg_error_exit1("Only the 3 plane formats supported"); ss_h = y4m_chroma_ss_x_ratio(chroma_mode).d; ss_v = y4m_chroma_ss_y_ratio(chroma_mode).d; width = columns; height = (rows * ss_v) / (ss_v + 1); chroma_width = width / ss_h; chroma_height = height / ss_v; uvlen = chroma_height * chroma_width; yuv[0] = malloc(height * width); yuv[1] = malloc(uvlen); yuv[2] = malloc(uvlen); if (yuv[0] == NULL || yuv[1] == NULL || yuv[2] == NULL) mjpeg_error_exit1("malloc yuv[]");/* * If the (sample) aspect ratio and frame rate were not specified on the * command line try to intuit the video norm of NTSC or PAL by looking at the * height of the frame.*/ if (Y4M_RATIO_EQL(aspect_ratio, y4m_sar_UNKNOWN)) { if (height == 480 || height == 240) { aspect_ratio = y4m_sar_NTSC_CCIR601; mjpeg_log(LOG_WARN, "sample aspect not specified, using NTSC CCIR601 value based on frame height of %d", height); } else if (height == 576 || height == 288) { aspect_ratio = y4m_sar_PAL_CCIR601; mjpeg_log(LOG_WARN, "sample aspect not specified, using PAL CCIR601 value based on frame height of %d", height); } else { mjpeg_log(LOG_WARN, "sample aspect not specified and can not be inferred from frame height of %d (leaving sar as unknown", height); } } if (Y4M_RATIO_EQL(rate_ratio, y4m_fps_UNKNOWN)) { if (height == 480 || height == 240) { rate_ratio = y4m_fps_NTSC; mjpeg_log(LOG_WARN, "frame rate not specified, using NTSC value based on frame height of %d", height); } else if (height == 576 || height == 288) { rate_ratio = y4m_fps_PAL; mjpeg_log(LOG_WARN, "frame rate not specified, using PAL value based on frame height of %d", height); } else { mjpeg_log(LOG_WARN, "frame rate not specified and can not be inferred from frame height of %d (using NTSC value)", height); rate_ratio = y4m_fps_NTSC; } } y4m_si_set_interlace(&ostream, ilace); y4m_si_set_framerate(&ostream, rate_ratio); y4m_si_set_sampleaspect(&ostream, aspect_ratio); y4m_si_set_width(&ostream, width); y4m_si_set_height(&ostream, height); y4m_write_stream_header(fdout, &ostream);/* * Now continue reading P5 frames as long as the magic number appears. Corrupt * (malformed) input or EOF will terminate the loop. The columns, rows and * maxval must be read to get to the raw data. It's probably not worth doing * anything (in fact it's unclear what could be done ;)) with the values * if they're different from the first header which was used to set the * output stream parameters.*/ frameno = 0; while (1) { for (i = 0; i < height; i++) { piperead(fdin, yuv[0] + i * width, width); piperead(fdin, junkbuffer, 2 * chroma_width - width); } for (i = 0; i < chroma_height; i++) { piperead(fdin, yuv[1] + i * chroma_width, chroma_width); piperead(fdin, yuv[2] + i * chroma_width, chroma_width); } y4m_write_frame(fdout, &ostream, &oframe, yuv); magicn = getmagicnumber(fdin); if (magicn != P5MAGIC) { mjpeg_log(LOG_DEBUG, "frame: %d got magic: %x\n", frameno, magicn); break; } columns = getint(fdin); rows = getint(fdin); maxval = getint(fdin); frameno++; mjpeg_log(LOG_DEBUG, "frame: %d P5MAGIC cols: %d rows: %d maxval: %d", frameno, columns, rows, maxval); } y4m_fini_frame_info(&oframe); y4m_fini_stream_info(&ostream); return 0; }static voidusage(char *progname) { fprintf(stderr, "%s usage: [-v n] [-i t|b|p] [-x chroma] [-a sample aspect] [-r rate]\n", progname); fprintf(stderr, "%s\taspect and rate in ratio form: -a 10:11 and -r 30000:1001 or -r 25:1 for example\n", progname); fprintf(stderr, "%s\t chroma default is 420mpeg2, -x help for list\n", progname); exit(0); }static intgetint(int fd) { char ch; int i; do { if (read(fd, &ch, 1) == -1) return(-1); if (ch == '#') { while (ch != '\n') { if (read(fd, &ch, 1) == -1) return(-1); } } } while (isspace(ch)); if (!isdigit(ch)) return(-1); i = 0; do { i = i * 10 + (ch - '0'); if (read(fd, &ch, 1) == -1) break; } while (isdigit(ch)); return(i); }void chroma_usage(char *pname) { int mode = 0; const char *keyword; fprintf(stderr, "%s -x usage: Only the 3 plane formats are actually supported\n", pname); for (mode = 0; (keyword = y4m_chroma_keyword(mode)) != NULL; mode++) fprintf(stderr, "\t%s - %s\n", keyword, y4m_chroma_description(mode)); exit(1); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -