/* 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_CDP_YES) //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #include "MediaInfo/Text/File_Cdp.h" #include "MediaInfo/MediaInfo_Config_MediaInfo.h" #if defined(MEDIAINFO_EIA608_YES) #include "MediaInfo/Text/File_Eia608.h" #endif #if MEDIAINFO_EVENTS #include "MediaInfo/MediaInfo_Events.h" #endif //MEDIAINFO_EVENTS using namespace std; //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- namespace MediaInfoLib { //--------------------------------------------------------------------------- //*************************************************************************** // Info //*************************************************************************** //--------------------------------------------------------------------------- static const char* Cdp_cc_type(int8u cc_type) { switch (cc_type) { case 0 : return "CEA-608 line 21 field 1 closed captions"; //closed caption 3 if this is second field case 1 : return "CEA-608 line 21 field 2 closed captions"; //closed caption 4 if this is second field case 2 : return "DTVCC Channel Packet Data"; case 3 : return "DTVCC Channel Packet Start"; default : return ""; } } //--------------------------------------------------------------------------- static float64 Cdp_cdp_frame_rate(int8u cdp_frame_rate) { switch (cdp_frame_rate) { case 1 : return (float64)24/1.001; case 2 : return (float64)24; case 3 : return (float64)25; case 4 : return (float64)30/1.001; case 5 : return (float64)30; case 6 : return (float64)50; case 7 : return (float64)60/1.001; case 8 : return (float64)60; default : return (float64) 0; } } //*************************************************************************** // Constructor/Destructor //*************************************************************************** //--------------------------------------------------------------------------- File_Cdp::File_Cdp() :File__Analyze() { //Config PTS_DTS_Needed=true; MustSynchronize=true; //In AspectRatio=0; //Temp ParserName="CDP"; #if MEDIAINFO_EVENTS ParserIDs[0]=MediaInfo_Parser_Cdp; StreamIDs_Width[0]=1; #endif //MEDIAINFO_EVENTS Streams.resize(3); //CEA-608 Field 1, CEA-608 Field 2, CEA-708 Channel Streams_Count=0; //In WithAppleHeader=false; AspectRatio=0; //Temp cdp_frame_rate=(int8u)-1; //Descriptors #if defined(MEDIAINFO_EIA608_YES) || defined(MEDIAINFO_EIA708_YES) ServiceDescriptors=new File__Analyze::servicedescriptors; #endif //cdp_length cdp_length_Min=(int8u)-1; cdp_length_Max=0; } //--------------------------------------------------------------------------- File_Cdp::~File_Cdp() { for (size_t Pos=0; PosParser && Streams[Pos]->Parser->Status[IsFilled] /*&& Streams[Pos]->Parser->Status[IsUpdated]*/ && Streams[Pos]->Parser->Count_Get(Stream_Text)) Streams_Update_PerStream(Pos); } //--------------------------------------------------------------------------- void File_Cdp::Streams_Update_PerStream(size_t Pos) { if (Streams[Pos]==NULL) return; Update(Streams[Pos]->Parser); if (Streams[Pos]->Parser) { for (size_t Pos2=0; Pos2Parser->Count_Get(Stream_Text); Pos2++) { Stream_Prepare(Stream_Text); Merge(*Streams[Pos]->Parser, Stream_Text, Pos2, StreamPos_Last); if (WithAppleHeader) Fill(Stream_Text, StreamPos_Last, "MuxingMode", "Final Cut"); Fill(Stream_Text, StreamPos_Last, "MuxingMode", "CDP"); if (cdp_frame_rate!=(int8u)-1) Fill(Stream_Text, StreamPos_Last, Text_FrameRate, Cdp_cdp_frame_rate(cdp_frame_rate)); Fill(Stream_Text, StreamPos_Last, Text_ID, Streams[Pos]->Parser->Retrieve(Stream_Text, Pos2, Text_ID), true); //cdp_length if (cdp_length_Min<=cdp_length_Max) { Fill(Stream_Text, StreamPos_Last, "cdp_length_Min", cdp_length_Min, 10, true); Fill(Stream_Text, StreamPos_Last, "cdp_length_Max", cdp_length_Max, 10, true); Fill_SetOptions(Stream_Text, StreamPos_Last, "cdp_length_Min", "N NT"); Fill_SetOptions(Stream_Text, StreamPos_Last, "cdp_length_Max", "N NT"); } } Ztring LawRating=Streams[Pos]->Parser->Retrieve(Stream_General, 0, General_LawRating); if (!LawRating.empty()) Fill(Stream_General, 0, General_LawRating, LawRating, true); Ztring Title=Streams[Pos]->Parser->Retrieve(Stream_General, 0, General_Title); if (!Title.empty() && Retrieve(Stream_General, 0, General_Title).empty()) Fill(Stream_General, 0, General_Title, Title); } } //--------------------------------------------------------------------------- void File_Cdp::Streams_Finish() { Clear(Stream_Text); //Per stream for (size_t Pos=0; PosParser && Streams[Pos]->Parser->Status[IsAccepted] /*&& Streams[Pos]->Parser->Status[IsUpdated]*/) { Finish(Streams[Pos]->Parser); Streams_Update_PerStream(Pos); } } //*************************************************************************** // Buffer - Synchro //*************************************************************************** //--------------------------------------------------------------------------- void File_Cdp::Read_Buffer_Unsynched() { //Parsing for (size_t Pos=0; PosParser) Streams[Pos]->Parser->Open_Buffer_Unsynch(); } //*************************************************************************** // Buffer - Synchro //*************************************************************************** //--------------------------------------------------------------------------- bool File_Cdp::Synchronize() { //Synchronizing while (Buffer_Offset+3<=Buffer_Size) { while (Buffer_Offset+3<=Buffer_Size && (Buffer[Buffer_Offset ]!=0x96 || Buffer[Buffer_Offset+1]!=0x69)) { Buffer_Offset++; while (Buffer_OffsetBuffer_Size) break; //CRC int8u CRC=0; int8u cdp_length=Buffer[Buffer_Offset+2]; //Must have enough buffer for having header if (Buffer_Offset+cdp_length>Buffer_Size) return false; const int8u* Buffer_Temp=Buffer+Buffer_Offset; const int8u* Buffer_End=Buffer+Buffer_Offset+cdp_length; while (Buffer_TempBuffer_Size) { if (Buffer_Offset+3==Buffer_Size && CC2(Buffer+Buffer_Offset)!=0x9669) Buffer_Offset++; if (Buffer_Offset+2==Buffer_Size && CC2(Buffer+Buffer_Offset)!=0x9669) Buffer_Offset++; if (Buffer_Offset+1==Buffer_Size && CC1(Buffer+Buffer_Offset)!=0x96) Buffer_Offset++; return false; } //Synched is OK return true; } //--------------------------------------------------------------------------- bool File_Cdp::Synched_Test() { //Must have enough buffer for having header if (Buffer_Offset+3>Buffer_Size) return false; //Quick test of synchro if (Buffer[Buffer_Offset ]!=0x96 || Buffer[Buffer_Offset+1]!=0x69) Synched=false; if (Synched) { //CRC int8u CRC=0; int8u cdp_length=Buffer[Buffer_Offset+2]; //Must have enough buffer for having header if (Buffer_Offset+cdp_length>Buffer_Size) return false; const int8u* Buffer_Temp=Buffer+Buffer_Offset; const int8u* Buffer_End=Buffer+Buffer_Offset+cdp_length; while (Buffer_TempElement_Size) End=Element_Size; while(Element_Offset=0x75 && section_id<=0xEF) future_section(); else Skip_XX(Element_Size-Element_Offset, "Unknown"); } } if (!IsSub) Element_End1("CDP"); } FILLING_BEGIN(); if (!Status[IsFilled] && Frame_Count>=1024 && Config->ParseSpeed<1.0) Fill(); if (!IsSub && Config->ParseSpeed<1.0 && Frame_Count>=300) Finish(); FILLING_END(); } //--------------------------------------------------------------------------- void File_Cdp::Read_Buffer_Continue() { if (Buffer_Size==0) return; if (WithAppleHeader) { int32u Size, Magic; Get_B4 (Size, "Size"); Get_B4 (Magic, "Magic"); FILLING_BEGIN(); if (Magic!=0x63636470) { Reject("CDP"); Skip_XX(Element_Size-Element_Offset, "Junk"); return; } FILLING_END(); } } //*************************************************************************** // Functions //*************************************************************************** //--------------------------------------------------------------------------- void File_Cdp::cdp_header() { Element_Begin1("cdp_header"); int16u cdp_identifier; Get_B2 ( cdp_identifier, "cdp_identifier"); Get_B1 ( cdp_length, "cdp_length"); BS_Begin(); Get_S1 (4, cdp_frame_rate, "cdp_frame_rate"); Param_Info1(Ztring::ToZtring(Cdp_cdp_frame_rate(cdp_frame_rate))+__T(" fps")); Skip_S1(4, "Reserved"); Skip_SB( "time_code_present"); Skip_SB( "ccdata_present"); Skip_SB( "svcinfo_present"); Skip_SB( "svc_info_start"); Skip_SB( "svc_info_change"); Skip_SB( "svc_info_complete"); Skip_SB( "caption_service_active"); Skip_SB( "Reserved"); BS_End(); Skip_B2( "cdp_hdr_sequence_cntr"); Element_End0(); FILLING_BEGIN(); //cdp_length if (cdp_length>cdp_length_Max) cdp_length_Max=cdp_length; if (cdp_length=2 && !Streams[2] && Config->File_DisplayCaptions_Get()==DisplayCaptions_Stream) CreateStream(2); #endif //MEDIAINFO_ADVANCED if (cc_valid) { Element_Begin1("cc_data"); //Calculating the parser position int8u Parser_Pos=cc_type==3?2:cc_type; //cc_type 2 and 3 are for the same text //Stream creation if (Streams[Parser_Pos]==NULL) CreateStream(Parser_Pos); //Parsing #if MEDIAINFO_DEMUX Element_Code=Parser_Pos; Demux(Buffer+(size_t)(Buffer_Offset+Element_Offset), 2, ContentType_MainStream); #endif //MEDIAINFO_DEMUX if (!Streams[Parser_Pos]->Parser->Status[IsFinished]) { if (Streams[Parser_Pos]->Parser->PTS_DTS_Needed) { Streams[Parser_Pos]->Parser->FrameInfo.PCR=FrameInfo.PCR; Streams[Parser_Pos]->Parser->FrameInfo.PTS=FrameInfo.PTS; Streams[Parser_Pos]->Parser->FrameInfo.DTS=FrameInfo.DTS; } if (Parser_Pos==2) { #if defined(MEDIAINFO_EIA708_YES) ((File_Eia708*)Streams[2]->Parser)->cc_type=cc_type; if (AspectRatio) ((File_Eia708*)Streams[2]->Parser)->AspectRatio=AspectRatio; #endif //defined(MEDIAINFO_EIA708_YES) } #if defined(MEDIAINFO_EIA608_YES) || defined(MEDIAINFO_EIA708_YES) Streams[Parser_Pos]->Parser->ServiceDescriptors=ServiceDescriptors; #endif Open_Buffer_Continue(Streams[Parser_Pos]->Parser, Buffer+(size_t)(Buffer_Offset+Element_Offset), 2); Element_Offset+=2; //Filled if (!Streams[Parser_Pos]->IsFilled && Streams[Parser_Pos]->Parser->Status[IsFilled]) { if (Count_Get(Stream_General)==0) Accept("CDP"); Streams_Count++; if (Streams_Count==3) Fill("CDP"); Streams[Parser_Pos]->IsFilled=true; } } else Skip_XX(2, "Data"); Element_End0(); } else Skip_XX(2, "Junk"); Element_End0(); } Element_End0(); Frame_Count++; Frame_Count_InThisBlock++; if (Frame_Count_NotParsedIncluded!=(int64u)-1) Frame_Count_NotParsedIncluded++; } //--------------------------------------------------------------------------- void File_Cdp::ccsvcinfo_section() { //Parsing int8u svc_count; Element_Begin1("ccsvcinfo_section"); Skip_B1( "ccsvcinfo_id"); BS_Begin(); Skip_SB( "reserved"); Skip_SB( "svc_info_start"); Skip_SB( "svc_info_change"); Skip_SB( "svc_info_complete"); Get_S1 (4, svc_count, "svc_count"); BS_End(); bool line21_field_Found[2]={false, false}; string line21_languages[2]; for (int8u Pos=0; PosServiceDescriptors708[caption_service_number].language=language; ServiceDescriptors->ServiceDescriptors708[caption_service_number].wide_aspect_ratio.set(0); ServiceDescriptors->ServiceDescriptors708[caption_service_number].wide_aspect_ratio.set(1, wide_aspect_ratio); if (!Streams[2]) CreateStream(2); #endif } else { #if defined(MEDIAINFO_EIA608_YES) line21_field_Found[line21_field]=true; line21_languages[line21_field]=language; #endif } #endif FILLING_END(); } Element_End0(); #if defined(MEDIAINFO_EIA608_YES) // From specs: line21_field is deprecated and language is indicated as having no meaning if digital_cc is clear // but some encoders fill language for CC1 and CC3, let's try to keep this metadata // but some encoders also fill line21_field to 1 for CC1 alone so let's ignore this field if there is only 1 CC announced if (!line21_field_Found[0] && line21_field_Found[1]) { swap(line21_field_Found[0], line21_field_Found[1]); swap(line21_languages[0], line21_languages[1]); } for (int i=0; i<=1; i++) if (line21_field_Found[i]) { ServiceDescriptors->ServiceDescriptors608[i].language=line21_languages[i]; if (!Streams[i]) CreateStream(i); } #endif } //--------------------------------------------------------------------------- void File_Cdp::cdp_footer() { Element_Begin1("cdp_footer"); Skip_B1( "cdp_footer_id"); Skip_B2( "cdp_ftr_sequence_cntr"); Skip_B1( "packet_checksum"); Element_End0(); } //--------------------------------------------------------------------------- void File_Cdp::future_section() { //Parsing int8u length; Element_Begin1("future_section"); Skip_B1( "future_section_id"); Get_B1 (length, "length"); Skip_XX(length, "Unknown"); Element_End0(); } //*************************************************************************** // Helpers //*************************************************************************** //--------------------------------------------------------------------------- void File_Cdp::CreateStream(int8u Parser_Pos) { if (Streams[Parser_Pos]) return; //Already done //Parsing #if MEDIAINFO_DEMUX Element_Code=Parser_Pos; #endif //MEDIAINFO_DEMUX //Creation of the parser Streams[Parser_Pos]=new stream; #if defined(MEDIAINFO_EIA608_YES) || defined(MEDIAINFO_EIA708_YES) if (Parser_Pos<2) { #if defined(MEDIAINFO_EIA608_YES) Streams[Parser_Pos]->Parser=new File_Eia608(); ((File_Eia608*)Streams[Parser_Pos]->Parser)->cc_type=Parser_Pos; #else //defined(MEDIAINFO_EIA608_YES) Streams[Parser_Pos]->Parser=new File__Analyze(); #endif //defined(MEDIAINFO_EIA608_YES) } else { #if defined(MEDIAINFO_EIA708_YES) Streams[Parser_Pos]->Parser=new File_Eia708(); #else //defined(MEDIAINFO_EIA708_YES) Streams[Parser_Pos]->Parser=new File__Analyze(); #endif //defined(MEDIAINFO_EIA708_YES) } #else //defined(MEDIAINFO_EIA608_YES) || defined(MEDIAINFO_EIA708_YES) Streams[Parser_Pos]->Parser=new File__Analyze(); #endif //defined(MEDIAINFO_EIA608_YES) || defined(MEDIAINFO_EIA708_YES) //Init Streams[Parser_Pos]->Parser->ServiceDescriptors=ServiceDescriptors; Open_Buffer_Init(Streams[Parser_Pos]->Parser); Streams[Parser_Pos]->Parser->Accept(); } //*************************************************************************** // C++ //*************************************************************************** } //NameSpace #endif //MEDIAINFO_CDP_YES