This source file includes following definitions.
- ghnt_New
- ghnt_del
- ghnt_Read
- ghnt_Write
- ghnt_Size
- gf_isom_hint_sample_new
- gf_isom_hint_sample_del
- gf_isom_hint_sample_read
- gf_isom_hint_sample_write
- gf_isom_hint_sample_size
- gf_isom_hint_pck_new
- gf_isom_hint_pck_del
- gf_isom_hint_pck_read
- gf_isom_hint_pck_write
- gf_isom_hint_pck_size
- gf_isom_hint_pck_offset
- gf_isom_hint_pck_add_dte
- gf_isom_hint_pck_length
- New_EmptyDTE
- New_ImmediateDTE
- New_SampleDTE
- New_StreamDescDTE
- NewDTE
- Del_EmptyDTE
- Del_ImmediateDTE
- Del_SampleDTE
- Del_StreamDescDTE
- DelDTE
- Read_EmptyDTE
- Read_ImmediateDTE
- Read_SampleDTE
- Read_StreamDescDTE
- ReadDTE
- Write_EmptyDTE
- Write_ImmediateDTE
- Write_SampleDTE
- Write_StreamDescDTE
- WriteDTE
- OffsetDTE
- gf_isom_hint_rtp_new
- gf_isom_hint_rtp_del
- gf_isom_hint_rtp_read
- gf_isom_hint_rtp_offset
- gf_isom_hint_rtp_length
- gf_isom_hint_rtp_size
- gf_isom_hint_rtp_write
- gf_isom_hint_rtcp_new
- gf_isom_hint_rtcp_del
- gf_isom_hint_rtcp_read
- gf_isom_hint_rtcp_length
- gf_isom_hint_rtcp_size
- gf_isom_hint_rtcp_write
- gf_isom_reset_hint_reader
- gf_isom_load_next_hint_sample
- gf_isom_get_data_sample
- gf_isom_next_hint_packet
#include <gpac/internal/isomedia_dev.h>
#if !defined(GPAC_DISABLE_ISOM) && !defined(GPAC_DISABLE_ISOM_HINTING)
GF_Box *ghnt_New()
{
GF_HintSampleEntryBox *tmp;
GF_SAFEALLOC(tmp, GF_HintSampleEntryBox);
if (tmp == NULL) return NULL;
tmp->type = GF_ISOM_BOX_TYPE_GHNT;
tmp->HintTrackVersion = 1;
tmp->LastCompatibleVersion = 1;
return (GF_Box *)tmp;
}
void ghnt_del(GF_Box *s)
{
GF_HintSampleEntryBox *ptr;
ptr = (GF_HintSampleEntryBox *)s;
if (ptr->hint_sample) gf_isom_hint_sample_del(ptr->hint_sample);
gf_free(ptr);
}
GF_Err ghnt_Read(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
GF_HintSampleEntryBox *ptr = (GF_HintSampleEntryBox *)s;
if (ptr == NULL) return GF_BAD_PARAM;
if (ptr->size < 16) return GF_ISOM_INVALID_FILE;
e = gf_isom_base_sample_entry_read((GF_SampleEntryBox *)ptr, bs);
if (e) return e;
ptr->HintTrackVersion = gf_bs_read_u16(bs);
ptr->LastCompatibleVersion = gf_bs_read_u16(bs);
ptr->size -= 12;
if ((s->type == GF_ISOM_BOX_TYPE_RTP_STSD) || (s->type == GF_ISOM_BOX_TYPE_SRTP_STSD) || (s->type == GF_ISOM_BOX_TYPE_RRTP_STSD) || (s->type == GF_ISOM_BOX_TYPE_RTCP_STSD)) {
ptr->MaxPacketSize = gf_bs_read_u32(bs);
ptr->size -= 4;
} else if (s->type == GF_ISOM_BOX_TYPE_FDP_STSD) {
ptr->partition_entry_ID = gf_bs_read_u16(bs);
ptr->FEC_overhead = gf_bs_read_u16(bs);
ptr->size -= 4;
}
return gf_isom_box_array_read(s, bs, gf_isom_box_add_default);
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err ghnt_Write(GF_Box *s, GF_BitStream *bs)
{
GF_Err e;
GF_HintSampleEntryBox *ptr = (GF_HintSampleEntryBox *)s;
e = gf_isom_box_write_header(s, bs);
if (e) return e;
gf_bs_write_data(bs, ptr->reserved, 6);
gf_bs_write_u16(bs, ptr->dataReferenceIndex);
gf_bs_write_u16(bs, ptr->HintTrackVersion);
gf_bs_write_u16(bs, ptr->LastCompatibleVersion);
gf_bs_write_u32(bs, ptr->MaxPacketSize);
return GF_OK;
}
GF_Err ghnt_Size(GF_Box *s)
{
GF_HintSampleEntryBox *ptr = (GF_HintSampleEntryBox *)s;
ptr->size += 16;
return GF_OK;
}
#endif
GF_HintSample *gf_isom_hint_sample_new(u32 ProtocolType)
{
GF_HintSample *tmp;
switch (ProtocolType) {
case GF_ISOM_BOX_TYPE_RTP_STSD:
case GF_ISOM_BOX_TYPE_SRTP_STSD:
case GF_ISOM_BOX_TYPE_RRTP_STSD:
case GF_ISOM_BOX_TYPE_RTCP_STSD:
break;
case GF_ISOM_BOX_TYPE_FDP_STSD:
return (GF_HintSample *) gf_isom_box_new(GF_ISOM_BOX_TYPE_FDSA);
break;
default:
return NULL;
}
GF_SAFEALLOC(tmp, GF_HintSample);
if (!tmp) return NULL;
tmp->packetTable = gf_list_new();
tmp->hint_subtype = ProtocolType;
return tmp;
}
void gf_isom_hint_sample_del(GF_HintSample *ptr)
{
GF_HintPacket *pck;
if (ptr->hint_subtype==GF_ISOM_BOX_TYPE_FDP_STSD) {
gf_isom_box_del((GF_Box*)ptr);
return;
}
while (gf_list_count(ptr->packetTable)) {
pck = (GF_HintPacket *)gf_list_get(ptr->packetTable, 0);
gf_isom_hint_pck_del(pck);
gf_list_rem(ptr->packetTable, 0);
}
gf_list_del(ptr->packetTable);
if (ptr->AdditionalData) gf_free(ptr->AdditionalData);
if (ptr->sample_cache) {
while (gf_list_count(ptr->sample_cache)) {
GF_HintDataCache *hdc = (GF_HintDataCache *)gf_list_get(ptr->sample_cache, 0);
gf_list_rem(ptr->sample_cache, 0);
if (hdc->samp) gf_isom_sample_del(&hdc->samp);
gf_free(hdc);
}
gf_list_del(ptr->sample_cache);
}
if (ptr->extra_data)
gf_isom_box_del((GF_Box*)ptr->extra_data);
if (ptr->other_boxes)
gf_isom_box_array_del(ptr->other_boxes);
gf_free(ptr);
}
GF_Err gf_isom_hint_sample_read(GF_HintSample *ptr, GF_BitStream *bs, u32 sampleSize)
{
u16 i;
u32 type;
GF_HintPacket *pck;
GF_Err e;
char *szName = (ptr->hint_subtype==GF_ISOM_BOX_TYPE_RTCP_STSD) ? "RTCP" : "RTP";
u64 sizeIn, sizeOut;
sizeIn = gf_bs_available(bs);
switch (ptr->hint_subtype) {
case GF_ISOM_BOX_TYPE_RTP_STSD:
case GF_ISOM_BOX_TYPE_SRTP_STSD:
case GF_ISOM_BOX_TYPE_RRTP_STSD:
case GF_ISOM_BOX_TYPE_RTCP_STSD:
break;
case GF_ISOM_BOX_TYPE_FDP_STSD:
ptr->size = gf_bs_read_u32(bs);
type = gf_bs_read_u32(bs);
if (type != GF_ISOM_BOX_TYPE_FDSA) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso] invalid FDT sample, top box type %s not fdsa\n", gf_4cc_to_str(type) ));
return GF_ISOM_INVALID_MEDIA;
}
return gf_isom_box_read((GF_Box*)ptr, bs);
default:
return GF_NOT_SUPPORTED;
}
ptr->packetCount = gf_bs_read_u16(bs);
ptr->reserved = gf_bs_read_u16(bs);
if (ptr->packetCount>=sampleSize) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso] broken %s sample: %d packet_count indicated but only %d bytes in samples\n", szName, ptr->packetCount, sampleSize));
return GF_ISOM_INVALID_MEDIA;
}
for (i = 0; i < ptr->packetCount; i++) {
if (! gf_bs_available(bs) ) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso] %s hint sample has no more data but still %d entries to read\n", szName, ptr->packetCount-i));
return GF_ISOM_INVALID_MEDIA;
}
pck = gf_isom_hint_pck_new(ptr->hint_subtype);
pck->trackID = ptr->trackID;
pck->sampleNumber = ptr->sampleNumber;
gf_list_add(ptr->packetTable, pck);
e = gf_isom_hint_pck_read(pck, bs);
if (e) return e;
}
if (ptr->hint_subtype==GF_ISOM_BOX_TYPE_RTCP_STSD) return GF_OK;
sizeOut = gf_bs_available(bs) - sizeIn;
if ((u32)sizeOut < sampleSize) {
ptr->dataLength = sampleSize - (u32)sizeOut;
ptr->AdditionalData = (char*)gf_malloc(sizeof(char) * ptr->dataLength);
gf_bs_read_data(bs, ptr->AdditionalData, ptr->dataLength);
}
return GF_OK;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err gf_isom_hint_sample_write(GF_HintSample *ptr, GF_BitStream *bs)
{
u32 count, i;
GF_HintPacket *pck;
GF_Err e;
if (ptr->hint_subtype==GF_ISOM_BOX_TYPE_FDP_STSD) {
e = gf_isom_box_size((GF_Box*)ptr);
if (!e) e = gf_isom_box_write((GF_Box*)ptr, bs);
return e;
}
count = gf_list_count(ptr->packetTable);
gf_bs_write_u16(bs, count);
gf_bs_write_u16(bs, ptr->reserved);
for (i=0; i<count; i++) {
pck = (GF_HintPacket *)gf_list_get(ptr->packetTable, i);
e = gf_isom_hint_pck_write(pck, bs);
if (e) return e;
}
if (ptr->AdditionalData) {
gf_bs_write_data(bs, ptr->AdditionalData, ptr->dataLength);
}
return GF_OK;
}
u32 gf_isom_hint_sample_size(GF_HintSample *ptr)
{
u32 size, count, i;
GF_HintPacket *pck;
if (ptr->hint_subtype==GF_ISOM_BOX_TYPE_FDP_STSD) {
gf_isom_box_size((GF_Box*)ptr);
size = (u32) ptr->size;
} else {
size = 4;
count = gf_list_count(ptr->packetTable);
for (i=0; i<count; i++) {
pck = (GF_HintPacket *)gf_list_get(ptr->packetTable, i);
size += gf_isom_hint_pck_size(pck);
}
size += ptr->dataLength;
}
return size;
}
#endif
GF_HintPacket *gf_isom_hint_pck_new(u32 HintType)
{
GF_HintPacket *pck;
switch (HintType) {
case GF_ISOM_BOX_TYPE_RTP_STSD:
case GF_ISOM_BOX_TYPE_SRTP_STSD:
case GF_ISOM_BOX_TYPE_RRTP_STSD:
pck = (GF_HintPacket *) gf_isom_hint_rtp_new();
if (pck) pck->hint_subtype = HintType;
return pck;
case GF_ISOM_BOX_TYPE_RTCP_STSD:
pck = (GF_HintPacket *) gf_isom_hint_rtcp_new();
if (pck) pck->hint_subtype = HintType;
return pck;
default:
return NULL;
}
}
void gf_isom_hint_pck_del(GF_HintPacket *ptr)
{
if (!ptr) return;
switch (ptr->hint_subtype) {
case GF_ISOM_BOX_TYPE_RTP_STSD:
case GF_ISOM_BOX_TYPE_SRTP_STSD:
case GF_ISOM_BOX_TYPE_RRTP_STSD:
gf_isom_hint_rtp_del((GF_RTPPacket *)ptr);
break;
case GF_ISOM_BOX_TYPE_RTCP_STSD:
gf_isom_hint_rtcp_del((GF_RTCPPacket *)ptr);
break;
default:
break;
}
}
GF_Err gf_isom_hint_pck_read(GF_HintPacket *ptr, GF_BitStream *bs)
{
if (!ptr) return GF_BAD_PARAM;
switch (ptr->hint_subtype) {
case GF_ISOM_BOX_TYPE_RTP_STSD:
case GF_ISOM_BOX_TYPE_SRTP_STSD:
case GF_ISOM_BOX_TYPE_RRTP_STSD:
return gf_isom_hint_rtp_read((GF_RTPPacket *)ptr, bs);
case GF_ISOM_BOX_TYPE_RTCP_STSD:
return gf_isom_hint_rtcp_read((GF_RTCPPacket *)ptr, bs);
default:
return GF_NOT_SUPPORTED;
}
}
#ifndef GPAC_DISABLE_ISOM_WRITE
GF_Err gf_isom_hint_pck_write(GF_HintPacket *ptr, GF_BitStream *bs)
{
if (!ptr) return GF_BAD_PARAM;
switch (ptr->hint_subtype) {
case GF_ISOM_BOX_TYPE_RTP_STSD:
case GF_ISOM_BOX_TYPE_SRTP_STSD:
case GF_ISOM_BOX_TYPE_RRTP_STSD:
return gf_isom_hint_rtp_write((GF_RTPPacket *)ptr, bs);
case GF_ISOM_BOX_TYPE_RTCP_STSD:
return gf_isom_hint_rtcp_write((GF_RTCPPacket *)ptr, bs);
default:
return GF_NOT_SUPPORTED;
}
}
u32 gf_isom_hint_pck_size(GF_HintPacket *ptr)
{
if (!ptr) return GF_BAD_PARAM;
switch (ptr->hint_subtype) {
case GF_ISOM_BOX_TYPE_RTP_STSD:
case GF_ISOM_BOX_TYPE_SRTP_STSD:
case GF_ISOM_BOX_TYPE_RRTP_STSD:
return gf_isom_hint_rtp_size((GF_RTPPacket *)ptr);
case GF_ISOM_BOX_TYPE_RTCP_STSD:
return gf_isom_hint_rtcp_size((GF_RTCPPacket *)ptr);
default:
return 0;
}
}
GF_Err gf_isom_hint_pck_offset(GF_HintPacket *ptr, u32 offset, u32 HintSampleNumber)
{
if (!ptr) return GF_BAD_PARAM;
switch (ptr->hint_subtype) {
case GF_ISOM_BOX_TYPE_RTP_STSD:
case GF_ISOM_BOX_TYPE_SRTP_STSD:
case GF_ISOM_BOX_TYPE_RRTP_STSD:
return gf_isom_hint_rtp_offset((GF_RTPPacket *)ptr, offset, HintSampleNumber);
case GF_ISOM_BOX_TYPE_RTCP_STSD:
return GF_BAD_PARAM;
default:
return GF_NOT_SUPPORTED;
}
}
GF_Err gf_isom_hint_pck_add_dte(GF_HintPacket *ptr, GF_GenericDTE *dte, u8 AtBegin)
{
if (!ptr) return GF_BAD_PARAM;
switch (ptr->hint_subtype) {
case GF_ISOM_BOX_TYPE_RTP_STSD:
case GF_ISOM_BOX_TYPE_SRTP_STSD:
case GF_ISOM_BOX_TYPE_RRTP_STSD:
if (AtBegin)
return gf_list_insert( ((GF_RTPPacket *)ptr)->DataTable, dte, 0);
else
return gf_list_add( ((GF_RTPPacket *)ptr)->DataTable, dte);
case GF_ISOM_BOX_TYPE_RTCP_STSD:
return GF_BAD_PARAM;
default:
return GF_NOT_SUPPORTED;
}
}
u32 gf_isom_hint_pck_length(GF_HintPacket *ptr)
{
if (!ptr) return 0;
switch (ptr->hint_subtype) {
case GF_ISOM_BOX_TYPE_RTP_STSD:
case GF_ISOM_BOX_TYPE_SRTP_STSD:
case GF_ISOM_BOX_TYPE_RRTP_STSD:
return gf_isom_hint_rtp_length((GF_RTPPacket *)ptr);
case GF_ISOM_BOX_TYPE_RTCP_STSD:
return gf_isom_hint_rtcp_length((GF_RTCPPacket *)ptr);
default:
return 0;
}
}
#endif
GF_GenericDTE *New_EmptyDTE()
{
GF_EmptyDTE *dte = (GF_EmptyDTE *)gf_malloc(sizeof(GF_EmptyDTE));
dte->source = 0;
return (GF_GenericDTE *)dte;
}
GF_GenericDTE *New_ImmediateDTE()
{
GF_ImmediateDTE *dte;
GF_SAFEALLOC(dte, GF_ImmediateDTE);
if (dte) {
dte->source = 1;
dte->dataLength = 0;
}
return (GF_GenericDTE *)dte;
}
GF_GenericDTE *New_SampleDTE()
{
GF_SampleDTE *dte = (GF_SampleDTE *)gf_malloc(sizeof(GF_SampleDTE));
dte->source = 2;
dte->trackRefIndex = (s8) -2;
dte->dataLength = 0;
dte->sampleNumber = 0;
dte->samplesPerComp = 1;
dte->byteOffset = 0;
dte->bytesPerComp = 1;
return (GF_GenericDTE *)dte;
}
GF_GenericDTE *New_StreamDescDTE()
{
GF_StreamDescDTE *dte = (GF_StreamDescDTE *)gf_malloc(sizeof(GF_StreamDescDTE));
dte->source = 3;
dte->byteOffset = 0;
dte->dataLength = 0;
dte->reserved = 0;
dte->streamDescIndex = 0;
dte->trackRefIndex = (s8) -2;
return (GF_GenericDTE *)dte;
}
GF_GenericDTE *NewDTE(u8 type)
{
switch (type) {
case 0:
return New_EmptyDTE();
case 1:
return New_ImmediateDTE();
case 2:
return New_SampleDTE();
case 3:
return New_StreamDescDTE();
default:
return NULL;
}
}
void Del_EmptyDTE(GF_EmptyDTE *dte)
{
gf_free(dte);
}
void Del_ImmediateDTE(GF_ImmediateDTE *dte)
{
gf_free(dte);
}
void Del_SampleDTE(GF_SampleDTE *dte)
{
gf_free(dte);
}
void Del_StreamDescDTE(GF_StreamDescDTE *dte)
{
gf_free(dte);
}
void DelDTE(GF_GenericDTE *dte)
{
switch (dte->source) {
case 0:
Del_EmptyDTE((GF_EmptyDTE *)dte);
break;
case 1:
Del_ImmediateDTE((GF_ImmediateDTE *)dte);
break;
case 2:
Del_SampleDTE((GF_SampleDTE *)dte);
break;
case 3:
Del_StreamDescDTE((GF_StreamDescDTE *)dte);
break;
default:
return;
}
}
GF_Err Read_EmptyDTE(GF_EmptyDTE *dte, GF_BitStream *bs)
{
char empty[15];
gf_bs_read_data(bs, empty, 15);
return GF_OK;
}
GF_Err Read_ImmediateDTE(GF_ImmediateDTE *dte, GF_BitStream *bs)
{
dte->dataLength = gf_bs_read_u8(bs);
if (dte->dataLength > 14) return GF_ISOM_INVALID_FILE;
gf_bs_read_data(bs, dte->data, dte->dataLength);
if (dte->dataLength < 14) gf_bs_skip_bytes(bs, 14 - dte->dataLength);
return GF_OK;
}
GF_Err Read_SampleDTE(GF_SampleDTE *dte, GF_BitStream *bs)
{
dte->trackRefIndex = (s8) gf_bs_read_u8(bs);
dte->dataLength = gf_bs_read_u16(bs);
dte->sampleNumber = gf_bs_read_u32(bs);
dte->byteOffset = gf_bs_read_u32(bs);
dte->bytesPerComp = gf_bs_read_u16(bs);
dte->samplesPerComp = gf_bs_read_u16(bs);
if (dte->bytesPerComp != 1) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso] hint packet constructor with bytesperblock %d, not 1\n", dte->bytesPerComp));
}
if (dte->samplesPerComp != 1) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso] hint packet constructor with samplesperblock %d, not 1\n", dte->bytesPerComp));
}
return GF_OK;
}
GF_Err Read_StreamDescDTE(GF_StreamDescDTE *dte, GF_BitStream *bs)
{
dte->trackRefIndex = gf_bs_read_u8(bs);
dte->dataLength = gf_bs_read_u16(bs);
dte->streamDescIndex = gf_bs_read_u32(bs);
dte->byteOffset = gf_bs_read_u32(bs);
dte->reserved = gf_bs_read_u32(bs);
return GF_OK;
}
GF_Err ReadDTE(GF_GenericDTE *dte, GF_BitStream *bs)
{
switch (dte->source) {
case 0:
return Read_EmptyDTE((GF_EmptyDTE *)dte, bs);
case 1:
return Read_ImmediateDTE((GF_ImmediateDTE *)dte, bs);
case 2:
return Read_SampleDTE((GF_SampleDTE *)dte, bs);
case 3:
return Read_StreamDescDTE((GF_StreamDescDTE *)dte, bs);
default:
return GF_ISOM_INVALID_FILE;
}
}
GF_Err Write_EmptyDTE(GF_EmptyDTE *dte, GF_BitStream *bs)
{
gf_bs_write_u8(bs, dte->source);
gf_bs_write_data(bs, "empty hint DTE", 15);
return GF_OK;
}
GF_Err Write_ImmediateDTE(GF_ImmediateDTE *dte, GF_BitStream *bs)
{
char data[14];
gf_bs_write_u8(bs, dte->source);
gf_bs_write_u8(bs, dte->dataLength);
gf_bs_write_data(bs, dte->data, dte->dataLength);
if (dte->dataLength < 14) {
memset(data, 0, 14);
gf_bs_write_data(bs, data, 14 - dte->dataLength);
}
return GF_OK;
}
GF_Err Write_SampleDTE(GF_SampleDTE *dte, GF_BitStream *bs)
{
gf_bs_write_u8(bs, dte->source);
gf_bs_write_u8(bs, dte->trackRefIndex);
gf_bs_write_u16(bs, dte->dataLength);
gf_bs_write_u32(bs, dte->sampleNumber);
gf_bs_write_u32(bs, dte->byteOffset);
gf_bs_write_u16(bs, dte->bytesPerComp);
gf_bs_write_u16(bs, dte->samplesPerComp);
return GF_OK;
}
GF_Err Write_StreamDescDTE(GF_StreamDescDTE *dte, GF_BitStream *bs)
{
gf_bs_write_u8(bs, dte->source);
gf_bs_write_u8(bs, dte->trackRefIndex);
gf_bs_write_u16(bs, dte->dataLength);
gf_bs_write_u32(bs, dte->streamDescIndex);
gf_bs_write_u32(bs, dte->byteOffset);
gf_bs_write_u32(bs, dte->reserved);
return GF_OK;
}
GF_Err WriteDTE(GF_GenericDTE *dte, GF_BitStream *bs)
{
switch (dte->source) {
case 0:
return Write_EmptyDTE((GF_EmptyDTE *)dte, bs);
case 1:
return Write_ImmediateDTE((GF_ImmediateDTE *)dte, bs);
case 2:
return Write_SampleDTE((GF_SampleDTE *)dte, bs);
case 3:
return Write_StreamDescDTE((GF_StreamDescDTE *)dte, bs);
default:
return GF_ISOM_INVALID_FILE;
}
}
GF_Err OffsetDTE(GF_GenericDTE *dte, u32 offset, u32 HintSampleNumber)
{
GF_SampleDTE *sDTE;
switch (dte->source) {
case 2:
break;
default:
return GF_OK;
}
sDTE = (GF_SampleDTE *)dte;
if (sDTE->trackRefIndex != (s8) -1) return GF_OK;
if (sDTE->sampleNumber != HintSampleNumber) return GF_OK;
sDTE->byteOffset += offset;
return GF_OK;
}
GF_RTPPacket *gf_isom_hint_rtp_new()
{
GF_RTPPacket *tmp;
GF_SAFEALLOC(tmp, GF_RTPPacket);
if (!tmp) return NULL;
tmp->TLV = gf_list_new();
tmp->DataTable = gf_list_new();
return tmp;
}
void gf_isom_hint_rtp_del(GF_RTPPacket *ptr)
{
GF_GenericDTE *p;
while (gf_list_count(ptr->DataTable)) {
p = (GF_GenericDTE *)gf_list_get(ptr->DataTable, 0);
DelDTE(p);
gf_list_rem(ptr->DataTable, 0);
}
gf_list_del(ptr->DataTable);
gf_isom_box_array_del(ptr->TLV);
gf_free(ptr);
}
GF_Err gf_isom_hint_rtp_read(GF_RTPPacket *ptr, GF_BitStream *bs)
{
GF_Err e;
u8 hasTLV, type;
u16 i, count;
u32 TLVsize, tempSize;
GF_GenericDTE *dte;
GF_Box *a;
ptr->relativeTransTime = gf_bs_read_u32(bs);
gf_bs_read_int(bs, 2);
ptr->P_bit = gf_bs_read_int(bs, 1);
ptr->X_bit = gf_bs_read_int(bs, 1);
gf_bs_read_int(bs, 4);
ptr->M_bit = gf_bs_read_int(bs, 1);
ptr->payloadType = gf_bs_read_int(bs, 7);
ptr->SequenceNumber = gf_bs_read_u16(bs);
gf_bs_read_int(bs, 13);
hasTLV = gf_bs_read_int(bs, 1);
ptr->B_bit = gf_bs_read_int(bs, 1);
ptr->R_bit = gf_bs_read_int(bs, 1);
count = gf_bs_read_u16(bs);
if (hasTLV) {
tempSize = 4;
TLVsize = gf_bs_read_u32(bs);
while (tempSize < TLVsize) {
e = gf_isom_box_parse(&a, bs);
if (e) return e;
gf_list_add(ptr->TLV, a);
tempSize += (u32) a->size;
}
if (tempSize != TLVsize) return GF_ISOM_INVALID_FILE;
}
for (i=0; i<count; i++) {
Bool add_it = 0;
type = gf_bs_read_u8(bs);
dte = NewDTE(type);
if (!dte) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso] invalid DTE code %d in hint sample %d of trackID %d\n", type, ptr->sampleNumber, ptr->trackID));
return GF_ISOM_INVALID_FILE;
}
e = ReadDTE(dte, bs);
if (e) return e;
switch (type) {
case 1:
if ( ((GF_ImmediateDTE *)dte)->dataLength) add_it = 1;
break;
case 2:
if ( ((GF_SampleDTE *)dte)->dataLength) add_it = 1;
break;
case 3:
if ( ((GF_StreamDescDTE *)dte)->dataLength) add_it = 1;
break;
}
if (add_it)
gf_list_add(ptr->DataTable, dte);
else
DelDTE(dte);
}
return GF_OK;
}
GF_Err gf_isom_hint_rtp_offset(GF_RTPPacket *ptr, u32 offset, u32 HintSampleNumber)
{
u32 count, i;
GF_GenericDTE *dte;
GF_Err e;
count = gf_list_count(ptr->DataTable);
for (i=0; i<count; i++) {
dte = (GF_GenericDTE *)gf_list_get(ptr->DataTable, i);
e = OffsetDTE(dte, offset, HintSampleNumber);
if (e) return e;
}
return GF_OK;
}
u32 gf_isom_hint_rtp_length(GF_RTPPacket *ptr)
{
u32 size, count, i;
GF_GenericDTE *dte;
size = 8;
size += 4;
count = gf_list_count(ptr->DataTable);
for (i=0; i<count; i++) {
dte = (GF_GenericDTE *)gf_list_get(ptr->DataTable, i);
switch (dte->source) {
case 0:
break;
case 1:
size += ((GF_ImmediateDTE *)dte)->dataLength;
break;
case 2:
size += ((GF_SampleDTE *)dte)->dataLength;
break;
case 3:
size += ((GF_StreamDescDTE *)dte)->dataLength;
break;
}
}
return size;
}
#ifndef GPAC_DISABLE_ISOM_WRITE
u32 gf_isom_hint_rtp_size(GF_RTPPacket *ptr)
{
GF_Box none;
u32 size, count;
size = 12;
count = gf_list_count(ptr->TLV);
if (count) {
none.size = 4;
none.type = 0;
gf_isom_box_array_size(&none, ptr->TLV);
size += (u32) none.size;
}
count = gf_list_count(ptr->DataTable);
size += count * 16;
return size;
}
GF_Err gf_isom_hint_rtp_write(GF_RTPPacket *ptr, GF_BitStream *bs)
{
GF_Err e;
u32 TLVcount, DTEcount, i;
GF_Box none;
GF_GenericDTE *dte;
gf_bs_write_u32(bs, ptr->relativeTransTime);
gf_bs_write_int(bs, 2, 2);
gf_bs_write_int(bs, ptr->P_bit, 1);
gf_bs_write_int(bs, ptr->X_bit, 1);
gf_bs_write_int(bs, 0, 4);
gf_bs_write_int(bs, ptr->M_bit, 1);
gf_bs_write_int(bs, ptr->payloadType, 7);
gf_bs_write_u16(bs, ptr->SequenceNumber);
gf_bs_write_int(bs, 0, 13);
TLVcount = gf_list_count(ptr->TLV);
DTEcount = gf_list_count(ptr->DataTable);
gf_bs_write_int(bs, TLVcount ? 1 : 0, 1);
gf_bs_write_int(bs, ptr->B_bit, 1);
gf_bs_write_int(bs, ptr->R_bit, 1);
gf_bs_write_u16(bs, DTEcount);
if (TLVcount) {
none.size = 4;
none.type = 0;
gf_isom_box_array_size(&none, ptr->TLV);
gf_bs_write_u32(bs, (u32) none.size);
e = gf_isom_box_array_write(&none, ptr->TLV, bs);
if (e) return e;
}
for (i = 0; i < DTEcount; i++) {
dte = (GF_GenericDTE *)gf_list_get(ptr->DataTable, i);
e = WriteDTE(dte, bs);
if (e) return e;
}
return GF_OK;
}
#endif
GF_RTCPPacket *gf_isom_hint_rtcp_new()
{
GF_RTCPPacket *tmp;
GF_SAFEALLOC(tmp, GF_RTCPPacket);
return tmp;
}
void gf_isom_hint_rtcp_del(GF_RTCPPacket *ptr)
{
if(ptr->data) gf_free(ptr->data);
gf_free(ptr);
}
GF_Err gf_isom_hint_rtcp_read(GF_RTCPPacket *ptr, GF_BitStream *bs)
{
ptr->Version = gf_bs_read_int(bs, 2);
ptr->Padding = gf_bs_read_int(bs, 1);
ptr->Count = gf_bs_read_int(bs, 5);
ptr->PayloadType = gf_bs_read_u8(bs);
ptr->length = 4 * gf_bs_read_u16(bs);
if (ptr->length<4) return GF_ISOM_INVALID_MEDIA;
if (gf_bs_available(bs) < ptr->length) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso] RTCP hint packet has more data (%d) than available\n", ptr->length ));
return GF_ISOM_INVALID_MEDIA;
}
ptr->data = gf_malloc(sizeof(char) * ptr->length);
gf_bs_read_data(bs, ptr->data, ptr->length);
return GF_OK;
}
u32 gf_isom_hint_rtcp_length(GF_RTCPPacket *ptr)
{
return 4 * (ptr->length + 1);
}
#ifndef GPAC_DISABLE_ISOM_WRITE
u32 gf_isom_hint_rtcp_size(GF_RTCPPacket *ptr)
{
return 4 * (ptr->length + 1);
}
GF_Err gf_isom_hint_rtcp_write(GF_RTCPPacket *ptr, GF_BitStream *bs)
{
gf_bs_write_int(bs, ptr->Version, 2);
gf_bs_write_int(bs, ptr->Padding, 1);
gf_bs_write_int(bs, ptr->Count, 5);
gf_bs_write_u8(bs, ptr->PayloadType);
gf_bs_write_u16(bs, 4*ptr->length);
gf_bs_write_data(bs, ptr->data, ptr->length);
return GF_OK;
}
#endif
GF_EXPORT
GF_Err gf_isom_reset_hint_reader(GF_ISOFile *the_file, u32 trackNumber, u32 sample_start, u32 ts_offset, u32 sn_offset, u32 ssrc)
{
GF_Err e;
GF_TrackBox *trak;
GF_HintSampleEntryBox *entry;
trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak) return GF_BAD_PARAM;
if (!sample_start) return GF_BAD_PARAM;
if (sample_start>=trak->Media->information->sampleTable->SampleSize->sampleCount) return GF_BAD_PARAM;
e = Media_GetSampleDesc(trak->Media, 1, (GF_SampleEntryBox **) &entry, NULL);
if (e) return e;
switch (entry->type) {
case GF_ISOM_BOX_TYPE_RTP_STSD:
case GF_ISOM_BOX_TYPE_SRTP_STSD:
case GF_ISOM_BOX_TYPE_RRTP_STSD:
break;
default:
return GF_NOT_SUPPORTED;
}
entry->hint_ref = NULL;
e = Track_FindRef(trak, GF_ISOM_REF_HINT, &entry->hint_ref);
if (e) return e;
entry->cur_sample = sample_start;
entry->pck_sn = 1 + sn_offset;
entry->ssrc = ssrc;
entry->ts_offset = ts_offset;
if (entry->hint_sample) gf_isom_hint_sample_del(entry->hint_sample);
entry->hint_sample = NULL;
return GF_OK;
}
static GF_Err gf_isom_load_next_hint_sample(GF_ISOFile *the_file, u32 trackNumber, GF_TrackBox *trak, GF_HintSampleEntryBox *entry)
{
GF_BitStream *bs;
u32 descIdx;
GF_ISOSample *samp;
if (!entry->cur_sample) return GF_BAD_PARAM;
if (entry->cur_sample>trak->Media->information->sampleTable->SampleSize->sampleCount) return GF_EOS;
samp = gf_isom_get_sample(the_file, trackNumber, entry->cur_sample, &descIdx);
if (!samp) return GF_IO_ERR;
entry->cur_sample++;
if (entry->hint_sample) gf_isom_hint_sample_del(entry->hint_sample);
bs = gf_bs_new(samp->data, samp->dataLength, GF_BITSTREAM_READ);
entry->hint_sample = gf_isom_hint_sample_new(entry->type);
gf_isom_hint_sample_read(entry->hint_sample, bs, samp->dataLength);
gf_bs_del(bs);
entry->hint_sample->TransmissionTime = samp->DTS;
gf_isom_sample_del(&samp);
entry->hint_sample->sample_cache = gf_list_new();
return GF_OK;
}
static GF_ISOSample *gf_isom_get_data_sample(GF_HintSample *hsamp, GF_TrackBox *trak, u32 sample_num)
{
GF_ISOSample *samp;
GF_HintDataCache *hdc;
u32 i, count;
count = gf_list_count(hsamp->sample_cache);
for (i=0; i<count; i++) {
hdc = (GF_HintDataCache *)gf_list_get(hsamp->sample_cache, i);
if ((hdc->sample_num==sample_num) && (hdc->trak==trak)) return hdc->samp;
}
samp = gf_isom_sample_new();
Media_GetSample(trak->Media, sample_num, &samp, &i, 0, NULL);
if (!samp) return NULL;
GF_SAFEALLOC(hdc, GF_HintDataCache);
if (!hdc) return NULL;
hdc->samp = samp;
hdc->sample_num = sample_num;
hdc->trak = trak;
gf_list_insert(hsamp->sample_cache, hdc, 0);
return samp;
}
GF_EXPORT
GF_Err gf_isom_next_hint_packet(GF_ISOFile *the_file, u32 trackNumber, char **pck_data, u32 *pck_size, Bool *disposable, Bool *repeated, u32 *trans_ts, u32 *sample_num)
{
GF_RTPPacket *pck;
GF_Err e;
GF_BitStream *bs;
GF_TrackBox *trak, *ref_trak;
GF_HintSampleEntryBox *entry;
u32 i, count, ts;
s32 cts_off;
*pck_data = NULL;
*pck_size = 0;
if (trans_ts) *trans_ts = 0;
if (disposable) *disposable = 0;
if (repeated) *repeated = 0;
if (sample_num) *sample_num = 0;
trak = gf_isom_get_track_from_file(the_file, trackNumber);
if (!trak) return GF_BAD_PARAM;
e = Media_GetSampleDesc(trak->Media, 1, (GF_SampleEntryBox **) &entry, NULL);
if (e) return e;
switch (entry->type) {
case GF_ISOM_BOX_TYPE_RTP_STSD:
case GF_ISOM_BOX_TYPE_SRTP_STSD:
case GF_ISOM_BOX_TYPE_RRTP_STSD:
break;
default:
return GF_NOT_SUPPORTED;
}
if (!entry->hint_sample) {
e = gf_isom_load_next_hint_sample(the_file, trackNumber, trak, entry);
if (e) return e;
}
pck = (GF_RTPPacket *)gf_list_get(entry->hint_sample->packetTable, 0);
gf_list_rem(entry->hint_sample->packetTable, 0);
if (!pck) return GF_BAD_PARAM;
bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
gf_bs_write_int(bs, 2, 2);
gf_bs_write_int(bs, pck->P_bit, 1);
gf_bs_write_int(bs, pck->X_bit, 1);
gf_bs_write_int(bs, 0, 4);
gf_bs_write_int(bs, pck->M_bit, 1);
gf_bs_write_int(bs, pck->payloadType, 7);
gf_bs_write_u16(bs, entry->pck_sn);
entry->pck_sn++;
cts_off = 0;
count = gf_list_count(pck->TLV);
for (i=0; i<count; i++) {
GF_RTPOBox *rtpo = (GF_RTPOBox *)gf_list_get(pck->TLV, i);
if (rtpo->type == GF_ISOM_BOX_TYPE_RTPO) {
cts_off = rtpo->timeOffset;
break;
}
}
ts = (u32) (entry->hint_sample->TransmissionTime + pck->relativeTransTime + entry->ts_offset + cts_off);
gf_bs_write_u32(bs, ts );
gf_bs_write_u32(bs, entry->ssrc);
count = gf_list_count(pck->DataTable);
for (i=0; i<count; i++) {
GF_GenericDTE *dte = (GF_GenericDTE *)gf_list_get(pck->DataTable, i);
switch (dte->source) {
case 0:
break;
case 1:
gf_bs_write_data(bs, ((GF_ImmediateDTE *)dte)->data, ((GF_ImmediateDTE *)dte)->dataLength);
break;
case 2:
{
GF_ISOSample *samp;
GF_SampleDTE *sdte = (GF_SampleDTE *)dte;
if (sdte->trackRefIndex != (s8) -1) {
if (!entry->hint_ref || !entry->hint_ref->trackIDs) {
gf_isom_hint_rtp_del(pck);
gf_bs_del(bs);
return GF_ISOM_INVALID_FILE;
}
ref_trak = gf_isom_get_track_from_id(trak->moov, entry->hint_ref->trackIDs[(u32)sdte->trackRefIndex]);
} else {
ref_trak = trak;
}
samp = gf_isom_get_data_sample(entry->hint_sample, ref_trak, sdte->sampleNumber);
if (!samp) {
gf_isom_hint_rtp_del(pck);
gf_bs_del(bs);
return GF_IO_ERR;
}
gf_bs_write_data(bs, samp->data + sdte->byteOffset, sdte->dataLength);
}
break;
case 3:
break;
}
}
if (trans_ts) *trans_ts = ts;
if (disposable) *disposable = pck->B_bit;
if (repeated) *repeated = pck->R_bit;
if (sample_num) *sample_num = entry->cur_sample-1;
gf_bs_get_content(bs, pck_data, pck_size);
gf_bs_del(bs);
gf_isom_hint_rtp_del(pck);
if (!gf_list_count(entry->hint_sample->packetTable)) {
gf_isom_hint_sample_del(entry->hint_sample);
entry->hint_sample = NULL;
}
return GF_OK;
}
#endif