Commit 88ba51fe authored by François Cartegnie's avatar François Cartegnie 🤞

packetizer: h264: refactor SEI parsing

All SEI are the same, only set differs between H264/HEVC
parent 0283f9f8
......@@ -7,6 +7,7 @@ libpacketizer_mpeg4audio_plugin_la_SOURCES = packetizer/mpeg4audio.c
libpacketizer_h264_plugin_la_SOURCES = \
packetizer/h264_nal.c packetizer/h264_nal.h \
packetizer/h264.c packetizer/hxxx_nal.h \
packetizer/hxxx_sei.c packetizer/hxxx_sei.h \
packetizer/hxxx_common.c packetizer/hxxx_common.h
libpacketizer_vc1_plugin_la_SOURCES = packetizer/vc1.c \
packetizer/hxxx_nal.h
......
......@@ -43,6 +43,7 @@
#include "../codec/cc.h"
#include "h264_nal.h"
#include "hxxx_nal.h"
#include "hxxx_sei.h"
#include "hxxx_common.h"
#include "packetizer_helper.h"
#include "startcode_helper.h"
......@@ -166,7 +167,7 @@ static void PutSPS( decoder_t *p_dec, block_t *p_frag );
static void PutPPS( decoder_t *p_dec, block_t *p_frag );
static bool ParseSlice( decoder_t *p_dec, bool *pb_new_picture, slice_t *p_slice,
int i_nal_ref_idc, int i_nal_type, const block_t *p_frag );
static void ParseSei( decoder_t *, block_t * );
static void ParseSeiCallback( decoder_t *p_dec, const hxxx_sei_data_t * );
static const uint8_t p_h264_startcode[3] = { 0x00, 0x00, 0x01 };
......@@ -531,7 +532,7 @@ static block_t *ParseNALBlock( decoder_t *p_dec, bool *pb_ts_used, block_t *p_fr
/* Parse SEI for CC support */
if( i_nal_type == H264_NAL_SEI )
{
ParseSei( p_dec, p_frag );
HxxxParseSEI( p_dec, p_frag->p_buffer, p_frag->i_buffer, 1, ParseSeiCallback );
}
else if( i_nal_type == H264_NAL_AU_DELIMITER )
{
......@@ -948,131 +949,46 @@ static bool ParseSlice( decoder_t *p_dec, bool *pb_new_picture, slice_t *p_slice
return true;
}
static void ParseSei( decoder_t *p_dec, block_t *p_frag )
static void ParseSeiCallback( decoder_t *p_dec, const hxxx_sei_data_t *p_sei_data )
{
decoder_sys_t *p_sys = p_dec->p_sys;
bs_t s;
unsigned i_bitflow = 0;
const uint8_t *p_stripped = p_frag->p_buffer;
size_t i_stripped = p_frag->i_buffer;
if( !hxxx_strip_AnnexB_startcode( &p_stripped, &i_stripped ) || i_stripped < 2 )
return;
bs_init( &s, p_stripped, i_stripped );
s.p_fwpriv = &i_bitflow;
s.pf_forward = hxxx_bsfw_ep3b_to_rbsp; /* Does the emulated 3bytes conversion to rbsp */
bs_skip( &s, 8 ); /* nal unit header */
while( bs_remain( &s ) >= 8 && bs_aligned( &s ) )
switch( p_sei_data->i_type )
{
/* Read type */
unsigned i_type = 0;
while( bs_remain( &s ) >= 8 )
/* Look for pic timing */
case HXXX_SEI_PIC_TIMING:
{
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;
/* Save start offset */
const unsigned i_start_bit_pos = bs_pos( &s );
switch( i_type )
{
/* Look for pic timing */
case H264_SEI_PIC_TIMING:
if( p_sys->b_cpb_dpb_delays_present_flag )
{
if( p_sys->b_cpb_dpb_delays_present_flag )
{
bs_read( &s, p_sys->i_cpb_removal_delay_length_minus1 + 1 );
bs_read( &s, p_sys->i_dpb_output_delay_length_minus1 + 1 );
}
bs_read( p_sei_data->p_bs, p_sys->i_cpb_removal_delay_length_minus1 + 1 );
bs_read( p_sei_data->p_bs, p_sys->i_dpb_output_delay_length_minus1 + 1 );
}
if( p_sys->b_pic_struct_present_flag )
p_sys->i_pic_struct = bs_read( &s, 4 );
/* + unparsed remains */
} break;
if( p_sys->b_pic_struct_present_flag )
p_sys->i_pic_struct = bs_read( p_sei_data->p_bs, 4 );
/* + unparsed remains */
} break;
/* Look for user_data_registered_itu_t_t35 */
case H264_SEI_USER_DATA_REGISTERED_ITU_T_T35:
{
/* TS 101 154 Auxiliary Data and H264/AVC video */
static const uint8_t p_DVB1_data_start_code[] = {
0xb5, /* United States */
0x00, 0x31, /* US provider code */
0x47, 0x41, 0x39, 0x34 /* user identifier */
};
static const uint8_t p_DIRECTV_data_start_code[] = {
0xb5, /* United States */
0x00, 0x2f, /* US provider code */
0x03 /* Captions */
};
unsigned i_t35;
uint8_t *p_t35 = malloc( i_size );
if( !p_t35 )
break;
for( i_t35 = 0; i_t35<i_size && bs_remain( &s ) >= 8; i_t35++ )
p_t35[i_t35] = bs_read( &s, 8 );
/* Check for we have DVB1_data() */
if( i_t35 >= sizeof(p_DVB1_data_start_code) &&
!memcmp( p_t35, p_DVB1_data_start_code, sizeof(p_DVB1_data_start_code) ) )
{
cc_Extract( &p_sys->cc_next, true, &p_t35[3], i_t35 - 3 );
} else if( i_t35 >= sizeof(p_DIRECTV_data_start_code) &&
!memcmp( p_t35, p_DIRECTV_data_start_code, sizeof(p_DIRECTV_data_start_code) ) )
{
cc_Extract( &p_sys->cc_next, true, &p_t35[3], i_t35 - 3 );
}
free( p_t35 );
} break;
case HXXX_SEI_USER_DATA_REGISTERED_ITU_T_T35:
{
cc_Extract( &p_sys->cc_next, true, p_sei_data->itu_t35.p_cc, p_sei_data->itu_t35.i_cc );
} break;
/* Look for SEI recovery point */
case H264_SEI_RECOVERY_POINT:
case HXXX_SEI_RECOVERY_POINT:
{
if( !p_sys->b_header )
{
int i_recovery_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 );
if( !p_sys->b_header )
{
msg_Dbg( p_dec, "Seen SEI recovery point, %d recovery frames", i_recovery_frames );
if ( p_sys->i_recovery_frames == -1 || i_recovery_frames < p_sys->i_recovery_frames )
p_sys->i_recovery_frames = i_recovery_frames;
}
} break;
default:
/* Will skip */
break;
}
msg_Dbg( p_dec, "Seen SEI recovery point, %d recovery frames", p_sei_data->recovery.i_frames );
if ( p_sys->i_recovery_frames == -1 || p_sei_data->recovery.i_frames < p_sys->i_recovery_frames )
p_sys->i_recovery_frames = p_sei_data->recovery.i_frames;
}
} 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 */
default:
/* Will skip */
break;
bs_skip( &s, i_size * 8 - ( i_end_bit_pos - i_start_bit_pos ) );
}
}
......
......@@ -73,14 +73,6 @@ enum h264_nal_unit_type_e
H264_NAL_RESERVED_23 = 23,
};
/* Defined in H.264 annex D */
enum h264_sei_type_e
{
H264_SEI_PIC_TIMING = 1,
H264_SEI_USER_DATA_REGISTERED_ITU_T_T35 = 4,
H264_SEI_RECOVERY_POINT = 6
};
typedef struct h264_sequence_parameter_set_t h264_sequence_parameter_set_t;
typedef struct h264_picture_parameter_set_t h264_picture_parameter_set_t;
......
/*****************************************************************************
* 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 <vlc_common.h>
#include <vlc_bits.h>
#include <vlc_block.h>
#include "hxxx_sei.h"
#include "hxxx_nal.h"
void HxxxParseSEI(decoder_t *p_dec, const uint8_t *p_buffer, size_t i_buffer,
uint8_t i_header, pf_hxxx_sei_callback pf_callback)
{
bs_t s;
unsigned i_bitflow = 0;
const uint8_t *p_stripped = p_buffer;
size_t i_stripped = i_buffer;
if( !hxxx_strip_AnnexB_startcode( &p_stripped, &i_stripped ) || i_stripped < 2 )
return;
bs_init( &s, p_stripped, i_stripped );
s.p_fwpriv = &i_bitflow;
s.pf_forward = hxxx_bsfw_ep3b_to_rbsp; /* Does the emulated 3bytes conversion to rbsp */
bs_skip( &s, i_header * 8 ); /* nal unit header */
while( bs_remain( &s ) >= 8 && bs_aligned( &s ) )
{
/* 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;
pf_callback( p_dec, &sei_data );
} break;
/* Look for user_data_registered_itu_t_t35 */
case HXXX_SEI_USER_DATA_REGISTERED_ITU_T_T35:
{
/* TS 101 154 Auxiliary Data and H264/AVC video */
static const uint8_t p_DVB1_data_start_code[] = {
0xb5, /* United States */
0x00, 0x31, /* US provider code */
0x47, 0x41, 0x39, 0x34 /* user identifier */
};
static const uint8_t p_DIRECTV_data_start_code[] = {
0xb5, /* United States */
0x00, 0x2f, /* US provider code */
0x03 /* Captions */
};
unsigned i_t35;
uint8_t *p_t35 = malloc( i_size );
if( !p_t35 )
break;
for( i_t35 = 0; i_t35<i_size && bs_remain( &s ) >= 8; i_t35++ )
p_t35[i_t35] = bs_read( &s, 8 );
/* Check for we have DVB1_data() */
if( ( i_t35 >= sizeof(p_DVB1_data_start_code) &&
!memcmp( p_t35, p_DVB1_data_start_code, sizeof(p_DVB1_data_start_code) ) ) ||
( i_t35 >= sizeof(p_DIRECTV_data_start_code) &&
!memcmp( p_t35, p_DIRECTV_data_start_code, sizeof(p_DIRECTV_data_start_code) ) ) )
{
sei_data.itu_t35.i_cc = i_t35 - 3;
sei_data.itu_t35.p_cc = &p_t35[3];
pf_callback( p_dec, &sei_data );
}
free( p_t35 );
} 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 );
pf_callback( p_dec, &sei_data );
} 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 ) );
}
}
/*****************************************************************************
* hxxx_sei.h: 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.
*****************************************************************************/
#ifndef HXXX_SEI_H
#define HXXX_SEI_H
/* Defined in H.264/H.265 annex D */
enum hxxx_sei_type_e
{
HXXX_SEI_PIC_TIMING = 1,
HXXX_SEI_USER_DATA_REGISTERED_ITU_T_T35 = 4,
HXXX_SEI_RECOVERY_POINT = 6
};
typedef struct
{
unsigned i_type;
union
{
bs_t *p_bs; /* for raw/unhandled in common code callbacks */
struct
{
const uint8_t *p_cc;
size_t i_cc;
} itu_t35;
struct
{
int i_frames;
} recovery;
};
} hxxx_sei_data_t;
typedef void (*pf_hxxx_sei_callback)(decoder_t *, const hxxx_sei_data_t *);
void HxxxParseSEI(decoder_t *, const uint8_t *, size_t, uint8_t, pf_hxxx_sei_callback);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment