/*
 * Prototypes 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_fns
#define _nalunit_fns

#include "nalunit_defns.h"

/*
 * Request details of the NAL unit contents as they are read
 */
extern void set_show_nal_reading_details(nal_unit_context_p  context,
                                         int                 show);

/*
 * Build a new NAL unit context, for reading NAL units from an ES.
 *
 * Returns 0 if it succeeds, 1 if some error occurs.
 */
extern int build_nal_unit_context(ES_p                es,
                                  nal_unit_context_p *context);
/*
 * Free a NAL unit context datastructure.
 *
 * Clears the datastructure, frees it, and returns `context` as NULL.
 *
 * Does nothing if `context` is already NULL.
 */
extern void free_nal_unit_context(nal_unit_context_p *context);
/*
 * Rewind a file being read as NAL units.
 *
 * A thin jacket for `seek_ES`.
 *
 * Doesn't unset the sequence and picture parameter dictionaries
 * that have been built up when reading the file - this may possibly
 * not be the desired behaviour, but should be OK for well behaved files.
 *
 * Returns 0 if all goes well, 1 if something goes wrong.
 */
extern int rewind_nal_unit_context(nal_unit_context_p  context);
/*
 * Build a new NAL unit datastructure.
 *
 * Returns 0 if it succeeds, 1 if some error occurs.
 */
extern int build_nal_unit(nal_unit_p  *nal);

/*
 * Tidy up and free a NAL unit datastructure after we've finished with it.
 *
 * Empties the NAL unit datastructure, frees it, and sets `nal` to NULL.
 *
 * If `nal` is already NULL, does nothing.
 */
extern void free_nal_unit(nal_unit_p  *nal);

/*
 * Find and read in the next NAL unit.
 *
 * - `context` is the NAL unit context we're reading from
 * - `verbose` is true if a brief report on the NAL unit should be given
 * - `nal` is the datastructure containing the NAL unit found, or NULL
 *   if there was none.
 *
 * Returns:
 * * 0 if it succeeds,
 * * EOF if the end-of-file is read (i.e., there is no next NAL unit),
 * * 2 if the NAL unit data does not make sense, so it should be ignored
 *   (specifically, if the NAL unit's RBSP data cannot be understood),
 * * 1 if some other error occurs.
 */
extern int find_next_NAL_unit(nal_unit_context_p  context,
                              int                 verbose,
                              nal_unit_p         *nal);

/*
 * Write (copy) the current NAL unit to the ES output stream.
 *
 * - `output` is the output stream (file descriptor) to write to
 * - `nal` is the NAL unit to write
 *
 * Returns 0 if all went well, 1 if something went wrong.
 */
extern int write_NAL_unit_as_ES(FILE       *output,
                                nal_unit_p  nal);
/*
 * Write (copy) the current NAL unit to the output stream, wrapped up in a
 * PES within TS.
 *
 * - `output` is the TS writer to write to
 * - `nal` is the NAL unit to write
 * - `video_pid` is the video PID to use
 *
 * Returns 0 if all went well, 1 if something went wrong.
 */
extern int write_NAL_unit_as_TS(TS_writer_p tswriter,
                                nal_unit_p  nal,
                                uint32_t    video_pid);

/*
 * Create a new "dictionary" for remembering picture or sequence
 * parameter sets.
 *
 * Returns 0 if it succeeds, 1 if some error occurs.
 */
extern int build_param_dict(param_dict_p *param_dict);

/*
 * Tidy up and free a parameters "dictionary" datastructure after we've
 * finished with it.
 *
 * Empties the datastructure, frees it, and sets `param_dict` to NULL.
 *
 * Does nothing if `param_dict` is already NULL.
 */
extern void free_param_dict(param_dict_p  *param_dict);

/*
 * Remember parameter set data in a "dictionary".
 *
 * - `param_dict` should be an appropriate "dictionary" - i.e., one
 *   being used to store picture or sequence parameter set data, as
 *   appropriate.
 * - `param_id` is the id for this picture or sequence parameter set.
 * - `nal` is the NAL unit containing the parameter set data.
 *   Note that a copy will be taken of the parameter set data, which
 *   means that the caller may free the NAL unit.
 *
 * Any previous data for this picture or sequence parameter set id will be
 * forgotten (overwritten).
 *
 * Returns 0 if it succeeds, 1 if some error occurs.
 */
extern int remember_param_data(param_dict_p  param_dict,
                               uint32_t      param_id,
                               nal_unit_p    nal);

/*
 * Retrieve the picture parameter set data for the given id.
 *
 * - `pic_param_dict` is a parameter "dictionary" of the appropriate type.
 * - `pic_param_id` is the id to look up.
 * - `pic_param_data` is the data for that id. Do not free this, it refers
 *   into the "dictionary" datastructure.
 *
 * Note that altering the "dictionary" (with `remember_param_data()`) may
 * cause the underlying datastructures to be realloc'ed, which in turn means
 * that the address returned as `pic_param_data` may not be valid after such
 * an action.
 *
 * Returns 0 if it succeeds, 1 if the id is not recognised.
 */
extern int get_pic_param_data(param_dict_p pic_param_dict,
                              uint32_t     pic_param_id,
                              nal_pic_param_data_p *pic_param_data);

/*
 * Retrieve the sequence parameter set data for the given id.
 *
 * - `seq_param_dict` is a parameter "dictionary" of the appropriate type.
 * - `seq_param_id` is the id to look up.
 * - `seq_param_data` is the data for that id. Do not free this, it refers
 *   into the "dictionary" datastructure.
 *
 * Note that altering the "dictionary" (with `remember_param_data()`) may
 * cause the underlying datastructures to be realloc'ed, which in turn means
 * that the address returned as `seq_param_data` may not be valid after such
 * an action.
 *
 * Returns 0 if it succeeds, 1 if the id is not recognised.
 */
extern int get_seq_param_data(param_dict_p seq_param_dict,
                              uint32_t     seq_param_id,
                              nal_seq_param_data_p *seq_param_data);

/*
 * Is this NAL unit a slice?
 *
 * Returns true if its ``nal_unit_type`` is 1 (coded slice of IDR picture)
 * or 5 (coded slice of IDR picture).
 */
extern int nal_is_slice(nal_unit_p  nal);

/*
 * Is this NAL unit a picture parameter set?
 *
 * Returns true if its ``nal_unit_type`` is 8.
 */
extern int nal_is_pic_param_set(nal_unit_p  nal);

/*
 * Is this NAL unit a sequence parameter set?
 *
 * Returns true if its ``nal_unit_type`` is 7.
 */
extern int nal_is_seq_param_set(nal_unit_p  nal);

/*
 * Is this NAL unit marked as part of a redundant picture?
 */
extern int nal_is_redundant(nal_unit_p  nal);

/*
 * Is this VCL NAL unit the first of a new primary coded picture?
 *
 * - `nal` is the NAL unit we need to decide about.
 * - `last` is a slice NAL unit from the last primary coded picture
 *    (likely to be the first NAL unit therefrom, in fact)
 *
 * Both `nal` and `last` must be VCL NALs representing slices of a reference
 * picture - i.e., with nal_unit_type 1 or 5 (if we were supporting type A
 * slice data partitions, we would have to take them into account as well).
 *
 * Both `nal` and `last` must have had their innards decoded with
 * `read_slice_data`, which should have occurred automatically if they are
 * both appropriate NAL units for this process.
 *
 * Acording to H.264 7.4.1.2.4 (from the JVT-J010d7 draft):
 *     
 *   The first NAL unit of a new primary code picture can be detected
 *   because:
 *
 *   - its frame number differs in value from that of the last slice (NB:
 *     IDR pictures always have frame_num == 0)
 *
 *   - its field_pic_flag differs in value (i.e., one is a field slice, and
 *     the other a frame slice)
 *
 *   - the bottom_field_flag is present in both (determined by
 *     frame_mbs_only_flag in the sequence parameter set, and by
 *     field_pic_flag) and differs (i.e., both are field slices, but one
 *     is top and the other bottom) [*]_
 *
 *   - nal_ref_idc differs in value, and one of them has nal_ref_idc == 0
 *     (i.e., one is a reference picture and the other is not)
 *
 *   - pic_order_cnt_type (found in the sequence parameter set) == 0 for
 *     both and either pic_order_cnt_lsb differs in value or
 *     delta_pic_order_cnt_bottom differs in value [*]_
 *
 *   - pic_order_cnt_type == 1 for both and either delta_pic_order_cnt[0]
 *     or delta_pic_order_cnt[1] differs in value [*]_
 *
 *   - nal_unit_type == 5 for one and not in the other (i.e., one is IDR
 *     and the other is not)
 *
 *   - nal_unit_type == 5 for both (i.e., both are IDR), and idr_pic_id
 *     differs (i.e., they're not the same IDR)
 *
 * It is possible that later drafts may alter/augment these criteria -
 * that has already happened between JVT-G050r1 and JVT-J010d7.
 *
 * .. [*] For these three items, we need to have decoded the active
 *    sequence parameter set (which, for now, I'll assume to be the last
 *    set we found with the appropriate id).
 */
extern int nal_is_first_VCL_NAL(nal_unit_p   nal,
                                nal_unit_p   last);


// ------------------------------------------------------------
// Lists of NAL units
//
// This duplicates the functionality provided by ES unit lists
// in es.h, but it works at the higher level of NAL units,
// which is useful if one wants to report on the content of the
// lists *as* NAL units.
// ------------------------------------------------------------
/*
 * Build a new list-of-nal-units datastructure.
 *
 * Returns 0 if it succeeds, 1 if some error occurs.
 */
extern int build_nal_unit_list(nal_unit_list_p  *list);

/*
 * Add a NAL unit to the end of the NAL unit list. Does not take a copy.
 *
 * Returns 0 if it succeeds, 1 if some error occurs.
 */
extern int append_to_nal_unit_list(nal_unit_list_p  list,
                                   nal_unit_p       nal);
/*
 * Reset (empty) a NAL unit list.
 *
 * If `deep` is true, then any NAL units in the list will be freed
 * as well (this will be a Bad Thing if anywhere else is using them).
 */
extern void reset_nal_unit_list(nal_unit_list_p  list,
                                int              deep);

/*
 * Tidy up and free a NAL unit list datastructure after we've finished with it.
 *
 * If `deep` is true, then any NAL units in the list will be freed
 * as well (this will be a Bad Thing if anywhere else is using them).
 *
 * Clears the datastructure, frees it and returns `list` as NULL.
 *
 * Does nothing if `list` is already NULL.
 */
extern void free_nal_unit_list(nal_unit_list_p  *list,
                               int               deep);

/*
 * Report on a NAL unit list's contents, to the given stream.
 */
extern void report_nal_unit_list(int    is_msg,
                                 char  *prefix,
                                 nal_unit_list_p  list);

/*
 * Print out useful information about this NAL unit, on the given stream.
 *
 * This is intended as a single line of information.
 */
extern void report_nal(int         is_msg,
                       nal_unit_p  nal);

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