/***************************************************************************** * hxxx_sei.c: AVC/HEVC packetizers SEI handling ***************************************************************************** * Copyright (C) 2001-2016 VLC authors and VideoLAN * * This program 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 2.1 of the License, or * (at your option) any later version. * * This program 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 program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include "hxxx_sei.h" #include "hxxx_nal.h" void HxxxParse_AnnexB_SEI(const uint8_t *p_buf, size_t i_buf, uint8_t i_header, pf_hxxx_sei_callback cb, void *cbdata) { if( hxxx_strip_AnnexB_startcode( &p_buf, &i_buf ) ) HxxxParseSEI(p_buf, i_buf, i_header, cb, cbdata); } void HxxxParseSEI(const uint8_t *p_buf, size_t i_buf, uint8_t i_header, pf_hxxx_sei_callback pf_callback, void *cbdata) { bs_t s_ep3b; bs_t s; unsigned i_bitflow = 0; bool b_continue = true; char buf[256]; int i = 0; if( i_buf <= i_header ) return; bs_init( &s_ep3b, &p_buf[i_header], i_buf - i_header ); /* skip nal unit header */ s_ep3b.p_fwpriv = &i_bitflow; s_ep3b.pf_forward = hxxx_bsfw_ep3b_to_rbsp; /* Does the emulated 3bytes conversion to rbsp */ /* While a NAL can technically be up to 65535 bytes, an SEI NAL will never be anywhere near that size */ if (bs_remain(&s_ep3b) / 8 > sizeof(buf)) return; while (bs_remain(&s_ep3b) > 0) buf[i++] = bs_read(&s_ep3b, 8); /* Parse the resulting RBSP bytes as SEI */ bs_init( &s, buf, i); while( bs_remain( &s ) >= 8 && bs_aligned( &s ) && b_continue ) { /* Read type */ unsigned i_type = 0; while( bs_remain( &s ) >= 8 ) { const uint8_t i_byte = bs_read( &s, 8 ); i_type += i_byte; if( i_byte != 0xff ) break; } /* Read size */ unsigned i_size = 0; while( bs_remain( &s ) >= 8 ) { const uint8_t i_byte = bs_read( &s, 8 ); i_size += i_byte; if( i_byte != 0xff ) break; } /* Check room */ if( bs_remain( &s ) < 8 ) break; hxxx_sei_data_t sei_data; sei_data.i_type = i_type; /* Save start offset */ const unsigned i_start_bit_pos = bs_pos( &s ); switch( i_type ) { /* Look for pic timing, do not decode locally */ case HXXX_SEI_PIC_TIMING: { sei_data.p_bs = &s; b_continue = pf_callback( &sei_data, cbdata ); } break; /* Look for user_data_registered_itu_t_t35 */ case HXXX_SEI_USER_DATA_REGISTERED_ITU_T_T35: { size_t i_t35; uint8_t *p_t35 = malloc( i_size ); if( !p_t35 ) break; for( i_t35 = 0; i_t35= 8; i_t35++ ) p_t35[i_t35] = bs_read( &s, 8 ); /* TS 101 154 Auxiliary Data and H264/AVC video */ if( i_t35 > 4 && p_t35[0] == 0xb5 /* United States */ ) { if( p_t35[1] == 0x00 && p_t35[2] == 0x31 && /* US provider code for ATSC / DVB1 */ i_t35 > 7 ) { switch( VLC_FOURCC(p_t35[3],p_t35[4],p_t35[5],p_t35[6]) ) { case VLC_FOURCC('G', 'A', '9', '4'): if( p_t35[7] == 0x03 ) { sei_data.itu_t35.type = HXXX_ITU_T35_TYPE_CC; sei_data.itu_t35.u.cc.i_data = i_t35 - 8; sei_data.itu_t35.u.cc.p_data = &p_t35[8]; b_continue = pf_callback( &sei_data, cbdata ); } break; default: break; } } else if( p_t35[1] == 0x00 && p_t35[2] == 0x2f && /* US provider code for DirecTV */ p_t35[3] == 0x03 && i_t35 > 5 ) { /* DirecTV does not use GA94 user_data identifier */ sei_data.itu_t35.type = HXXX_ITU_T35_TYPE_CC; sei_data.itu_t35.u.cc.i_data = i_t35 - 5; sei_data.itu_t35.u.cc.p_data = &p_t35[5]; b_continue = pf_callback( &sei_data, cbdata ); } } free( p_t35 ); } break; case HXXX_SEI_FRAME_PACKING_ARRANGEMENT: { bs_read_ue( &s ); if ( !bs_read1( &s ) ) { sei_data.frame_packing.type = bs_read( &s, 7 ); bs_read( &s, 1 ); if( bs_read( &s, 6 ) == 2 ) /*intpr type*/ sei_data.frame_packing.b_left_first = false; else sei_data.frame_packing.b_left_first = true; sei_data.frame_packing.b_flipped = bs_read1( &s ); sei_data.frame_packing.b_fields = bs_read1( &s ); sei_data.frame_packing.b_frame0 = bs_read1( &s ); } else sei_data.frame_packing.type = FRAME_PACKING_CANCEL; } break; /* Look for SEI recovery point */ case HXXX_SEI_RECOVERY_POINT: { sei_data.recovery.i_frames = bs_read_ue( &s ); //bool b_exact_match = bs_read( &s, 1 ); //bool b_broken_link = bs_read( &s, 1 ); //int i_changing_slice_group = bs_read( &s, 2 ); b_continue = pf_callback( &sei_data, cbdata ); } break; case HXXX_SEI_MASTERING_DISPLAY_COLOUR_VOLUME: { if ( bs_remain( &s ) < (16*6+16*2+32+32) ) /* not enough data */ break; for ( size_t i = 0; i < 6 ; ++i) sei_data.colour_volume.primaries[i] = bs_read( &s, 16 ); for ( size_t i = 0; i < 2 ; ++i) sei_data.colour_volume.white_point[i] = bs_read( &s, 16 ); sei_data.colour_volume.max_luminance = bs_read( &s, 32 ); sei_data.colour_volume.min_luminance = bs_read( &s, 32 ); b_continue = pf_callback( &sei_data, cbdata ); } break; case HXXX_SEI_CONTENT_LIGHT_LEVEL: { if ( bs_remain( &s ) < (16+16) ) /* not enough data */ break; sei_data.content_light_lvl.MaxCLL = bs_read( &s, 16 ); sei_data.content_light_lvl.MaxFALL = bs_read( &s, 16 ); b_continue = pf_callback( &sei_data, cbdata ); } break; default: /* Will skip */ break; } const unsigned i_end_bit_pos = bs_pos( &s ); /* Skip unsparsed content */ if( i_end_bit_pos - i_start_bit_pos > i_size * 8 ) /* Something went wrong with _ue reads */ break; bs_skip( &s, i_size * 8 - ( i_end_bit_pos - i_start_bit_pos ) ); } }