/* 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. */ //--------------------------------------------------------------------------- // Pre-compilation #include "MediaInfo/PreComp.h" #ifdef __BORLANDC__ #pragma hdrstop #endif //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #include "MediaInfo/Setup.h" //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #if defined(MEDIAINFO_EIA608_YES) //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #include "MediaInfo/Text/File_Eia608.h" #include "MediaInfo/MediaInfo_Config_MediaInfo.h" #if MEDIAINFO_EVENTS #include "MediaInfo/MediaInfo_Config_MediaInfo.h" #include "MediaInfo/MediaInfo_Events_Internal.h" #endif //MEDIAINFO_EVENTS using namespace std; //--------------------------------------------------------------------------- //*************************************************************************** // Constants //*************************************************************************** //--------------------------------------------------------------------------- // CAE-608-E section F.1.1.5 static const int8u Eia608_PAC_Row[]= { 10, 0, //or 1 2, //or 3 11, //or 12 13, //or 14 4, //or 5 6, //or 7 8 //or 9 }; //*************************************************************************** // //*************************************************************************** namespace MediaInfoLib { //*************************************************************************** // Constructor/Destructor //*************************************************************************** //--------------------------------------------------------------------------- File_Eia608::File_Eia608() :File__Analyze() { //Configuration #if MEDIAINFO_EVENTS ParserIDs[0]=MediaInfo_Parser_Eia608; StreamIDs_Width[0]=1; #endif //MEDIAINFO_EVENTS ParserName="EIA-608"; PTS_DTS_Needed=true; //In cc_type=(int8u)-1; #if MEDIAINFO_EVENTS MuxingMode=(int8u)-1; #endif //MEDIAINFO_EVENTS //Temp XDS_Level=(size_t)-1; TextMode=false; DataChannelMode=false; cc_data_1_Old=0x00; cc_data_2_Old=0x00; HasContent=false; HasJumped=false; } //--------------------------------------------------------------------------- File_Eia608::~File_Eia608() { for (size_t Pos=0; PosFile_DisplayCaptions_Get(); if (DisplayCaptions==DisplayCaptions_Stream && Streams.size()<2) Streams.resize(2); if (!HasContent && ServiceDescriptors && ServiceDescriptors->ServiceDescriptors608.find(cc_type)!=ServiceDescriptors->ServiceDescriptors608.end()) { TextMode=0; DataChannelMode=0; Special_14(0x20); //CC1/CC3 fake RCL - Resume Caption Loading } for (size_t Pos=0; PosHasContent(); if (!HasContent && DisplayCaptions==DisplayCaptions_Content) continue; Stream_Prepare(Stream_Text); Fill(Stream_Text, StreamPos_Last, Text_Format, "EIA-608"); Fill(Stream_Text, StreamPos_Last, Text_StreamSize, 0); Fill(Stream_Text, StreamPos_Last, Text_BitRate_Mode, "CBR"); if (cc_type!=(int8u)-1) { string ID=Pos<2?"CC":"T"; ID+='1'+(cc_type*2)+(Pos%2); Fill(Stream_Text, StreamPos_Last, Text_ID, ID); Fill(Stream_Text, StreamPos_Last, "CaptionServiceName", ID); Fill_SetOptions(Stream_Text, StreamPos_Last, "CaptionServiceName", "N NT"); } if (Config->ParseSpeed>=1.0) { Fill(Stream_Text, StreamPos_Last, "CaptionServiceContent_IsPresent", HasContent?"Yes":"No", Unlimited, true, true); Fill_SetOptions(Stream_Text, StreamPos_Last, "CaptionServiceContent_IsPresent", "N NT"); } if (ServiceDescriptors) { servicedescriptors608::iterator ServiceDescriptor=ServiceDescriptors->ServiceDescriptors608.find(cc_type); if (ServiceDescriptor!=ServiceDescriptors->ServiceDescriptors608.end()) { if (Pos==0 && Retrieve(Stream_Text, StreamPos_Last, Text_Language).empty()) //Only CC1/CC3 Fill(Stream_Text, StreamPos_Last, Text_Language, ServiceDescriptor->second.language, true); Fill(Stream_Text, StreamPos_Last, "CaptionServiceDescriptor_IsPresent", "Yes", Unlimited, true, true); Fill_SetOptions(Stream_Text, StreamPos_Last, "CaptionServiceDescriptor_IsPresent", "N NT"); } else //ServiceDescriptors pointer is for the support by the transport layer of the info { Fill(Stream_Text, StreamPos_Last, "CaptionServiceDescriptor_IsPresent", "No", Unlimited, true, true); Fill_SetOptions(Stream_Text, StreamPos_Last, "CaptionServiceDescriptor_IsPresent", "N NT"); } } if (!HasContent) { Fill(Stream_Text, StreamPos_Last, "InternalDetectionKind", HasCommand?"Command":"Stream", Unlimited, true, true); Fill_SetOptions(Stream_Text, StreamPos_Last, "InternalDetectionKind", "N NT"); } } } } //--------------------------------------------------------------------------- static const char* FirstDisplay_Type_Name[]= { "PopOn", "RollUp", "PaintOn", }; void File_Eia608::Streams_Finish() { if (PTS_End>PTS_Begin) Fill(Stream_General, 0, General_Duration, float64_int64s(((float64)(PTS_End-PTS_Begin))/1000000)); auto DisplayCaptions=Config->File_DisplayCaptions_Get(); size_t i=0; for (size_t StreamPos=0; StreamPosDemux_FirstFrameNumber_Get(); if (FrameInfo.DUR==(int64u)-1 && Config->Demux_Rate_Get()) FrameInfo.DUR=float64_int64s(((float64)1000000000)/Config->Demux_Rate_Get()); if (FrameInfo.DTS==(int64u)-1) FrameInfo.DTS=Config->Demux_FirstDts_Get(); #endif //MEDIAINFO_DEMUX #if MEDIAINFO_EVENTS if (MuxingMode==(int8u)-1) { if (StreamIDs_Size>=3 && ParserIDs[StreamIDs_Size-3]==MediaInfo_Parser_Mpegv && StreamIDs[StreamIDs_Size-3]==0x4741393400000003LL) MuxingMode=0; //A/53 / DTVCC Transport if (StreamIDs_Size>=3 && ParserIDs[StreamIDs_Size-3]==MediaInfo_Parser_Mpegv && StreamIDs[StreamIDs_Size-3]==0x0000000300000000LL) MuxingMode=1; //SCTE 20 if (StreamIDs_Size>=3 && ParserIDs[StreamIDs_Size-3]==MediaInfo_Parser_Mpegv && StreamIDs[StreamIDs_Size-3]==0x434301F800000000LL) MuxingMode=2; //DVD-Video if (StreamIDs_Size>=4 && (ParserIDs[StreamIDs_Size-4]==MediaInfo_Parser_Gxf || ParserIDs[StreamIDs_Size-4]==MediaInfo_Parser_Lxf || ParserIDs[StreamIDs_Size-4]==MediaInfo_Parser_Mxf) && ParserIDs[StreamIDs_Size-2]==MediaInfo_Parser_Cdp) MuxingMode=3; //Ancillary data / CDP if (StreamIDs_Size>=3 && ParserIDs[StreamIDs_Size-3]==MediaInfo_Parser_Avc) MuxingMode=4; //SCTE 128 / DTVCC Transport if (StreamIDs_Size>=2 && ParserIDs[StreamIDs_Size-2]==MediaInfo_Parser_DvDif) MuxingMode=5; //DV if (StreamIDs_Size>=3 && ParserIDs[StreamIDs_Size-3]==MediaInfo_Parser_Mpeg4 && ParserIDs[StreamIDs_Size-2]==MediaInfo_Parser_Cdp) MuxingMode=6; //Final Cut / CDP if (StreamIDs_Size>=2 && ParserIDs[StreamIDs_Size-2]==MediaInfo_Parser_Scc) MuxingMode=10; //SCC if (StreamIDs_Size>=3 && ParserIDs[StreamIDs_Size-3]==MediaInfo_Parser_Mpeg4 && ParserIDs[StreamIDs_Size-2]==MediaInfo_Parser_Mpeg4) MuxingMode=14; //Final Cut / cdat } #endif //MEDIAINFO_EVENTS } //--------------------------------------------------------------------------- void File_Eia608::Read_Buffer_AfterParsing() { Frame_Count++; Frame_Count_InThisBlock++; if (Frame_Count_NotParsedIncluded!=(int64u)-1) Frame_Count_NotParsedIncluded++; if (FrameInfo.DUR!=(int64u)-1) { if (FrameInfo.DTS!=(int64u)-1) FrameInfo.DTS+=FrameInfo.DUR; if (FrameInfo.PTS!=(int64u)-1) { FrameInfo.PTS+=FrameInfo.DUR; PTS_End=FrameInfo.PTS; } else PTS_End=0; } else { PTS_End=FrameInfo.PTS!=(int64u)-1?FrameInfo.PTS:0; // Let's keep the last frame PTS if we don't have the duration of the last frame FrameInfo.DTS=(int64u)-1; FrameInfo.PTS=(int64u)-1; } if (Status[IsFilled] && Frame_Count>=1024 && Config->ParseSpeed<1.0) Fill(); } //--------------------------------------------------------------------------- void File_Eia608::Read_Buffer_Continue() { FrameInfo.PTS=FrameInfo.DTS; if (Frame_Count==0) PTS_Begin=FrameInfo.PTS; if (!Status[IsAccepted]) Accept("EIA-608"); while (Element_Offset+1Duration_End_Command_WasJustUpdated && FrameInfo.DTS!=(int64u)-1 && FrameInfo.DUR!=(int64u)-1 ) { Streams[StreamPos]->Duration_End_Command=(FrameInfo.DTS)/1000000.0; Streams[StreamPos]->Duration_End_Command_WasJustUpdated=false; } return; //Nothing to do } else if (cc_type==0) // Field 1 only { //They should be duplicated, there is a problem } cc_data_1_Old=0x00; cc_data_2_Old=0x00; } for (size_t StreamPos=0; StreamPosDuration_End_Command_WasJustUpdated=false; if ((cc_data_1 && cc_data_1<0x10) || (XDS_Level!=(size_t)-1 && cc_data_1>=0x20)) //XDS { XDS(cc_data_1, cc_data_2); } else if (cc_data_1>=0x20) //Basic characters { size_t StreamPos=TextMode*2+DataChannelMode; if (StreamPos>=Streams.size() || Streams[StreamPos]==NULL || !Streams[StreamPos]->Synched) return; //Not synched Standard(cc_data_1); if ((cc_data_2&0x7F)>=0x20) Standard(cc_data_2); } else if (cc_data_1) //Special Special(cc_data_1, cc_data_2); } } //*************************************************************************** // Functions //*************************************************************************** //--------------------------------------------------------------------------- void File_Eia608::XDS(int8u cc_data_1, int8u cc_data_2) { if (cc_data_1 && cc_data_1<0x10 && cc_data_1%2==0) { // Continue cc_data_1--; for (XDS_Level=0; XDS_Level=2 && XDS_Data[XDS_Level][0]==cc_data_1 && XDS_Data[XDS_Level][1]==cc_data_2) break; if (XDS_Level>=XDS_Data.size()) XDS_Level=(size_t)-1; // There is a problem return; } else if (cc_data_1 && cc_data_1<0x0F) { // Start for (XDS_Level=0; XDS_Level=2 && XDS_Data[XDS_Level][0]==cc_data_1 && XDS_Data[XDS_Level][1]==cc_data_2) break; if (XDS_Level>=XDS_Data.size()) { XDS_Level=XDS_Data.size(); XDS_Data.resize(XDS_Level+1); } else XDS_Data[XDS_Level].clear(); // There is a problem, erasing the previous item } if (XDS_Level==(size_t)-1) return; //There is a problem XDS_Data[XDS_Level].push_back(cc_data_1); XDS_Data[XDS_Level].push_back(cc_data_2); if (cc_data_1==0x0F) XDS(); if (XDS_Level!=(size_t)-1 && XDS_Data[XDS_Level].size()>=36) XDS_Data[XDS_Level].clear(); // Clear, this is a security TextMode=0; // This is CC } //--------------------------------------------------------------------------- void File_Eia608::XDS() { if (XDS_Data[XDS_Level].size()<4) { XDS_Data.erase(XDS_Data.begin()+XDS_Level); XDS_Level=(size_t)-1; return; //There is a problem } switch (XDS_Data[XDS_Level][0]) { case 0x01 : XDS_Current(); break; case 0x05 : XDS_Channel(); break; case 0x09 : XDS_PublicService(); break; default : ; } XDS_Data.erase(XDS_Data.begin()+XDS_Level); XDS_Level=(size_t)-1; } //--------------------------------------------------------------------------- void File_Eia608::XDS_Current() { switch (XDS_Data[XDS_Level][1]) { case 0x03 : XDS_Current_ProgramName(); break; case 0x05 : XDS_Current_ContentAdvisory(); break; case 0x08 : XDS_Current_CopyAndRedistributionControlPacket(); break; default : ; } } //--------------------------------------------------------------------------- void File_Eia608::XDS_Current_ContentAdvisory() { if (XDS_Data[XDS_Level].size()!=6) { return; //There is a problem } Clear(Stream_General, 0, General_LawRating); int8u a1a0=(XDS_Data[XDS_Level][2]>>3)&0x3; const char* ContentAdvisory=NULL; string ContentDescriptors; switch (a1a0) { case 0: case 2: switch (XDS_Data[XDS_Level][2]&0x7) //r2r1r0 { case 0 : ContentAdvisory="N/A"; break; case 1 : ContentAdvisory="G"; break; case 2 : ContentAdvisory="PG"; break; case 3 : ContentAdvisory="PG-13"; break; case 4 : ContentAdvisory="R"; break; case 5 : ContentAdvisory="NC-17"; break; case 6 : ContentAdvisory="C"; break; default: ; } break; case 1: switch (XDS_Data[XDS_Level][3]&0x7) //g2g1g0 { case 0 : ContentAdvisory="None"; break; case 1 : ContentAdvisory="TV-Y"; break; case 2 : ContentAdvisory="TV-Y7"; break; case 3 : ContentAdvisory="TV-G"; break; case 4 : ContentAdvisory="TV-PG"; break; case 5 : ContentAdvisory="TV-14"; break; case 6 : ContentAdvisory="TV-MA"; break; case 7 : ContentAdvisory="None"; break; default: ; } if (XDS_Data[XDS_Level][2]&0x20) //Suggestive dialogue ContentDescriptors+='D'; if (XDS_Data[XDS_Level][3]&0x8) //Coarse language ContentDescriptors+='L'; if (XDS_Data[XDS_Level][3]&0x10) //Sexual content ContentDescriptors+='S'; if (XDS_Data[XDS_Level][3]&0x20) //Violence { if ((XDS_Data[XDS_Level][3]&0x7)==2) //"TV-Y7" --> Fantasy Violence ContentDescriptors+="FV"; else ContentDescriptors+='V'; } break; case 3: if (XDS_Data[XDS_Level][3]&0x8) //a3 { ContentAdvisory="(Reserved)"; } else { if (XDS_Data[XDS_Level][2]&0x20) //a2 switch (XDS_Data[XDS_Level][3]&0x7) //g2g1g0 { case 0 : ContentAdvisory="E"; break; case 1 : ContentAdvisory="G"; break; case 2 : ContentAdvisory="8+"; break; case 3 : ContentAdvisory="13+"; break; case 4 : ContentAdvisory="16+"; break; case 5 : ContentAdvisory="18+"; break; default: ; } else switch (XDS_Data[XDS_Level][3]&0x7) //g2g1g0 { case 0 : ContentAdvisory="E"; break; case 1 : ContentAdvisory="C"; break; case 2 : ContentAdvisory="C8+"; break; case 3 : ContentAdvisory="G"; break; case 4 : ContentAdvisory="PG"; break; case 5 : ContentAdvisory="14+"; break; case 6 : ContentAdvisory="18+"; break; default: ; } } break; default: ; } if (ContentAdvisory) { string ContentAdvisory_String=ContentAdvisory; if (!ContentDescriptors.empty()) ContentAdvisory_String+=" ("+ContentDescriptors+')'; Fill(Stream_General, 0, General_LawRating, ContentAdvisory_String.c_str()); } } //--------------------------------------------------------------------------- void File_Eia608::XDS_Current_ProgramName() { string ValueS; for (size_t Pos=2; Pos' ); break; case 0x3F : Character_Fill(L'?' ); break; case 0x40 : Character_Fill(L'@' ); break; case 0x41 : Character_Fill(L'A' ); break; case 0x42 : Character_Fill(L'B' ); break; case 0x43 : Character_Fill(L'C' ); break; case 0x44 : Character_Fill(L'D' ); break; case 0x45 : Character_Fill(L'E' ); break; case 0x46 : Character_Fill(L'F' ); break; case 0x47 : Character_Fill(L'G' ); break; case 0x48 : Character_Fill(L'H' ); break; case 0x49 : Character_Fill(L'I' ); break; case 0x4A : Character_Fill(L'J' ); break; case 0x4B : Character_Fill(L'K' ); break; case 0x4C : Character_Fill(L'L' ); break; case 0x4D : Character_Fill(L'M' ); break; case 0x4E : Character_Fill(L'N' ); break; case 0x4F : Character_Fill(L'O' ); break; case 0x50 : Character_Fill(L'P' ); break; case 0x51 : Character_Fill(L'Q' ); break; case 0x52 : Character_Fill(L'R' ); break; case 0x53 : Character_Fill(L'S' ); break; case 0x54 : Character_Fill(L'T' ); break; case 0x55 : Character_Fill(L'U' ); break; case 0x56 : Character_Fill(L'V' ); break; case 0x57 : Character_Fill(L'W' ); break; case 0x58 : Character_Fill(L'X' ); break; case 0x59 : Character_Fill(L'Y' ); break; case 0x5A : Character_Fill(L'Z' ); break; case 0x5B : Character_Fill(L'[' ); break; case 0x5C : Character_Fill(L'\xE9' ); break; //e acute case 0x5D : Character_Fill(L']' ); break; case 0x5E : Character_Fill(L'\xED' ); break; //i acute case 0x5F : Character_Fill(L'\xF3' ); break; //o acute case 0x60 : Character_Fill(L'\xFA' ); break; //u acute case 0x61 : Character_Fill(L'a' ); break; case 0x62 : Character_Fill(L'b' ); break; case 0x63 : Character_Fill(L'c' ); break; case 0x64 : Character_Fill(L'd' ); break; case 0x65 : Character_Fill(L'e' ); break; case 0x66 : Character_Fill(L'f' ); break; case 0x67 : Character_Fill(L'g' ); break; case 0x68 : Character_Fill(L'h' ); break; case 0x69 : Character_Fill(L'i' ); break; case 0x6A : Character_Fill(L'j' ); break; case 0x6B : Character_Fill(L'k' ); break; case 0x6C : Character_Fill(L'l' ); break; case 0x6D : Character_Fill(L'm' ); break; case 0x6E : Character_Fill(L'n' ); break; case 0x6F : Character_Fill(L'o' ); break; case 0x70 : Character_Fill(L'p' ); break; case 0x71 : Character_Fill(L'q' ); break; case 0x72 : Character_Fill(L'r' ); break; case 0x73 : Character_Fill(L's' ); break; case 0x74 : Character_Fill(L't' ); break; case 0x75 : Character_Fill(L'u' ); break; case 0x76 : Character_Fill(L'v' ); break; case 0x77 : Character_Fill(L'w' ); break; case 0x78 : Character_Fill(L'x' ); break; case 0x79 : Character_Fill(L'y' ); break; case 0x7A : Character_Fill(L'z' ); break; case 0x7B : Character_Fill(L'\xE7' ); break; //c with cedilla case 0x7C : Character_Fill(L'\xF7' ); break; //division symbol case 0x7D : Character_Fill(L'\xD1' ); break; //N tilde case 0x7E : Character_Fill(L'\xF1' ); break; //n tilde case 0x7F : Character_Fill(L'\x25A0'); break; //Solid block default : Illegal(0x00, Character); } } //--------------------------------------------------------------------------- void File_Eia608::Character_Fill(wchar_t Character) { size_t StreamPos=TextMode*2+DataChannelMode; if (StreamPos>=Streams.size() || Streams[StreamPos]==NULL || !Streams[StreamPos]->Synched) return; //Not synched stream& Stream=*Streams[StreamPos]; if (!Stream.InBack) { Stream.Count_CurrentHasContent=true; } if (Stream.x==Eia608_Columns) { Stream.x--; //There is a problem //TODO: Put it at the end, for the conversion //TODO: Handle special chars } if (Stream.InBack) Stream.CC_NonDisplayed[Stream.y][Stream.x].Value=Character; else { vector >& CC_Displayed=Stream.CC_Displayed; bool HasContent=false; vector& Line=CC_Displayed[Stream.y]; for (int8u x=0; x& Line=CC_Displayed[Pos_Y]; for (int8u Pos_X=0; Pos_X=Streams.size() || Streams[StreamPos]==NULL || !Streams[StreamPos]->Synched) return; //Not synched if (FrameInfo.DTS!=(int64u)-1) { if (!HasJumped && Streams[StreamPos]->Duration_Start==FLT_MAX) Streams[StreamPos]->Duration_Start=FrameInfo.DTS/1000000.0; Streams[StreamPos]->Duration_End=(FrameInfo.DTS)/1000000.0; } #if MEDIAINFO_EVENTS if (StreamPosCC_Displayed.size(); Pos_Y++) { for (size_t Pos_X=0; Pos_XCC_Displayed[Pos_Y].size(); Pos_X++) { Event.Row_Values[Pos_Y][Pos_X]=Streams[StreamPos]->CC_Displayed[Pos_Y][Pos_X].Value; Event.Row_Attributes[Pos_Y][Pos_X]=Streams[StreamPos]->CC_Displayed[Pos_Y][Pos_X].Attribute; } Event.Row_Values[Pos_Y][32]=L'\0'; } EVENT_END () #endif //MEDIAINFO_EVENTS } //--------------------------------------------------------------------------- void File_Eia608::Illegal(int8u cc_data_1, int8u cc_data_2) { } //*************************************************************************** // C++ //*************************************************************************** } //NameSpace #endif //MEDIAINFO_EIA608_YES