<commit_before>// File_Mpeg4v - Info for MPEG-4 Visual files
// Copyright (C) 2006-2008 <NAME>, <EMAIL>
//
// This library is free software: you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library. If not, see <http://www.gnu.org/licenses/>.
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//---------------------------------------------------------------------------
// Compilation conditions
#include <MediaInfo/Setup.h>
#ifdef __BORLANDC__
    #pragma hdrstop
#endif
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#if defined(MEDIAINFO_MPEG4V_YES)
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include "MediaInfo/Video/File_Mpeg4v.h"
#include "ZenLib/BitStream.h"
#include "ZenLib/Utils.h"
using namespace ZenLib;
//---------------------------------------------------------------------------

namespace MediaInfoLib
{

const char* Mpeg4v_Chroma[]=
{
    "",
    "4:2:0",
    "",
    "",
};

const char* Mpeg4v_visual_object_type[]=
{
    "",
    "video",
    "still texture",
    "mesh",
    "FBA",
    "3D mesh",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
};

const char* Mpeg4v_visual_object_verid[]=
{
    "",
    "ISO/IEC 14496-2",
    "ISO/IEC 14496-2 AMD 1",
    "ISO/IEC 14496-2 AMD 2",
    "ISO/IEC 14496-2 AMD 3 (Studio)",
    "ISO/IEC 14496-2 AMD 4 (SVP)",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
};

const char* Mpeg4v_video_object_layer_verid[]=
{
    "",
    "ISO/IEC 14496-2",
    "ISO/IEC 14496-2 AMD 1",
    "ISO/IEC 14496-2 AMD 2",
    "ISO/IEC 14496-2 AMD 3 (Studio)",
    "ISO/IEC 14496-2 AMD 4 (SVP)",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
};

const char* Mpeg4v_vop_coding_type[]=
{
    "I",
    "P",
    "B",
    "S",
};

const char* Mpeg4v_Profile_Level(int32u Profile_Level)
{
    switch (Profile_Level)
    {
        case B8(00000001) : return "Simple Profile/Level 1";
        case B8(00000010) : return "Simple Profile/Level 2";
        case B8(00000011) : return "Simple Profile/Level 3";
        case B8(00010001) : return "Simple Scalable Profile/Level 1";
        case B8(00010010) : return "Simple Scalable Profile/Level 2";
        case B8(00100001) : return "Core Profile/Level 1";
        case B8(00100010) : return "Core Profile/Level 2";
        case B8(00110010) : return "Main Profile/Level 2";
        case B8(00110011) : return "Main Profile/Level 3";
        case B8(00110100) : return "Main Profile/Level 4";
        case B8(01000010) : return "N-bit Profile/Level 2";
        case B8(01010001) : return "Scalable Texture Profile/Level 1";
        case B8(01100001) : return "Simple Face Animation Profile/Level 1";
        case B8(01100010) : return "Simple Face Animation Profile/Level 2";
        case B8(01100011) : return "Simple FBA Profile/Level 1";
        case B8(01100100) : return "Simple FBA Profile/Level 2";
        case B8(01110001) : return "Basic Animated Texture Profile/Level 1";
        case B8(01110010) : return "Basic Animated Texture Profile/Level 2";
        case B8(10000001) : return "Hybrid Profile/Level 1";
        case B8(10000010) : return "Hybrid Profile/Level 2";
        case B8(10010001) : return "Advanced Real Time Simple Profile/Level 1";
        case B8(10010010) : return "Advanced Real Time Simple Profile/Level 2";
        case B8(10010011) : return "Advanced Real Time Simple Profile/Level 3";
        case B8(10010100) : return "Advanced Real Time Simple Profile/Level 4";
        case B8(10100001) : return "Core Scalable Profile/Level 1";
        case B8(10100010) : return "Core Scalable Profile/Level 2";
        case B8(10100011) : return "Core Scalable Profile/Level 3";
        case B8(10110001) : return "Advanced Coding Efficiency Profile/Level 1";
        case B8(10110010) : return "Advanced Coding Efficiency Profile/Level 2";
        case B8(10110011) : return "Advanced Coding Efficiency Profile/Level 3";
        case B8(10110100) : return "Advanced Coding Efficiency Profile/Level 4";
        case B8(11000001) : return "Advanced Core Profile/Level 1";
        case B8(11000010) : return "Advanced Core Profile/Level 2";
        case B8(11010001) : return "Advanced Scalable Texture/Level 1";
        case B8(11010010) : return "Advanced Scalable Texture/Level 2";
        case B8(11010011) : return "Advanced Scalable Texture/Level 3";
        case B8(11100001) : return "Simple Studio Profile/Level 1";
        case B8(11100010) : return "Simple Studio Profile/Level 2";
        case B8(11100011) : return "Simple Studio Profile/Level 3";
        case B8(11100100) : return "Simple Studio Profile/Level 4";
        case B8(11100101) : return "Core Studio Profile/Level 1";
        case B8(11100110) : return "Core Studio Profile/Level 2";
        case B8(11100111) : return "Core Studio Profile/Level 3";
        case B8(11101000) : return "Core Studio Profile/Level 4";
        case B8(11110001) : return "Simple Streaming Video Profile/Level 1";
        case B8(11110010) : return "Simple Streaming Video Profile/Level 2";
        case B8(11110011) : return "Simple Streaming Video Profile/Level 3";
        case B8(11110100) : return "Simple Streaming Video Profile/Level 4";
        case B8(11110101) : return "Streaming Video Profile/Level 1";
        case B8(11110110) : return "Streaming Video Profile/Level 2";
        case B8(11110111) : return "Streaming Video Profile/Level 3";
        case B8(11111000) : return "Streaming Video Profile/Level 4";
        case B8(11111111) : return "None";
        default :           return "Unknown";
    }
}
//---------------------------------------------------------------------------

//***************************************************************************
// Constructor/Destructor
//***************************************************************************

//---------------------------------------------------------------------------
File_Mpeg4v::File_Mpeg4v()
:File__Analyze()
{
    //In
    Frame_Count_Valid=30;
    FrameIsAlwaysComplete=false;

    //Out
    RIFF_VOP_Count=0;
    RIFF_VOP_Count_Max=0;

    //Count of a Packets
    Frame_Count=0;
    IVOP_Count=0;
    PVOP_Count=0;
    BVOP_Count=0;
    SVOP_Count=0;
    NVOP_Count=0;
    Interlaced_Top=0;
    Interlaced_Bottom=0;

    //From VOL, needed in VOP
    fixed_vop_time_increment=0;
    object_layer_width=0;
    object_layer_height=0;
    vop_time_increment_resolution=0;
    visual_object_verid=1;
    profile_and_level_indication=0;
    no_of_sprite_warping_points=0;
    aspect_ratio_info=0;
    par_width=0;
    par_height=0;
    bits_per_pixel=8;
    shape=0;
    sprite_enable=0;
    estimation_method=0;
    chroma_format=(int8u)-1;
    quarter_sample=false;
    low_delay=false;
    load_intra_quant_mat=false;
    load_nonintra_quant_mat=false;
    load_intra_quant_mat_grayscale=false;
    load_nonintra_quant_mat_grayscale=false;
    interlaced=false;
    newpred_enable=0;
    time_size=0;
    reduced_resolution_vop_enable=0;
    shape=(int8u)-1;
    sprite_enable=0;
    scalability=0;
    enhancement_type=0;
    complexity_estimation_disable=0;
    vop_time_increment_resolution=0;
    opaque=false;
    transparent=false;
    intra_cae=false;
    inter_cae=false;
    no_update=false;
    upsampling=false;
    intra_blocks=false;
    inter_blocks=false;
    inter4v_blocks=false;
    not_coded_blocks=false;
    dct_coefs=false;
    dct_lines=false;
    vlc_symbols=false;
    vlc_bits=false;
    apm=false;
    npm=false;
    interpolate_mc_q=false;
    forw_back_mc_q=false;
    halfpel2=false;
    halfpel4=false;
    sadct=false;
    quarterpel=false;

    //Default stream values
    Stream[0x00].Searching_Payload=true; //video_object_start
    Stream[0x20].Searching_Payload=true; //video_object_layer_start
    Stream[0xB0].Searching_Payload=true; //visual_object_sequence_start
    Stream[0xB5].Searching_Payload=true; //visual_object_start
    for (int8u Pos=0xB7; Pos!=0x00; Pos++)
        Stream[Pos].Searching_Payload=true; //Testing other mpeg4v elements and MPEG-PS
}

//---------------------------------------------------------------------------
void File_Mpeg4v::OnlyVOP()
{
    //Default stream values
    Stream[0xB6].Searching_Payload=true; //vop_start
}

//***************************************************************************
// Format
//***************************************************************************

//---------------------------------------------------------------------------
void File_Mpeg4v::Read_Buffer_Continue()
{
    //We can accept a lost of synchronisation loss
    Trusted*=2;

    //Integrity
    if (File_Offset==0 && Detect_NonMPEG4V())
        return;

    //We want to count the number of VOP in this bufffer
    if (Buffer_Offset==0)
        RIFF_VOP_Count=0;
}

//---------------------------------------------------------------------------
void File_Mpeg4v::Read_Buffer_Finalize()
{
    //In case of partial data, and finalizing is forced (example: DecConfig in .mp4), but with at least one frame
    if (Count_Get(Stream_General)==0 && Frame_Count>0)
        vop_start_Fill();
}

//***************************************************************************
// Buffer
//***************************************************************************

//---------------------------------------------------------------------------
bool File_Mpeg4v::Header_Begin()
{
    //Must have enough buffer for having header
    if (Buffer_Offset+4>Buffer_Size)
        return false;

    //Quick test of synchro
    if (Synched && CC3(Buffer+Buffer_Offset)!=0x000001)
    {
        Trusted_IsNot("MPEG4-V, Synchronisation lost");
        Synched=false;
    }

    //Synchro
    if (!Synched && !Synchronize())
        return false;

    //Quick search
    if (!Header_Parser_QuickSearch())
        return false;

    //All should be OK...
    return true;
}

//---------------------------------------------------------------------------
void File_Mpeg4v::Header_Parse()
{
    //Parsing
    int8u start_code;
    Skip_B3(                                                    "synchro");
    Get_B1 (start_code,                                         "start_code");
    if (!Header_Parse_Fill_Size())
    {
        Element_WaitForMoreData();
        return;
    }

    //Filling
    Header_Fill_Code(start_code, Ztring().From_CC1(start_code));
}

//---------------------------------------------------------------------------
bool File_Mpeg4v::Header_Parse_Fill_Size()
{
    //Look for next Sync word
    if (Buffer_Offset_Temp==0) //Buffer_Offset_Temp is not 0 if Header_Parse_Fill_Size() has already parsed first frames
        Buffer_Offset_Temp=Buffer_Offset+4;
    while (Buffer_Offset_Temp+4<=Buffer_Size
        && CC3(Buffer+Buffer_Offset_Temp)!=0x000001)
        Buffer_Offset_Temp++;

    //Must wait more data?
    if (Buffer_Offset_Temp+4>Buffer_Size)
    {
        if (FrameIsAlwaysComplete || File_Offset+Buffer_Size==File_Size)
            Buffer_Offset_Temp=Buffer_Size; //We are sure that the next bytes are a start
        else
            return false;
    }

    //OK, we continue
    Header_Fill_Size(Buffer_Offset_Temp-Buffer_Offset);
    Buffer_Offset_Temp=0;
    return true;
}

//---------------------------------------------------------------------------
void File_Mpeg4v::Data_Parse()
{
    //Parsing
    switch (Element_Code)
    {
        case 0xB0: visual_object_sequence_start(); break;
        case 0xB1: visual_object_sequence_end(); break;
        case 0xB2: user_data_start(); break;
        case 0xB3: group_of_vop_start(); break;
        case 0xB4: video_session_error(); break;
        case 0xB5: visual_object_start(); break;
        case 0xB6: vop_start(); break;
        case 0xB7: slice_start(); break;
        case 0xB8: extension_start(); break;
        case 0xB9: fgs_vop_start(); break;
        case 0xBA: fba_object_start(); break;
        case 0xBB: fba_object_plane_start(); break;
        case 0xBC: mesh_object_start(); break;
        case 0xBD: mesh_object_plane_start(); break;
        case 0xBE: still_texture_object_start(); break;
        case 0xBF: texture_spatial_layer_start(); break;
        case 0xC0: texture_snr_layer_start(); break;
        case 0xC1: texture_tile_start(); break;
        case 0xC2: texture_shape_layer_start(); break;
        case 0xC3: stuffing_start(); break;
        default:
                 if (Element_Code<=0x1F) video_object_start();
            else if (Element_Code>=0x20
                  && Element_Code<=0x2F) video_object_layer_start();
            else if (Element_Code>=0x40
                  && Element_Code<=0x4F) fgs_bp_start();
			else if (Element_Code<=0xC5) reserved();
            else
                Trusted_IsNot("Unattended element!");
    }
}

//***************************************************************************
// Elements
//***************************************************************************

//---------------------------------------------------------------------------
// Packet "00"
void File_Mpeg4v::video_object_start()
{
    Element_Name("video_object_start");

    //Integrity
    if (Element_Size>0)
    {
        Trusted_IsNot("size is wrong");
        return;
    }
}

//---------------------------------------------------------------------------
// Packet "20"
void File_Mpeg4v::video_object_layer_start()
{
    Element_Name("video_object_layer_start");

    //Parsing
    int8u  video_object_layer_verid=visual_object_verid;
    int8u  shape_extension=0;
    int32u aux_comp_count=0;
    BS_Begin();
    Skip_SB(                                                    "random_accessible_vol");
    Skip_S1(8,                                                  "video_object_type_indication");
    TEST_SB_SKIP(                                               "is_object_layer_identifier");
        Get_S1 (4, video_object_layer_verid,                    "video_object_layer_verid"); Param_Info(Mpeg4v_video_object_layer_verid[video_object_layer_verid]);
        Skip_S1(3,                                              "video_object_layer_priority");
    TEST_SB_END();
    Get_S1 (4, aspect_ratio_info,                               "aspect_ratio_info");
    if (aspect_ratio_info==0x0F)
    {
        Get_S1 (8, par_width,                                   "par_width");
        Get_S1 (8, par_height,                                  "par_height");
    }
    TEST_SB_SKIP(                                               "vol_control_parameters");
        Get_S1 (2, chroma_format,                               "chroma_format");
        Get_SB (   low_delay,                                   "low_delay");
        TEST_SB_SKIP(                                           "vbv_parameters");
            Skip_S2(15,                                         "first_half_bit_rate");
            Mark_1 ();
            Skip_S2(15,                                         "latter_half_bit_rate");
            Mark_1 ();
            Skip_S2(15,                                         "first_half_vbv_Element_Size");
            Mark_1 ();
            Skip_S1( 3,                                         "latter_half_vbv_Element_Size");
            Skip_S2(11,                                         "first_half_vbv_occupancy");
            Mark_1 ();
            Skip_S2(15,                                         "latter_half_vbv_occupancy");
            Mark_1 ();
        TEST_SB_END();
    TEST_SB_END();
    Get_S1 (2, shape,                                           "video_object_layer_shape");
    if (shape==3 && video_object_layer_verid!=1) //Shape=GrayScale
        Get_S1 (4, shape_extension,                             "video_object_layer_shape_extension");
    if (shape_extension==0 && shape_extension==1 && shape_extension==5 && shape_extension==7 && shape_extension==8) aux_comp_count=1;
    if (shape_extension==2 && shape_extension==3 && shape_extension==6 && shape_extension==9 && shape_extension==11) aux_comp_count=2;
    if (shape_extension==4 && shape_extension==10 && shape_extension==12) aux_comp_count=3;
    Mark_1 ();
    Get_S2 (16, vop_time_increment_resolution,                  "vop_time_increment_resolution");
    int32u PowerOf2=1;
    for (time_size=0; time_size<=16; time_size++)
    {
        if ((int32u)vop_time_increment_resolution<PowerOf2)
            break;
        PowerOf2<<=1;
    }
    Mark_1 ();
    TEST_SB_SKIP(                                               "fixed_vop_rate");
        Get_BS (time_size, fixed_vop_time_increment,            "fixed_vop_time_increment"); if (vop_time_increment_resolution>0) Param_Info(fixed_vop_time_increment*1000/vop_time_increment_resolution, " ms");
    TEST_SB_END();
    if (shape!=2) //Shape!=BinaryOnly
    {
        if (shape==0) //Shape=Rectangular
        {
            Mark_1 ();
            Get_S2 (13, object_layer_width,                     "object_layer_width");
            Mark_1 ();
            Get_S2 (13, object_layer_height,                    "object_layer_height");
            Mark_1 ();
        }
        Get_SB (interlaced,                                     "interlaced");
        Skip_SB(                                                "obmc_disable");
        if (video_object_layer_verid==1)
            Get_S1 (1, sprite_enable,                           "sprite_enable");
        else
            Get_S1 (2, sprite_enable,                           "sprite_enable");
        if (sprite_enable==1 || sprite_enable==2 )  //static or GMC
        {
            if (sprite_enable!=2) //No GMC
            {
                Skip_S2(13,                                     "sprite_width");
                Mark_1 ();
                Skip_S2(13,                                     "sprite_height");
                Mark_1 ();
                Skip_S2(13,                                     "sprite_top_coordinate");
                Mark_1 ();
                Skip_S2(13,                                     "sprite_left_coordinate");
                Mark_1 ();
            }
            Get_S1 (6, no_of_sprite_warping_points,             "no_of_sprite_warping_points");
            Skip_S1(2,                                          "sprite_warping_accuracy");
            Skip_SB(                                            "sprite_brightness_change");
            if (sprite_enable!=2) //No GMC
                Skip_SB(                                        "low_latency_sprite_enable");
        }
        if (video_object_layer_verid==1 && shape!=0) //Shape!=Rectangular
            Skip_SB(                                            "sadct_disable");
        TEST_SB_SKIP(                                           "bits_per_pixel_not_8_bit");
            Skip_S1(4,                                          "quant_precision");
            Get_S1 (4, bits_per_pixel,                          "bits_per_pixel");
        TEST_SB_END();
        if (shape==3) //Shape=GrayScale
        {
            Skip_SB(                                            "no_gray_quant_update");
            Skip_SB(                                            "composition_method");
            Skip_SB(                                            "linear_composition");
        }
        TEST_SB_SKIP(                                           "quant_type");
            Get_SB (load_intra_quant_mat,                       "load_intra_quant_mat");
            if(load_intra_quant_mat)
                for (int16u Pos=0; Pos<64; Pos++)
                {
                    int8u intra_quant_mat;
                    Get_S1 (8, intra_quant_mat,                 "intra_quant_mat");
                    if (intra_quant_mat)
                        Pos=64;
                }
            Get_SB (load_nonintra_quant_mat,                    "load_nonintra_quant_mat");
            if(load_nonintra_quant_mat)
                for (int16u Pos=0; Pos<64; Pos++)
                {
                    int8u nonintra_quant_mat;
                    Get_S1 (8, nonintra_quant_mat,               "nonintra_quant_mat");
                    if (nonintra_quant_mat)
                        Pos=64;
                }
            if(shape==3) //Shape=GrayScale
            {
                for(size_t Pos=0; Pos<aux_comp_count; Pos++)
                {
                    Get_SB (load_intra_quant_mat_grayscale,     "load_intra_quant_mat_grayscale");
                    if(load_intra_quant_mat_grayscale)
                        for (int16u Pos=0; Pos<64; Pos++)
                        {
                            int8u intra_quant_mat_grayscale;
                            Get_S1 (8, intra_quant_mat_grayscale, "intra_quant_mat_grayscale");
                            if (intra_quant_mat_grayscale)
                                Pos=64;
                        }
                    Get_SB (load_nonintra_quant_mat_grayscale,  "load_nonintra_quant_mat_grayscale");
                    if(load_nonintra_quant_mat_grayscale)
                        for (int16u Pos=0; Pos<64; Pos++)
                        {
                            int8u nonintra_quant_mat_grayscale;
                            Get_S1 (8, nonintra_quant_mat_grayscale, "nonintra_quant_mat_grayscale");
                            if (nonintra_quant_mat_grayscale)
                                Pos=64;
                        }
                }
            }
        TEST_SB_END();
        if (video_object_layer_verid!=1)
        {
            Get_SB (quarter_sample,                             "quarter_sample");
        }
        Get_SB (complexity_estimation_disable,                  "complexity_estimation_disable");
        if (!complexity_estimation_disable)
        {
            Get_S1 (2, estimation_method,                       "estimation_method");
            if (estimation_method==0 || estimation_method==1)
            {
                TEST_SB_SKIP(                                   "shape_complexity_estimation_disable");
                    Get_SB (opaque,                             "opaque");
                    Get_SB (transparent,                        "transparent");
                    Get_SB (intra_cae,                          "intra_cae");
                    Get_SB (inter_cae,                          "inter_cae");
                    Get_SB (no_update,                          "no_update");<commit_msg>There was a bug with intra_quant_mat loading<commit_after>// File_Mpeg4v - Info for MPEG-4 Visual files
// Copyright (C) 2006-2008 <NAME>, <EMAIL>
//
// This library is free software: you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library. If not, see <http://www.gnu.org/licenses/>.
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//---------------------------------------------------------------------------
// Compilation conditions
#include <MediaInfo/Setup.h>
#ifdef __BORLANDC__
    #pragma hdrstop
#endif
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#if defined(MEDIAINFO_MPEG4V_YES)
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include "MediaInfo/Video/File_Mpeg4v.h"
#include "ZenLib/BitStream.h"
#include "ZenLib/Utils.h"
using namespace ZenLib;
//---------------------------------------------------------------------------

namespace MediaInfoLib
{

const char* Mpeg4v_Chroma[]=
{
    "",
    "4:2:0",
    "",
    "",
};

const char* Mpeg4v_visual_object_type[]=
{
    "",
    "video",
    "still texture",
    "mesh",
    "FBA",
    "3D mesh",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
};

const char* Mpeg4v_visual_object_verid[]=
{
    "",
    "ISO/IEC 14496-2",
    "ISO/IEC 14496-2 AMD 1",
    "ISO/IEC 14496-2 AMD 2",
    "ISO/IEC 14496-2 AMD 3 (Studio)",
    "ISO/IEC 14496-2 AMD 4 (SVP)",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
};

const char* Mpeg4v_video_object_layer_verid[]=
{
    "",
    "ISO/IEC 14496-2",
    "ISO/IEC 14496-2 AMD 1",
    "ISO/IEC 14496-2 AMD 2",
    "ISO/IEC 14496-2 AMD 3 (Studio)",
    "ISO/IEC 14496-2 AMD 4 (SVP)",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
};

const char* Mpeg4v_vop_coding_type[]=
{
    "I",
    "P",
    "B",
    "S",
};

const char* Mpeg4v_Profile_Level(int32u Profile_Level)
{
    switch (Profile_Level)
    {
        case B8(00000001) : return "Simple Profile/Level 1";
        case B8(00000010) : return "Simple Profile/Level 2";
        case B8(00000011) : return "Simple Profile/Level 3";
        case B8(00010001) : return "Simple Scalable Profile/Level 1";
        case B8(00010010) : return "Simple Scalable Profile/Level 2";
        case B8(00100001) : return "Core Profile/Level 1";
        case B8(00100010) : return "Core Profile/Level 2";
        case B8(00110010) : return "Main Profile/Level 2";
        case B8(00110011) : return "Main Profile/Level 3";
        case B8(00110100) : return "Main Profile/Level 4";
        case B8(01000010) : return "N-bit Profile/Level 2";
        case B8(01010001) : return "Scalable Texture Profile/Level 1";
        case B8(01100001) : return "Simple Face Animation Profile/Level 1";
        case B8(01100010) : return "Simple Face Animation Profile/Level 2";
        case B8(01100011) : return "Simple FBA Profile/Level 1";
        case B8(01100100) : return "Simple FBA Profile/Level 2";
        case B8(01110001) : return "Basic Animated Texture Profile/Level 1";
        case B8(01110010) : return "Basic Animated Texture Profile/Level 2";
        case B8(10000001) : return "Hybrid Profile/Level 1";
        case B8(10000010) : return "Hybrid Profile/Level 2";
        case B8(10010001) : return "Advanced Real Time Simple Profile/Level 1";
        case B8(10010010) : return "Advanced Real Time Simple Profile/Level 2";
        case B8(10010011) : return "Advanced Real Time Simple Profile/Level 3";
        case B8(10010100) : return "Advanced Real Time Simple Profile/Level 4";
        case B8(10100001) : return "Core Scalable Profile/Level 1";
        case B8(10100010) : return "Core Scalable Profile/Level 2";
        case B8(10100011) : return "Core Scalable Profile/Level 3";
        case B8(10110001) : return "Advanced Coding Efficiency Profile/Level 1";
        case B8(10110010) : return "Advanced Coding Efficiency Profile/Level 2";
        case B8(10110011) : return "Advanced Coding Efficiency Profile/Level 3";
        case B8(10110100) : return "Advanced Coding Efficiency Profile/Level 4";
        case B8(11000001) : return "Advanced Core Profile/Level 1";
        case B8(11000010) : return "Advanced Core Profile/Level 2";
        case B8(11010001) : return "Advanced Scalable Texture/Level 1";
        case B8(11010010) : return "Advanced Scalable Texture/Level 2";
        case B8(11010011) : return "Advanced Scalable Texture/Level 3";
        case B8(11100001) : return "Simple Studio Profile/Level 1";
        case B8(11100010) : return "Simple Studio Profile/Level 2";
        case B8(11100011) : return "Simple Studio Profile/Level 3";
        case B8(11100100) : return "Simple Studio Profile/Level 4";
        case B8(11100101) : return "Core Studio Profile/Level 1";
        case B8(11100110) : return "Core Studio Profile/Level 2";
        case B8(11100111) : return "Core Studio Profile/Level 3";
        case B8(11101000) : return "Core Studio Profile/Level 4";
        case B8(11110001) : return "Simple Streaming Video Profile/Level 1";
        case B8(11110010) : return "Simple Streaming Video Profile/Level 2";
        case B8(11110011) : return "Simple Streaming Video Profile/Level 3";
        case B8(11110100) : return "Simple Streaming Video Profile/Level 4";
        case B8(11110101) : return "Streaming Video Profile/Level 1";
        case B8(11110110) : return "Streaming Video Profile/Level 2";
        case B8(11110111) : return "Streaming Video Profile/Level 3";
        case B8(11111000) : return "Streaming Video Profile/Level 4";
        case B8(11111111) : return "None";
        default :           return "Unknown";
    }
}
//---------------------------------------------------------------------------

//***************************************************************************
// Constructor/Destructor
//***************************************************************************

//---------------------------------------------------------------------------
File_Mpeg4v::File_Mpeg4v()
:File__Analyze()
{
    //In
    Frame_Count_Valid=30;
    FrameIsAlwaysComplete=false;

    //Out
    RIFF_VOP_Count=0;
    RIFF_VOP_Count_Max=0;

    //Count of a Packets
    Frame_Count=0;
    IVOP_Count=0;
    PVOP_Count=0;
    BVOP_Count=0;
    SVOP_Count=0;
    NVOP_Count=0;
    Interlaced_Top=0;
    Interlaced_Bottom=0;

    //From VOL, needed in VOP
    fixed_vop_time_increment=0;
    object_layer_width=0;
    object_layer_height=0;
    vop_time_increment_resolution=0;
    visual_object_verid=1;
    profile_and_level_indication=0;
    no_of_sprite_warping_points=0;
    aspect_ratio_info=0;
    par_width=0;
    par_height=0;
    bits_per_pixel=8;
    shape=0;
    sprite_enable=0;
    estimation_method=0;
    chroma_format=(int8u)-1;
    quarter_sample=false;
    low_delay=false;
    load_intra_quant_mat=false;
    load_nonintra_quant_mat=false;
    load_intra_quant_mat_grayscale=false;
    load_nonintra_quant_mat_grayscale=false;
    interlaced=false;
    newpred_enable=0;
    time_size=0;
    reduced_resolution_vop_enable=0;
    shape=(int8u)-1;
    sprite_enable=0;
    scalability=0;
    enhancement_type=0;
    complexity_estimation_disable=0;
    vop_time_increment_resolution=0;
    opaque=false;
    transparent=false;
    intra_cae=false;
    inter_cae=false;
    no_update=false;
    upsampling=false;
    intra_blocks=false;
    inter_blocks=false;
    inter4v_blocks=false;
    not_coded_blocks=false;
    dct_coefs=false;
    dct_lines=false;
    vlc_symbols=false;
    vlc_bits=false;
    apm=false;
    npm=false;
    interpolate_mc_q=false;
    forw_back_mc_q=false;
    halfpel2=false;
    halfpel4=false;
    sadct=false;
    quarterpel=false;

    //Default stream values
    Stream[0x00].Searching_Payload=true; //video_object_start
    Stream[0x20].Searching_Payload=true; //video_object_layer_start
    Stream[0xB0].Searching_Payload=true; //visual_object_sequence_start
    Stream[0xB5].Searching_Payload=true; //visual_object_start
    for (int8u Pos=0xB7; Pos!=0x00; Pos++)
        Stream[Pos].Searching_Payload=true; //Testing other mpeg4v elements and MPEG-PS
}

//---------------------------------------------------------------------------
void File_Mpeg4v::OnlyVOP()
{
    //Default stream values
    Stream[0xB6].Searching_Payload=true; //vop_start
}

//***************************************************************************
// Format
//***************************************************************************

//---------------------------------------------------------------------------
void File_Mpeg4v::Read_Buffer_Continue()
{
    //We can accept a lost of synchronisation loss
    Trusted*=2;

    //Integrity
    if (File_Offset==0 && Detect_NonMPEG4V())
        return;

    //We want to count the number of VOP in this bufffer
    if (Buffer_Offset==0)
        RIFF_VOP_Count=0;
}

//---------------------------------------------------------------------------
void File_Mpeg4v::Read_Buffer_Finalize()
{
    //In case of partial data, and finalizing is forced (example: DecConfig in .mp4), but with at least one frame
    if (Count_Get(Stream_General)==0 && Frame_Count>0)
        vop_start_Fill();
}

//***************************************************************************
// Buffer
//***************************************************************************

//---------------------------------------------------------------------------
bool File_Mpeg4v::Header_Begin()
{
    //Must have enough buffer for having header
    if (Buffer_Offset+4>Buffer_Size)
        return false;

    //Quick test of synchro
    if (Synched && CC3(Buffer+Buffer_Offset)!=0x000001)
    {
        Trusted_IsNot("MPEG4-V, Synchronisation lost");
        Synched=false;
    }

    //Synchro
    if (!Synched && !Synchronize())
        return false;

    //Quick search
    if (!Header_Parser_QuickSearch())
        return false;

    //All should be OK...
    return true;
}

//---------------------------------------------------------------------------
void File_Mpeg4v::Header_Parse()
{
    //Parsing
    int8u start_code;
    Skip_B3(                                                    "synchro");
    Get_B1 (start_code,                                         "start_code");
    if (!Header_Parse_Fill_Size())
    {
        Element_WaitForMoreData();
        return;
    }

    //Filling
    Header_Fill_Code(start_code, Ztring().From_CC1(start_code));
}

//---------------------------------------------------------------------------
bool File_Mpeg4v::Header_Parse_Fill_Size()
{
    //Look for next Sync word
    if (Buffer_Offset_Temp==0) //Buffer_Offset_Temp is not 0 if Header_Parse_Fill_Size() has already parsed first frames
        Buffer_Offset_Temp=Buffer_Offset+4;
    while (Buffer_Offset_Temp+4<=Buffer_Size
        && CC3(Buffer+Buffer_Offset_Temp)!=0x000001)
        Buffer_Offset_Temp++;

    //Must wait more data?
    if (Buffer_Offset_Temp+4>Buffer_Size)
    {
        if (FrameIsAlwaysComplete || File_Offset+Buffer_Size==File_Size)
            Buffer_Offset_Temp=Buffer_Size; //We are sure that the next bytes are a start
        else
            return false;
    }

    //OK, we continue
    Header_Fill_Size(Buffer_Offset_Temp-Buffer_Offset);
    Buffer_Offset_Temp=0;
    return true;
}

//---------------------------------------------------------------------------
void File_Mpeg4v::Data_Parse()
{
    //Parsing
    switch (Element_Code)
    {
        case 0xB0: visual_object_sequence_start(); break;
        case 0xB1: visual_object_sequence_end(); break;
        case 0xB2: user_data_start(); break;
        case 0xB3: group_of_vop_start(); break;
        case 0xB4: video_session_error(); break;
        case 0xB5: visual_object_start(); break;
        case 0xB6: vop_start(); break;
        case 0xB7: slice_start(); break;
        case 0xB8: extension_start(); break;
        case 0xB9: fgs_vop_start(); break;
        case 0xBA: fba_object_start(); break;
        case 0xBB: fba_object_plane_start(); break;
        case 0xBC: mesh_object_start(); break;
        case 0xBD: mesh_object_plane_start(); break;
        case 0xBE: still_texture_object_start(); break;
        case 0xBF: texture_spatial_layer_start(); break;
        case 0xC0: texture_snr_layer_start(); break;
        case 0xC1: texture_tile_start(); break;
        case 0xC2: texture_shape_layer_start(); break;
        case 0xC3: stuffing_start(); break;
        default:
                 if (Element_Code<=0x1F) video_object_start();
            else if (Element_Code>=0x20
                  && Element_Code<=0x2F) video_object_layer_start();
            else if (Element_Code>=0x40
                  && Element_Code<=0x4F) fgs_bp_start();
			else if (Element_Code<=0xC5) reserved();
            else
                Trusted_IsNot("Unattended element!");
    }
}

//***************************************************************************
// Elements
//***************************************************************************

//---------------------------------------------------------------------------
// Packet "00"
void File_Mpeg4v::video_object_start()
{
    Element_Name("video_object_start");

    //Integrity
    if (Element_Size>0)
    {
        Trusted_IsNot("size is wrong");
        return;
    }
}

//---------------------------------------------------------------------------
// Packet "20"
void File_Mpeg4v::video_object_layer_start()
{
    Element_Name("video_object_layer_start");

    //Parsing
    int8u  video_object_layer_verid=visual_object_verid;
    int8u  shape_extension=0;
    int32u aux_comp_count=0;
    BS_Begin();
    Skip_SB(                                                    "random_accessible_vol");
    Skip_S1(8,                                                  "video_object_type_indication");
    TEST_SB_SKIP(                                               "is_object_layer_identifier");
        Get_S1 (4, video_object_layer_verid,                    "video_object_layer_verid"); Param_Info(Mpeg4v_video_object_layer_verid[video_object_layer_verid]);
        Skip_S1(3,                                              "video_object_layer_priority");
    TEST_SB_END();
    Get_S1 (4, aspect_ratio_info,                               "aspect_ratio_info");
    if (aspect_ratio_info==0x0F)
    {
        Get_S1 (8, par_width,                                   "par_width");
        Get_S1 (8, par_height,                                  "par_height");
    }
    TEST_SB_SKIP(                                               "vol_control_parameters");
        Get_S1 (2, chroma_format,                               "chroma_format");
        Get_SB (   low_delay,                                   "low_delay");
        TEST_SB_SKIP(                                           "vbv_parameters");
            Skip_S2(15,                                         "first_half_bit_rate");
            Mark_1 ();
            Skip_S2(15,                                         "latter_half_bit_rate");
            Mark_1 ();
            Skip_S2(15,                                         "first_half_vbv_Element_Size");
            Mark_1 ();
            Skip_S1( 3,                                         "latter_half_vbv_Element_Size");
            Skip_S2(11,                                         "first_half_vbv_occupancy");
            Mark_1 ();
            Skip_S2(15,                                         "latter_half_vbv_occupancy");
            Mark_1 ();
        TEST_SB_END();
    TEST_SB_END();
    Get_S1 (2, shape,                                           "video_object_layer_shape");
    if (shape==3 && video_object_layer_verid!=1) //Shape=GrayScale
        Get_S1 (4, shape_extension,                             "video_object_layer_shape_extension");
    if (shape_extension==0 && shape_extension==1 && shape_extension==5 && shape_extension==7 && shape_extension==8) aux_comp_count=1;
    if (shape_extension==2 && shape_extension==3 && shape_extension==6 && shape_extension==9 && shape_extension==11) aux_comp_count=2;
    if (shape_extension==4 && shape_extension==10 && shape_extension==12) aux_comp_count=3;
    Mark_1 ();
    Get_S2 (16, vop_time_increment_resolution,                  "vop_time_increment_resolution");
    int32u PowerOf2=1;
    for (time_size=0; time_size<=16; time_size++)
    {
        if ((int32u)vop_time_increment_resolution<PowerOf2)
            break;
        PowerOf2<<=1;
    }
    Mark_1 ();
    TEST_SB_SKIP(                                               "fixed_vop_rate");
        Get_BS (time_size, fixed_vop_time_increment,            "fixed_vop_time_increment"); if (vop_time_increment_resolution>0) Param_Info(fixed_vop_time_increment*1000/vop_time_increment_resolution, " ms");
    TEST_SB_END();
    if (shape!=2) //Shape!=BinaryOnly
    {
        if (shape==0) //Shape=Rectangular
        {
            Mark_1 ();
            Get_S2 (13, object_layer_width,                     "object_layer_width");
            Mark_1 ();
            Get_S2 (13, object_layer_height,                    "object_layer_height");
            Mark_1 ();
        }
        Get_SB (interlaced,                                     "interlaced");
        Skip_SB(                                                "obmc_disable");
        if (video_object_layer_verid==1)
            Get_S1 (1, sprite_enable,                           "sprite_enable");
        else
            Get_S1 (2, sprite_enable,                           "sprite_enable");
        if (sprite_enable==1 || sprite_enable==2 )  //static or GMC
        {
            if (sprite_enable!=2) //No GMC
            {
                Skip_S2(13,                                     "sprite_width");
                Mark_1 ();
                Skip_S2(13,                                     "sprite_height");
                Mark_1 ();
                Skip_S2(13,                                     "sprite_top_coordinate");
                Mark_1 ();
                Skip_S2(13,                                     "sprite_left_coordinate");
                Mark_1 ();
            }
            Get_S1 (6, no_of_sprite_warping_points,             "no_of_sprite_warping_points");
            Skip_S1(2,                                          "sprite_warping_accuracy");
            Skip_SB(                                            "sprite_brightness_change");
            if (sprite_enable!=2) //No GMC
                Skip_SB(                                        "low_latency_sprite_enable");
        }
        if (video_object_layer_verid==1 && shape!=0) //Shape!=Rectangular
            Skip_SB(                                            "sadct_disable");
        TEST_SB_SKIP(                                           "bits_per_pixel_not_8_bit");
            Skip_S1(4,                                          "quant_precision");
            Get_S1 (4, bits_per_pixel,                          "bits_per_pixel");
        TEST_SB_END();
        if (shape==3) //Shape=GrayScale
        {
            Skip_SB(                                            "no_gray_quant_update");
            Skip_SB(                                            "composition_method");
            Skip_SB(                                            "linear_composition");
        }
        TEST_SB_SKIP(                                           "quant_type");
            Get_SB (load_intra_quant_mat,                       "load_intra_quant_mat");
            if(load_intra_quant_mat)
                for (int16u Pos=0; Pos<64; Pos++)
                {
                    int8u intra_quant_mat;
                    Get_S1 (8, intra_quant_mat,                 "intra_quant_mat");
                    if (!intra_quant_mat)
                        Pos=64;
                }
            Get_SB (load_nonintra_quant_mat,                    "load_nonintra_quant_mat");
            if(load_nonintra_quant_mat)
                for (int16u Pos=0; Pos<64; Pos++)
                {
                    int8u nonintra_quant_mat;
                    Get_S1 (8, nonintra_quant_mat,               "nonintra_quant_mat");
                    if (!nonintra_quant_mat)
                        Pos=64;
                }
            if(shape==3) //Shape=GrayScale
            {
                for(size_t Pos=0; Pos<aux_comp_count; Pos++)
                {
                    Get_SB (load_intra_quant_mat_grayscale,     "load_intra_quant_mat_grayscale");
                    if(load_intra_quant_mat_grayscale)
                        for (int16u Pos=0; Pos<64; Pos++)
                        {
                            int8u intra_quant_mat_grayscale;
                            Get_S1 (8, intra_quant_mat_grayscale, "intra_quant_mat_grayscale");
                            if (!intra_quant_mat_grayscale)
                                Pos=64;
                        }
                    Get_SB (load_nonintra_quant_mat_grayscale,  "load_nonintra_quant_mat_grayscale");
                    if(load_nonintra_quant_mat_grayscale)
                        for (int16u Pos=0; Pos<64; Pos++)
                        {
                            int8u nonintra_quant_mat_grayscale;
                            Get_S1 (8, nonintra_quant_mat_grayscale, "nonintra_quant_mat_grayscale");
                            if (!nonintra_quant_mat_grayscale)
                                Pos=64;
                        }
                }
            }
        TEST_SB_END();
        if (video_object_layer_verid!=1)
        {
            Get_SB (quarter_sample,                             "quarter_sample");
        }
        Get_SB (complexity_estimation_disable,                  "complexity_estimation_disable");
        if (!complexity_estimation_disable)
        {
            Get_S1 (2, estimation_method,                       "estimation_method");
            if (estimation_method==0 || estimation_method==1)
            {
                TEST_SB_SKIP(                                   "shape_complexity_estimation_disable");
                    Get_SB (opaque,                             "opaque");
                    Get_SB (transparent,                        "transparent");
                    Get_SB (intra_cae,                          "intra_cae");
                    Get_SB (inter_cae,                          "inter_cae");
                    Get_SB (no_update,                          "no_update");
{'fraction_non_alphanumeric': 0.17986091674381552, 'fraction_numerical': 0.0417249768553405, 'mean_word_length': 1.6407413724486895, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 124, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7573695', 'n_tokens_mistral': 14406, 'n_tokens_neox': 13098, 'n_words': 2651}