/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* Copyright (c) 2011, The WebRTC project authors. All rights reserved.
 * Copyright (c) 2014, Mozilla
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 ** Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *
 ** Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in
 *  the documentation and/or other materials provided with the
 *  distribution.
 *
 ** Neither the name of Google nor the names of its contributors may
 *  be used to endorse or promote products derived from this software
 *  without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef GMP_VIDEO_CODEC_h_
#define GMP_VIDEO_CODEC_h_

#include <stdint.h>
#include <stddef.h>

enum { kGMPPayloadNameSize = 32 };
enum { kGMPMaxSimulcastStreams = 4 };

enum GMPVideoCodecComplexity {
  kGMPComplexityNormal = 0,
  kGMPComplexityHigh = 1,
  kGMPComplexityHigher = 2,
  kGMPComplexityMax = 3,
  kGMPComplexityInvalid  // Should always be last
};

enum GMPVP8ResilienceMode {
  kResilienceOff,     // The stream produced by the encoder requires a
                      // recovery frame (typically a key frame) to be
                      // decodable after a packet loss.
  kResilientStream,   // A stream produced by the encoder is resilient to
                      // packet losses, but packets within a frame subsequent
                      // to a loss can't be decoded.
  kResilientFrames,   // Same as kResilientStream but with added resilience
                      // within a frame.
  kResilienceInvalid  // Should always be last.
};

// VP8 specific
struct GMPVideoCodecVP8 {
  bool mPictureLossIndicationOn;
  bool mFeedbackModeOn;
  GMPVideoCodecComplexity mComplexity;
  GMPVP8ResilienceMode mResilience;
  uint32_t mNumberOfTemporalLayers;
  bool mDenoisingOn;
  bool mErrorConcealmentOn;
  bool mAutomaticResizeOn;
};

// H264 specific

// Needs to match a binary spec for this structure.
// Note: the mSPS at the end of this structure is variable length.
struct GMPVideoCodecH264AVCC {
  uint8_t mVersion;  // == 0x01
  uint8_t mProfile;  // these 3 are profile_level_id
  uint8_t mConstraints;
  uint8_t mLevel;
  uint8_t mLengthSizeMinusOne;  // lower 2 bits (== GMPBufferType-1). Top 6
                                // reserved (1's)

  // SPS/PPS will not generally be present for interactive use unless SDP
  // parameter-sets are used.
  uint8_t mNumSPS;  // lower 5 bits; top 5 reserved (1's)

  /*** uint8_t   mSPS[];  (Not defined due to compiler warnings and
   * warnings-as-errors ...) **/
  // Following mNumSPS is a variable number of bytes, which is the SPS and PPS.
  // Each SPS == 16 bit size, ("N"), then "N" bytes,
  // then uint8_t mNumPPS, then each PPS == 16 bit size ("N"), then "N" bytes.
};

// Codec specific data for H.264 decoding/encoding.
// Cast the "aCodecSpecific" parameter of GMPVideoDecoder::InitDecode() and
// GMPVideoEncoder::InitEncode() to this structure.
struct GMPVideoCodecH264 {
  uint8_t mPacketizationMode;  // 0 or 1
  struct GMPVideoCodecH264AVCC
      mAVCC;  // holds a variable-sized struct GMPVideoCodecH264AVCC mAVCC;
};

enum GMPVideoCodecType {
  kGMPVideoCodecVP8,

  // Encoded frames are in AVCC format; NAL length field of 4 bytes, followed
  // by frame data. May be multiple NALUs per sample. Codec specific extra data
  // is the AVCC extra data (in AVCC format).
  kGMPVideoCodecH264,
  kGMPVideoCodecVP9,
  kGMPVideoCodecInvalid  // Should always be last.
};

// Simulcast is when the same stream is encoded multiple times with different
// settings such as resolution.
struct GMPSimulcastStream {
  uint32_t mWidth;
  uint32_t mHeight;
  uint32_t mNumberOfTemporalLayers;
  uint32_t mMaxBitrate;     // kilobits/sec.
  uint32_t mTargetBitrate;  // kilobits/sec.
  uint32_t mMinBitrate;     // kilobits/sec.
  uint32_t mQPMax;          // minimum quality
};

enum GMPVideoCodecMode {
  kGMPRealtimeVideo,
  kGMPScreensharing,
  kGMPStreamingVideo,
  kGMPNonRealtimeVideo,
  kGMPCodecModeInvalid  // Should always be last.
};

enum GMPLogLevel {
  kGMPLogDefault,
  kGMPLogQuiet,
  kGMPLogError,
  kGMPLogWarning,
  kGMPLogInfo,
  kGMPLogDebug,
  kGMPLogDetail,
  kGMPLogInvalid  // Should always be last.
};

enum GMPProfile {
  kGMPH264ProfileUnknown,
  kGMPH264ProfileBaseline,
  kGMPH264ProfileMain,
  kGMPH264ProfileExtended,
  kGMPH264ProfileHigh,
  kGMPH264ProfileHigh10,
  kGMPH264ProfileHigh422,
  kGMPH264ProfileHigh444,
  kGMPH264ProfileCavlc444,
  kGMPH264ProfileScalableBaseline,
  kGMPH264ProfileScalableHigh
};

enum GMPLevel {
  kGMPH264LevelUnknown,
  kGMPH264Level1_0,
  kGMPH264Level1_B,
  kGMPH264Level1_1,
  kGMPH264Level1_2,
  kGMPH264Level1_3,
  kGMPH264Level2_0,
  kGMPH264Level2_1,
  kGMPH264Level2_2,
  kGMPH264Level3_0,
  kGMPH264Level3_1,
  kGMPH264Level3_2,
  kGMPH264Level4_0,
  kGMPH264Level4_1,
  kGMPH264Level4_2,
  kGMPH264Level5_0,
  kGMPH264Level5_1,
  kGMPH264Level5_2
};

enum GMPRateControlMode {
  kGMPRateControlUnknown,
  kGMPRateControlBitrate,
  kGMPRateControlQuality,
  kGMPRateControlBufferBased,
  kGMPRateControlTimestamp,
  kGMPRateControlBitratePostskip,
  kGMPRateControlOff
};

enum GMPSliceMode {
  kGMPSliceUnknown,
  kGMPSliceSingle,
  kGMPSliceFixedSlcNum,
  kGMPSliceRaster,
  kGMPSliceSizeLimited
};

enum GMPApiVersion {
  kGMPVersion32 =
      1,  // leveraging that V32 had mCodecType first, and only supported H264
  kGMPVersion33 = 33,

  // Adds GMPVideoi420Frame::SetUpdatedTimestamp/UpdatedTimestamp
  kGMPVersion34 = 34,

  // Adds new options for encoding
  kGMPVersion35 = 35,
};

struct GMPVideoCodec {
  uint32_t mGMPApiVersion;

  GMPVideoCodecType mCodecType;
  char mPLName[kGMPPayloadNameSize];  // Must be NULL-terminated!
  uint32_t mPLType;

  uint32_t mWidth;
  uint32_t mHeight;

  uint32_t mStartBitrate;  // kilobits/sec.
  uint32_t mMaxBitrate;    // kilobits/sec.
  uint32_t mMinBitrate;    // kilobits/sec.
  uint32_t mMaxFramerate;

  bool mFrameDroppingOn;
  int32_t mKeyFrameInterval;

  uint32_t mQPMax;
  uint32_t mNumberOfSimulcastStreams;
  GMPSimulcastStream mSimulcastStream[kGMPMaxSimulcastStreams];

  GMPVideoCodecMode mMode;

  // Since GMP version 34
  bool mUseThreadedDecode;
  GMPLogLevel mLogLevel;

  // Since GMP version 35
  GMPLevel mLevel;
  GMPProfile mProfile;
  GMPRateControlMode mRateControlMode;
  GMPSliceMode mSliceMode;
  bool mUseThreadedEncode;
};

// Either single encoded unit, or multiple units separated by 8/16/24/32
// bit lengths, all with the same timestamp.  Note there is no final 0-length
// entry; one should check the overall end-of-buffer against where the next
// length would be.
enum GMPBufferType {
  GMP_BufferSingle = 0,
  GMP_BufferLength8,
  GMP_BufferLength16,
  GMP_BufferLength24,
  GMP_BufferLength32,
  GMP_BufferInvalid,
};

struct GMPCodecSpecificInfoGeneric {
  uint8_t mSimulcastIdx;
};

struct GMPCodecSpecificInfoH264 {
  uint8_t mSimulcastIdx;
};

// Note: if any pointers are added to this struct, it must be fitted
// with a copy-constructor. See below.
struct GMPCodecSpecificInfoVP8 {
  bool mHasReceivedSLI;
  uint8_t mPictureIdSLI;
  bool mHasReceivedRPSI;
  uint64_t mPictureIdRPSI;
  int16_t mPictureId;  // negative value to skip pictureId
  bool mNonReference;
  uint8_t mSimulcastIdx;
  uint8_t mTemporalIdx;
  bool mLayerSync;
  int32_t mTL0PicIdx;  // negative value to skip tl0PicIdx
  int8_t mKeyIdx;      // negative value to skip keyIdx
};

union GMPCodecSpecificInfoUnion {
  GMPCodecSpecificInfoGeneric mGeneric;
  GMPCodecSpecificInfoVP8 mVP8;
  GMPCodecSpecificInfoH264 mH264;
};

// Note: if any pointers are added to this struct or its sub-structs, it
// must be fitted with a copy-constructor. This is because it is copied
// in the copy-constructor of VCMEncodedFrame.
struct GMPCodecSpecificInfo {
  GMPVideoCodecType mCodecType;
  GMPBufferType mBufferType;
  GMPCodecSpecificInfoUnion mCodecSpecific;
};

#endif  // GMP_VIDEO_CODEC_h_