Maybe this will help you get started.

There are a number of conversion formulas from yuv to rgb. 
An authoritative source for this is ISO 13818-2, the MPEG2 standard; paragraph 
6.3.6.  

A software implementation can be found in the source of mpeg2decode 
ftp://ftp.mpeg.org/pub/mpeg/mssg/mpeg2vidcodec_v12.tar.gz , file store.c. Start 
reading at the comment  /* matrix coefficients */ .

Attached a verilog implementation.

regards,

koen
/*
 * Conversion from Y, U, V into R, G, B.
 *
 * Copyright Koen De Vleeschauwer, 2006. All rights reserved.
 * Licensed under the GPL.
 *
 * Mon Jul 31 20:24:50 CEST 2006
 */

`include "timescale.v"

`undef DEBUG
//`define DEBUG 1

module yuv2rgb (clk, clk_en, rst,
                matrix_coefficients, y, u, v, h_sync_in, v_sync_in, pixel_en_in,
                r, g, b, h_sync_out, v_sync_out, pixel_en_out
                );
  input  clk;
  input  clk_en;
  input  rst;

  input [7:0] matrix_coefficients; /* extracted from mpeg2 bitstream. 
Determines yuv -> rgb conversion factors. ISO/IEC 13818-2, par. 6.3.6 */

  input [7:0]y;
  input [7:0]u;
  input [7:0]v;

  output reg [7:0]r;
  output reg [7:0]g;
  output reg [7:0]b;

  /*
   * pixel_en_out, h_sync_out, v_sync_out are pixel_en_in, h_sync_in and 
v_sync_in, delayed so as to balance the delay from yuv -> rgb.
   * Typical use is to connect r, g, b to the 24-bit data-in of the dvi 
transmitter,
   * pixel_en_out, h_sync_out and video_out to de (data enable), h_sync and 
v_sync of the dvi transmitter.
   */

  input pixel_en_in;
  input h_sync_in;
  input v_sync_in;
  output reg pixel_en_out;
  output reg h_sync_out;
  output reg v_sync_out;

  reg signed [26:0]cy_y;
  reg signed [26:0]crv_v;
  reg signed [26:0]cbu_u;
  reg signed [26:0]cgu_u;
  reg signed [26:0]cgv_v;

  reg signed [17:0]crv;
  reg signed [17:0]cbu;
  reg signed [17:0]cgu;
  reg signed [17:0]cgv;

  reg signed [8:0]y_offset;
  reg signed [8:0]u_offset;
  reg signed [8:0]v_offset;

  reg signed [29:0]r_0;
  reg signed [29:0]g1_0;
  reg signed [29:0]g2_0;
  reg signed [29:0]b_0;

  reg signed [29:0]r_1;
  reg signed [29:0]g_1;
  reg signed [29:0]b_1;

  reg pixel_en_0;
  reg h_sync_0;
  reg v_sync_0;

  reg pixel_en_1;
  reg h_sync_1;
  reg v_sync_1;

  reg pixel_en_2;
  reg h_sync_2;
  reg v_sync_2;

  reg pixel_en_3;
  reg h_sync_3;
  reg v_sync_3;


  /*
   * Simplify matrix_coefficients: values 8..255 are reserved and should not 
occur.
   * If value of matrix_coefficients outside 0..7 range, replace with 0.
   */

  reg         [2:0]mat_coeff;
  always @(posedge clk)
    if (~rst) mat_coeff <= 0;
    else if (clk_en && (matrix_coefficients[7:3] == 5'b0)) mat_coeff <= 
matrix_coefficients[2:0];
    else mat_coeff <= 0;

  /*
   *
   * Table 6-9 inverted.
   *
   * y        = cr * r + cg * g + cb * b
   * cr + cg + cb = 1
   *
   * cy       = (255/219) * 32768
   * crv      = (255/224) * 32768 * (1-cr) / 0.5
   * cbu      = (255/224) * 32768 * (1-cb) / 0.5
   * cgu      = (255/224) * 32768 * (cb/cg) * (1 - cb) / 0.5
   * cgv      = (255/224) * 32768 * (cr/cg) * (1 - cr) / 0.5
   * r        = ( cy * (y - 16)                   + crv * (v - 128) + 16384) >> 
15;
   * g        = ( cy * (y - 16) - cgu * (u - 128) + crv * (v - 128) + 16384) >> 
15;
   * b        = ( cy * (y - 16) - cbu * (u - 128)                   + 16384) >> 
15;
   */

  parameter signed [17:0]
    cy = 18'sd38155;

  always @(posedge clk)
    if (clk_en)
      case (mat_coeff)
        3'd0, /* default value, no sequence_display_extension */
        3'd1: /* ITU-R Rec. 709 (1990) */
              begin
                crv <= 18'sd58752;
                cbu <= 18'sd69227;
                cgu <= 18'sd6977;
                cgv <= 18'sd17452;
              end
        3'd2, /* unspecified */
        3'd3, /* reserved */
        3'd5, /* ITU-R Rec. 624-4 System B, G */
        3'd6: /* SMPTE 170M */
              begin
                crv <= 18'sd52299;
                cbu <= 18'sd66101;
                cgu <= 18'sd12838;
                cgv <= 18'sd26640;
              end
        3'd4: /* FCC */
              begin
                crv <= 18'sd52224;
                cbu <= 18'sd66399;
                cgu <= 18'sd12380;
                cgv <= 18'sd26555;
              end
        3'd7: /* SMPTE 240M (1987) */
              begin
                crv <= 18'sd58790;
                cbu <= 18'sd68115;
                cgu <= 18'sd8454;
                cgv <= 18'sd17780;
              end
     endcase

  /* conversion */
  always @(posedge clk)
    if (~rst)
      begin
        y_offset <= 0;
        u_offset <= 0;
        v_offset <= 0;

        cy_y  <= 0;
        crv_v <= 0;
        cgv_v <= 0;
        cgu_u <= 0;
        cbu_u <= 0;

        r_0   <= 0;
        g1_0  <= 0;
        g2_0  <= 0;
        b_0   <= 0;

        r_1   <= 0;
        g_1   <= 0;
        b_1   <= 0;
      end
    else if (clk_en)
      begin
        y_offset <= {1'b0, y} - 9'sd16;
        u_offset <= {1'b0, u} - 9'sd128;
        v_offset <= {1'b0, v} - 9'sd128;

        cy_y  <= cy  * y_offset;
        cgu_u <= cgu * u_offset;
        cbu_u <= cbu * u_offset;
        crv_v <= crv * v_offset;
        cgv_v <= cgv * v_offset;

        r_0   <=   {{3{cy_y[26]}}, cy_y}  + {{3{crv_v[26]}}, crv_v};
        g1_0  <=   {{3{cy_y[26]}}, cy_y}  - {{3{cgu_u[26]}}, cgu_u};
        g2_0  <=                          - {{3{cgv_v[26]}}, cgv_v} + 
30'sd16384;
        b_0   <=   {{3{cy_y[26]}}, cy_y}  + {{3{cbu_u[26]}}, cbu_u};

        r_1   <= (r_0 + 30'sd16384) >>> 15;
        g_1   <= (g1_0 + g2_0) >>> 15;
        b_1   <= (b_0 + 30'sd16384) >>> 15;
      end
    else
      begin
        y_offset <= y_offset;
        u_offset <= u_offset;
        v_offset <= v_offset;

        cy_y  <= cy_y;
        cgu_u <= cgu_u;
        cbu_u <= cbu_u;
        crv_v <= crv_v;
        cgv_v <= cgv_v;

        r_0   <= r_0;
        g1_0  <= g1_0;
        g2_0  <= g2_0;
        b_0   <= b_0;

        r_1   <= r_1;
        g_1   <= r_1;
        b_1   <= r_1;
      end

  /* clipping */
  always @(posedge clk)
    if (~rst) r <= 8'd0;
    else if (clk_en && r_1[29]) r <= 8'd0; /* negative, clip to 0 */
    else if (clk_en && (r_1[29:8] != 22'b0)) r <= 8'd255; /* 256 or more, clip 
to 255 */
    else if (clk_en) r <= r_1[7:0]; /* between 0 and 255, copy */
    else r <= r;

  always @(posedge clk)
    if (~rst) g <= 8'd0;
    else if (clk_en && g_1[29]) g <= 8'd0;
    else if (clk_en && (g_1[29:8] != 22'b0)) g <= 8'd255;
    else if (clk_en) g <= g_1[7:0];
    else g <= g;

  always @(posedge clk)
    if (~rst) b <= 8'd0;
    else if (clk_en && b_1[29]) b <= 8'd0;
    else if (clk_en && (b_1[29:8] != 22'b0)) b <= 8'd255;
    else if (clk_en) b <= b_1[7:0];
    else b <= b;

 /* delay pixel_en, h_sync and v_sync so they are balanced with r, g, b */

  always @(posedge clk)
    if (~rst)
      begin
        pixel_en_0 <= 1'b0;
        pixel_en_1 <= 1'b0;
        pixel_en_2 <= 1'b0;
        pixel_en_3 <= 1'b0;
        pixel_en_out <= 1'b0;
     end
   else if (clk_en)
     begin
        pixel_en_0 <= pixel_en_in;
        pixel_en_1 <= pixel_en_0;
        pixel_en_2 <= pixel_en_1;
        pixel_en_3 <= pixel_en_2;
        pixel_en_out <= pixel_en_3;
     end
   else
     begin
        pixel_en_0 <= pixel_en_0;
        pixel_en_1 <= pixel_en_1;
        pixel_en_2 <= pixel_en_2;
        pixel_en_3 <= pixel_en_3;
        pixel_en_out <= pixel_en_out;
     end

  always @(posedge clk)
    if (~rst)
      begin
        h_sync_0 <= 1'b0;
        h_sync_1 <= 1'b0;
        h_sync_2 <= 1'b0;
        h_sync_3 <= 1'b0;
        h_sync_out <= 1'b0;
     end
   else if (clk_en)
     begin
        h_sync_0 <= h_sync_in;
        h_sync_1 <= h_sync_0;
        h_sync_2 <= h_sync_1;
        h_sync_3 <= h_sync_2;
        h_sync_out <= h_sync_3;
     end
   else
     begin
        h_sync_0 <= h_sync_0;
        h_sync_1 <= h_sync_1;
        h_sync_2 <= h_sync_2;
        h_sync_3 <= h_sync_3;
        h_sync_out <= h_sync_out;
     end

  always @(posedge clk)
    if (~rst)
      begin
        v_sync_0 <= 1'b0;
        v_sync_1 <= 1'b0;
        v_sync_2 <= 1'b0;
        v_sync_3 <= 1'b0;
        v_sync_out <= 1'b0;
     end
   else if (clk_en)
     begin
        v_sync_0 <= v_sync_in;
        v_sync_1 <= v_sync_0;
        v_sync_2 <= v_sync_1;
        v_sync_3 <= v_sync_2;
        v_sync_out <= v_sync_3;
     end
   else
     begin
        v_sync_0 <= v_sync_0;
        v_sync_1 <= v_sync_1;
        v_sync_2 <= v_sync_2;
        v_sync_3 <= v_sync_3;
        v_sync_out <= v_sync_out;
     end

`ifdef DEBUG
  always @(posedge clk)
    begin
//      $strobe("%0d %0d %0d", r, g, b);
      $strobe("yuv: %0d %0d %0d rgb: %0d %0d %0d", y, u, v, r, g, b);
      /*
      $strobe("%m\tmatrix_coefficients: %4d y: %4d u: %4d v: %d y_offset: %d 
u_offset: %d v_offset: %d cy_y: %d crv_v: %d cgv_v: %d cgu_u: %d cbu_u: %d r_0: 
%d g1_0: %d g2_0: %d b_0: %d r_1: %d g_1: %d b_1: %d r: %4d g: %4d b: %4d ", 
                   matrix_coefficients,     y,     u,     v,    y_offset,    
u_offset,    v_offset,    cy_y,    crv_v,    cgv_v,    cgu_u,    cbu_u,    r_0, 
   g1_0,    g2_0,    b_0,    r_1,    g_1,    b_1,    r,     g,     b);
      */
    end
`endif
endmodule
/* not truncated */
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)

Reply via email to