Commit 3d1ccaf4 authored by François Cartegnie's avatar François Cartegnie 🤞

packetizer: hevc: add broadcast support

Does reinject xps NAL on I Frame. Still not optimal
and duplicate prone, but that's what current
AVC muxer does.
parent 0457a2b2
......@@ -37,6 +37,7 @@
#include <vlc_block_helper.h>
#include "packetizer_helper.h"
#include "hevc_nal.h"
#include "hxxx_nal.h"
#include "hxxx_common.h"
/*****************************************************************************
......@@ -71,8 +72,14 @@ struct decoder_sys_t
packetizer_t packetizer;
block_t *p_frame;
block_t **pp_frame_last;
uint8_t i_nal_length_size;
block_t *rgi_p_vps[HEVC_VPS_MAX];
block_t *rgi_p_sps[HEVC_SPS_MAX];
block_t *rgi_p_pps[HEVC_PPS_MAX];
hevc_sequence_parameter_set_t *rgi_p_decsps[HEVC_SPS_MAX];
hevc_picture_parameter_set_t *rgi_p_decpps[HEVC_PPS_MAX];
};
static const uint8_t p_hevc_startcode[3] = {0x00, 0x00, 0x01};
......@@ -92,6 +99,8 @@ static int Open(vlc_object_t *p_this)
if (!p_dec->p_sys)
return VLC_ENOMEM;
p_sys->pp_frame_last = &p_sys->p_frame;
packetizer_Init(&p_dec->p_sys->packetizer,
p_hevc_startcode, sizeof(p_hevc_startcode),
p_hevc_startcode, 1, 5,
......@@ -126,6 +135,13 @@ static int Open(vlc_object_t *p_this)
}
p_dec->pf_flush = PacketizeFlush;
if(p_dec->fmt_out.i_extra)
{
/* Feed with AnnexB VPS/SPS/PPS/SEI extradata */
packetizer_Header(&p_sys->packetizer,
p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra);
}
return VLC_SUCCESS;
}
......@@ -138,6 +154,26 @@ static void Close(vlc_object_t *p_this)
decoder_sys_t *p_sys = p_dec->p_sys;
packetizer_Clean(&p_sys->packetizer);
for(unsigned i=0;i<HEVC_PPS_MAX; i++)
{
if(p_sys->rgi_p_pps[i])
block_Release(p_sys->rgi_p_pps[i]);
if(p_sys->rgi_p_decpps[i])
hevc_rbsp_release_pps(p_sys->rgi_p_decpps[i]);
}
for(unsigned i=0;i<HEVC_SPS_MAX; i++)
{
if(p_sys->rgi_p_sps[i])
block_Release(p_sys->rgi_p_sps[i]);
if(p_sys->rgi_p_decsps[i])
hevc_rbsp_release_sps(p_sys->rgi_p_decsps[i]);
}
for(unsigned i=0;i<HEVC_VPS_MAX; i++)
if(p_sys->rgi_p_vps[i])
block_Release(p_sys->rgi_p_vps[i]);
free(p_sys);
}
......@@ -178,6 +214,200 @@ static void PacketizeReset(void *p_private, bool b_broken)
block_ChainRelease(p_sys->p_frame);
p_sys->p_frame = NULL;
p_sys->pp_frame_last = &p_sys->p_frame;
}
static void InsertXPS(decoder_t *p_dec, uint8_t i_nal_type, uint8_t i_id,
block_t *p_nalb)
{
decoder_sys_t *p_sys = p_dec->p_sys;
block_t **pp_xps = NULL;
switch(i_nal_type)
{
case HEVC_NAL_VPS:
if(i_id < HEVC_VPS_MAX)
pp_xps = p_sys->rgi_p_vps;
break;
case HEVC_NAL_SPS:
if(i_id < HEVC_SPS_MAX)
pp_xps = p_sys->rgi_p_sps;
break;
case HEVC_NAL_PPS:
if(i_id < HEVC_PPS_MAX)
pp_xps = p_sys->rgi_p_pps;
break;
default: /* That shouln't happen */
return;
}
if(!pp_xps)
return;
if(pp_xps[i_id])
{
if( p_nalb->i_buffer != pp_xps[i_id]->i_buffer ||
!memcmp(pp_xps[i_id]->p_buffer, p_nalb->p_buffer,
__MIN(pp_xps[i_id]->i_buffer, p_nalb->i_buffer)) )
return;
block_Release(pp_xps[i_id]);
/* Free associated decoded version */
if(i_nal_type == HEVC_NAL_SPS && p_sys->rgi_p_decsps[i_id])
{
hevc_rbsp_release_sps(p_sys->rgi_p_decsps[i_id]);
p_sys->rgi_p_decsps[i_id] = NULL;
}
else if(i_nal_type == HEVC_NAL_PPS && p_sys->rgi_p_decpps[i_id])
{
hevc_rbsp_release_pps(p_sys->rgi_p_decpps[i_id]);
p_sys->rgi_p_decpps[i_id] = NULL;
}
}
pp_xps[i_id] = block_Duplicate(p_nalb);
if(pp_xps[i_id] && i_nal_type != HEVC_NAL_VPS)
{
const uint8_t *p_buffer = p_nalb->p_buffer;
size_t i_buffer = p_nalb->i_buffer;
if( hxxx_strip_AnnexB_startcode( &p_buffer, &i_buffer ) )
{
/* Create decoded entries */
if(i_nal_type == HEVC_NAL_SPS)
{
p_sys->rgi_p_decsps[i_id] = hevc_decode_sps(p_buffer, i_buffer, true);
if(!p_sys->rgi_p_decsps[i_id])
msg_Err(p_dec, "Failed decoding SPS id %d", i_id);
}
else if(i_nal_type == HEVC_NAL_PPS)
{
p_sys->rgi_p_decpps[i_id] = hevc_decode_pps(p_buffer, i_buffer, true);
if(!p_sys->rgi_p_decpps[i_id])
msg_Err(p_dec, "Failed decoding PPS id %d", i_id);
}
}
}
}
static block_t *CopyXPS(decoder_sys_t *p_sys)
{
block_t *p_chain = NULL;
block_t **p_chain_tail = &p_chain;
block_t *p_dup;
for(unsigned i=0;i<HEVC_VPS_MAX; i++)
{
if(p_sys->rgi_p_vps[i] && (p_dup = block_Duplicate(p_sys->rgi_p_vps[i])))
block_ChainLastAppend(&p_chain_tail, p_dup);
}
for(unsigned i=0;i<HEVC_SPS_MAX; i++)
{
if(p_sys->rgi_p_sps[i] && (p_dup = block_Duplicate(p_sys->rgi_p_sps[i])))
block_ChainLastAppend(&p_chain_tail, p_dup);
}
for(unsigned i=0;i<HEVC_PPS_MAX; i++)
{
if(p_sys->rgi_p_pps[i] && (p_dup = block_Duplicate(p_sys->rgi_p_pps[i])))
block_ChainLastAppend(&p_chain_tail, p_dup);
}
return p_chain;
}
static block_t *ParseVCL(decoder_t *p_dec, uint8_t i_nal_type, block_t *p_frag)
{
decoder_sys_t *p_sys = p_dec->p_sys;
block_t *p_frame = NULL;
const uint8_t *p_buffer = p_frag->p_buffer;
size_t i_buffer = p_frag->i_buffer;
if(unlikely(!hxxx_strip_AnnexB_startcode(&p_buffer, &i_buffer) || i_buffer < 7))
return NULL;
bool b_first_slice_in_pic = p_buffer[2] & 0x80;
if (b_first_slice_in_pic)
{
if(p_sys->p_frame)
{
/* Starting new frame, gather and return previous frame data */
p_frame = block_ChainGather(p_sys->p_frame);
p_sys->p_frame = NULL;
p_sys->pp_frame_last = &p_sys->p_frame;
}
switch(i_nal_type)
{
case HEVC_NAL_BLA_W_LP:
case HEVC_NAL_BLA_W_RADL:
case HEVC_NAL_BLA_N_LP:
case HEVC_NAL_IDR_W_RADL:
case HEVC_NAL_IDR_N_LP:
case HEVC_NAL_CRA:
p_frag->i_flags |= BLOCK_FLAG_TYPE_I;
break;
default:
{
hevc_slice_segment_header_t *p_sli = hevc_decode_slice_header( p_buffer, i_buffer, true,
p_sys->rgi_p_decsps, p_sys->rgi_p_decpps );
if( p_sli )
{
enum hevc_slice_type_e type;
if( hevc_get_slice_type( p_sli, &type ) )
{
if( type == HEVC_SLICE_TYPE_P )
p_frag->i_flags |= BLOCK_FLAG_TYPE_P;
else
p_frag->i_flags |= BLOCK_FLAG_TYPE_B;
}
hevc_rbsp_release_slice_header( p_sli );
}
}
break;
}
}
if( p_frag->i_flags & BLOCK_FLAG_TYPE_I )
{
block_t *p_header = CopyXPS(p_sys);
if(p_header)
block_ChainLastAppend(&p_sys->pp_frame_last, p_header);
}
block_ChainLastAppend(&p_sys->pp_frame_last, p_frag);
return p_frame;
}
static block_t *ParseNonVCL(decoder_t *p_dec, uint8_t i_nal_type, block_t *p_nalb)
{
block_t *p_ret = p_nalb;
switch(i_nal_type)
{
case HEVC_NAL_VPS:
case HEVC_NAL_SPS:
case HEVC_NAL_PPS:
{
uint8_t i_id;
if( hevc_get_xps_id(p_nalb->p_buffer, p_nalb->i_buffer, &i_id) )
InsertXPS(p_dec, i_nal_type, i_id, p_nalb);
block_Release( p_nalb );
p_ret = NULL;
}
break;
case HEVC_NAL_AUD:
case HEVC_NAL_EOS:
case HEVC_NAL_EOB:
case HEVC_NAL_FD:
break;
}
return p_ret;
}
/*****************************************************************************
......@@ -188,7 +418,7 @@ static block_t *ParseNALBlock(decoder_t *p_dec, bool *pb_ts_used, block_t *p_fra
{
decoder_sys_t *p_sys = p_dec->p_sys;
block_t * p_nal = NULL;
block_t * p_ret = NULL;
if(unlikely(p_frag->i_buffer < 5))
{
......@@ -203,39 +433,35 @@ static block_t *ParseNALBlock(decoder_t *p_dec, bool *pb_ts_used, block_t *p_fra
block_ChainRelease(p_sys->p_frame);
block_Release(p_frag);
p_sys->p_frame = NULL;
p_sys->pp_frame_last = &p_sys->p_frame;
return NULL;
}
/* Get NALU type */
uint8_t nalu_type = ((p_frag->p_buffer[4] & 0x7E) >> 1);
if (nalu_type < HEVC_NAL_VPS)
uint8_t i_nal_type = ((p_frag->p_buffer[4] & 0x7E) >> 1);
if (i_nal_type < HEVC_NAL_VPS)
{
/* NAL is a VCL NAL */
if(likely(p_frag->i_buffer > 6))
{
bool first_slice_in_pic = p_frag->p_buffer[6] & 0x80;
if (first_slice_in_pic && p_sys->p_frame)
{
p_nal = block_ChainGather(p_sys->p_frame);
p_sys->p_frame = NULL;
}
}
block_ChainAppend(&p_sys->p_frame, p_frag);
p_ret = ParseVCL(p_dec, i_nal_type, p_frag);
}
else
{
p_ret = ParseNonVCL(p_dec, i_nal_type, p_frag);
if (p_sys->p_frame)
{
p_nal = block_ChainGather(p_sys->p_frame);
p_nal->p_next = p_frag;
p_sys->p_frame = NULL;
p_frag = p_ret;
if( (p_ret = block_ChainGather(p_sys->p_frame)) )
{
p_sys->p_frame = NULL;
p_sys->pp_frame_last = &p_sys->p_frame;
p_ret->p_next = p_frag;
}
else p_ret = p_frag;
}
else
p_nal = p_frag;
}
*pb_ts_used = false;
return p_nal;
return p_ret;
}
static block_t *PacketizeParse(void *p_private, bool *pb_ts_used, block_t *p_block)
......
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