// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// A parser for H.264 bitstream. It will determine will kind of Netowrk
// Abstraction Layer Unit (NALU) we have received from the guest.

#pragma once

#include <cstdint>
#include <string>

namespace android {
namespace emulation {

// All H.264 frames are structured in the following way:
//
// ===============================================================================
// | start code header | forbidden zero bit | nal_ref_idc | nal_unit_type | data |
// | 3 or 4 bytes      | 1 bit              | 2 bits      | 5 bits        | any  |
// ===============================================================================
//
// - Start code header:
//
//   Can be either 0x00 00 01 or 0x00 00 00 01. The start code header indicates where
//   each Network Abstraction Layer Unit (NALU) begins, since this is a continuous
//   stream of data.
//
// - forbidden zero bit:
//
//   Used as an error-indicator. 0 means the transmission is normal, while 1 means there
//   is a syntax violation.
//
// - nal_ref_idc:
//
//   Indicates whether the NALU is a reference field, frame or picture.
//
// - nal_unit_type:
//
//   The type of data contained in the frame. See H264NaluType below for a list of the types.
//

class H264NaluParser {
public:
enum class H264NaluType : uint8_t {
    Unspecified0 = 0,
    CodedSliceNonIDR = 1,
    CodedSlicePartitionA = 2,
    CodedSlicePartitionB = 3,
    CodedSlicePartitionC = 4,
    CodedSliceIDR = 5,
    SEI = 6,
    SPS = 7,
    PPS = 8,
    AccessUnitDelimiter = 9,
    EndOfSequence = 10,
    EndOfStream = 11,
    FillerData = 12,
    SPSExtension = 13,
    PrefixNALU = 14,
    SPSSubset = 15,
    Reserved0 = 16,
    Reserved1 = 17,
    Reserved2 = 18,
    CodedSliceAuxiliary = 19,
    CodedSliceExtension = 20,
    CodedSliceExtDepthComponents = 21,
    Reserved3 = 22,
    Reserved4 = 23,
    STAP_A = 24,
    STAP_B = 25,
    MTAP16 = 26,
    MTAP24 = 27,
    FU_A = 28,
    FU_B = 29,
    Unspecified1 = 30,
    Unspecified2 = 31,
    Undefined = 32, // not in H.264 nalu type; just here to cap the enums so checking is simpler.
};

static bool checkSpsFrame(const uint8_t* frame, size_t szBytes);
static bool checkPpsFrame(const uint8_t* frame, size_t szBytes);
static bool checkIFrame(const uint8_t* frame, size_t szBytes);
// Returns the description of the H264NaluType.
static const std::string& naluTypeToString(H264NaluType n);
// Parses |frame| for the NALU type. |szBytes| is the size of |frame|, |data| will be set to
// the location after the start code header. This means that the first byte of |data| will still
// contain the NALU type in the lower 5-bits.
static H264NaluType getFrameNaluType(const uint8_t* frame, size_t szBytes, uint8_t** data = nullptr);

// Finds the position of the next start code header. Returns null if not found, otherwise returns
// a pointer to the beginning of the next start code header.
static const uint8_t* getNextStartCodeHeader(const uint8_t* frame, size_t szBytes);
};

}  // namespace emulation
}  // namespace android
