Blame examples/dump_psnr.c

Packit 00c01a
/********************************************************************
Packit 00c01a
 *                                                                  *
Packit 00c01a
 * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE.   *
Packit 00c01a
 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
Packit 00c01a
 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
Packit 00c01a
 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
Packit 00c01a
 *                                                                  *
Packit 00c01a
 * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009                *
Packit 00c01a
 * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
Packit 00c01a
 *                                                                  *
Packit 00c01a
 ********************************************************************
Packit 00c01a
Packit 00c01a
  function: example dumpvid application; dumps  Theora streams
Packit 00c01a
  last mod: $Id: dump_video.c 15675 2009-02-06 09:43:27Z tterribe $
Packit 00c01a
Packit 00c01a
 ********************************************************************/
Packit 00c01a
Packit 00c01a
#if !defined(_GNU_SOURCE)
Packit 00c01a
#define _GNU_SOURCE
Packit 00c01a
#endif
Packit 00c01a
#if !defined(_LARGEFILE_SOURCE)
Packit 00c01a
#define _LARGEFILE_SOURCE
Packit 00c01a
#endif
Packit 00c01a
#if !defined(_LARGEFILE64_SOURCE)
Packit 00c01a
#define _LARGEFILE64_SOURCE
Packit 00c01a
#endif
Packit 00c01a
#if !defined(_FILE_OFFSET_BITS)
Packit 00c01a
#define _FILE_OFFSET_BITS 64
Packit 00c01a
#endif
Packit 00c01a
Packit 00c01a
#include <stdio.h>
Packit 00c01a
#if !defined(_WIN32)
Packit 00c01a
#include <getopt.h>
Packit 00c01a
#include <unistd.h>
Packit 00c01a
#else
Packit 00c01a
#include "getopt.h"
Packit 00c01a
#endif
Packit 00c01a
#include <stdlib.h>
Packit 00c01a
#include <string.h>
Packit 00c01a
#include <sys/timeb.h>
Packit 00c01a
#include <sys/types.h>
Packit 00c01a
#include <sys/stat.h>
Packit 00c01a
/*Yes, yes, we're going to hell.*/
Packit 00c01a
#if defined(_WIN32)
Packit 00c01a
#include <io.h>
Packit 00c01a
#endif
Packit 00c01a
#include <fcntl.h>
Packit 00c01a
#include <math.h>
Packit 00c01a
#include <signal.h>
Packit 00c01a
#include "theora/theoradec.h"
Packit 00c01a
Packit 00c01a
const char *optstring = "fsy";
Packit 00c01a
struct option options [] = {
Packit 00c01a
  {"frame-type",no_argument,NULL,'f'},
Packit 00c01a
  {"summary",no_argument,NULL,'s'},
Packit 00c01a
  {"luma-only",no_argument,NULL,'y'},
Packit 00c01a
  {NULL,0,NULL,0}
Packit 00c01a
};
Packit 00c01a
Packit 00c01a
static int show_frame_type;
Packit 00c01a
static int summary_only;
Packit 00c01a
static int luma_only;
Packit 00c01a
Packit 00c01a
typedef struct y4m_input y4m_input;
Packit 00c01a
Packit 00c01a
/*The function used to perform chroma conversion.*/
Packit 00c01a
typedef void (*y4m_convert_func)(y4m_input *_y4m,
Packit 00c01a
 unsigned char *_dst,unsigned char *_aux);
Packit 00c01a
Packit 00c01a
struct y4m_input{
Packit 00c01a
  int               frame_w;
Packit 00c01a
  int               frame_h;
Packit 00c01a
  int               pic_w;
Packit 00c01a
  int               pic_h;
Packit 00c01a
  int               pic_x;
Packit 00c01a
  int               pic_y;
Packit 00c01a
  int               fps_n;
Packit 00c01a
  int               fps_d;
Packit 00c01a
  int               par_n;
Packit 00c01a
  int               par_d;
Packit 00c01a
  char              interlace;
Packit 00c01a
  int               src_c_dec_h;
Packit 00c01a
  int               src_c_dec_v;
Packit 00c01a
  int               dst_c_dec_h;
Packit 00c01a
  int               dst_c_dec_v;
Packit 00c01a
  char              chroma_type[16];
Packit 00c01a
  /*The size of each converted frame buffer.*/
Packit 00c01a
  size_t            dst_buf_sz;
Packit 00c01a
  /*The amount to read directly into the converted frame buffer.*/
Packit 00c01a
  size_t            dst_buf_read_sz;
Packit 00c01a
  /*The size of the auxilliary buffer.*/
Packit 00c01a
  size_t            aux_buf_sz;
Packit 00c01a
  /*The amount to read into the auxilliary buffer.*/
Packit 00c01a
  size_t            aux_buf_read_sz;
Packit 00c01a
  y4m_convert_func  convert;
Packit 00c01a
  unsigned char    *dst_buf;
Packit 00c01a
  unsigned char    *aux_buf;
Packit 00c01a
};
Packit 00c01a
Packit 00c01a
Packit 00c01a
static int y4m_parse_tags(y4m_input *_y4m,char *_tags){
Packit 00c01a
  int   got_w;
Packit 00c01a
  int   got_h;
Packit 00c01a
  int   got_fps;
Packit 00c01a
  int   got_interlace;
Packit 00c01a
  int   got_par;
Packit 00c01a
  int   got_chroma;
Packit 00c01a
  char *p;
Packit 00c01a
  char *q;
Packit 00c01a
  got_w=got_h=got_fps=got_interlace=got_par=got_chroma=0;
Packit 00c01a
  for(p=_tags;;p=q){
Packit 00c01a
    /*Skip any leading spaces.*/
Packit 00c01a
    while(*p==' ')p++;
Packit 00c01a
    /*If that's all we have, stop.*/
Packit 00c01a
    if(p[0]=='\0')break;
Packit 00c01a
    /*Find the end of this tag.*/
Packit 00c01a
    for(q=p+1;*q!='\0'&&*q!=' ';q++);
Packit 00c01a
    /*Process the tag.*/
Packit 00c01a
    switch(p[0]){
Packit 00c01a
      case 'W':{
Packit 00c01a
        if(sscanf(p+1,"%d",&_y4m->pic_w)!=1)return -1;
Packit 00c01a
        got_w=1;
Packit 00c01a
      }break;
Packit 00c01a
      case 'H':{
Packit 00c01a
        if(sscanf(p+1,"%d",&_y4m->pic_h)!=1)return -1;
Packit 00c01a
        got_h=1;
Packit 00c01a
      }break;
Packit 00c01a
      case 'F':{
Packit 00c01a
        if(sscanf(p+1,"%d:%d",&_y4m->fps_n,&_y4m->fps_d)!=2){
Packit 00c01a
          return -1;
Packit 00c01a
        }
Packit 00c01a
        got_fps=1;
Packit 00c01a
      }break;
Packit 00c01a
      case 'I':{
Packit 00c01a
        _y4m->interlace=p[1];
Packit 00c01a
        got_interlace=1;
Packit 00c01a
      }break;
Packit 00c01a
      case 'A':{
Packit 00c01a
        if(sscanf(p+1,"%d:%d",&_y4m->par_n,&_y4m->par_d)!=2){
Packit 00c01a
          return -1;
Packit 00c01a
        }
Packit 00c01a
        got_par=1;
Packit 00c01a
      }break;
Packit 00c01a
      case 'C':{
Packit 00c01a
        if(q-p>16)return -1;
Packit 00c01a
        memcpy(_y4m->chroma_type,p+1,q-p-1);
Packit 00c01a
        _y4m->chroma_type[q-p-1]='\0';
Packit 00c01a
        got_chroma=1;
Packit 00c01a
      }break;
Packit 00c01a
      /*Ignore unknown tags.*/
Packit 00c01a
    }
Packit 00c01a
  }
Packit 00c01a
  if(!got_w||!got_h||!got_fps||!got_interlace||!got_par)return -1;
Packit 00c01a
  /*Chroma-type is not specified in older files, e.g., those generated by
Packit 00c01a
     mplayer.*/
Packit 00c01a
  if(!got_chroma)strcpy(_y4m->chroma_type,"420");
Packit 00c01a
  return 0;
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
/*All anti-aliasing filters in the following conversion functions are based on
Packit 00c01a
   one of two window functions:
Packit 00c01a
  The 6-tap Lanczos window (for down-sampling and shifts):
Packit 00c01a
   sinc(\pi*t)*sinc(\pi*t/3), |t|<3  (sinc(t)==sin(t)/t)
Packit 00c01a
   0,                         |t|>=3
Packit 00c01a
  The 4-tap Mitchell window (for up-sampling):
Packit 00c01a
   7|t|^3-12|t|^2+16/3,             |t|<1
Packit 00c01a
   -(7/3)|x|^3+12|x|^2-20|x|+32/3,  |t|<2
Packit 00c01a
   0,                               |t|>=2
Packit 00c01a
  The number of taps is intentionally kept small to reduce computational
Packit 00c01a
   overhead and limit ringing.
Packit 00c01a
Packit 00c01a
  The taps from these filters are scaled so that their sum is 1, and the result
Packit 00c01a
   is scaled by 128 and rounded to integers to create a filter whose
Packit 00c01a
   intermediate values fit inside 16 bits.
Packit 00c01a
  Coefficients are rounded in such a way as to ensure their sum is still 128,
Packit 00c01a
   which is usually equivalent to normal rounding.*/
Packit 00c01a
Packit 00c01a
#define OC_MINI(_a,_b)      ((_a)>(_b)?(_b):(_a))
Packit 00c01a
#define OC_MAXI(_a,_b)      ((_a)<(_b)?(_b):(_a))
Packit 00c01a
#define OC_CLAMPI(_a,_b,_c) (OC_MAXI(_a,OC_MINI(_b,_c)))
Packit 00c01a
Packit 00c01a
/*420jpeg chroma samples are sited like:
Packit 00c01a
  Y-------Y-------Y-------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |   BR  |       |   BR  |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  Y-------Y-------Y-------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  Y-------Y-------Y-------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |   BR  |       |   BR  |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  Y-------Y-------Y-------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
Packit 00c01a
  420mpeg2 chroma samples are sited like:
Packit 00c01a
  Y-------Y-------Y-------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  BR      |       BR      |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  Y-------Y-------Y-------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  Y-------Y-------Y-------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  BR      |       BR      |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  Y-------Y-------Y-------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
Packit 00c01a
  We use a resampling filter to shift the site locations one quarter pixel (at
Packit 00c01a
   the chroma plane's resolution) to the right.
Packit 00c01a
  The 4:2:2 modes look exactly the same, except there are twice as many chroma
Packit 00c01a
   lines, and they are vertically co-sited with the luma samples in both the
Packit 00c01a
   mpeg2 and jpeg cases (thus requiring no vertical resampling).*/
Packit 00c01a
static void y4m_convert_42xmpeg2_42xjpeg(y4m_input *_y4m,unsigned char *_dst,
Packit 00c01a
 unsigned char *_aux){
Packit 00c01a
  int c_w;
Packit 00c01a
  int c_h;
Packit 00c01a
  int pli;
Packit 00c01a
  int y;
Packit 00c01a
  int x;
Packit 00c01a
  /*Skip past the luma data.*/
Packit 00c01a
  _dst+=_y4m->pic_w*_y4m->pic_h;
Packit 00c01a
  /*Compute the size of each chroma plane.*/
Packit 00c01a
  c_w=(_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h;
Packit 00c01a
  c_h=(_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v;
Packit 00c01a
  for(pli=1;pli<3;pli++){
Packit 00c01a
    for(y=0;y
Packit 00c01a
      /*Filter: [4 -17 114 35 -9 1]/128, derived from a 6-tap Lanczos
Packit 00c01a
         window.*/
Packit 00c01a
      for(x=0;x
Packit 00c01a
        _dst[x]=(unsigned char)OC_CLAMPI(0,4*_aux[0]-17*_aux[OC_MAXI(x-1,0)]+
Packit 00c01a
         114*_aux[x]+35*_aux[OC_MINI(x+1,c_w-1)]-9*_aux[OC_MINI(x+2,c_w-1)]+
Packit 00c01a
         _aux[OC_MINI(x+3,c_w-1)]+64>>7,255);
Packit 00c01a
      }
Packit 00c01a
      for(;x
Packit 00c01a
        _dst[x]=(unsigned char)OC_CLAMPI(0,4*_aux[x-2]-17*_aux[x-1]+
Packit 00c01a
         114*_aux[x]+35*_aux[x+1]-9*_aux[x+2]+_aux[x+3]+64>>7,255);
Packit 00c01a
      }
Packit 00c01a
      for(;x
Packit 00c01a
        _dst[x]=(unsigned char)OC_CLAMPI(0,4*_aux[x-2]-17*_aux[x-1]+
Packit 00c01a
         114*_aux[x]+35*_aux[OC_MINI(x+1,c_w-1)]-9*_aux[OC_MINI(x+2,c_w-1)]+
Packit 00c01a
         _aux[c_w-1]+64>>7,255);
Packit 00c01a
      }
Packit 00c01a
      _dst+=c_w;
Packit 00c01a
      _aux+=c_w;
Packit 00c01a
    }
Packit 00c01a
  }
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
/*This format is only used for interlaced content, but is included for
Packit 00c01a
   completeness.
Packit 00c01a
Packit 00c01a
  420jpeg chroma samples are sited like:
Packit 00c01a
  Y-------Y-------Y-------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |   BR  |       |   BR  |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  Y-------Y-------Y-------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  Y-------Y-------Y-------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |   BR  |       |   BR  |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  Y-------Y-------Y-------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
Packit 00c01a
  420paldv chroma samples are sited like:
Packit 00c01a
  YR------Y-------YR------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  YB------Y-------YB------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  YR------Y-------YR------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  YB------Y-------YB------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
Packit 00c01a
  We use a resampling filter to shift the site locations one quarter pixel (at
Packit 00c01a
   the chroma plane's resolution) to the right.
Packit 00c01a
  Then we use another filter to move the C_r location down one quarter pixel,
Packit 00c01a
   and the C_b location up one quarter pixel.*/
Packit 00c01a
static void y4m_convert_42xpaldv_42xjpeg(y4m_input *_y4m,unsigned char *_dst,
Packit 00c01a
 unsigned char *_aux){
Packit 00c01a
  unsigned char *tmp;
Packit 00c01a
  int            c_w;
Packit 00c01a
  int            c_h;
Packit 00c01a
  int            c_sz;
Packit 00c01a
  int            pli;
Packit 00c01a
  int            y;
Packit 00c01a
  int            x;
Packit 00c01a
  /*Skip past the luma data.*/
Packit 00c01a
  _dst+=_y4m->pic_w*_y4m->pic_h;
Packit 00c01a
  /*Compute the size of each chroma plane.*/
Packit 00c01a
  c_w=(_y4m->pic_w+1)/2;
Packit 00c01a
  c_h=(_y4m->pic_h+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h;
Packit 00c01a
  c_sz=c_w*c_h;
Packit 00c01a
  /*First do the horizontal re-sampling.
Packit 00c01a
    This is the same as the mpeg2 case, except that after the horizontal case,
Packit 00c01a
     we need to apply a second vertical filter.*/
Packit 00c01a
  tmp=_aux+2*c_sz;
Packit 00c01a
  for(pli=1;pli<3;pli++){
Packit 00c01a
    for(y=0;y
Packit 00c01a
      /*Filter: [4 -17 114 35 -9 1]/128, derived from a 6-tap Lanczos
Packit 00c01a
         window.*/
Packit 00c01a
      for(x=0;x
Packit 00c01a
        tmp[x]=(unsigned char)OC_CLAMPI(0,4*_aux[0]-17*_aux[OC_MAXI(x-1,0)]+
Packit 00c01a
         114*_aux[x]+35*_aux[OC_MINI(x+1,c_w-1)]-9*_aux[OC_MINI(x+2,c_w-1)]+
Packit 00c01a
         _aux[OC_MINI(x+3,c_w-1)]+64>>7,255);
Packit 00c01a
      }
Packit 00c01a
      for(;x
Packit 00c01a
        tmp[x]=(unsigned char)OC_CLAMPI(0,4*_aux[x-2]-17*_aux[x-1]+
Packit 00c01a
         114*_aux[x]+35*_aux[x+1]-9*_aux[x+2]+_aux[x+3]+64>>7,255);
Packit 00c01a
      }
Packit 00c01a
      for(;x
Packit 00c01a
        tmp[x]=(unsigned char)OC_CLAMPI(0,4*_aux[x-2]-17*_aux[x-1]+
Packit 00c01a
         114*_aux[x]+35*_aux[OC_MINI(x+1,c_w-1)]-9*_aux[OC_MINI(x+2,c_w-1)]+
Packit 00c01a
         _aux[c_w-1]+64>>7,255);
Packit 00c01a
      }
Packit 00c01a
      tmp+=c_w;
Packit 00c01a
      _aux+=c_w;
Packit 00c01a
    }
Packit 00c01a
    switch(pli){
Packit 00c01a
      case 1:{
Packit 00c01a
        tmp-=c_sz;
Packit 00c01a
        /*Slide C_b up a quarter-pel.
Packit 00c01a
          This is the same filter used above, but in the other order.*/
Packit 00c01a
        for(x=0;x
Packit 00c01a
          for(y=0;y
Packit 00c01a
            _dst[y*c_w]=(unsigned char)OC_CLAMPI(0,tmp[0]-
Packit 00c01a
             9*tmp[OC_MAXI(y-2,0)*c_w]+35*tmp[OC_MAXI(y-1,0)*c_w]+
Packit 00c01a
             114*tmp[y*c_w]-17*tmp[OC_MINI(y+1,c_h-1)*c_w]+
Packit 00c01a
             4*tmp[OC_MINI(y+2,c_h-1)*c_w]+64>>7,255);
Packit 00c01a
          }
Packit 00c01a
          for(;y
Packit 00c01a
            _dst[y*c_w]=(unsigned char)OC_CLAMPI(0,tmp[(y-3)*c_w]-
Packit 00c01a
             9*tmp[(y-2)*c_w]+35*tmp[(y-1)*c_w]+114*tmp[y*c_w]-
Packit 00c01a
             17*tmp[(y+1)*c_w]+4*tmp[(y+2)*c_w]+64>>7,255);
Packit 00c01a
          }
Packit 00c01a
          for(;y
Packit 00c01a
            _dst[y*c_w]=(unsigned char)OC_CLAMPI(0,tmp[(y-3)*c_w]-
Packit 00c01a
             9*tmp[(y-2)*c_w]+35*tmp[(y-1)*c_w]+114*tmp[y*c_w]-
Packit 00c01a
             17*tmp[OC_MINI(y+1,c_h-1)*c_w]+4*tmp[(c_h-1)*c_w]+64>>7,255);
Packit 00c01a
          }
Packit 00c01a
          _dst++;
Packit 00c01a
          tmp++;
Packit 00c01a
        }
Packit 00c01a
        _dst+=c_sz-c_w;
Packit 00c01a
        tmp-=c_w;
Packit 00c01a
      }break;
Packit 00c01a
      case 2:{
Packit 00c01a
        tmp-=c_sz;
Packit 00c01a
        /*Slide C_r down a quarter-pel.
Packit 00c01a
          This is the same as the horizontal filter.*/
Packit 00c01a
        for(x=0;x
Packit 00c01a
          for(y=0;y
Packit 00c01a
            _dst[y*c_w]=(unsigned char)OC_CLAMPI(0,4*tmp[0]-
Packit 00c01a
             17*tmp[OC_MAXI(y-1,0)*c_w]+114*tmp[y*c_w]+
Packit 00c01a
             35*tmp[OC_MINI(y+1,c_h-1)*c_w]-9*tmp[OC_MINI(y+2,c_h-1)*c_w]+
Packit 00c01a
             tmp[OC_MINI(y+3,c_h-1)*c_w]+64>>7,255);
Packit 00c01a
          }
Packit 00c01a
          for(;y
Packit 00c01a
            _dst[y*c_w]=(unsigned char)OC_CLAMPI(0,4*tmp[(y-2)*c_w]-
Packit 00c01a
             17*tmp[(y-1)*c_w]+114*tmp[y*c_w]+35*tmp[(y+1)*c_w]-
Packit 00c01a
             9*tmp[(y+2)*c_w]+tmp[(y+3)*c_w]+64>>7,255);
Packit 00c01a
          }
Packit 00c01a
          for(;y
Packit 00c01a
            _dst[y*c_w]=(unsigned char)OC_CLAMPI(0,4*tmp[(y-2)*c_w]-
Packit 00c01a
             17*tmp[(y-1)*c_w]+114*tmp[y*c_w]+35*tmp[OC_MINI(y+1,c_h-1)*c_w]-
Packit 00c01a
             9*tmp[OC_MINI(y+2,c_h-1)*c_w]+tmp[(c_h-1)*c_w]+64>>7,255);
Packit 00c01a
          }
Packit 00c01a
          _dst++;
Packit 00c01a
          tmp++;
Packit 00c01a
        }
Packit 00c01a
      }break;
Packit 00c01a
    }
Packit 00c01a
    /*For actual interlaced material, this would have to be done separately on
Packit 00c01a
       each field, and the shift amounts would be different.
Packit 00c01a
      C_r moves down 1/8, C_b up 3/8 in the top field, and C_r moves down 3/8,
Packit 00c01a
       C_b up 1/8 in the bottom field.
Packit 00c01a
      The corresponding filters would be:
Packit 00c01a
       Down 1/8 (reverse order for up): [3 -11 125 15 -4 0]/128
Packit 00c01a
       Down 3/8 (reverse order for up): [4 -19 98 56 -13 2]/128*/
Packit 00c01a
  }
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
/*422jpeg chroma samples are sited like:
Packit 00c01a
  Y---BR--Y-------Y---BR--Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  Y---BR--Y-------Y---BR--Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  Y---BR--Y-------Y---BR--Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  Y---BR--Y-------Y---BR--Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
Packit 00c01a
  411 chroma samples are sited like:
Packit 00c01a
  YBR-----Y-------Y-------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  YBR-----Y-------Y-------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  YBR-----Y-------Y-------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  YBR-----Y-------Y-------Y-------
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
  |       |       |       |
Packit 00c01a
Packit 00c01a
  We use a filter to resample at site locations one eighth pixel (at the source
Packit 00c01a
   chroma plane's horizontal resolution) and five eighths of a pixel to the
Packit 00c01a
   right.*/
Packit 00c01a
static void y4m_convert_411_422jpeg(y4m_input *_y4m,unsigned char *_dst,
Packit 00c01a
 unsigned char *_aux){
Packit 00c01a
  int c_w;
Packit 00c01a
  int dst_c_w;
Packit 00c01a
  int c_h;
Packit 00c01a
  int pli;
Packit 00c01a
  int y;
Packit 00c01a
  int x;
Packit 00c01a
  /*Skip past the luma data.*/
Packit 00c01a
  _dst+=_y4m->pic_w*_y4m->pic_h;
Packit 00c01a
  /*Compute the size of each chroma plane.*/
Packit 00c01a
  c_w=(_y4m->pic_w+_y4m->src_c_dec_h-1)/_y4m->src_c_dec_h;
Packit 00c01a
  dst_c_w=(_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h;
Packit 00c01a
  c_h=(_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v;
Packit 00c01a
  for(pli=1;pli<3;pli++){
Packit 00c01a
    for(y=0;y
Packit 00c01a
      /*Filters: [1 110 18 -1]/128 and [-3 50 86 -5]/128, both derived from a
Packit 00c01a
         4-tap Mitchell window.*/
Packit 00c01a
      for(x=0;x
Packit 00c01a
        _dst[x<<1]=(unsigned char)OC_CLAMPI(0,111*_aux[0]+
Packit 00c01a
         18*_aux[OC_MINI(1,c_w-1)]-_aux[OC_MINI(2,c_w-1)]+64>>7,255);
Packit 00c01a
        _dst[x<<1|1]=(unsigned char)OC_CLAMPI(0,47*_aux[0]+
Packit 00c01a
         86*_aux[OC_MINI(1,c_w-1)]-5*_aux[OC_MINI(2,c_w-1)]+64>>7,255);
Packit 00c01a
      }
Packit 00c01a
      for(;x
Packit 00c01a
        _dst[x<<1]=(unsigned char)OC_CLAMPI(0,_aux[x-1]+110*_aux[x]+
Packit 00c01a
         18*_aux[x+1]-_aux[x+2]+64>>7,255);
Packit 00c01a
        _dst[x<<1|1]=(unsigned char)OC_CLAMPI(0,-3*_aux[x-1]+50*_aux[x]+
Packit 00c01a
         86*_aux[x+1]-5*_aux[x+2]+64>>7,255);
Packit 00c01a
      }
Packit 00c01a
      for(;x
Packit 00c01a
        _dst[x<<1]=(unsigned char)OC_CLAMPI(0,_aux[x-1]+110*_aux[x]+
Packit 00c01a
         18*_aux[OC_MINI(x+1,c_w-1)]-_aux[c_w-1]+64>>7,255);
Packit 00c01a
        if((x<<1|1)
Packit 00c01a
          _dst[x<<1|1]=(unsigned char)OC_CLAMPI(0,-3*_aux[x-1]+50*_aux[x]+
Packit 00c01a
           86*_aux[OC_MINI(x+1,c_w-1)]-5*_aux[c_w-1]+64>>7,255);
Packit 00c01a
        }
Packit 00c01a
      }
Packit 00c01a
      _dst+=dst_c_w;
Packit 00c01a
      _aux+=c_w;
Packit 00c01a
    }
Packit 00c01a
  }
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
/*The image is padded with empty chroma components at 4:2:0.
Packit 00c01a
  This costs about 17 bits a frame to code.*/
Packit 00c01a
static void y4m_convert_mono_420jpeg(y4m_input *_y4m,unsigned char *_dst,
Packit 00c01a
 unsigned char *_aux){
Packit 00c01a
  int c_sz;
Packit 00c01a
  _dst+=_y4m->pic_w*_y4m->pic_h;
Packit 00c01a
  c_sz=((_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h)*
Packit 00c01a
   ((_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v);
Packit 00c01a
  memset(_dst,128,c_sz*2);
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
#if 0
Packit 00c01a
/*Right now just 444 to 420.
Packit 00c01a
  Not too hard to generalize.*/
Packit 00c01a
static void y4m_convert_4xxjpeg_42xjpeg(y4m_input *_y4m,unsigned char *_dst,
Packit 00c01a
 unsigned char *_aux){
Packit 00c01a
  unsigned char *tmp;
Packit 00c01a
  int            c_w;
Packit 00c01a
  int            c_h;
Packit 00c01a
  int            pic_sz;
Packit 00c01a
  int            tmp_sz;
Packit 00c01a
  int            c_sz;
Packit 00c01a
  int            pli;
Packit 00c01a
  int            y;
Packit 00c01a
  int            x;
Packit 00c01a
  /*Compute the size of each chroma plane.*/
Packit 00c01a
  c_w=(_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h;
Packit 00c01a
  c_h=(_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v;
Packit 00c01a
  pic_sz=_y4m->pic_w*_y4m->pic_h;
Packit 00c01a
  tmp_sz=c_w*_y4m->pic_h;
Packit 00c01a
  c_sz=c_w*c_h;
Packit 00c01a
  _dst+=pic_sz;
Packit 00c01a
  for(pli=1;pli<3;pli++){
Packit 00c01a
    tmp=_aux+pic_sz;
Packit 00c01a
    /*In reality, the horizontal and vertical steps could be pipelined, for
Packit 00c01a
       less memory consumption and better cache performance, but we do them
Packit 00c01a
       separately for simplicity.*/
Packit 00c01a
    /*First do horizontal filtering (convert to 4:2:2)*/
Packit 00c01a
    /*Filter: [3 -17 78 78 -17 3]/128, derived from a 6-tap Lanczos window.*/
Packit 00c01a
    for(y=0;y<_y4m->pic_h;y++){
Packit 00c01a
      for(x=0;x<OC_MINI(_y4m->pic_w,2);x+=2){
Packit 00c01a
        tmp[x>>1]=OC_CLAMPI(0,64*_aux[0]+78*_aux[OC_MINI(1,_y4m->pic_w-1)]
Packit 00c01a
         -17*_aux[OC_MINI(2,_y4m->pic_w-1)]
Packit 00c01a
         +3*_aux[OC_MINI(3,_y4m->pic_w-1)]+64>>7,255);
Packit 00c01a
      }
Packit 00c01a
      for(;x<_y4m->pic_w-3;x+=2){
Packit 00c01a
        tmp[x>>1]=OC_CLAMPI(0,3*(_aux[x-2]+_aux[x+3])-17*(_aux[x-1]+_aux[x+2])+
Packit 00c01a
         78*(_aux[x]+_aux[x+1])+64>>7,255);
Packit 00c01a
      }
Packit 00c01a
      for(;x<_y4m->pic_w;x+=2){
Packit 00c01a
        tmp[x>>1]=OC_CLAMPI(0,3*(_aux[x-2]+_aux[_y4m->pic_w-1])-
Packit 00c01a
         17*(_aux[x-1]+_aux[OC_MINI(x+2,_y4m->pic_w-1)])+
Packit 00c01a
         78*(_aux[x]+_aux[OC_MINI(x+1,_y4m->pic_w-1)])+64>>7,255);
Packit 00c01a
      }
Packit 00c01a
      tmp+=c_w;
Packit 00c01a
      _aux+=_y4m->pic_w;
Packit 00c01a
    }
Packit 00c01a
    _aux-=pic_sz;
Packit 00c01a
    tmp-=tmp_sz;
Packit 00c01a
    /*Now do the vertical filtering.*/
Packit 00c01a
    for(x=0;x
Packit 00c01a
      for(y=0;y<OC_MINI(_y4m->pic_h,2);y+=2){
Packit 00c01a
        _dst[(y>>1)*c_w]=OC_CLAMPI(0,64*tmp[0]
Packit 00c01a
         +78*tmp[OC_MINI(1,_y4m->pic_h-1)*c_w]
Packit 00c01a
         -17*tmp[OC_MINI(2,_y4m->pic_h-1)*c_w]
Packit 00c01a
         +3*tmp[OC_MINI(3,_y4m->pic_h-1)*c_w]+64>>7,255);
Packit 00c01a
      }
Packit 00c01a
      for(;y<_y4m->pic_h-3;y+=2){
Packit 00c01a
        _dst[(y>>1)*c_w]=OC_CLAMPI(0,3*(tmp[(y-2)*c_w]+tmp[(y+3)*c_w])-
Packit 00c01a
         17*(tmp[(y-1)*c_w]+tmp[(y+2)*c_w])+78*(tmp[y*c_w]+tmp[(y+1)*c_w])+
Packit 00c01a
         64>>7,255);
Packit 00c01a
      }
Packit 00c01a
      for(;y<_y4m->pic_h;y+=2){
Packit 00c01a
        _dst[(y>>1)*c_w]=OC_CLAMPI(0,3*(tmp[(y-2)*c_w]
Packit 00c01a
         +tmp[(_y4m->pic_h-1)*c_w])-17*(tmp[(y-1)*c_w]
Packit 00c01a
         +tmp[OC_MINI(y+2,_y4m->pic_h-1)*c_w])
Packit 00c01a
         +78*(tmp[y*c_w]+tmp[OC_MINI(y+1,_y4m->pic_h-1)*c_w])+64>>7,255);
Packit 00c01a
      }
Packit 00c01a
      tmp++;
Packit 00c01a
      _dst++;
Packit 00c01a
    }
Packit 00c01a
    _dst-=c_w;
Packit 00c01a
  }
Packit 00c01a
}
Packit 00c01a
#endif
Packit 00c01a
Packit 00c01a
/*No conversion function needed.*/
Packit 00c01a
static void y4m_convert_null(y4m_input *_y4m,unsigned char *_dst,
Packit 00c01a
 unsigned char *_aux){
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
static int y4m_input_open(y4m_input *_y4m,FILE *_fin,char *_skip,int _nskip){
Packit 00c01a
  char buffer[80];
Packit 00c01a
  int  ret;
Packit 00c01a
  int  i;
Packit 00c01a
  /*Read until newline, or 80 cols, whichever happens first.*/
Packit 00c01a
  for(i=0;i<79;i++){
Packit 00c01a
    if(_nskip>0){
Packit 00c01a
      buffer[i]=*_skip++;
Packit 00c01a
      _nskip--;
Packit 00c01a
    }
Packit 00c01a
    else{
Packit 00c01a
      ret=fread(buffer+i,1,1,_fin);
Packit 00c01a
      if(ret<1)return -1;
Packit 00c01a
    }
Packit 00c01a
    if(buffer[i]=='\n')break;
Packit 00c01a
  }
Packit 00c01a
  /*We skipped too much header data.*/
Packit 00c01a
  if(_nskip>0)return -1;
Packit 00c01a
  if(i==79){
Packit 00c01a
    fprintf(stderr,"Error parsing header; not a YUV2MPEG2 file?\n");
Packit 00c01a
    return -1;
Packit 00c01a
  }
Packit 00c01a
  buffer[i]='\0';
Packit 00c01a
  if(memcmp(buffer,"YUV4MPEG",8)){
Packit 00c01a
    fprintf(stderr,"Incomplete magic for YUV4MPEG file.\n");
Packit 00c01a
    return -1;
Packit 00c01a
  }
Packit 00c01a
  if(buffer[8]!='2'){
Packit 00c01a
    fprintf(stderr,"Incorrect YUV input file version; YUV4MPEG2 required.\n");
Packit 00c01a
  }
Packit 00c01a
  ret=y4m_parse_tags(_y4m,buffer+5);
Packit 00c01a
  if(ret<0){
Packit 00c01a
    fprintf(stderr,"Error parsing YUV4MPEG2 header.\n");
Packit 00c01a
    return ret;
Packit 00c01a
  }
Packit 00c01a
  if(_y4m->interlace!='p'){
Packit 00c01a
    fprintf(stderr,"Input video is interlaced; "
Packit 00c01a
     "Theora only handles progressive scan.\n");
Packit 00c01a
    return -1;
Packit 00c01a
  }
Packit 00c01a
  if(strcmp(_y4m->chroma_type,"420")==0||
Packit 00c01a
   strcmp(_y4m->chroma_type,"420jpeg")==0){
Packit 00c01a
    _y4m->src_c_dec_h=_y4m->dst_c_dec_h=_y4m->src_c_dec_v=_y4m->dst_c_dec_v=2;
Packit 00c01a
    _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h
Packit 00c01a
     +2*((_y4m->pic_w+1)/2)*((_y4m->pic_h+1)/2);
Packit 00c01a
    /*Natively supported: no conversion required.*/
Packit 00c01a
    _y4m->aux_buf_sz=_y4m->aux_buf_read_sz=0;
Packit 00c01a
    _y4m->convert=y4m_convert_null;
Packit 00c01a
  }
Packit 00c01a
  else if(strcmp(_y4m->chroma_type,"420mpeg2")==0){
Packit 00c01a
    _y4m->src_c_dec_h=_y4m->dst_c_dec_h=_y4m->src_c_dec_v=_y4m->dst_c_dec_v=2;
Packit 00c01a
    _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h;
Packit 00c01a
    /*Chroma filter required: read into the aux buf first.*/
Packit 00c01a
    _y4m->aux_buf_sz=_y4m->aux_buf_read_sz=
Packit 00c01a
     2*((_y4m->pic_w+1)/2)*((_y4m->pic_h+1)/2);
Packit 00c01a
    _y4m->convert=y4m_convert_42xmpeg2_42xjpeg;
Packit 00c01a
  }
Packit 00c01a
  else if(strcmp(_y4m->chroma_type,"420paldv")==0){
Packit 00c01a
    _y4m->src_c_dec_h=_y4m->dst_c_dec_h=_y4m->src_c_dec_v=_y4m->dst_c_dec_v=2;
Packit 00c01a
    _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h;
Packit 00c01a
    /*Chroma filter required: read into the aux buf first.
Packit 00c01a
      We need to make two filter passes, so we need some extra space in the
Packit 00c01a
       aux buffer.*/
Packit 00c01a
    _y4m->aux_buf_sz=3*((_y4m->pic_w+1)/2)*((_y4m->pic_h+1)/2);
Packit 00c01a
    _y4m->aux_buf_read_sz=2*((_y4m->pic_w+1)/2)*((_y4m->pic_h+1)/2);
Packit 00c01a
    _y4m->convert=y4m_convert_42xpaldv_42xjpeg;
Packit 00c01a
  }
Packit 00c01a
  else if(strcmp(_y4m->chroma_type,"422")==0){
Packit 00c01a
    _y4m->src_c_dec_h=_y4m->dst_c_dec_h=2;
Packit 00c01a
    _y4m->src_c_dec_v=_y4m->dst_c_dec_v=1;
Packit 00c01a
    _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h;
Packit 00c01a
    /*Chroma filter required: read into the aux buf first.*/
Packit 00c01a
    _y4m->aux_buf_sz=_y4m->aux_buf_read_sz=2*((_y4m->pic_w+1)/2)*_y4m->pic_h;
Packit 00c01a
    _y4m->convert=y4m_convert_42xmpeg2_42xjpeg;
Packit 00c01a
  }
Packit 00c01a
  else if(strcmp(_y4m->chroma_type,"411")==0){
Packit 00c01a
    _y4m->src_c_dec_h=4;
Packit 00c01a
    /*We don't want to introduce any additional sub-sampling, so we
Packit 00c01a
       promote 4:1:1 material to 4:2:2, as the closest format Theora can
Packit 00c01a
       handle.*/
Packit 00c01a
    _y4m->dst_c_dec_h=2;
Packit 00c01a
    _y4m->src_c_dec_v=_y4m->dst_c_dec_v=1;
Packit 00c01a
    _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h;
Packit 00c01a
    /*Chroma filter required: read into the aux buf first.*/
Packit 00c01a
    _y4m->aux_buf_sz=_y4m->aux_buf_read_sz=2*((_y4m->pic_w+3)/4)*_y4m->pic_h;
Packit 00c01a
    _y4m->convert=y4m_convert_411_422jpeg;
Packit 00c01a
  }
Packit 00c01a
  else if(strcmp(_y4m->chroma_type,"444")==0){
Packit 00c01a
    _y4m->src_c_dec_h=_y4m->dst_c_dec_h=_y4m->src_c_dec_v=_y4m->dst_c_dec_v=1;
Packit 00c01a
    _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h*3;
Packit 00c01a
    /*Natively supported: no conversion required.*/
Packit 00c01a
    _y4m->aux_buf_sz=_y4m->aux_buf_read_sz=0;
Packit 00c01a
    _y4m->convert=y4m_convert_null;
Packit 00c01a
  }
Packit 00c01a
  else if(strcmp(_y4m->chroma_type,"444alpha")==0){
Packit 00c01a
    _y4m->src_c_dec_h=_y4m->dst_c_dec_h=_y4m->src_c_dec_v=_y4m->dst_c_dec_v=1;
Packit 00c01a
    _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h*3;
Packit 00c01a
    /*Read the extra alpha plane into the aux buf.
Packit 00c01a
      It will be discarded.*/
Packit 00c01a
    _y4m->aux_buf_sz=_y4m->aux_buf_read_sz=_y4m->pic_w*_y4m->pic_h;
Packit 00c01a
    _y4m->convert=y4m_convert_null;
Packit 00c01a
  }
Packit 00c01a
  else if(strcmp(_y4m->chroma_type,"mono")==0){
Packit 00c01a
    _y4m->src_c_dec_h=_y4m->src_c_dec_v=0;
Packit 00c01a
    _y4m->dst_c_dec_h=_y4m->dst_c_dec_v=2;
Packit 00c01a
    _y4m->dst_buf_read_sz=_y4m->pic_w*_y4m->pic_h;
Packit 00c01a
    /*No extra space required, but we need to clear the chroma planes.*/
Packit 00c01a
    _y4m->aux_buf_sz=_y4m->aux_buf_read_sz=0;
Packit 00c01a
    _y4m->convert=y4m_convert_mono_420jpeg;
Packit 00c01a
  }
Packit 00c01a
  else{
Packit 00c01a
    fprintf(stderr,"Unknown chroma sampling type: %s\n",_y4m->chroma_type);
Packit 00c01a
    return -1;
Packit 00c01a
  }
Packit 00c01a
  /*The size of the final frame buffers is always computed from the
Packit 00c01a
     destination chroma decimation type.*/
Packit 00c01a
  _y4m->dst_buf_sz=_y4m->pic_w*_y4m->pic_h
Packit 00c01a
   +2*((_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h)*
Packit 00c01a
   ((_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v);
Packit 00c01a
  /*Scale the picture size up to a multiple of 16.*/
Packit 00c01a
  _y4m->frame_w=_y4m->pic_w+15&~0xF;
Packit 00c01a
  _y4m->frame_h=_y4m->pic_h+15&~0xF;
Packit 00c01a
  /*Force the offsets to be even so that chroma samples line up like we
Packit 00c01a
     expect.*/
Packit 00c01a
  _y4m->pic_x=_y4m->frame_w-_y4m->pic_w>>1&~;;
Packit 00c01a
  _y4m->pic_y=_y4m->frame_h-_y4m->pic_h>>1&~;;
Packit 00c01a
  _y4m->dst_buf=(unsigned char *)malloc(_y4m->dst_buf_sz);
Packit 00c01a
  _y4m->aux_buf=(unsigned char *)malloc(_y4m->aux_buf_sz);
Packit 00c01a
  return 0;
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
static void y4m_input_get_info(y4m_input *_y4m,th_info *_ti){
Packit 00c01a
  _ti->frame_width=_y4m->frame_w;
Packit 00c01a
  _ti->frame_height=_y4m->frame_h;
Packit 00c01a
  _ti->pic_width=_y4m->pic_w;
Packit 00c01a
  _ti->pic_height=_y4m->pic_h;
Packit 00c01a
  _ti->pic_x=_y4m->pic_x;
Packit 00c01a
  _ti->pic_y=_y4m->pic_y;
Packit 00c01a
  _ti->fps_numerator=_y4m->fps_n;
Packit 00c01a
  _ti->fps_denominator=_y4m->fps_d;
Packit 00c01a
  _ti->aspect_numerator=_y4m->par_n;
Packit 00c01a
  _ti->aspect_denominator=_y4m->par_d;
Packit 00c01a
  _ti->pixel_fmt=_y4m->dst_c_dec_h==2?
Packit 00c01a
   (_y4m->dst_c_dec_v==2?TH_PF_420:TH_PF_422):TH_PF_444;
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
static int y4m_input_fetch_frame(y4m_input *_y4m,FILE *_fin,
Packit 00c01a
 th_ycbcr_buffer _ycbcr){
Packit 00c01a
  char frame[6];
Packit 00c01a
  int  pic_sz;
Packit 00c01a
  int  frame_c_w;
Packit 00c01a
  int  frame_c_h;
Packit 00c01a
  int  c_w;
Packit 00c01a
  int  c_h;
Packit 00c01a
  int  c_sz;
Packit 00c01a
  int  ret;
Packit 00c01a
  pic_sz=_y4m->pic_w*_y4m->pic_h;
Packit 00c01a
  frame_c_w=_y4m->frame_w/_y4m->dst_c_dec_h;
Packit 00c01a
  frame_c_h=_y4m->frame_h/_y4m->dst_c_dec_v;
Packit 00c01a
  c_w=(_y4m->pic_w+_y4m->dst_c_dec_h-1)/_y4m->dst_c_dec_h;
Packit 00c01a
  c_h=(_y4m->pic_h+_y4m->dst_c_dec_v-1)/_y4m->dst_c_dec_v;
Packit 00c01a
  c_sz=c_w*c_h;
Packit 00c01a
  /*Read and skip the frame header.*/
Packit 00c01a
  ret=fread(frame,1,6,_fin);
Packit 00c01a
  if(ret<6)return 0;
Packit 00c01a
  if(memcmp(frame,"FRAME",5)){
Packit 00c01a
    fprintf(stderr,"Loss of framing in YUV input data\n");
Packit 00c01a
    exit(1);
Packit 00c01a
  }
Packit 00c01a
  if(frame[5]!='\n'){
Packit 00c01a
    char c;
Packit 00c01a
    int  j;
Packit 00c01a
    for(j=0;j<79&&fread(&c,1,1,_fin)&&c!='\n';j++);
Packit 00c01a
    if(j==79){
Packit 00c01a
      fprintf(stderr,"Error parsing YUV frame header\n");
Packit 00c01a
      return -1;
Packit 00c01a
    }
Packit 00c01a
  }
Packit 00c01a
  /*Read the frame data that needs no conversion.*/
Packit 00c01a
  if(fread(_y4m->dst_buf,1,_y4m->dst_buf_read_sz,_fin)!=_y4m->dst_buf_read_sz){
Packit 00c01a
    fprintf(stderr,"Error reading YUV frame data.\n");
Packit 00c01a
    return -1;
Packit 00c01a
  }
Packit 00c01a
  /*Read the frame data that does need conversion.*/
Packit 00c01a
  if(fread(_y4m->aux_buf,1,_y4m->aux_buf_read_sz,_fin)!=_y4m->aux_buf_read_sz){
Packit 00c01a
    fprintf(stderr,"Error reading YUV frame data.\n");
Packit 00c01a
    return -1;
Packit 00c01a
  }
Packit 00c01a
  /*Now convert the just read frame.*/
Packit 00c01a
  (*_y4m->convert)(_y4m,_y4m->dst_buf,_y4m->aux_buf);
Packit 00c01a
  /*Fill in the frame buffer pointers.*/
Packit 00c01a
  _ycbcr[0].width=_y4m->frame_w;
Packit 00c01a
  _ycbcr[0].height=_y4m->frame_h;
Packit 00c01a
  _ycbcr[0].stride=_y4m->pic_w;
Packit 00c01a
  _ycbcr[0].data=_y4m->dst_buf-_y4m->pic_x-_y4m->pic_y*_y4m->pic_w;
Packit 00c01a
  _ycbcr[1].width=frame_c_w;
Packit 00c01a
  _ycbcr[1].height=frame_c_h;
Packit 00c01a
  _ycbcr[1].stride=c_w;
Packit 00c01a
  _ycbcr[1].data=_y4m->dst_buf+pic_sz-(_y4m->pic_x/_y4m->dst_c_dec_h)-
Packit 00c01a
   (_y4m->pic_y/_y4m->dst_c_dec_v)*c_w;
Packit 00c01a
  _ycbcr[2].width=frame_c_w;
Packit 00c01a
  _ycbcr[2].height=frame_c_h;
Packit 00c01a
  _ycbcr[2].stride=c_w;
Packit 00c01a
  _ycbcr[2].data=_ycbcr[1].data+c_sz;
Packit 00c01a
  return 1;
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
static void y4m_input_close(y4m_input *_y4m){
Packit 00c01a
  free(_y4m->dst_buf);
Packit 00c01a
  free(_y4m->aux_buf);
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
Packit 00c01a
Packit 00c01a
typedef struct th_input th_input;
Packit 00c01a
Packit 00c01a
struct th_input{
Packit 00c01a
  ogg_sync_state    oy;
Packit 00c01a
  int               theora_p;
Packit 00c01a
  ogg_stream_state  to;
Packit 00c01a
  th_info           ti;
Packit 00c01a
  th_comment        tc;
Packit 00c01a
  th_dec_ctx       *td;
Packit 00c01a
};
Packit 00c01a
Packit 00c01a
Packit 00c01a
Packit 00c01a
/*Grab some more compressed bitstream and sync it for page extraction.*/
Packit 00c01a
static int th_input_buffer_data(th_input *_th,FILE *_fin){
Packit 00c01a
  char *buffer;
Packit 00c01a
  int bytes;
Packit 00c01a
  buffer=ogg_sync_buffer(&_th->oy,4096);
Packit 00c01a
  bytes=fread(buffer,1,4096,_fin);
Packit 00c01a
  ogg_sync_wrote(&_th->oy,bytes);
Packit 00c01a
  return bytes;
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
/*Push a page into the appropriate steam.
Packit 00c01a
  This can be done blindly; a stream won't accept a page that doesn't belong to
Packit 00c01a
   it.*/
Packit 00c01a
static void th_input_queue_page(th_input *_th,ogg_page *_og){
Packit 00c01a
  if(_th->theora_p)ogg_stream_pagein(&_th->to,_og);
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
static int th_input_open_impl(th_input *_th,th_setup_info **_ts,FILE *_fin,
Packit 00c01a
 char *_sig,int _nsig){
Packit 00c01a
  ogg_packet op;
Packit 00c01a
  ogg_page   og;
Packit 00c01a
  int        nheaders_left;
Packit 00c01a
  int        done_headers;
Packit 00c01a
  ogg_sync_init(&_th->oy);
Packit 00c01a
  th_info_init(&_th->ti);
Packit 00c01a
  th_comment_init(&_th->tc);
Packit 00c01a
  *_ts=NULL;
Packit 00c01a
  /*Buffer any initial data read for file ID.*/
Packit 00c01a
  if(_nsig>0){
Packit 00c01a
    char *buffer;
Packit 00c01a
    buffer=ogg_sync_buffer(&_th->oy,_nsig);
Packit 00c01a
    memcpy(buffer,_sig,_nsig);
Packit 00c01a
    ogg_sync_wrote(&_th->oy,_nsig);
Packit 00c01a
  }
Packit 00c01a
  _th->theora_p=0;
Packit 00c01a
  nheaders_left=0;
Packit 00c01a
  for(done_headers=0;!done_headers;){
Packit 00c01a
    if(th_input_buffer_data(_th,_fin)==0)break;
Packit 00c01a
    while(ogg_sync_pageout(&_th->oy,&og)>0){
Packit 00c01a
      ogg_stream_state test;
Packit 00c01a
      /*Is this a mandated initial header?
Packit 00c01a
        If not, stop parsing.*/
Packit 00c01a
      if(!ogg_page_bos(&og)){
Packit 00c01a
        /*Don't leak the page; get it into the appropriate stream.*/
Packit 00c01a
        th_input_queue_page(_th,&og);
Packit 00c01a
        done_headers=1;
Packit 00c01a
        break;
Packit 00c01a
      }
Packit 00c01a
      ogg_stream_init(&test,ogg_page_serialno(&og);;
Packit 00c01a
      ogg_stream_pagein(&test,&og);
Packit 00c01a
      ogg_stream_packetpeek(&test,&op);
Packit 00c01a
      /*Identify the codec: try Theora.*/
Packit 00c01a
      if(!_th->theora_p){
Packit 00c01a
        nheaders_left=th_decode_headerin(&_th->ti,&_th->tc,_ts,&op);
Packit 00c01a
        if(nheaders_left>=0){
Packit 00c01a
          /*It is Theora.*/
Packit 00c01a
          memcpy(&_th->to,&test,sizeof(test));
Packit 00c01a
          _th->theora_p=1;
Packit 00c01a
          /*Advance past the successfully processed header.*/
Packit 00c01a
          if(nheaders_left>0)ogg_stream_packetout(&_th->to,NULL);
Packit 00c01a
          continue;
Packit 00c01a
        }
Packit 00c01a
      }
Packit 00c01a
      /*Whatever it is, we don't care about it.*/
Packit 00c01a
      ogg_stream_clear(&test);
Packit 00c01a
    }
Packit 00c01a
  }
Packit 00c01a
  /*We're expecting more header packets.*/
Packit 00c01a
  while(_th->theora_p&&nheaders_left>0){
Packit 00c01a
    int ret;
Packit 00c01a
    while(nheaders_left>0){
Packit 00c01a
      ret=ogg_stream_packetpeek(&_th->to,&op);
Packit 00c01a
      if(ret==0)break;
Packit 00c01a
      if(ret<0)continue;
Packit 00c01a
      nheaders_left=th_decode_headerin(&_th->ti,&_th->tc,_ts,&op);
Packit 00c01a
      if(nheaders_left<0){
Packit 00c01a
        fprintf(stderr,"Error parsing Theora stream headers; "
Packit 00c01a
         "corrupt stream?\n");
Packit 00c01a
        return -1;
Packit 00c01a
      }
Packit 00c01a
      /*Advance past the successfully processed header.*/
Packit 00c01a
      else if(nheaders_left>0)ogg_stream_packetout(&_th->to,NULL);
Packit 00c01a
      _th->theora_p++;
Packit 00c01a
    }
Packit 00c01a
    /*Stop now so we don't fail if there aren't enough pages in a short
Packit 00c01a
       stream.*/
Packit 00c01a
    if(!(_th->theora_p&&nheaders_left>0))break;
Packit 00c01a
    /*The header pages/packets will arrive before anything else we care
Packit 00c01a
       about, or the stream is not obeying spec.*/
Packit 00c01a
    if(ogg_sync_pageout(&_th->oy,&og)>0)th_input_queue_page(_th,&og);
Packit 00c01a
    /*We need more data.*/
Packit 00c01a
    else if(th_input_buffer_data(_th,_fin)==0){
Packit 00c01a
      fprintf(stderr,"End of file while searching for codec headers.\n");
Packit 00c01a
      return -1;
Packit 00c01a
    }
Packit 00c01a
  }
Packit 00c01a
  /*And now we have it all.
Packit 00c01a
    Initialize the decoder.*/
Packit 00c01a
  if(_th->theora_p){
Packit 00c01a
    _th->td=th_decode_alloc(&_th->ti,*_ts);
Packit 00c01a
    if(_th->td!=NULL){
Packit 00c01a
      fprintf(stderr,"Ogg logical stream %lx is Theora %ix%i %.02f fps video.\n"
Packit 00c01a
       "Encoded frame content is %ix%i with %ix%i offset.\n",
Packit 00c01a
       _th->to.serialno,_th->ti.frame_width,_th->ti.frame_height,
Packit 00c01a
       (double)_th->ti.fps_numerator/_th->ti.fps_denominator,
Packit 00c01a
       _th->ti.pic_width,_th->ti.pic_height,_th->ti.pic_x,_th->ti.pic_y);
Packit 00c01a
      return 1;
Packit 00c01a
    }
Packit 00c01a
  }
Packit 00c01a
  return -1;
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
static void th_input_close(th_input *_th){
Packit 00c01a
  if(_th->theora_p){
Packit 00c01a
    ogg_stream_clear(&_th->to);
Packit 00c01a
    th_decode_free(_th->td);
Packit 00c01a
  }
Packit 00c01a
  th_comment_clear(&_th->tc);
Packit 00c01a
  th_info_clear(&_th->ti);
Packit 00c01a
  ogg_sync_clear(&_th->oy);
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
static int th_input_open(th_input *_th,FILE *_fin,char *_sig,int _nsig){
Packit 00c01a
  th_input       th;
Packit 00c01a
  th_setup_info *ts;
Packit 00c01a
  int            ret;
Packit 00c01a
  ret=th_input_open_impl(&th,&ts,_fin,_sig,_nsig);
Packit 00c01a
  th_setup_free(ts);
Packit 00c01a
  /*Clean up on failure.*/
Packit 00c01a
  if(ret<0)th_input_close(&th);
Packit 00c01a
  else memcpy(_th,&th,sizeof(th));
Packit 00c01a
  return ret;
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
static void th_input_get_info(th_input *_th,th_info *_ti){
Packit 00c01a
  memcpy(_ti,&_th->ti,sizeof(*_ti));
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
static int th_input_fetch_frame(th_input *_th,FILE *_fin,
Packit 00c01a
 th_ycbcr_buffer _ycbcr){
Packit 00c01a
  for(;;){
Packit 00c01a
    ogg_page   og;
Packit 00c01a
    ogg_packet op;
Packit 00c01a
    if(ogg_stream_packetout(&_th->to,&op)>0){
Packit 00c01a
      if(th_decode_packetin(_th->td,&op,NULL)>=0){
Packit 00c01a
        th_decode_ycbcr_out(_th->td,_ycbcr);
Packit 00c01a
        if(!summary_only&&show_frame_type){
Packit 00c01a
          printf("%c",th_packet_iskeyframe(&op)?'K':'D');
Packit 00c01a
          if(op.bytes>0)printf("%02i ",op.packet[0]&0x3F);
Packit 00c01a
          else printf("-- ");
Packit 00c01a
        }
Packit 00c01a
        return 1;
Packit 00c01a
      }
Packit 00c01a
      else return -1;
Packit 00c01a
    }
Packit 00c01a
    while(ogg_sync_pageout(&_th->oy,&og)<=0){
Packit 00c01a
      if(th_input_buffer_data(_th,_fin)==0)return feof(_fin)?0:-1;
Packit 00c01a
    }
Packit 00c01a
    th_input_queue_page(_th,&og);
Packit 00c01a
  }
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
Packit 00c01a
Packit 00c01a
typedef struct video_input video_input;
Packit 00c01a
typedef void (*video_input_get_info_func)(void *_ctx,th_info *_ti);
Packit 00c01a
typedef int (*video_input_fetch_frame_func)(void *_ctx,FILE *_fin,
Packit 00c01a
 th_ycbcr_buffer _ycbcr);
Packit 00c01a
typedef void (*video_input_close_func)(void *_ctx);
Packit 00c01a
Packit 00c01a
struct video_input{
Packit 00c01a
  FILE                         *fin;
Packit 00c01a
  video_input_get_info_func     get_info;
Packit 00c01a
  video_input_fetch_frame_func  fetch_frame;
Packit 00c01a
  video_input_close_func        close;
Packit 00c01a
  union{
Packit 00c01a
    y4m_input y4m;
Packit 00c01a
    th_input  th;
Packit 00c01a
  }ctx;
Packit 00c01a
};
Packit 00c01a
Packit 00c01a
static int video_input_open(video_input *_vid,FILE *_fin){
Packit 00c01a
  char buffer[4];
Packit 00c01a
  int  ret;
Packit 00c01a
  /* look for magic */
Packit 00c01a
  ret=fread(buffer,1,4,_fin);
Packit 00c01a
  if(ret<4)fprintf(stderr,"EOF determining file type of file.\n");
Packit 00c01a
  else{
Packit 00c01a
    if(!memcmp(buffer,"YUV4",4)){
Packit 00c01a
      if(y4m_input_open(&_vid->ctx.y4m,_fin,buffer,4)>=0){
Packit 00c01a
        /*fprintf(stderr,"Original %s is %dx%d %.02f fps %s video.\n",
Packit 00c01a
         f,_y4m->pic_w,_y4m->pic_h,(double)_y4m->fps_n/_y4m->fps_d,_y4m->chroma_type);*/
Packit 00c01a
        _vid->fin=_fin;
Packit 00c01a
        _vid->get_info=(video_input_get_info_func)y4m_input_get_info;
Packit 00c01a
        _vid->fetch_frame=(video_input_fetch_frame_func)y4m_input_fetch_frame;
Packit 00c01a
        _vid->close=(video_input_close_func)y4m_input_close;
Packit 00c01a
        return 0;
Packit 00c01a
      }
Packit 00c01a
    }
Packit 00c01a
    else if(!memcmp(buffer,"OggS",4)){
Packit 00c01a
      if(th_input_open(&_vid->ctx.th,_fin,buffer,4)>=0){
Packit 00c01a
        _vid->fin=_fin;
Packit 00c01a
        _vid->get_info=(video_input_get_info_func)th_input_get_info;
Packit 00c01a
        _vid->fetch_frame=(video_input_fetch_frame_func)th_input_fetch_frame;
Packit 00c01a
        _vid->close=(video_input_close_func)th_input_close;
Packit 00c01a
        return 0;
Packit 00c01a
      }
Packit 00c01a
    }
Packit 00c01a
    else fprintf(stderr,"Unknown file type.\n");
Packit 00c01a
  }
Packit 00c01a
  return -1;
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
static void video_input_get_info(video_input *_vid,th_info *_ti){
Packit 00c01a
  (*_vid->get_info)(&_vid->ctx,_ti);
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
static int video_input_fetch_frame(video_input *_vid,th_ycbcr_buffer _ycbcr){
Packit 00c01a
  return (*_vid->fetch_frame)(&_vid->ctx,_vid->fin,_ycbcr);
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
static void video_input_close(video_input *_vid){
Packit 00c01a
  (*_vid->close)(&_vid->ctx);
Packit 00c01a
  fclose(_vid->fin);
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
Packit 00c01a
Packit 00c01a
static void usage(char *_argv[]){
Packit 00c01a
  fprintf(stderr,"Usage: %s [options] <video1> <video2>\n"
Packit 00c01a
   "    <video1> and <video1> may be either YUV4MPEG or Ogg Theora files.\n\n"
Packit 00c01a
   "    Options:\n\n"
Packit 00c01a
   "      -f --frame-type Show frame type and QI value for each Theora frame.\n"
Packit 00c01a
   "      -s --summary    Only output the summary line.\n"
Packit 00c01a
   "      -y --luma-only  Only output values for the luma channel.\n",_argv[0]);
Packit 00c01a
}
Packit 00c01a
Packit 00c01a
int main(int _argc,char *_argv[]){
Packit 00c01a
  video_input  vid1;
Packit 00c01a
  th_info      ti1;
Packit 00c01a
  video_input  vid2;
Packit 00c01a
  th_info      ti2;
Packit 00c01a
  ogg_int64_t  gsqerr;
Packit 00c01a
  ogg_int64_t  gnpixels;
Packit 00c01a
  ogg_int64_t  gplsqerr[3];
Packit 00c01a
  ogg_int64_t  gplnpixels[3];
Packit 00c01a
  int          frameno;
Packit 00c01a
  FILE        *fin;
Packit 00c01a
  int          long_option_index;
Packit 00c01a
  int          c;
Packit 00c01a
#ifdef _WIN32
Packit 00c01a
  /*We need to set stdin/stdout to binary mode on windows.
Packit 00c01a
    Beware the evil ifdef.
Packit 00c01a
    We avoid these where we can, but this one we cannot.
Packit 00c01a
    Don't add any more, you'll probably go to hell if you do.*/
Packit 00c01a
  _setmode(_fileno(stdin),_O_BINARY);
Packit 00c01a
#endif
Packit 00c01a
  /*Process option arguments.*/
Packit 00c01a
  while((c=getopt_long(_argc,_argv,optstring,options,&long_option_index))!=EOF){
Packit 00c01a
    switch(c){
Packit 00c01a
      case 'f':show_frame_type=1;break;
Packit 00c01a
      case 's':summary_only=1;break;
Packit 00c01a
      case 'y':luma_only=1;break;
Packit 00c01a
      default:usage(_argv);break;
Packit 00c01a
    }
Packit 00c01a
  }
Packit 00c01a
  if(optind+2!=_argc){
Packit 00c01a
    usage(_argv);
Packit 00c01a
    exit(1);
Packit 00c01a
  }
Packit 00c01a
  fin=strcmp(_argv[optind],"-")==0?stdin:fopen(_argv[optind],"rb");
Packit 00c01a
  if(fin==NULL){
Packit 00c01a
    fprintf(stderr,"Unable to open '%s' for extraction.\n",_argv[optind]);
Packit 00c01a
    exit(1);
Packit 00c01a
  }
Packit 00c01a
  fprintf(stderr,"Opening %s...\n",_argv[optind]);
Packit 00c01a
  if(video_input_open(&vid1,fin)<0)exit(1);
Packit 00c01a
  video_input_get_info(&vid1,&ti1;;
Packit 00c01a
  fin=strcmp(_argv[optind+1],"-")==0?stdin:fopen(_argv[optind+1],"rb");
Packit 00c01a
  if(fin==NULL){
Packit 00c01a
    fprintf(stderr,"Unable to open '%s' for extraction.\n",_argv[optind+1]);
Packit 00c01a
    exit(1);
Packit 00c01a
  }
Packit 00c01a
  fprintf(stderr,"Opening %s...\n",_argv[optind+1]);
Packit 00c01a
  if(video_input_open(&vid2,fin)<0)exit(1);
Packit 00c01a
  video_input_get_info(&vid2,&ti2;;
Packit 00c01a
  /*Check to make sure these videos are compatible.*/
Packit 00c01a
  if(ti1.pic_width!=ti2.pic_width||ti1.pic_height!=ti2.pic_height){
Packit 00c01a
    fprintf(stderr,"Video resolution does not match.\n");
Packit 00c01a
    exit(1);
Packit 00c01a
  }
Packit 00c01a
  if(ti1.pixel_fmt!=ti2.pixel_fmt){
Packit 00c01a
    fprintf(stderr,"Pixel formats do not match.\n");
Packit 00c01a
    exit(1);
Packit 00c01a
  }
Packit 00c01a
  if((ti1.pic_x&!(ti1.pixel_fmt&1))!=(ti2.pic_x&!(ti2.pixel_fmt&1))||
Packit 00c01a
   (ti1.pic_y&!(ti1.pixel_fmt&2))!=(ti2.pic_y&!(ti2.pixel_fmt&2))){
Packit 00c01a
    fprintf(stderr,"Chroma subsampling offsets do not match.\n");
Packit 00c01a
    exit(1);
Packit 00c01a
  }
Packit 00c01a
  if(ti1.fps_numerator*(ogg_int64_t)ti2.fps_denominator!=
Packit 00c01a
   ti2.fps_numerator*(ogg_int64_t)ti1.fps_denominator){
Packit 00c01a
    fprintf(stderr,"Warning: framerates do not match.\n");
Packit 00c01a
  }
Packit 00c01a
  if(ti1.aspect_numerator*(ogg_int64_t)ti2.aspect_denominator!=
Packit 00c01a
   ti2.aspect_numerator*(ogg_int64_t)ti1.aspect_denominator){
Packit 00c01a
    fprintf(stderr,"Warning: aspect ratios do not match.\n");
Packit 00c01a
  }
Packit 00c01a
  gsqerr=gplsqerr[0]=gplsqerr[1]=gplsqerr[2]=0;
Packit 00c01a
  gnpixels=gplnpixels[0]=gplnpixels[1]=gplnpixels[2]=0;
Packit 00c01a
  for(frameno=0;;frameno++){
Packit 00c01a
    th_ycbcr_buffer f1;
Packit 00c01a
    th_ycbcr_buffer f2;
Packit 00c01a
    ogg_int64_t     plsqerr[3];
Packit 00c01a
    long            plnpixels[3];
Packit 00c01a
    ogg_int64_t     sqerr;
Packit 00c01a
    long            npixels;
Packit 00c01a
    int             ret1;
Packit 00c01a
    int             ret2;
Packit 00c01a
    int             pli;
Packit 00c01a
    ret1=video_input_fetch_frame(&vid1,f1);
Packit 00c01a
    ret2=video_input_fetch_frame(&vid2,f2);
Packit 00c01a
    if(ret1==0&&ret2==0)break;
Packit 00c01a
    else if(ret1<0||ret2<0)break;
Packit 00c01a
    else if(ret1==0){
Packit 00c01a
      fprintf(stderr,"%s ended before %s.\n",
Packit 00c01a
       _argv[optind],_argv[optind+1]);
Packit 00c01a
      break;
Packit 00c01a
    }
Packit 00c01a
    else if(ret2==0){
Packit 00c01a
      fprintf(stderr,"%s ended before %s.\n",
Packit 00c01a
       _argv[optind+1],_argv[optind]);
Packit 00c01a
      break;
Packit 00c01a
    }
Packit 00c01a
    /*Okay, we got one frame from each.*/
Packit 00c01a
    sqerr=0;
Packit 00c01a
    npixels=0;
Packit 00c01a
    for(pli=0;pli<3;pli++){
Packit 00c01a
      int xdec;
Packit 00c01a
      int ydec;
Packit 00c01a
      int y1;
Packit 00c01a
      int y2;
Packit 00c01a
      xdec=pli&&!(ti1.pixel_fmt&1;;
Packit 00c01a
      ydec=pli&&!(ti1.pixel_fmt&2;;
Packit 00c01a
      plsqerr[pli]=0;
Packit 00c01a
      plnpixels[pli]=0;
Packit 00c01a
      for(y1=ti1.pic_y>>ydec,y2=ti2.pic_y>>ydec;
Packit 00c01a
       y1<ti1.pic_y+ti1.pic_height+ydec>>ydec;y1++,y2++){
Packit 00c01a
        int x1;
Packit 00c01a
        int x2;
Packit 00c01a
        for(x1=ti1.pic_x>>xdec,x2=ti2.pic_x>>xdec;
Packit 00c01a
         x1<ti1.pic_x+ti1.pic_width+xdec>>xdec;x1++,x2++){
Packit 00c01a
          int d;
Packit 00c01a
          d=*(f1[pli].data+y1*f1[pli].stride+x1)-
Packit 00c01a
           *(f2[pli].data+y2*f2[pli].stride+x2);
Packit 00c01a
          plsqerr[pli]+=d*d;
Packit 00c01a
          plnpixels[pli]++;
Packit 00c01a
        }
Packit 00c01a
      }
Packit 00c01a
      sqerr+=plsqerr[pli];
Packit 00c01a
      gplsqerr[pli]+=plsqerr[pli];
Packit 00c01a
      npixels+=plnpixels[pli];
Packit 00c01a
      gplnpixels[pli]+=plnpixels[pli];
Packit 00c01a
    }
Packit 00c01a
    if(!summary_only){
Packit 00c01a
      if(!luma_only){
Packit 00c01a
        printf("%08i: %-7lG  (Y': %-7lG  Cb: %-7lG  Cr: %-7lG)\n",frameno,
Packit 00c01a
         10*(log10(255*255)+log10(npixels)-log10(sqerr)),
Packit 00c01a
         10*(log10(255*255)+log10(plnpixels[0])-log10(plsqerr[0])),
Packit 00c01a
         10*(log10(255*255)+log10(plnpixels[1])-log10(plsqerr[1])),
Packit 00c01a
         10*(log10(255*255)+log10(plnpixels[2])-log10(plsqerr[2])));
Packit 00c01a
      }
Packit 00c01a
      else{
Packit 00c01a
        printf("%08i: %-7lG\n",frameno,
Packit 00c01a
         10*(log10(255*255)+log10(plnpixels[0])-log10(plsqerr[0])));
Packit 00c01a
      }
Packit 00c01a
    }
Packit 00c01a
    gsqerr+=sqerr;
Packit 00c01a
    gnpixels+=npixels;
Packit 00c01a
  }
Packit 00c01a
  if(!luma_only){
Packit 00c01a
    printf("Total: %-7lG  (Y': %-7lG  Cb: %-7lG  Cr: %-7lG)\n",
Packit 00c01a
     10*(log10(255*255)+log10(gnpixels)-log10(gsqerr)),
Packit 00c01a
     10*(log10(255*255)+log10(gplnpixels[0])-log10(gplsqerr[0])),
Packit 00c01a
     10*(log10(255*255)+log10(gplnpixels[1])-log10(gplsqerr[1])),
Packit 00c01a
     10*(log10(255*255)+log10(gplnpixels[2])-log10(gplsqerr[2])));
Packit 00c01a
  }
Packit 00c01a
  else{
Packit 00c01a
    printf("Total: %-7lG\n",
Packit 00c01a
     10*(log10(255*255)+log10(gplnpixels[0])-log10(gplsqerr[0])));
Packit 00c01a
  }
Packit 00c01a
  video_input_close(&vid1);
Packit 00c01a
  video_input_close(&vid2);
Packit 00c01a
  return 0;
Packit 00c01a
}