/* 
 *  place.c
 *
 *     Copyright (C) Charles 'Buck' Krasic - April 2000
 *     Copyright (C) Erik Walthinsen - April 2000
 *
 *  This file is part of libdv, a free DV (IEC 61834/SMPTE 314M)
 *  codec.
 *
 *  libdv is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU Lesser Public License as published by
 *  the Free Software Foundation; either version 2.1, or (at your
 *  option) any later version.
 *   
 *  libdv 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
 *  Lesser Public License for more details.
 *   
 *  You should have received a copy of the GNU Lesser Public License
 *  along with libdv; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
 *
 *  The libdv homepage is http://libdv.sourceforge.net/.  
 */

#if HAVE_CONFIG_H
# include <config.h>
#endif

#include "place.h"

#define DEBUG_HIGHLIGHT_MBS 0

static const int dv_super_map_vertical[5] = { 2, 6, 8, 0, 4 };
static const int dv_super_map_horizontal[5] = { 2, 1, 3, 0, 4 };

void 
dv_place_init(void) {
  return;
} // dv_place_init

static inline void
dv_place_411_macroblock(dv_macroblock_t *mb) {
  int mb_num; // mb number withing the 6 x 5 zig-zag pattern 
  int mb_num_mod_6, mb_num_div_6; // temporaries
  int mb_row;    // mb row within sb (de-zigzag)
  int mb_col;    // mb col within sb (de-zigzag)
  // Column offset of superblocks in macroblocks.  
  static const unsigned int column_offset[] = {0, 4, 9, 13, 18};  

  // Consider the area spanned super block as 30 element macroblock
  // grid (6 rows x 5 columns).  The macroblocks are laid out in a in
  // a zig-zag down and up the columns of the grid.  Of course,
  // superblocks are not perfect rectangles, since there are only 27
  // blocks.  The missing three macroblocks are either at the start
  // or end depending on the superblock column.

  // Within a superblock, the macroblocks start at the topleft corner
  // for even-column superblocks, and 3 down for odd-column
  // superblocks.
  mb_num = ((mb->j % 2) == 1) ? mb->k + 3: mb->k;  
  mb_num_mod_6 = mb_num % 6;
  mb_num_div_6 = mb_num / 6;
  // Compute superblock-relative row position (de-zigzag)
  mb_row = ((mb_num_div_6 % 2) == 0) ? mb_num_mod_6 : (5 - mb_num_mod_6); 
  // Compute macroblock's frame-relative column position (in blocks)
  mb_col = (mb_num_div_6 + column_offset[mb->j]) * 4;
  // Compute frame-relative byte offset of macroblock's top-left corner
  // with special case for right-edge macroblocks
  if(mb_col < (22 * 4)) {
    // Convert from superblock-relative row position to frame relative (in blocks).
    mb_row += (mb->i * 6); // each superblock is 6 blocks high 
    // Normal case
  } else { 
    // Convert from superblock-relative row position to frame relative (in blocks).
    mb_row = mb_row * 2 + mb->i * 6; // each right-edge macroblock is 2 blocks high, and each superblock is 6 blocks high
  } // else
  mb->x = mb_col * 8;
  mb->y = mb_row * 8;
} // dv_place_411_macroblock

static inline void 
dv_place_420_macroblock(dv_macroblock_t *mb) {
  int mb_num; // mb number withing the 6 x 5 zig-zag pattern 
  int mb_num_mod_3, mb_num_div_3; // temporaries
  int mb_row;    // mb row within sb (de-zigzag)
  int mb_col;    // mb col within sb (de-zigzag)
  // Column offset of superblocks in macroblocks.  
  static const unsigned int column_offset[] = {0, 9, 18, 27, 36};  

  // Consider the area spanned super block as 30 element macroblock
  // grid (6 rows x 5 columns).  The macroblocks are laid out in a in
  // a zig-zag down and up the columns of the grid.  Of course,
  // superblocks are not perfect rectangles, since there are only 27
  // blocks.  The missing three macroblocks are either at the start
  // or end depending on the superblock column.

  // Within a superblock, the macroblocks start at the topleft corner
  // for even-column superblocks, and 3 down for odd-column
  // superblocks.
  mb_num = mb->k;  
  mb_num_mod_3 = mb_num % 3;
  mb_num_div_3 = mb_num / 3;
  // Compute superblock-relative row position (de-zigzag)
  mb_row = ((mb_num_div_3 % 2) == 0) ? mb_num_mod_3 : (2 - mb_num_mod_3); 
  // Compute macroblock's frame-relative column position (in blocks)
  mb_col = mb_num_div_3 + column_offset[mb->j];
  // Compute frame-relative byte offset of macroblock's top-left corner
  // Convert from superblock-relative row position to frame relative (in blocks).
  mb_row += (mb->i * 3); // each right-edge macroblock is 2 blocks high, and each superblock is 6 blocks high
  mb->x = mb_col * 16;
  mb->y = mb_row * 16;
} // dv_place_420_macroblock

void 
dv_place_macroblock(dv_decoder_t *dv, dv_videosegment_t *seg, dv_macroblock_t *mb, int m) {
  mb->i = (seg->i + dv_super_map_vertical[m]) % dv->num_dif_seqs;
  mb->j = dv_super_map_horizontal[m];
  mb->k = seg->k;
  // calculate x,y
  if(dv->sampling == e_dv_sample_411)
    dv_place_411_macroblock(mb); 
  else
    dv_place_420_macroblock(mb);
} // dv_place_macroblock

void
dv_place_video_segment(dv_decoder_t *dv, dv_videosegment_t *seg) {
  dv_macroblock_t *mb;
  int m; 
  for (m=0,mb = seg->mb;
       m<5;
       m++,mb++) {
    mb->i = (seg->i + dv_super_map_vertical[m]) % dv->num_dif_seqs;
    mb->j = dv_super_map_horizontal[m];
    mb->k = seg->k;
    // calculate x,y
    if(dv->sampling == e_dv_sample_411)
      dv_place_411_macroblock(mb); 
    else
      dv_place_420_macroblock(mb);
  } // for m
} // dv_place_video_segment

void
dv_place_frame(dv_decoder_t *dv, dv_frame_t *frame) {
  dv_videosegment_t *seg;
  int ds, v; // dif sequence, video segment
  unsigned int dif = 0;
  for (ds=0; ds < dv->num_dif_seqs; ds++) { 
    dif += 6; // skip the first 6 dif blocks in a dif sequence 
    // Loop through video segments 
    for (v=0; v<27;v++) {
	if(!(v % 3)) dif++; 
	seg = &frame->ds[ds].seg[v];
	seg->i = ds;
	seg->k = v;
	seg->isPAL = (dv->system == e_dv_system_625_50);
	dif+=5;
	dv_place_video_segment(dv,seg);
    } // for v
  } // for ds
} /* dv_place_frame */





