/*
 *  stillsstreams.c: Class for elemenary still video streams
 *                   Most functionality is inherited from VideoStream
 *
 *  Copyright (C) 2001 Andrew Stevens <andrew.stevens@philips.com>
 *
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of version 2 of the GNU General Public License
 *  as published by the Free Software Foundation.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */


#include <format_codes.h>

#include "stillsstream.hh"
#include "outputstream.hh"
#include <cassert>

void
StillsStream::Init ()
{
  int stream_id = 0;
  int buffer_size = 0;

  SetBufSize (4 * 1024 * 1024);
  InitAUbuffer ();
  ScanFirstSeqHeader ();

  mjpeg_debug ("SETTING video buffer to %d", muxinto.video_buffer_size);
  switch (opt_mux_format) {
    case MPEG_FORMAT_VCD_STILL:
      if (horizontal_size > 352) {
	stream_id = VIDEO_STR_0 + 2;
	buffer_size = vbv_buffer_size * 2048;
	mjpeg_info ("Stills Stream %02x: high-resolution VCD stills %d KB each",
		    stream_id, buffer_size);
	if (buffer_size < 46 * 1024)
	  mjpeg_error_exit1
	    ("I Can't multiplex high-res stills smaller than normal res stills - sorry!");

      } else {
	stream_id = VIDEO_STR_0 + 1;
	buffer_size = 46 * 1024;
	mjpeg_info ("Stills Stream %02x: normal VCD stills", stream_id);
      }
      break;
    case MPEG_FORMAT_SVCD_STILL:
      if (horizontal_size > 480) {
	stream_id = VIDEO_STR_0 + 1;
	buffer_size = 230 * 1024;
	mjpeg_info ("Stills Stream %02x: high-resolution SVCD stills.", stream_id);
      } else {
	stream_id = VIDEO_STR_0 + 1;
	buffer_size = 230 * 1024;
	mjpeg_info ("Stills Stream %02x: normal-resolution SVCD stills.", stream_id);
      }
      break;
  }


  MuxStream::Init (stream_id, 1,	// Buffer scale
		   buffer_size, 0,	// Zero stuffing
		   muxinto.buffers_in_video, muxinto.always_buffers_in_video);

  /* Skip to the end of the 1st AU (*2nd* Picture start!)
   */
  AU_hdr = SEQUENCE_HEADER;
  AU_pict_data = 0;
  AU_start = 0LL;

  OutputSeqhdrInfo ();

}




/*
 * Compute DTS / PTS for a VCD/SVCD Stills sequence
 * TODO: Very crude. Simply assumes each still stays for the specified
 * frame interval and that enough run-in delay is present for the first
 * frame to be loaded.
 *
 */

void
StillsStream::NextDTSPTS (clockticks & DTS, clockticks & PTS)
{
  clockticks interval = static_cast < clockticks >
    (intervals->NextFrameInterval () * CLOCKS / frame_rate);
  clockticks time_for_xfer;

  muxinto.ByteposTimecode (BufferSize (), time_for_xfer);

  DTS = current_PTS + time_for_xfer;	// This frame decoded just after
  // Predecessor completed.
  PTS = current_PTS + time_for_xfer + interval;
  current_PTS = PTS;
  current_DTS = DTS;
}

/*
 * VCD mixed stills segment items have the constraint that both stills
 * streams must end together.  To do this each stream has to know
 * about its "sibling".
 *
 */

void
VCDStillsStream::SetSibling (VCDStillsStream * _sibling)
{
  assert (_sibling != 0);
  sibling = _sibling;
  if (sibling->stream_id == stream_id) {
    mjpeg_error_exit1 ("VCD mixed stills stream cannot contain two streams of the same type!");
  }

}

/*
 * Check if we've reached the last sector of the last AU.  Note: that
 * we know no PTS/DTS time-stamps will be needed because no new AU
 * will appear in the last sector.  WARNING: We assume a still won't
 * fit into a single secotr.
 *
 */

bool
VCDStillsStream::LastSectorLastAU ()
{
  return (Lookahead () == 0 &&
	  au_unsent <= muxinto.PacketPayload (*this, buffers_in_header, false, false)
    );
}


/*
 * The requirement that VCD mixed stills segment items constituent streams
 * end together means we can't mux the last sector of the last AU of
 * such streams until its sibling has already completed muxing or is
 * also ready to mux the last sector of its last AU.
 *
 * NOTE: Will not work right if sector_align_iframe_AUs not set as this
 * will allow multiple AU's in  a sector.
 *
 */


bool
VCDStillsStream::MuxPossible ()
{
  if (bufmodel.Size () < au_unsent) {
    mjpeg_error_exit1
      ("Illegal VCD still: larger than maximum permitted by its buffering parameters!");
  }
  if (RunOutComplete () || bufmodel.Space () < au_unsent) {
    return false;
  }

  if (LastSectorLastAU ()) {
    if (sibling != 0) {
      if (!stream_mismatch_warned && sibling->NextAUType () != NOFRAME) {
	mjpeg_warn ("One VCD stills stream runs significantly longer than the other!");
	mjpeg_warn ("Simultaneous stream ending recommended by standard not possible");
	return true;
      }
      return sibling->MuxCompleted () || sibling->LastSectorLastAU ();
    } else
      return true;
  } else
    return true;
}




/* 
 * Local variables:
 *  c-file-style: "stroustrup"
 *  tab-width: 4
 *  indent-tabs-mode: nil
 * End:
 */