/* * mpegconsts.c: Video format constants for MPEG and utilities for display * and conversion to format used for yuv4mpeg * * Copyright (C) 2001 Andrew Stevens * Copyright (C) 2001 Matthew Marjanovic * * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. * * 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 #include "mpegconsts.h" #include "yuv4mpeg.h" #include "yuv4mpeg_intern.h" static y4m_ratio_t mpeg_framerates[] = { Y4M_FPS_UNKNOWN, Y4M_FPS_NTSC_FILM, Y4M_FPS_FILM, Y4M_FPS_PAL, Y4M_FPS_NTSC, Y4M_FPS_30, Y4M_FPS_PAL_FIELD, Y4M_FPS_NTSC_FIELD, Y4M_FPS_60 }; #define MPEG_NUM_RATES (sizeof(mpeg_framerates)/sizeof(mpeg_framerates[0])) const mpeg_framerate_code_t mpeg_num_framerates = MPEG_NUM_RATES; static const char *framerate_definitions[MPEG_NUM_RATES] = { "illegal", "24000.0/1001.0 (NTSC 3:2 pulldown converted FILM)", "24.0 (NATIVE FILM)", "25.0 (PAL/SECAM VIDEO / converted FILM)", "30000.0/1001.0 (NTSC VIDEO)", "30.0", "50.0 (PAL FIELD RATE)", "60000.0/1001.0 (NTSC FIELD RATE)", "60.0" }; static const char *mpeg1_aspect_ratio_definitions[] = { "1:1 (square pixels)", "1:0.6735", "1:0.7031 (16:9 Anamorphic PAL/SECAM for 720x578/352x288 images)", "1:0.7615", "1:0.8055", "1:0.8437 (16:9 Anamorphic NTSC for 720x480/352x240 images)", "1:0.8935", "1:0.9375 (4:3 PAL/SECAM for 720x578/352x288 images)", "1:0.9815", "1:1.0255", "1:1:0695", "1:1.1250 (4:3 NTSC for 720x480/352x240 images)", "1:1.1575", "1:1.2015" }; static const y4m_ratio_t mpeg1_aspect_ratios[] = { Y4M_SAR_MPEG1_1, Y4M_SAR_MPEG1_2, Y4M_SAR_MPEG1_3, /* Anamorphic 16:9 PAL */ Y4M_SAR_MPEG1_4, Y4M_SAR_MPEG1_5, Y4M_SAR_MPEG1_6, /* Anamorphic 16:9 NTSC */ Y4M_SAR_MPEG1_7, Y4M_SAR_MPEG1_8, /* PAL/SECAM 4:3 */ Y4M_SAR_MPEG1_9, Y4M_SAR_MPEG1_10, Y4M_SAR_MPEG1_11, Y4M_SAR_MPEG1_12, /* NTSC 4:3 */ Y4M_SAR_MPEG1_13, Y4M_SAR_MPEG1_14, }; static const char *mpeg2_aspect_ratio_definitions[] = { "1:1 pixels", "4:3 display", "16:9 display", "2.21:1 display" }; static const y4m_ratio_t mpeg2_aspect_ratios[] = { Y4M_DAR_MPEG2_1, Y4M_DAR_MPEG2_2, Y4M_DAR_MPEG2_3, Y4M_DAR_MPEG2_4 }; static const char **aspect_ratio_definitions[2] = { mpeg1_aspect_ratio_definitions, mpeg2_aspect_ratio_definitions }; static const y4m_ratio_t *mpeg_aspect_ratios[2] = { mpeg1_aspect_ratios, mpeg2_aspect_ratios }; const mpeg_aspect_code_t mpeg_num_aspect_ratios[2] = { sizeof (mpeg1_aspect_ratios) / sizeof (mpeg1_aspect_ratios[0]), sizeof (mpeg2_aspect_ratios) / sizeof (mpeg2_aspect_ratios[0]) }; /* * Convert MPEG frame-rate code to corresponding frame-rate */ y4m_ratio_t mpeg_framerate (mpeg_framerate_code_t code) { if (code == 0 || code > mpeg_num_framerates) return y4m_fps_UNKNOWN; else return mpeg_framerates[code]; } /* * Look-up MPEG frame rate code for a (exact) frame rate. */ mpeg_framerate_code_t mpeg_framerate_code (y4m_ratio_t framerate) { mpeg_framerate_code_t i; y4m_ratio_reduce (&framerate); for (i = 1; i < mpeg_num_framerates; ++i) { if (Y4M_RATIO_EQL (framerate, mpeg_framerates[i])) return i; } return 0; } /* small enough to distinguish 1/1000 from 1/1001 */ #define MPEG_FPS_TOLERANCE 0.0001 y4m_ratio_t mpeg_conform_framerate (double fps) { mpeg_framerate_code_t i; y4m_ratio_t result; /* try to match it to a standard frame rate */ for (i = 1; i < mpeg_num_framerates; i++) { double deviation = 1.0 - (Y4M_RATIO_DBL (mpeg_framerates[i]) / fps); if ((deviation > -MPEG_FPS_TOLERANCE) && (deviation < +MPEG_FPS_TOLERANCE)) return mpeg_framerates[i]; } /* no luck? just turn it into a ratio (6 decimal place accuracy) */ result.n = (int) ((fps * 1000000.0) + 0.5); result.d = 1000000; y4m_ratio_reduce (&result); return result; } /* * Convert MPEG aspect-ratio code to corresponding aspect-ratio */ y4m_ratio_t mpeg_aspect_ratio (int mpeg_version, mpeg_aspect_code_t code) { y4m_ratio_t ratio; if (mpeg_version < 1 || mpeg_version > 2) return y4m_sar_UNKNOWN; if (code == 0 || code > mpeg_num_aspect_ratios[mpeg_version - 1]) return y4m_sar_UNKNOWN; else { ratio = mpeg_aspect_ratios[mpeg_version - 1][code - 1]; y4m_ratio_reduce (&ratio); return ratio; } } /* * Look-up corresponding MPEG aspect ratio code given an exact aspect ratio. * * WARNING: The semantics of aspect ratio coding *changed* between * MPEG1 and MPEG2. In MPEG1 it is the *pixel* aspect ratio. In * MPEG2 it is the (far more sensible) aspect ratio of the eventual * display. * */ mpeg_aspect_code_t mpeg_frame_aspect_code (int mpeg_version, y4m_ratio_t aspect_ratio) { mpeg_aspect_code_t i; y4m_ratio_t red_ratio = aspect_ratio; y4m_ratio_reduce (&red_ratio); if (mpeg_version < 1 || mpeg_version > 2) return 0; for (i = 1; i < mpeg_num_aspect_ratios[mpeg_version - 1]; ++i) { y4m_ratio_t red_entry = mpeg_aspect_ratios[mpeg_version - 1][i - 1]; y4m_ratio_reduce (&red_entry); if (Y4M_RATIO_EQL (red_entry, red_ratio)) return i; } return 0; } /* * Guess the correct MPEG aspect ratio code, * given the true sample aspect ratio and frame size of a video stream * (and the MPEG version, 1 or 2). * * Returns 0 if it has no good guess. * */ /* this is big enough to accommodate the difference between 720 and 704 */ #define GUESS_ASPECT_TOLERANCE 0.03 mpeg_aspect_code_t mpeg_guess_mpeg_aspect_code (int mpeg_version, y4m_ratio_t sampleaspect, int frame_width, int frame_height) { if (Y4M_RATIO_EQL (sampleaspect, y4m_sar_UNKNOWN)) { return 0; } switch (mpeg_version) { case 1: if (Y4M_RATIO_EQL (sampleaspect, y4m_sar_SQUARE)) { return 1; } else if (Y4M_RATIO_EQL (sampleaspect, y4m_sar_NTSC_CCIR601)) { return 12; } else if (Y4M_RATIO_EQL (sampleaspect, y4m_sar_NTSC_16_9)) { return 6; } else if (Y4M_RATIO_EQL (sampleaspect, y4m_sar_PAL_CCIR601)) { return 8; } else if (Y4M_RATIO_EQL (sampleaspect, y4m_sar_PAL_16_9)) { return 3; } return 0; break; case 2: if (Y4M_RATIO_EQL (sampleaspect, y4m_sar_SQUARE)) { return 1; /* '1' means square *pixels* in MPEG-2; go figure. */ } else { unsigned int i; double true_far; /* true frame aspect ratio */ true_far = (double) (sampleaspect.n * frame_width) / (double) (sampleaspect.d * frame_height); /* start at '2'... */ for (i = 2; i < mpeg_num_aspect_ratios[mpeg_version - 1]; i++) { double ratio = true_far / Y4M_RATIO_DBL (mpeg_aspect_ratios[mpeg_version - 1][i - 1]); if ((ratio > (1.0 - GUESS_ASPECT_TOLERANCE)) && (ratio < (1.0 + GUESS_ASPECT_TOLERANCE))) return i; } return 0; } break; default: return 0; break; } } /* * Guess the true sample aspect ratio of a video stream, * given the MPEG aspect ratio code and the actual frame size * (and the MPEG version, 1 or 2). * * Returns y4m_sar_UNKNOWN if it has no good guess. * */ y4m_ratio_t mpeg_guess_sample_aspect_ratio (int mpeg_version, mpeg_aspect_code_t code, int frame_width, int frame_height) { switch (mpeg_version) { case 1: /* MPEG-1 codes turn into SAR's, just not quite the right ones. For the common/known values, we provide the ratio used in practice, otherwise say we don't know. */ switch (code) { case 1: return y4m_sar_SQUARE; break; case 3: return y4m_sar_PAL_16_9; break; case 6: return y4m_sar_NTSC_16_9; break; case 8: return y4m_sar_PAL_CCIR601; break; case 12: return y4m_sar_NTSC_CCIR601; break; default: return y4m_sar_UNKNOWN; break; } break; case 2: /* MPEG-2 codes turn into Frame Aspect Ratios, though not exactly the FAR's used in practice. For common/standard frame sizes, we provide the original SAR; otherwise, we say we don't know. */ if (code == 1) { return y4m_sar_SQUARE; /* '1' means square *pixels* in MPEG-2 */ } else if ((code >= 2) && (code <= 4)) { return y4m_guess_sar (frame_width, frame_height, mpeg2_aspect_ratios[code - 1]); } else { return y4m_sar_UNKNOWN; } break; default: return y4m_sar_UNKNOWN; break; } } /* * Look-up MPEG explanatory definition string for frame rate code * */ const char * mpeg_framerate_code_definition (mpeg_framerate_code_t code) { if (code == 0 || code >= mpeg_num_framerates) return "UNDEFINED: illegal/reserved frame-rate ratio code"; return framerate_definitions[code]; } /* * Look-up MPEG explanatory definition string aspect ratio code for an * aspect ratio code * */ const char * mpeg_aspect_code_definition (int mpeg_version, mpeg_aspect_code_t code) { if (mpeg_version < 1 || mpeg_version > 2) return "UNDEFINED: illegal MPEG version"; if (code < 1 || code > mpeg_num_aspect_ratios[mpeg_version - 1]) return "UNDEFINED: illegal aspect ratio code"; return aspect_ratio_definitions[mpeg_version - 1][code - 1]; } /* * Look-up explanatory definition of interlace field order code * */ const char * mpeg_interlace_code_definition (int yuv4m_interlace_code) { const char *def; switch (yuv4m_interlace_code) { case Y4M_UNKNOWN: def = "unknown"; break; case Y4M_ILACE_NONE: def = "none/progressive"; break; case Y4M_ILACE_TOP_FIRST: def = "top-field-first"; break; case Y4M_ILACE_BOTTOM_FIRST: def = "bottom-field-first"; break; default: def = "UNDEFINED: illegal video interlacing type-code!"; break; } return def; } /* * Local variables: * c-file-style: "stroustrup" * tab-width: 4 * indent-tabs-mode: nil * End: */