/*  Copyright (c) MediaArea.net SARL. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license that can
 *  be found in the License.html file in the root of the source tree.
 */
 
//---------------------------------------------------------------------------
//
// Source:
// http://wiki.multimedia.cx/index.php?title=YUV4MPEG2
//
//---------------------------------------------------------------------------
 
//---------------------------------------------------------------------------
// Pre-compilation
#include "MediaInfo/PreComp.h"
#ifdef __BORLANDC__
    #pragma hdrstop
#endif
//---------------------------------------------------------------------------
 
//---------------------------------------------------------------------------
#include "MediaInfo/Setup.h"
//---------------------------------------------------------------------------
 
//---------------------------------------------------------------------------
#if defined(MEDIAINFO_Y4M_YES)
//---------------------------------------------------------------------------
 
//---------------------------------------------------------------------------
#include "MediaInfo/Video/File_Y4m.h"
//---------------------------------------------------------------------------
 
//---------------------------------------------------------------------------
namespace MediaInfoLib
{
//---------------------------------------------------------------------------
 
//***************************************************************************
// Infos
//***************************************************************************
 
//***************************************************************************
// Constructor/Destructor
//***************************************************************************
 
//---------------------------------------------------------------------------
File_Y4m::File_Y4m()
:File__Analyze()
{
    //Configuration
    ParserName="YUV4MPEG2";
    #if MEDIAINFO_TRACE
        Trace_Layers_Update(8); //Stream
    #endif //MEDIAINFO_TRACE
    StreamSource=IsStream;
    Frame_Count_NotParsedIncluded=0;
 
    //Temp
    HeaderEnd=0;
}
 
//---------------------------------------------------------------------------
File_Y4m::~File_Y4m()
{
}
 
//***************************************************************************
// Streams management
//***************************************************************************
 
//---------------------------------------------------------------------------
void File_Y4m::Streams_Accept()
{
    Fill(Stream_General, 0, General_Format, "YUV4MPEG2");
 
    Stream_Prepare(Stream_Video);
    Fill(Stream_Video, 0, Video_Format, "YUV");
    Fill(Stream_Video, 0, Video_ColorSpace, "YUV");
}
 
//---------------------------------------------------------------------------
void File_Y4m::Streams_Fill()
{
}
 
//***************************************************************************
// Buffer - File header
//***************************************************************************
 
//---------------------------------------------------------------------------
bool File_Y4m::FileHeader_Begin()
{
    if (Buffer_Size<10)
        return false;
 
    if (!(Buffer[0]==0x59
       && Buffer[1]==0x55
       && Buffer[2]==0x56
       && Buffer[3]==0x34
       && Buffer[4]==0x4D
       && Buffer[5]==0x50
       && Buffer[6]==0x45
       && Buffer[7]==0x47
       && Buffer[8]==0x32
       && Buffer[9]==0x20))
    {
        Reject();
        return false;
    }
 
    for (; HeaderEnd<Buffer_Size; HeaderEnd++)
    {
        if (Buffer[HeaderEnd]==0x0A)
        {
            Accept();
            return true;
        }
    }
 
    return false;
}
 
//---------------------------------------------------------------------------
void File_Y4m::FileHeader_Parse()
{
    //Parsing
    Ztring Header;
    Get_UTF8(HeaderEnd, Header,                                 "Data");
 
    ZtringList List; List.Separator_Set(0, " ");
    List.Write(Header);
    int64u Width=0, Height=0, Multiplier=0, Divisor=1;
    float64 FrameRate=0;
    for (size_t Pos=1; Pos<List.size(); Pos++)
    {
        if (!List[Pos].empty())
        {
            switch (List[Pos][0])
            {
                case 'A' :  //Pixel aspect ratio
                            {
                            ZtringList Value; Value.Separator_Set(0, ":");
                            Value.Write(List[Pos].substr(1));
                            if (Value.size()==2)
                            {
                                float64 x=Value[0].To_float64();
                                float64 y=Value[1].To_float64();
                                if (x && y)
                                    Fill(Stream_Video, 0, Video_PixelAspectRatio, x/y, 3);
                            }
                            }
                            break;
                case 'C' :  //Color space
                            if (List[Pos]==__T("C420jpeg") || List[Pos]==__T("C420paldv") || List[Pos]==__T("C420"))
                            {
                                Fill(Stream_Video, 0, Video_ChromaSubsampling, "4:2:0");
                                Multiplier=3;
                                Divisor=2;
                            }
                            if (List[Pos]==__T("C422"))
                            {
                                Fill(Stream_Video, 0, Video_ChromaSubsampling, "4:2:2");
                                Multiplier=2;
                            }
                            if (List[Pos]==__T("C444"))
                            {
                                Fill(Stream_Video, 0, Video_ChromaSubsampling, "4:4:4");
                                Multiplier=3;
                            }
                            break;
                case 'F' :  //Frame rate
                            {
                            ZtringList Value; Value.Separator_Set(0, ":");
                            Value.Write(List[Pos].substr(1));
                            if (Value.size()==2)
                            {
                                float64 N=Value[0].To_float64();
                                float64 D=Value[1].To_float64();
                                if (N && D)
                                {
                                    FrameRate=N/D;
                                    Fill(Stream_Video, 0, Video_FrameRate, FrameRate, 3);
                                }
                            }
                            }
                            break;
                case 'H' :  //Height
                            {
                            Ztring Value=List[Pos].substr(1);
                            Height=Value.To_int64u();
                            Fill(Stream_Video, 0, Video_Height, Height);
                            }
                            break;
                case 'I' :  //Interlacing
                            if (List[Pos].size()==2)
                                switch (List[Pos][1])
                                {
                                    case 'p' : Fill(Stream_Video, 0, Video_ScanType, "Progressive"); break;
                                    case 't' : Fill(Stream_Video, 0, Video_ScanType, "Progressive"); Fill(Stream_Video, 0, Video_ScanOrder, "TFF"); break;
                                    case 'b' : Fill(Stream_Video, 0, Video_ScanType, "Progressive"); Fill(Stream_Video, 0, Video_ScanOrder, "BFF"); break;
                                    case 'm' : Fill(Stream_Video, 0, Video_ScanType, "Mixed"); break;
                                    default  : ;
                                }
                            break;
                case 'W' :  //Width
                            {
                            Ztring Value=List[Pos].substr(1);
                            Width=Value.To_int64u();
                            Fill(Stream_Video, 0, Video_Width, Width);
                            }
                            break;
                default  : ;
            }
        }
    }
 
    //Duration (we expect no meta per frame)
    if (Width && Height && Multiplier)
    {
        int64u Frame_ByteSize=6+Width*Height*Multiplier/Divisor; //5 for "FRAME\0"
        Fill(Stream_Video, 0, Video_FrameCount, File_Size/Frame_ByteSize);
        if (FrameRate)
            Fill(Stream_Video, 0, Video_BitRate, Width*Height*Multiplier/Divisor*8*FrameRate);
    }
 
    Finish();
}
 
} //NameSpace
 
#endif //MEDIAINFO_Y4M_YES

V550 An odd precise comparison. It's probably better to use a comparison with defined precision: fabs(FrameRate) > Epsilon.