/*
 * Datastructures for manipulating NAL units in H.264 elementary streams.
 *
 * ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is the MPEG TS, PS and ES tools.
 *
 * The Initial Developer of the Original Code is Amino Communications Ltd.
 * Portions created by the Initial Developer are Copyright (C) 2008
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Amino Communications Ltd, Swavesey, Cambridge UK
 *
 * ***** END LICENSE BLOCK *****
 */

#ifndef _nalunit_defns
#define _nalunit_defns

#include <stdio.h>
#include "compat.h"
#include "es_defns.h"
#include "bitdata_defns.h"

// ------------------------------------------------------------
// Constants and definitions
// ------------------------------------------------------------
enum NAL_UNIT_TYPE
{
  NAL_UNSPECIFIED,
  NAL_NON_IDR,
  NAL_PARTITION_A,
  NAL_PARTITION_B,
  NAL_PARTITION_C,
  NAL_IDR,
  NAL_SEI,
  NAL_SEQ_PARAM_SET,
  NAL_PIC_PARAM_SET,
  NAL_ACCESS_UNIT_DELIM,
  NAL_END_OF_SEQ,
  NAL_END_OF_STREAM,
  NAL_FILLER
};

#define NAL_UNIT_TYPE_STR(a) \
    ((a)==NAL_UNSPECIFIED?"unspecified":              \
     (a)==NAL_NON_IDR?"non-IDR":                      \
     (a)==NAL_PARTITION_A?"partition A":              \
     (a)==NAL_PARTITION_B?"partition B":              \
     (a)==NAL_PARTITION_C?"partition C":              \
     (a)==NAL_IDR?"IDR":                              \
     (a)==NAL_SEI?"SEI":                              \
     (a)==NAL_SEQ_PARAM_SET?"seq param set":          \
     (a)==NAL_PIC_PARAM_SET?"pic param set":          \
     (a)==NAL_ACCESS_UNIT_DELIM?"access unit delim":  \
     (a)==NAL_END_OF_SEQ?"end of seq":                \
     (a)==NAL_END_OF_STREAM?"end of stream":          \
     (a)==NAL_FILLER?"filler":"???")

#define SLICE_P        0
#define SLICE_B        1
#define SLICE_I        2
#define SLICE_SP       3
#define SLICE_SI       4
#define ALL_SLICES_P   5
#define ALL_SLICES_B   6
#define ALL_SLICES_I   7
#define ALL_SLICES_SP  8
#define ALL_SLICES_SI  9

#define NAL_SLICE_TYPE_STR(a)	\
  ((a)==SLICE_P?"First P": (a)==SLICE_B?"First B": (a)==SLICE_I?"First I":     	\
   (a)==SLICE_SP?"First SP": (a)==SLICE_SI?"First SI":                         	\
   (a)==ALL_SLICES_P?"All P": (a)==ALL_SLICES_B?"All B":           		\
   (a)==ALL_SLICES_I?"All I": (a)==ALL_SLICES_SP?"All SP":         		\
   (a)==ALL_SLICES_SI?"All SI":"??")


// ------------------------------------------------------------
// Datastructures
// ------------------------------------------------------------
// Data for a slice NAL unit
struct nal_slice_data
{
  uint32_t seq_param_set_pic_order_cnt_type;  // from the seq param set
  uint32_t first_mb_in_slice;
  uint32_t slice_type;
  uint32_t pic_parameter_set_id;
  uint32_t frame_num;
  // From here onwards, the fields are not necessarily all present
  byte     field_pic_flag;     // frame or field? 0 if absent
  byte     bottom_field_flag;  // 0 if absent
  int      bottom_field_flag_present;
  uint32_t idr_pic_id;
  uint32_t pic_order_cnt_lsb;
  int32_t  delta_pic_order_cnt_bottom;
  int32_t  delta_pic_order_cnt[2];
  uint32_t redundant_pic_cnt;
  int      redundant_pic_cnt_present;
};
typedef struct nal_slice_data *nal_slice_data_p;
#define SIZEOF_NAL_SLICE_DATA sizeof(struct nal_slice_data)

// ------------------------------------------------------------
// Data for a sequence parameter set
struct nal_seq_param_data
{
  byte     profile_idc;
  byte     constraint_set0_flag;
  byte     constraint_set1_flag;
  byte     constraint_set2_flag;
  byte     level_idc;
  uint32_t seq_parameter_set_id;   // our own id (0..31)
  uint32_t log2_max_frame_num;
  uint32_t pic_order_cnt_type;
  uint32_t log2_max_pic_order_cnt_lsb;
  byte     delta_pic_order_always_zero_flag;
  byte     frame_mbs_only_flag;
};
typedef struct nal_seq_param_data *nal_seq_param_data_p;
#define SIZEOF_NAL_SEQ_PARAM_DATA sizeof(struct nal_seq_param_data)

// ------------------------------------------------------------
// Data for a picture parameter set
struct nal_pic_param_data
{
  int      pic_parameter_set_id;               // our own id  (0..255)
  int      seq_parameter_set_id;               // we use this
  byte     entropy_coding_mode_flag;
  byte     pic_order_present_flag;             // we use this
  uint32_t num_slice_groups;
  uint32_t slice_group_map_type;
  // lots of ignored things
  byte     redundant_pic_cnt_present_flag;     // this is mildly interesting
};
typedef struct nal_pic_param_data *nal_pic_param_data_p;
#define SIZEOF_NAL_PIC_PARAM_DATA sizeof(struct nal_pic_param_data)

// ------------------------------------------------------------
// Data for a Supplemental enhancement information (SEI) nal unit
struct nal_SEI_recovery_data
{
  int      payloadType;               // type of SEI unit
  int      payloadSize;               // in byte    

  int      recovery_frame_cnt;
  byte     exact_match_flag;
  byte     broken_link_flag;
  uint32_t changing_slice_group_idc;
};
typedef struct nal_SEI_recovery_data *nal_SEI_recovery_data_p;
#define SIZEOF_NAL_SEI_RECOVERY_DATA sizeof(struct nal_SEI_recovery_data)

// ------------------------------------------------------------
// An individual NAL unit might hold any one of those...
union nal_innards
{
  struct nal_slice_data         slice;
  struct nal_seq_param_data     seq;
  struct nal_pic_param_data     pic;
  struct nal_SEI_recovery_data  sei_recovery;
};
typedef union nal_innards *nal_innards_p;
#define SIZEOF_NAL_INNARDS sizeof(union nal_innards)

// ------------------------------------------------------------
// "Dictionaries" for finding a specific picture parameter set or
// sequence parameter set
// Picture parameter set ids are in the range 0..255
// Sequence parameter set ids are in the range 0..31
struct param_dict
{
  int      last_id;    // The id of the last parameter set we wanted
  int      last_index; // and its index in the arrays
  int      *ids;       // The ids for...
  union nal_innards *params;    // ...the data
  ES_offset         *posns;     // Where each was read from...
  uint32_t          *data_lens; // ...and its size
  int      size, length; // of the arrays and their content
};
typedef struct param_dict *param_dict_p;
#define SIZEOF_PARAM_DICT sizeof(struct param_dict)

#define NAL_PIC_PARAM_START_SIZE  20
#define NAL_PIC_PARAM_INCREMENT   20

// ------------------------------------------------------------
// A single NAL unit
struct nal_unit
{
  struct ES_unit  unit;           // The actual data

  // For most purposes, it's simplest to think about the NAL unit's data as
  // being the data *after* the start code prefix. Indeed, that is the way
  // that it is presented in the standard. Thus we provide aliases here, which
  // do so
  // (NB: since these point "into" the .unit structure, they will only be
  // meaningful after we've finished reading in a NAL unit's data - before
  // then they're undefined)
  byte     *data;         // The current NAL unit's data, excluding 00 00 01
  int       data_len;     // And its length/size

  // And for some processing, we need to work with the data after
  // it has had its emulation 3 bytes removed
  byte     *rbsp;         // The data with 00 00 03 bytes "fixed"
  int       rbsp_len;
  bitdata_p bit_data;     // And a view of that as bits
  
  // Information obtained by inspection of the NAL units content
  int                 nal_ref_idc;
  enum NAL_UNIT_TYPE  nal_unit_type;
  int                 starts_picture_decided;
  int                 starts_picture;
  char               *start_reason;  // If it starts a picture, why

  int       decoded;      // Have we "read" the innards of the NAL unit?
  union     nal_innards u;    // Admittedly an unimaginative name, but short
};
typedef struct nal_unit *nal_unit_p;
#define SIZEOF_NAL_UNIT sizeof(struct nal_unit)

// ------------------------------------------------------------
// An expandable list of NAL units
struct nal_unit_list
{
  nal_unit_p *array;   // The current array of nal units */
  int         length;  // How many there are
  int         size;    // How big the array is
};
typedef struct nal_unit_list *nal_unit_list_p;
#define SIZEOF_NAL_UNIT_LIST sizeof(struct nal_unit_list)

#define NAL_UNIT_LIST_START_SIZE  20
#define NAL_UNIT_LIST_INCREMENT   20

// ------------------------------------------------------------
// A context for reading NAL units from an Elementary Stream
struct nal_unit_context
{
  ES_p           es;
  int            count;
  // Sequence and picture parameter set "dictionaries"
  param_dict_p   seq_param_dict;
  param_dict_p   pic_param_dict;

  // Show details of each NAL units content as it is read?
  int            show_nal_details;
};
typedef struct nal_unit_context *nal_unit_context_p;
#define SIZEOF_NAL_UNIT_CONTEXT sizeof(struct nal_unit_context)

#endif // _nalunit_defns

// Local Variables:
// tab-width: 8
// indent-tabs-mode: nil
// c-basic-offset: 2
// End:
// vim: set tabstop=8 shiftwidth=2 expandtab:
