Commit 18ae72bb authored by François Cartegnie's avatar François Cartegnie 🤞

packetizer: hevc: extract closed captions

parent a7d79e04
......@@ -16,6 +16,7 @@ libpacketizer_dirac_plugin_la_SOURCES = packetizer/dirac.c
libpacketizer_flac_plugin_la_SOURCES = packetizer/flac.c
libpacketizer_hevc_plugin_la_SOURCES = packetizer/hevc.c \
packetizer/hevc_nal.h packetizer/hevc_nal.c \
packetizer/hxxx_sei.c packetizer/hxxx_sei.h \
packetizer/hxxx_nal.h \
packetizer/hxxx_common.c packetizer/hxxx_common.h
libpacketizer_a52_plugin_la_SOURCES = packetizer/a52.c packetizer/a52.h
......
......@@ -33,12 +33,14 @@
#include <vlc_plugin.h>
#include <vlc_codec.h>
#include <vlc_block.h>
#include <vlc_bits.h>
#include <vlc_block_helper.h>
#include "packetizer_helper.h"
#include "startcode_helper.h"
#include "hevc_nal.h"
#include "hxxx_nal.h"
#include "hxxx_sei.h"
#include "hxxx_common.h"
/*****************************************************************************
......@@ -66,6 +68,8 @@ static void PacketizeReset(void *p_private, bool b_broken);
static block_t *PacketizeParse(void *p_private, bool *pb_ts_used, block_t *);
static block_t *ParseNALBlock(decoder_t *, bool *pb_ts_used, block_t *);
static int PacketizeValidate(void *p_private, block_t *);
static bool ParseSEICallback( const hxxx_sei_data_t *, void * );
static block_t *GetCc( decoder_t *, bool pb_present[4] );
struct decoder_sys_t
{
......@@ -83,6 +87,9 @@ struct decoder_sys_t
hevc_sequence_parameter_set_t *rgi_p_decsps[HEVC_SPS_MAX];
hevc_picture_parameter_set_t *rgi_p_decpps[HEVC_PPS_MAX];
bool b_init_sequence_complete;
/* */
cc_storage_t *p_ccs;
};
static const uint8_t p_hevc_startcode[3] = {0x00, 0x00, 0x01};
......@@ -154,6 +161,13 @@ static int Open(vlc_object_t *p_this)
if (!p_dec->p_sys)
return VLC_ENOMEM;
p_sys->p_ccs = cc_storage_new();
if(unlikely(!p_sys->p_ccs))
{
free(p_dec->p_sys);
return VLC_ENOMEM;
}
INITQ(pre);
INITQ(frame);
INITQ(post);
......@@ -191,6 +205,7 @@ static int Open(vlc_object_t *p_this)
p_dec->pf_packetize = PacketizeAnnexB;
}
p_dec->pf_flush = PacketizeFlush;
p_dec->pf_get_cc = GetCc;
if(p_dec->fmt_out.i_extra)
{
......@@ -233,6 +248,8 @@ static void Close(vlc_object_t *p_this)
hevc_rbsp_release_vps(p_sys->rgi_p_decvps[i]);
}
cc_storage_delete( p_sys->p_ccs );
free(p_sys);
}
......@@ -261,6 +278,14 @@ static void PacketizeFlush( decoder_t *p_dec )
packetizer_Flush( &p_sys->packetizer );
}
/*****************************************************************************
* GetCc:
*****************************************************************************/
static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] )
{
return cc_storage_get_current( p_dec->p_sys->p_ccs, pb_present );
}
/****************************************************************************
* Packetizer Helpers
****************************************************************************/
......@@ -440,6 +465,9 @@ static block_t *ParseVCL(decoder_t *p_dec, uint8_t i_nal_type, block_t *p_frag)
p_sys->b_init_sequence_complete = true;
}
if( !p_sys->b_init_sequence_complete )
cc_storage_reset( p_sys->p_ccs );
block_ChainLastAppend(&p_sys->frame.pp_chain_last, p_frag);
return p_outputchain;
......@@ -511,8 +539,14 @@ static block_t * ParseAUHead(decoder_t *p_dec, uint8_t i_nal_type, block_t *p_na
}
}
}
break;
}
// ft
case HEVC_NAL_PREF_SEI:
HxxxParse_AnnexB_SEI( p_nalb->p_buffer, p_nalb->i_buffer,
2 /* nal header */, ParseSEICallback, p_dec );
break;
default:
break;
}
......@@ -535,6 +569,11 @@ static block_t * ParseAUTail(decoder_t *p_dec, uint8_t i_nal_type, block_t *p_na
case HEVC_NAL_EOB:
p_ret = OutputQueues(p_sys, true);
break;
case HEVC_NAL_SUFF_SEI:
HxxxParse_AnnexB_SEI( p_nalb->p_buffer, p_nalb->i_buffer,
2 /* nal header */, ParseSEICallback, p_dec );
break;
}
if(!p_ret && p_sys->frame.p_chain == NULL)
......@@ -630,12 +669,17 @@ static block_t *ParseNALBlock(decoder_t *p_dec, bool *pb_ts_used, block_t *p_fra
static block_t *PacketizeParse(void *p_private, bool *pb_ts_used, block_t *p_block)
{
decoder_t *p_dec = p_private;
decoder_sys_t *p_sys = p_dec->p_sys;
/* Remove trailing 0 bytes */
while (p_block->i_buffer > 5 && p_block->p_buffer[p_block->i_buffer-1] == 0x00 )
p_block->i_buffer--;
return ParseNALBlock( p_dec, pb_ts_used, p_block );
p_block = ParseNALBlock( p_dec, pb_ts_used, p_block );
if( p_block )
cc_storage_commit( p_sys->p_ccs, p_block );
return p_block;
}
static int PacketizeValidate( void *p_private, block_t *p_au )
......@@ -644,3 +688,14 @@ static int PacketizeValidate( void *p_private, block_t *p_au )
VLC_UNUSED(p_au);
return VLC_SUCCESS;
}
static bool ParseSEICallback( const hxxx_sei_data_t *p_sei_data, void *cbdata )
{
decoder_t *p_dec = (decoder_t *) cbdata;
decoder_sys_t *p_sys = p_dec->p_sys;
if( p_sei_data->i_type == HXXX_SEI_USER_DATA_REGISTERED_ITU_T_T35 )
cc_storage_append( p_sys->p_ccs, true, p_sei_data->itu_t35.p_cc, p_sei_data->itu_t35.i_cc );
return true;
}
......@@ -25,6 +25,83 @@
#include <vlc_block.h>
#include <vlc_codec.h>
#include "../codec/cc.h"
/****************************************************************************
* Closed captions handling
****************************************************************************/
struct cc_storage_t
{
uint32_t i_flags;
mtime_t i_dts;
mtime_t i_pts;
cc_data_t current;
cc_data_t next;
};
cc_storage_t * cc_storage_new( void )
{
cc_storage_t *p_ccs = malloc( sizeof(*p_ccs) );
if( likely(p_ccs) )
{
p_ccs->i_pts = VLC_TS_INVALID;
p_ccs->i_dts = VLC_TS_INVALID;
p_ccs->i_flags = 0;
cc_Init( &p_ccs->current );
cc_Init( &p_ccs->next );
}
return p_ccs;
}
void cc_storage_delete( cc_storage_t *p_ccs )
{
cc_Exit( &p_ccs->current );
cc_Exit( &p_ccs->next );
free( p_ccs );
}
void cc_storage_reset( cc_storage_t *p_ccs )
{
cc_Flush( &p_ccs->next );
}
void cc_storage_append( cc_storage_t *p_ccs, bool b_top_field_first,
const uint8_t *p_buf, size_t i_buf )
{
cc_Extract( &p_ccs->next, b_top_field_first, p_buf, i_buf );
}
void cc_storage_commit( cc_storage_t *p_ccs, block_t *p_pic )
{
p_ccs->i_pts = p_pic->i_pts;
p_ccs->i_dts = p_pic->i_dts;
p_ccs->i_flags = p_pic->i_flags;
p_ccs->current = p_ccs->next;
cc_Flush( &p_ccs->next );
}
block_t * cc_storage_get_current( cc_storage_t *p_ccs, bool pb_present[4] )
{
block_t *p_block;
for( int i = 0; i < 4; i++ )
pb_present[i] = p_ccs->current.pb_present[i];
if( p_ccs->current.i_data <= 0 )
return NULL;
p_block = block_Alloc( p_ccs->current.i_data);
if( p_block )
{
memcpy( p_block->p_buffer, p_ccs->current.p_data, p_ccs->current.i_data );
p_block->i_dts =
p_block->i_pts = p_ccs->current.b_reorder ? p_ccs->i_pts : p_ccs->i_dts;
p_block->i_flags = ( p_ccs->current.b_reorder ? p_ccs->i_flags : BLOCK_FLAG_TYPE_P ) & BLOCK_FLAG_TYPE_MASK;
}
cc_Flush( &p_ccs->current );
return p_block;
}
/****************************************************************************
* PacketizeXXC1: Takes VCL blocks of data and creates annexe B type NAL stream
......
......@@ -22,6 +22,21 @@
#include <vlc_common.h>
/* */
typedef struct cc_storage_t cc_storage_t;
cc_storage_t * cc_storage_new( void );
void cc_storage_delete( cc_storage_t *p_ccs );
void cc_storage_reset( cc_storage_t *p_ccs );
void cc_storage_append( cc_storage_t *p_ccs, bool b_top_field_first,
const uint8_t *p_buf, size_t i_buf );
void cc_storage_commit( cc_storage_t *p_ccs, block_t *p_pic );
block_t * cc_storage_get_current( cc_storage_t *p_ccs, bool pb_present[4] );
/* */
typedef block_t * (*pf_annexb_nal_packetizer)(decoder_t *, bool *, block_t *);
block_t *PacketizeXXC1( decoder_t *, uint8_t, block_t **, pf_annexb_nal_packetizer );
......
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