function A = ivtc(at,ab,bt,bb, shift, pulldown)
%A = ivtc(at,ab,bt,bb, shift, pulldown)
%  Performs single-frame inverse telecine
%    at,ab,bt,bb: the next four fields in the telecined video, where at and
%      ab are the top and bottom fields, respectively, in the current
%      telecined frame.  bt and bb are the top and bottom fields of the
%      next telecined frame.
%    shift: what part of the telecine cycle do these fields correspond to?
%      For example, if the video underwent 2:3:2:3 telecine and the first
%      telecined frame was at the beginning of the first 2-pull, the first
%      four fields should use shift=0.  fields 3:6 should use shift=2, and
%      so on.  
%    pulldown: the pulldown pattern.  For example, the most common pulldown
%      used to convert cinema content (24fps) to US television (30fps) is
%      2:3:2:3.  The pulldown parameter in this case would be [2 3 2 3].
%      This pattern is often referred-to as 2:3 pulldown.  If the sum of
%      the pulled fields is odd, we automatically repeat it, so [2 3] and
%      [2 3 2 3] produce the same results.
%  If the current time slot does not correspond to a unique progressive
%  frame, [] is returned.
%
%TODO: 
%  * document more fully
%  * optionally handle bottom field first 
%  * make an optimized streaming version
%    * embed in videoIO?  
%       * We'll need a good way to configure ffdshow on Windows
%       * best way on Linux?
%  * make a version that takes two pre-interleaved frames 
%  * return a smoothed timestamp
%  * if this is the first frame and it's the last part of a >=3 pull,
%    figure out how to keep it (or maybe bias all large pulls to the right) 
%
%By Gerald Dalley

assert(mod(shift,2)==0); % at must be a top field
if (mod(sum(pulldown),2)==1) % make sure field reversals are balanced (2:3 --> 2:3:2:3)
  pulldown = [pulldown(:)' pulldown(:)'];
end
N = sum(pulldown); % # of fields in a pulldown cycle
% we can't reconstruct progressive frames if some progressive fields were
% dropped
assert(all(pulldown>1)); 

% If we always reconstruct frames the first chance we get, we can drop
% frames in a sane manner.  We also compute at which shift positions we'll
% need to use at&ab vs bt&ab.
firstFieldGivenFrame = [0 cumsum(pulldown(1:end-1))];
whenToReconstruct = floor(firstFieldGivenFrame/2)*2;
needToFlipFields  = (mod(firstFieldGivenFrame, 2) == 1);

% wrap our indicator of the current part of the pulldown cycle
shift = mod(mod(shift+N,N)+N, N);

[doReconstruction,reconstrFrameShift] = ismember(shift, whenToReconstruct);
if doReconstruction
  if (needToFlipFields(reconstrFrameShift))
    A = interleaveFields(bt,ab);
  else
    A = interleaveFields(at,ab);    
  end
else
  A = [];
end
