/********************************************************************
 *                                                                  *
 * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE.   *
 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
 *                                                                  *
 * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2003                *
 * by the Xiph.Org Foundation http://www.xiph.org/                  *
 *                                                                  *
 ********************************************************************

  function:
  last mod: $Id: theora.h,v 1.17 2003/12/06 18:06:19 arc Exp $

 ********************************************************************/

#ifndef _O_THEORA_H_
#define _O_THEORA_H_

#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */

#ifndef LIBOGG2
#include <ogg/ogg.h>
#else
#include <ogg2/ogg.h>
/* This is temporary until libogg2 is more complete */
ogg_buffer_state *ogg_buffer_create(void);
#endif

/** \mainpage
 * 
 * \section intro Introduction
 *
 * This is the documentation for the libtheora C API.
 * libtheora is the reference implementation for
 * <a href="http://www.theora.org/">Theora</a>, a free video codec.
 * Theora is derived from On2's VP3 codec with improved integration for
 * Ogg multimedia formats by <a href="http://www.xiph.org/">Xiph.Org</a>.
 */

/** \file
 * The libtheora C API.
 */

/**
 * A YUV buffer for passing uncompressed frames to and from the codec.
 * This holds a Y'CbCr frame in planar format. The CbCr planes can be
 * subsampled and have their own separate dimensions and row stride
 * offsets. Note that the strides may be negative in some 
 * configurations. For theora the width and height of the largest plane
 * must be a multiple of 16. The actual meaningful picture size and 
 * offset are stored in the theora_info structure; frames returned by
 * the decoder my been to be cropped for display. 
 * All samples are 8 bits.
 */
typedef struct {
    int   y_width;	/**< width of the Y' luminance plane */
    int   y_height;	/**< height of the luminance plane */
    int   y_stride;	/**< offset in bytes between successive rows */

    int   uv_width;	/**< height of the Cb and Cr chroma planes */
    int   uv_height;	/**< width of the chroma planes */
    int   uv_stride;	/**< offset between successive chroma rows */
    unsigned char *y;	/**< pointer to start of luminance data */
    unsigned char *u;	/**< pointer to start of Cb data */
    unsigned char *v;	/**< pointer to start of Cr data */

} yuv_buffer;

/**
 * A Colorspace.
 */
typedef enum {
  OC_CS_UNSPECIFIED,	/**< the colorspace is unknown or unspecified */
  OC_CS_ITU_REC_470M,	/**< best option for 'NTSC' content */
  OC_CS_ITU_REC_470BG,	/**< best option for 'PAL' content */
} theora_colorspace;

/**
 * Theora bitstream info.
 * Contains the basic playback parameters for a stream,
 * corresponds to the initial 'info' header packet.
 * 
 * Encoded theora frames must be a multiple of 16 is size;
 * this is what the width and height members represent. To
 * handle other sizes, a crop rectangle is specified in 
 * frame_height and frame_width, offset_x and offset_y. The
 * offset and size should still be a power of 2 to avoid
 * chroma sampling shifts.
 *
 * Frame rate, in frames per second is stored as a rational
 * fraction. So is the aspect ratio. Note that this refers
 * to the aspect ratio of the frame pixels, not of the
 * overall frame itself.
 * 
 * see the example code for use of the other parameters and
 * good default settings for the encoder parameters.
 */
typedef struct {
  ogg_uint32_t  width;
  ogg_uint32_t  height;
  ogg_uint32_t  frame_width;
  ogg_uint32_t  frame_height;
  ogg_uint32_t  offset_x;
  ogg_uint32_t  offset_y;
  ogg_uint32_t  fps_numerator;
  ogg_uint32_t  fps_denominator;
  ogg_uint32_t  aspect_numerator;
  ogg_uint32_t  aspect_denominator;
  theora_colorspace colorspace;
  int           target_bitrate;
  int           quality;  /**< nominal quality setting, 0-63 */
  int           quick_p;  /**< quick encode/decode */

  /* decode only */
  unsigned char version_major;
  unsigned char version_minor;
  unsigned char version_subminor;

  void *codec_setup;

  /* encode only */
  int           dropframes_p;
  int           keyframe_auto_p;
  ogg_uint32_t  keyframe_frequency;
  ogg_uint32_t  keyframe_frequency_force;  /* also used for decode init to
                                              get granpos shift correct */
  ogg_uint32_t  keyframe_data_target_bitrate;
  ogg_int32_t   keyframe_auto_threshold;
  ogg_uint32_t  keyframe_mindistance;
  ogg_int32_t   noise_sensitivity;
  ogg_int32_t   sharpness;

} theora_info;

/** Codec internal state and context.
 */
typedef struct{
  theora_info *i;
  ogg_int64_t granulepos;

  void *internal_encode;
  void *internal_decode;

} theora_state;

/** 
 * Comment header metadata.
 *
 * This structure holds the in-stream metadata corresponding to
 * the 'comment' header packet.
 *
 * Meta data is stored as a series of (tag, value) pairs, in
 * length-encoded string vectors. The first occurence of the 
 * '=' character delimits the tag and value. A particular tag
 * may occur more than once. The character set encoding for
 * the strings is always utf-8, but the tag names are limited
 * to case-insensitive ascii. See the spec for details.
 *
 * In filling in this structure, theora_decode_header() will
 * null-terminate the user_comment strings for safety. However,
 * the bitstream format itself treats them as 8-bit clean,
 * and so the length array should be treated as authoritative
 * for their length.
 */
typedef struct theora_comment{
  char **user_comments;		/**< an array of comment string vectors */
  int   *comment_lengths;	/**< an array of corresponding string vector lengths in bytes */
  int    comments;		/**< the total number of comment string vectors */
  char  *vendor;		/**< the vendor string identifying the encoder, null terminated */

} theora_comment;

#define OC_FAULT       -1	/**< general failure */
#define OC_EINVAL      -10	/**< library encountered invalid internal data */
#define OC_DISABLED    -11	/**< requested action is disabled */
#define OC_BADHEADER   -20	/**< header packet was corrupt/invalid */
#define OC_NOTFORMAT   -21	/**< packet is not a theora packet */
#define OC_VERSION     -22	/**< bitstream version is not handled */
#define OC_IMPL        -23	/**< feature or action not implemented */
#define OC_BADPACKET   -24	/**< packet is corrupt */
#define OC_NEWPACKET   -25	/**< packet is an (ignorable) unhandled extension */

/** 
 * Retrieve a human-readable string to identify the encoder vendor and version.
 * \returns a version string.
 */
extern const char *theora_version_string(void);

/**
 * Retrieve a 32-bit version number.
 * This number is composed of a 16-bit major version, 8-bit minor version
 * and 8 bit sub-version, composed as follows:
<pre>
   (VERSION_MAJOR<<16) + (VERSION_MINOR<<8) + (VERSION_SUB)
</pre>
* \returns the version number.
*/
extern ogg_uint32_t theora_version_number(void);

/**
 * Initialize the theora encoder.
 * \param th The theora_state handle to initialize for encoding.
 * \param ti A theora_info struct filled with the desired encoding parameters.
 * \returns 0 Success
 */
extern int theora_encode_init(theora_state *th, theora_info *c);

/**
 * Submit a YUV buffer to the theora encoder.
 * \param t A theora_state handle previously initialized for encoding.
 * \param yuv A buffer of YUV data to encode.
 * \retval OC_EINVAL Encoder is not ready, or is finished.
 * \retval -1 The size of the given frame differs from those previously input
 * \retval 0 Success
 */
extern int theora_encode_YUVin(theora_state *t, yuv_buffer *yuv);

/**
 * Request the next packet of encoded video. 
 * The encoded data is placed in a user-provided ogg_packet structure.
 * \param t A theora_state handle previously initialized for encoding.
 * \param last_p whether this is the last packet the encoder should produce.
 * \param op An ogg_packet structure to fill. libtheora will set all
 *           elements of this structure, including a pointer to encoded
 *           data. The memory for the encoded data is owned by libtheora.
 * \retval 0 No internal storage exists OR no packet is ready
 * \retval -1 The encoding process has completed
 * \retval 1 Success
 */
extern int theora_encode_packetout( theora_state *t, int last_p,
                                    ogg_packet *op);

/**
 * Request a packet containing the initial header.
 * A pointer to the header data is placed in a user-provided ogg_packet
 * structure.
 * \param t A theora_state handle previously initialized for encoding.
 * \param op An ogg_packet structure to fill. libtheora will set all
 *           elements of this structure, including a pointer to the header
 *           data. The memory for the header data is owned by libtheora.
 * \retval 0 Success
 */
extern int theora_encode_header(theora_state *t, ogg_packet *op);

/**
 * Request a comment header packet from provided metadata.
 * A pointer to the comment data is placed in a user-provided ogg_packet
 * structure.
 * \param tc A theora_comment structure filled with the desired metadata
 * \param op An ogg_packet structure to fill. libtheora will set all
 *           elements of this structure, including a pointer to the encoded
 *           comment data. The memory for the comment data is owned by
 *           libtheora.
 * \retval 0 Success
 */
extern int theora_encode_comment(theora_comment *tc, ogg_packet *op);

/**
 * Request a packet containing the codebook tables for the stream.
 * A pointer to the codebook data is placed in a user-provided ogg_packet
 * structure.
 * \param t A theora_state handle previously initialized for encoding.
 * \param op An ogg_packet structure to fill. libtheora will set all
 *           elements of this structure, including a pointer to the codebook
 *           data. The memory for the header data is owned by libtheora.
 * \retval 0 Success
 */
extern int theora_encode_tables(theora_state *t, ogg_packet *op);

/**
 * Decode an Ogg packet, with the expectation that the packet contains
 * an initial header, comment data or codebook tables.
 *
 * \param ci A theora_info structure to fill. This must have been previously
 *           initialized with theora_info_init(). If \a op contains an initial
 *           header, theora_decode_header() will fill \a ci with the
 *           parsed header values. If \a op contains codebook tables,
 *           theora_decode_header() will parse these and attach an internal
 *           representation to \a ci->codec_setup.
 * \param cc A theora_comment structure to fill. If \a op contains comment
 *           data, theora_decode_header() will fill \a cc with the parsed
 *           comments.
 * \param op An ogg_packet structure which you expect contains an initial
 *           header, comment data or codebook tables.
 *
 * \retval OC_BADHEADER \a op is NULL; OR the first byte of \a op->packet
 *                      has the signature of an initial packet, but op is
 *                      not a b_o_s packet; OR this packet has the signature
 *                      of an initial header packet, but an initial header
 *                      packet has already been seen; OR this packet has the
 *                      signature of a comment packet, but the initial header
 *                      has not yet been seen; OR this packet has the signature
 *                      of a comment packet, but contains invalid data; OR
 *                      this packet has the signature of codebook tables,
 *                      but the initial header or comments have not yet
 *                      been seen; OR this packet has the signature of codebook
 *                      tables, but contains invalid data;
 *                      OR the stream being decoded has a compatible version
 *                      but this packet does not have the signature of a
 *                      theora initial header, comments, or codebook packet
 * \retval OC_VERSION   The packet data of \a op is an initial header with
 *                      a version which is incompatible with this version of
 *                      libtheora.
 * \retval OC_NEWPACKET the stream being decoded has an incompatible (future)
 *                      version and contains an unknown signature.
 * \retval 0            Success
 *
 * \note The normal usage is that theora_decode_header() be called on the
 *       first three packets of a theora logical bitstream in succession.
 */
extern int theora_decode_header(theora_info *ci, theora_comment *cc,
                                ogg_packet *op);

/**
 * Initialize a theora_state handle for decoding.
 * \param th The theora_state handle to initialize.
 * \param c  A theora_info struct filled with the desired decoding parameters.
 *           This is of course usually obtained from a previous call to
 *           theora_decode_header().
 * \returns 0 Success
 */
extern int theora_decode_init(theora_state *th, theora_info *c);

/**
 * Input a packet containing encoded data into the theora decoder.
 * \param th A theora_state handle previously initialized for decoding.
 * \param op An ogg_packet containing encoded theora data.
 * \retval OC_BADPACKET \a op does not contain encoded video data
 */
extern int theora_decode_packetin(theora_state *th,ogg_packet *op);

/**
 * Output the next available frame of decoded YUV data.
 * \param th A theora_state handle previously initialized for decoding.
 * \param yuv A yuv_buffer in which libtheora should place the decoded data.
 * \retval 0 Success
 */
extern int theora_decode_YUVout(theora_state *th,yuv_buffer *yuv);

/**
 * Report whether a theora packet is a header or not
 * This function does no verification beyond checking the header
 * flag bit so it should not be used for bitstream identification;
 * use theora_decode_header() for that.
 *
 * \param op An ogg_packet containing encoded theora data.
 * \retval 1 The packet is a header packet
 * \retval 0 The packet is not a header packet (and so contains frame data)
 *
 * Thus function was added in the 1.0alpha4 release.
 */
extern int theora_packet_isheader(ogg_packet *op);

/**
 * Report whether a theora packet is a keyframe or not
 *
 * \param op An ogg_packet containing encoded theora data.
 * \retval 1 The packet contains a keyframe image
 * \retval 0 The packet is contains an interframe delta
 * \retval -1 the packet is not an image data packet at all
 *
 * Thus function was added in the 1.0alpha4 release.
 */
extern int theora_packet_iskeyframe(ogg_packet *op);

/**
 * Convert a granulepos to an absolute frame number. The granulepos is
 * interpreted in the context of a given theora_state handle.
 *
 * \param th A previously initialized theora_state handle (encode or decode)
 * \param granulepos The granulepos to convert.
 * \returns The frame number corresponding to \a granulepos.
 * \retval -1 The given granulepos is invalid (ie. negative)
 *
 * Thus function was added in the 1.0alpha4 release.
 */
extern ogg_int64_t theora_granule_frame(theora_state *th,ogg_int64_t granulepos);

/**
 * Convert a granulepos to absolute time in seconds. The granulepos is
 * interpreted in the context of a given theora_state handle.
 * \param th A previously initialized theora_state handle (encode or decode)
 * \param granulepos The granulepos to convert.
 * \returns The absolute time in seconds corresponding to \a granulepos.
 * \retval -1 The given granulepos is invalid (ie. negative)
 */
extern double theora_granule_time(theora_state *th,ogg_int64_t granulepos);

/**
 * Initialize a theora_info structure. All values within the given theora_info
 * structure are initialized, and space is allocated within libtheora for
 * internal codec setup data.
 * \param c A theora_info struct to initialize.
 */
extern void theora_info_init(theora_info *c);

/**
 * Clear a theora_info structure. All values within the given theora_info
 * structure are cleared, and associated internal codec setup data is freed.
 * \param c A theora_info struct to initialize.
 */
extern void theora_info_clear(theora_info *c);

/**
 * Free all internal data associated with a theora_state handle.
 * \param t A theora_state handle.
 */
extern void theora_clear(theora_state *t);

/** Initialize an allocated theora_comment structure */
extern void theora_comment_init(theora_comment *tc);
/** Add a comment to an initialized theora_comment structure
    \param comment must be a null-terminated string encoding
      the comment in "TAG=the value" form */
extern void theora_comment_add(theora_comment *tc, char *comment);
/** Add a comment to an initialized theora_comment structure
    \param tag a null-terminated string containing the tag 
      associated with the comment.
    \param value the corresponding value as a null-terminated string
    Neither theora_comment_add() nor theora_comment_add_tag() support
    comments containing null values, although the bitstream format
    supports this. To add such comments you will need to manipulate
    the theora_comment structure directly */
extern void theora_comment_add_tag(theora_comment *tc,
                                       char *tag, char *value);
/** look up a comment value by tag
    \param tc an initialized theora_comment structure
    \param tag the tag to look up
    \param count the instance of the tag. The same tag can appear 
      multiple times, each with a distinct and ordered value, so
      an index is required to retrieve them all.
    Use theora_comment_query_count() to get the legal range for the
    count parameter
    \returns a pointer to the queried tag's value
    \retval NULL if no matching tag is found */
extern char *theora_comment_query(theora_comment *tc, char *tag, int count);
/** look up the number of instances of a tag
    \param tc an initialized theora_comment structure
    \param tag the tag to look up
    \returns the number on instances of a particular tag.
    Call this first when querying for a specific tag and then interate
    over the number of instances with separate calls to 
    theora_comment_query() to retrieve all instances in order. */
extern int   theora_comment_query_count(theora_comment *tc, char *tag);
/** clears an allocated theora_comment struct so that it can be freed. */
extern void  theora_comment_clear(theora_comment *tc);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* _O_THEORA_H_ */
