This source file includes following definitions.
- gf_rtp_build_au_hdr_size
- gf_rtp_build_au_hdr_write
- gp_rtp_builder_do_mpeg4
- gp_rtp_builder_do_avc
- gp_rtp_builder_do_hevc
- latm_flush
- gp_rtp_builder_do_latm
#include <gpac/internal/ietf_dev.h>
#ifndef GPAC_DISABLE_STREAMING
#include <gpac/constants.h>
static u32 gf_rtp_build_au_hdr_size(GP_RTPPacketizer *builder, GF_SLHeader *slh)
{
u32 nbBits = 0;
if (builder->flags & GP_RTP_PCK_SELECTIVE_ENCRYPTION) nbBits += 8;
nbBits += builder->first_sl_in_rtp ? 8*builder->slMap.IV_length : 8*builder->slMap.IV_delta_length;
if (builder->first_sl_in_rtp || (builder->flags & GP_RTP_PCK_KEY_IDX_PER_AU)) {
nbBits += 8*builder->slMap.KI_length;
}
if (!slh) {
if (!builder->slMap.ConstantSize) nbBits += builder->slMap.SizeLength;
nbBits += builder->first_sl_in_rtp ? builder->slMap.IndexLength : builder->slMap.IndexDeltaLength;
if (builder->slMap.CTSDeltaLength) {
nbBits += 1;
if (!builder->first_sl_in_rtp) nbBits += builder->slMap.CTSDeltaLength;
}
if (builder->slMap.DTSDeltaLength) nbBits += 1 + builder->slMap.DTSDeltaLength;
if (builder->flags & GP_RTP_PCK_SELECTIVE_ENCRYPTION) nbBits += 8;
return nbBits;
}
if (!builder->slMap.ConstantSize) nbBits += builder->slMap.SizeLength;
if (builder->first_sl_in_rtp) {
if (builder->slMap.IndexLength) nbBits += builder->slMap.IndexLength;
} else {
if (builder->slMap.IndexDeltaLength) nbBits += builder->slMap.IndexDeltaLength;
}
if (builder->slMap.CTSDeltaLength) {
if (builder->first_sl_in_rtp) slh->compositionTimeStampFlag = 0;
nbBits += 1;
} else {
slh->compositionTimeStampFlag = 0;
}
if (slh->compositionTimeStampFlag) nbBits += builder->slMap.CTSDeltaLength;
if (builder->slMap.DTSDeltaLength) {
nbBits += 1;
} else {
slh->decodingTimeStampFlag = 0;
}
if (slh->decodingTimeStampFlag) nbBits += builder->slMap.DTSDeltaLength;
if (builder->slMap.RandomAccessIndication) nbBits ++;
nbBits += builder->slMap.StreamStateIndication;
return nbBits;
}
u32 gf_rtp_build_au_hdr_write(GP_RTPPacketizer *builder, u32 PayloadSize, u32 RTP_TS)
{
u32 nbBits = 0;
s32 delta;
if (builder->flags & GP_RTP_PCK_SELECTIVE_ENCRYPTION) {
gf_bs_write_int(builder->pck_hdr, builder->is_encrypted, 1);
gf_bs_write_int(builder->pck_hdr, 0, 7);
nbBits = 8;
}
if (builder->first_sl_in_rtp) {
if (builder->slMap.IV_length) {
gf_bs_write_long_int(builder->pck_hdr, builder->IV, 8*builder->slMap.IV_length);
nbBits += 8*builder->slMap.IV_length;
}
} else if (builder->slMap.IV_delta_length) {
}
if (builder->slMap.KI_length) {
if (builder->first_sl_in_rtp || (builder->flags & GP_RTP_PCK_KEY_IDX_PER_AU)) {
if (builder->key_indicator) gf_bs_write_data(builder->pck_hdr, builder->key_indicator, builder->slMap.KI_length);
else gf_bs_write_int(builder->pck_hdr, 0, 8*builder->slMap.KI_length);
nbBits += 8*builder->slMap.KI_length;
}
}
if (builder->slMap.ConstantSize) {
if (PayloadSize != builder->slMap.ConstantSize) return nbBits;
} else if (builder->slMap.SizeLength) {
if (builder->sl_header.accessUnitLength >= (1<<builder->slMap.SizeLength)) {
gf_bs_write_int(builder->pck_hdr, 0, builder->slMap.SizeLength);
} else {
gf_bs_write_int(builder->pck_hdr, builder->sl_header.accessUnitLength, builder->slMap.SizeLength);
}
nbBits += builder->slMap.SizeLength;
}
if (builder->first_sl_in_rtp) {
if (builder->slMap.IndexLength) {
gf_bs_write_int(builder->pck_hdr, builder->sl_header.AU_sequenceNumber, builder->slMap.IndexLength);
nbBits += builder->slMap.IndexLength;
}
} else {
if (builder->slMap.IndexDeltaLength) {
delta = builder->sl_header.AU_sequenceNumber - builder->last_au_sn;
delta -= 1;
gf_bs_write_int(builder->pck_hdr, delta, builder->slMap.IndexDeltaLength);
nbBits += builder->slMap.IndexDeltaLength;
}
}
if (builder->slMap.CTSDeltaLength) {
if (builder->first_sl_in_rtp) {
builder->sl_header.compositionTimeStampFlag = 0;
builder->sl_header.compositionTimeStamp = RTP_TS;
}
gf_bs_write_int(builder->pck_hdr, builder->sl_header.compositionTimeStampFlag, 1);
nbBits += 1;
}
if (builder->sl_header.compositionTimeStampFlag) {
delta = (u32) builder->sl_header.compositionTimeStamp - RTP_TS;
gf_bs_write_int(builder->pck_hdr, delta, builder->slMap.CTSDeltaLength);
nbBits += builder->slMap.CTSDeltaLength;
}
if (builder->slMap.DTSDeltaLength) {
gf_bs_write_int(builder->pck_hdr, builder->sl_header.decodingTimeStampFlag, 1);
nbBits += 1;
}
if (builder->sl_header.decodingTimeStampFlag) {
delta = (u32) (builder->sl_header.compositionTimeStamp - builder->sl_header.decodingTimeStamp);
gf_bs_write_int(builder->pck_hdr, delta, builder->slMap.DTSDeltaLength);
nbBits += builder->slMap.DTSDeltaLength;
}
if (builder->slMap.RandomAccessIndication) {
gf_bs_write_int(builder->pck_hdr, builder->sl_header.randomAccessPointFlag, 1);
nbBits ++;
}
if (builder->slMap.StreamStateIndication) {
gf_bs_write_int(builder->pck_hdr, builder->sl_header.AU_sequenceNumber, builder->slMap.StreamStateIndication);
nbBits += builder->slMap.StreamStateIndication;
}
return nbBits;
}
GF_Err gp_rtp_builder_do_mpeg4(GP_RTPPacketizer *builder, char *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
{
char *sl_buffer, *payl_buffer;
u32 sl_buffer_size, payl_buffer_size;
u32 auh_size_tmp, bytesLeftInPacket, infoSize, pckSize;
u64 pos;
u8 flush_pck, no_split;
flush_pck = 0;
bytesLeftInPacket = data_size;
if (!data) {
if (builder->payload) goto flush_packet;
return GF_OK;
}
if (builder->payload && builder->force_flush) goto flush_packet;
while (bytesLeftInPacket) {
no_split = 0;
if (builder->sl_header.accessUnitStartFlag) {
if (builder->sl_header.compositionTimeStamp != builder->sl_header.decodingTimeStamp) {
builder->sl_header.decodingTimeStampFlag = 1;
}
builder->sl_header.compositionTimeStampFlag = 1;
builder->sl_header.accessUnitLength = FullAUSize;
if (builder->payload) {
if ( (builder->flags & GP_RTP_PCK_SIGNAL_TS)
&& (builder->sl_header.compositionTimeStamp - builder->rtp_header.TimeStamp >= (u32) ( 1 << builder->slMap.CTSDeltaLength) ) ) {
goto flush_packet;
}
if (builder->sl_header.compositionTimeStamp != builder->rtp_header.TimeStamp)
no_split = 1;
}
}
if (!builder->payload) {
builder->first_sl_in_rtp = GF_TRUE;
builder->rtp_header.Marker = 1;
builder->rtp_header.PayloadType = builder->PayloadType;
builder->rtp_header.SequenceNumber += 1;
builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
builder->pck_hdr = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
builder->payload = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
builder->bytesInPacket = 0;
builder->auh_size = 0;
if (builder->has_AU_header) {
builder->auh_size = 16;
gf_bs_write_int(builder->pck_hdr, 0, 16);
}
flush_pck = 0;
builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
}
if (builder->slMap.IndexDeltaLength
&& !builder->first_sl_in_rtp
&& (builder->sl_header.AU_sequenceNumber - builder->last_au_sn >= (u32) 1<<builder->slMap.IndexDeltaLength)) {
goto flush_packet;
}
if (builder->max_ptime && ( (u32) builder->sl_header.compositionTimeStamp >= builder->rtp_header.TimeStamp + builder->max_ptime) )
goto flush_packet;
auh_size_tmp = gf_rtp_build_au_hdr_size(builder, &builder->sl_header);
infoSize = auh_size_tmp + builder->auh_size;
infoSize /= 8;
if ( (builder->auh_size + auh_size_tmp) % 8) infoSize += 1;
if (bytesLeftInPacket + infoSize + builder->bytesInPacket <= builder->Path_MTU) {
pckSize = bytesLeftInPacket;
builder->sl_header.accessUnitEndFlag = IsAUEnd;
builder->auh_size += auh_size_tmp;
builder->sl_header.paddingFlag = builder->sl_header.paddingBits ? 1 : 0;
} else {
if (no_split) goto flush_packet;
builder->auh_size += auh_size_tmp;
pckSize = builder->Path_MTU - (infoSize + builder->bytesInPacket);
flush_pck = 1;
builder->rtp_header.Marker = 0;
}
gf_rtp_build_au_hdr_write(builder, pckSize, builder->rtp_header.TimeStamp);
if (builder->OnDataReference)
builder->OnDataReference(builder->cbk_obj, pckSize, data_size - bytesLeftInPacket);
else
gf_bs_write_data(builder->payload, data + (data_size - bytesLeftInPacket), pckSize);
bytesLeftInPacket -= pckSize;
builder->bytesInPacket += pckSize;
builder->IV += pckSize;
builder->sl_header.paddingFlag = 0;
builder->sl_header.accessUnitStartFlag = 0;
if (bytesLeftInPacket) {
builder->sl_header.packetSequenceNumber += 1;
} else if (! (builder->flags & GP_RTP_PCK_USE_MULTI) ) {
builder->rtp_header.Marker = 1;
flush_pck = 1;
}
builder->first_sl_in_rtp = GF_FALSE;
builder->last_au_sn = builder->sl_header.AU_sequenceNumber;
if (!flush_pck) continue;
flush_packet:
gf_bs_align(builder->pck_hdr);
if (builder->slMap.AuxiliaryDataSizeLength) {
gf_bs_write_int(builder->pck_hdr, 0, builder->slMap.AuxiliaryDataSizeLength);
}
if (builder->has_AU_header) {
pos = gf_bs_get_position(builder->pck_hdr);
gf_bs_seek(builder->pck_hdr, 0);
builder->auh_size -= 16;
gf_bs_write_int(builder->pck_hdr, builder->auh_size, 16);
gf_bs_seek(builder->pck_hdr, pos);
}
sl_buffer = NULL;
gf_bs_get_content(builder->pck_hdr, &sl_buffer, &sl_buffer_size);
gf_bs_del(builder->pck_hdr);
builder->pck_hdr = NULL;
payl_buffer = NULL;
payl_buffer_size = 0;
if (!builder->OnDataReference)
gf_bs_get_content(builder->payload, &payl_buffer, &payl_buffer_size);
gf_bs_del(builder->payload);
builder->payload = NULL;
builder->OnData(builder->cbk_obj, sl_buffer, sl_buffer_size, GF_TRUE);
if (payl_buffer) {
builder->OnData(builder->cbk_obj, payl_buffer, payl_buffer_size, GF_FALSE);
gf_free(payl_buffer);
}
builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
gf_free(sl_buffer);
}
if (IsAUEnd) {
builder->sl_header.accessUnitStartFlag = 1;
builder->sl_header.accessUnitEndFlag = 0;
}
return GF_OK;
}
GF_Err gp_rtp_builder_do_avc(GP_RTPPacketizer *builder, char *nalu, u32 nalu_size, u8 IsAUEnd, u32 FullAUSize)
{
u32 do_flush, bytesLeft, size, nal_type;
char shdr[2];
char stap_hdr;
do_flush = 0;
if (!nalu) do_flush = 1;
else if (builder->sl_header.accessUnitStartFlag) do_flush = 1;
else if (builder->bytesInPacket + nalu_size >= builder->Path_MTU) do_flush = 2;
else if (! (builder->flags & GP_RTP_PCK_USE_MULTI) ) do_flush = 2;
if (builder->bytesInPacket && do_flush) {
builder->rtp_header.Marker = (do_flush==1) ? 1 : 0;
builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
builder->bytesInPacket = 0;
}
if (!nalu) return GF_OK;
if (!builder->bytesInPacket) {
builder->rtp_header.PayloadType = builder->PayloadType;
builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
builder->rtp_header.SequenceNumber += 1;
builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
builder->avc_non_idr = GF_TRUE;
}
nal_type = nalu[0] & 0x1F;
switch (nal_type) {
case GF_AVC_NALU_NON_IDR_SLICE:
case GF_AVC_NALU_ACCESS_UNIT:
case GF_AVC_NALU_END_OF_SEQ:
case GF_AVC_NALU_END_OF_STREAM:
case GF_AVC_NALU_FILLER_DATA:
break;
default:
builder->avc_non_idr = GF_FALSE;
break;
}
if (builder->bytesInPacket+nalu_size<builder->Path_MTU) {
Bool use_stap = GF_TRUE;
if (IsAUEnd && !builder->bytesInPacket) use_stap = GF_FALSE;
if (use_stap) {
if (!builder->bytesInPacket) {
stap_hdr = (nalu[0] & 0xE0) | 24;
builder->OnData(builder->cbk_obj, (char *) &stap_hdr, 1, GF_FALSE);
builder->bytesInPacket = 1;
}
shdr[0] = nalu_size>>8;
shdr[1] = nalu_size&0x00ff;
builder->OnData(builder->cbk_obj, (char *)shdr, 2, GF_FALSE);
builder->bytesInPacket += 2;
}
if (builder->OnDataReference)
builder->OnDataReference(builder->cbk_obj, nalu_size, 0);
else
builder->OnData(builder->cbk_obj, nalu, nalu_size, GF_FALSE);
builder->bytesInPacket += nalu_size;
if (IsAUEnd) {
builder->rtp_header.Marker = 1;
builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
builder->bytesInPacket = 0;
}
}
else {
u32 offset;
assert(nalu_size>=builder->Path_MTU);
assert(!builder->bytesInPacket);
bytesLeft = nalu_size - 1;
offset = 1;
while (bytesLeft) {
if (2 + bytesLeft > builder->Path_MTU) {
size = builder->Path_MTU - 2;
} else {
size = bytesLeft;
}
shdr[0] = (nalu[0] & 0xE0) | 28;
shdr[1] = (nalu[0] & 0x1F);
if (offset==1) shdr[1] |= 0x80;
else if (size == bytesLeft) shdr[1] |= 0x40;
builder->OnData(builder->cbk_obj, (char *)shdr, 2, GF_FALSE);
if (builder->OnDataReference)
builder->OnDataReference(builder->cbk_obj, size, offset);
else
builder->OnData(builder->cbk_obj, nalu+offset, size, GF_FALSE);
offset += size;
bytesLeft -= size;
builder->rtp_header.Marker = (IsAUEnd && !bytesLeft) ? 1 : 0;
builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
builder->bytesInPacket = 0;
if (bytesLeft) {
builder->rtp_header.PayloadType = builder->PayloadType;
builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
builder->rtp_header.SequenceNumber += 1;
builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
}
}
}
return GF_OK;
}
GF_Err gp_rtp_builder_do_hevc(GP_RTPPacketizer *builder, char *nalu, u32 nalu_size, u8 IsAUEnd, u32 FullAUSize)
{
u32 do_flush, bytesLeft, size;
do_flush = 0;
if (!nalu) do_flush = 1;
else if (builder->sl_header.accessUnitStartFlag) do_flush = 1;
else if (builder->bytesInPacket + nalu_size + 4 >= builder->Path_MTU) do_flush = 2;
else if (! (builder->flags & GP_RTP_PCK_USE_MULTI) ) do_flush = 2;
if (builder->bytesInPacket && do_flush) {
builder->rtp_header.Marker = (do_flush==1) ? 1 : 0;
if (strlen(builder->hevc_payload_hdr)) {
builder->OnData(builder->cbk_obj, (char *)builder->hevc_payload_hdr, 2, GF_TRUE);
memset(builder->hevc_payload_hdr, 0, 2);
}
builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
builder->bytesInPacket = 0;
}
if (!nalu) return GF_OK;
if (!builder->bytesInPacket) {
builder->rtp_header.PayloadType = builder->PayloadType;
builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
builder->rtp_header.SequenceNumber += 1;
builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
}
if (builder->bytesInPacket+nalu_size+4 < builder->Path_MTU) {
Bool use_AP = (builder->flags & GP_RTP_PCK_USE_MULTI) ? GF_TRUE : GF_FALSE;
if (IsAUEnd && !builder->bytesInPacket) use_AP = GF_FALSE;
if (use_AP) {
char nal_s[2];
if (!builder->bytesInPacket) {
builder->hevc_payload_hdr[0] = (nalu[0] & 0x81) | (48 << 1);
builder->hevc_payload_hdr[1] = nalu[1];
}
else {
u8 cur_LayerId, cur_TID, new_LayerId, new_TID;
builder->hevc_payload_hdr[0] |= (nalu[0] & 0x80);
cur_LayerId = ((builder->hevc_payload_hdr[0] & 0x01) << 5) + ((builder->hevc_payload_hdr[1] & 0xF8) >> 3);
new_LayerId = ((nalu[0] & 0x01) << 5) + ((nalu[1] & 0xF8) >> 3);
if (cur_LayerId > new_LayerId) {
builder->hevc_payload_hdr[0] = (builder->hevc_payload_hdr[0] & 0xFE) | (nalu[0] & 0x01);
builder->hevc_payload_hdr[1] = (builder->hevc_payload_hdr[1] & 0x07) | (nalu[1] & 0xF8);
}
cur_TID = builder->hevc_payload_hdr[1] & 0x07;
new_TID = nalu[1] & 0x07;
if (cur_TID > new_TID) {
builder->hevc_payload_hdr[1] = (builder->hevc_payload_hdr[1] & 0xF8) | (nalu[1] & 0x07);
}
}
nal_s[0] = nalu_size>>8;
nal_s[1] = nalu_size&0x00ff;
builder->OnData(builder->cbk_obj, (char *)nal_s, 2, GF_FALSE);
builder->bytesInPacket += 2;
}
if (builder->OnDataReference)
builder->OnDataReference(builder->cbk_obj, nalu_size, 0);
else
builder->OnData(builder->cbk_obj, nalu, nalu_size, GF_FALSE);
builder->bytesInPacket += nalu_size;
if (IsAUEnd) {
builder->rtp_header.Marker = 1;
if (strlen(builder->hevc_payload_hdr)) {
builder->OnData(builder->cbk_obj, (char *)builder->hevc_payload_hdr, 2, GF_TRUE);
memset(builder->hevc_payload_hdr, 0, 2);
}
builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
builder->bytesInPacket = 0;
}
}
else {
u32 offset;
char payload_hdr[2];
char shdr;
assert(nalu_size + 4 >=builder->Path_MTU);
assert(!builder->bytesInPacket);
bytesLeft = nalu_size - 2;
offset = 2;
while (bytesLeft) {
if (3 + bytesLeft > builder->Path_MTU) {
size = builder->Path_MTU - 3;
} else {
size = bytesLeft;
}
memset(payload_hdr, 0, 2);
payload_hdr[0] = (nalu[0] & 0x81) | (49 << 1);
payload_hdr[1] = nalu[1];
builder->OnData(builder->cbk_obj, (char *)payload_hdr, 2, GF_FALSE);
shdr = 0;
shdr |= (nalu[0] & 0x7E) >> 1;
if (offset==2) shdr |= 0x80;
else if (size == bytesLeft) shdr |= 0x40;
builder->OnData(builder->cbk_obj, &shdr, 1, GF_FALSE);
if (builder->OnDataReference)
builder->OnDataReference(builder->cbk_obj, size, offset);
else
builder->OnData(builder->cbk_obj, nalu+offset, size, GF_FALSE);
offset += size;
bytesLeft -= size;
builder->rtp_header.Marker = (IsAUEnd && !bytesLeft) ? 1 : 0;
builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
builder->bytesInPacket = 0;
if (bytesLeft) {
builder->rtp_header.PayloadType = builder->PayloadType;
builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
builder->rtp_header.SequenceNumber += 1;
builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
}
}
}
return GF_OK;
}
void latm_flush(GP_RTPPacketizer *builder)
{
if (builder->bytesInPacket) {
builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
builder->bytesInPacket = 0;
}
builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
}
GF_Err gp_rtp_builder_do_latm(GP_RTPPacketizer *builder, char *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize, u32 duration)
{
u32 size, latm_hdr_size, i, data_offset;
Bool fragmented;
unsigned char *latm_hdr;
if (!data) {
latm_flush(builder);
return GF_OK;
}
if ((builder->flags & GP_RTP_PCK_USE_MULTI) && builder->max_ptime) {
if ((u32) builder->sl_header.compositionTimeStamp + duration >= builder->rtp_header.TimeStamp + builder->max_ptime)
latm_flush(builder);
}
latm_hdr_size = (data_size / 255) + 1;
if (latm_hdr_size+data_size > builder->Path_MTU - builder->bytesInPacket) {
latm_flush(builder);
}
data_offset = 0;
fragmented = GF_FALSE;
while (data_size > 0) {
latm_hdr_size = (data_size / 255) + 1;
if (latm_hdr_size + data_size > builder->Path_MTU) {
assert(!builder->bytesInPacket);
fragmented = GF_TRUE;
latm_hdr_size = (builder->Path_MTU / 255) + 1;
size = builder->Path_MTU - latm_hdr_size;
builder->rtp_header.Marker = 0;
}
else {
fragmented = GF_FALSE;
size = data_size;
builder->rtp_header.Marker = 1;
}
data_size -= size;
if (!builder->bytesInPacket) {
builder->rtp_header.SequenceNumber += 1;
builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
}
latm_hdr_size = (size / 255) + 1;
latm_hdr = (unsigned char *)gf_malloc( sizeof(char) * latm_hdr_size);
for (i=0; i<latm_hdr_size-1; i++) latm_hdr[i] = 255;
latm_hdr[latm_hdr_size-1] = size % 255;
builder->OnData(builder->cbk_obj, (char*) latm_hdr, latm_hdr_size, GF_FALSE);
builder->bytesInPacket += latm_hdr_size;
gf_free(latm_hdr);
if (builder->OnDataReference) {
builder->OnDataReference(builder->cbk_obj, size, data_offset);
} else
builder->OnData(builder->cbk_obj, data, size, GF_FALSE);
builder->bytesInPacket += size;
data_offset += size;
if (!builder->rtp_header.Marker) latm_flush(builder);
}
if (! (builder->flags & GP_RTP_PCK_USE_MULTI) ) fragmented = GF_TRUE;
if (fragmented) latm_flush(builder);
return GF_OK;
}
#endif