text: /*-*- mode:c;indent-tabs-mode:t;c-basic-offset:4;tab-width:4;coding:utf-8   -*-│
  │vi: set et ft=c ts=4 sw=4 fenc=utf-8                                       :vi│
  ╞══════════════════════════════════════════════════════════════════════════════╡
  │  PL_MPEG - MPEG1 Video decoder, MP2 Audio decoder, MPEG-PS demuxer           │
  │  Dominic Szablewski - https://phoboslab.org                                  │
  │                                                                              │
  │  The MIT License(MIT)                                                        │
  │  Copyright(c) 2019 Dominic Szablewski                                        │
  │                                                                              │
  │  Permission is hereby granted, free of charge, to any person obtaining       │
  │  a copy of this software and associated documentation files(the              │
  │  "Software"), to deal in the Software without restriction, including         │
  │  without limitation the rights to use, copy, modify, merge, publish,         │
  │  distribute, sublicense, and / or sell copies of the Software, and to        │
  │  permit persons to whom the Software is furnished to do so, subject to       │
  │  the following conditions:                                                   │
  │                                                                              │
  │    The above copyright notice and this permission notice shall be            │
  │    included in all copies or substantial portions of the Software.           │
  │                                                                              │
  │  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,             │
  │  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF          │
  │  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND                       │
  │  NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE       │
  │  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN             │
  │  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN           │
  │  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE            │
  │  SOFTWARE.                                                                   │
  ╚─────────────────────────────────────────────────────────────────────────────*/
  #include "dsp/mpeg/mpeg.h"
  #include "libc/macros.internal.h"
  
  asm(".ident\t\"\\n\\n\
  PL_MPEG (MIT License)\\n\
  Copyright(c) 2019 Dominic Szablewski\\n\
  https://phoboslab.org\"");
  asm(".include \"libc/disclaimer.inc\"");
  
  /**
   * @see YCbCr2RGB() in tool/viz/lib/ycbcr2rgb.c
   */
  void plm_frame_to_rgb(plm_frame_t *frame, uint8_t *rgb) {
    // Chroma values are the same for each block of 4 pixels, so we proccess
    // 2 lines at a time, 2 neighboring pixels each.
    int w = frame->y.width, w2 = w >> 1;
    int y_index1 = 0, y_index2 = w, y_next_2_lines = w + (w - frame->width);
    int c_index = 0, c_next_line = w2 - (frame->width >> 1);
    int rgb_index1 = 0, rgb_index2 = frame->width * 3,
        rgb_next_2_lines = frame->width * 3;
    int cols = frame->width >> 1, rows = frame->height >> 1;
    int ccb, ccr, r, g, b;
    uint8_t *y = frame->y.data, *cb = frame->cb.data, *cr = frame->cr.data;
    for (int row = 0; row < rows; row++) {
      for (int col = 0; col < cols; col++) {
        ccb = cb[c_index];
        ccr = cr[c_index];
        c_index++;
        r = (ccr + ((ccr * 103) >> 8)) - 179;
        g = ((ccb * 88) >> 8) - 44 + ((ccr * 183) >> 8) - 91;
        b = (ccb + ((ccb * 198) >> 8)) - 227;
        // Line 1
        int y1 = y[y_index1++];
        int y2 = y[y_index1++];
        rgb[rgb_index1 + 0] = MAX(0, MIN(255, y1 + r));
        rgb[rgb_index1 + 1] = MAX(0, MIN(255, y1 - g));
        rgb[rgb_index1 + 2] = MAX(0, MIN(255, y1 + b));
        rgb[rgb_index1 + 3] = MAX(0, MIN(255, y2 + r));
        rgb[rgb_index1 + 4] = MAX(0, MIN(255, y2 - g));
        rgb[rgb_index1 + 5] = MAX(0, MIN(255, y2 + b));
        rgb_index1 += 6;
        // Line 2
        int y3 = y[y_index2++];
        int y4 = y[y_index2++];
        rgb[rgb_index2 + 0] = MAX(0, MIN(255, y3 + r));
        rgb[rgb_index2 + 1] = MAX(0, MIN(255, y3 - g));
        rgb[rgb_index2 + 2] = MAX(0, MIN(255, y3 + b));
        rgb[rgb_index2 + 3] = MAX(0, MIN(255, y4 + r));
        rgb[rgb_index2 + 4] = MAX(0, MIN(255, y4 - g));
        rgb[rgb_index2 + 5] = MAX(0, MIN(255, y4 + b));
        rgb_index2 += 6;
      }
      y_index1 += y_next_2_lines;
      y_index2 += y_next_2_lines;
      rgb_index1 += rgb_next_2_lines;
      rgb_index2 += rgb_next_2_lines;
      c_index += c_next_line;
    }
  }
  