GF_Err senc_Write(GF_Box *s, GF_BitStream *bs) { GF_Err e; u32 sample_count; GF_SampleEncryptionBox *ptr = (GF_SampleEncryptionBox *) s; e = gf_isom_box_write_header(s, bs); if (e) return e; //WARNING - PSEC (UUID) IS TYPECASTED TO SENC (FULL BOX) SO WE CANNOT USE USUAL FULL BOX FUNCTIONS gf_bs_write_u8(bs, ptr->version); gf_bs_write_u24(bs, ptr->flags); sample_count = gf_list_count(ptr->samp_aux_info); gf_bs_write_u32(bs, sample_count); if (sample_count) { u32 i, j; e = store_senc_info(ptr, bs); if (e) return e; for (i = 0; i < sample_count; i++) { GF_CENCSampleAuxInfo *sai = (GF_CENCSampleAuxInfo *)gf_list_get(ptr->samp_aux_info, i); //for cbcs scheme, IV_size is 0, constant IV shall be used. It is written in tenc box rather than in sai if (sai->IV_size) gf_bs_write_data(bs, (char *)sai->IV, sai->IV_size); if (ptr->flags & 0x00000002) { gf_bs_write_u16(bs, sai->subsample_count); for (j = 0; j < sai->subsample_count; j++) { gf_bs_write_u16(bs, sai->subsamples[j].bytes_clear_data); gf_bs_write_u32(bs, sai->subsamples[j].bytes_encrypted_data); } } } } return GF_OK; }
GF_Err piff_tenc_Write(GF_Box *s, GF_BitStream *bs) { GF_Err e; GF_PIFFTrackEncryptionBox *ptr = (GF_PIFFTrackEncryptionBox *) s; if (!s) return GF_BAD_PARAM; e = gf_isom_box_write_header(s, bs); if (e) return e; gf_bs_write_u8(bs, ptr->version); gf_bs_write_u24(bs, ptr->flags); gf_bs_write_int(bs, ptr->AlgorithmID, 24); gf_bs_write_u8(bs, ptr->IV_size); gf_bs_write_data(bs, (char *) ptr->KID, 16); return GF_OK; }
GF_Err piff_pssh_Write(GF_Box *s, GF_BitStream *bs) { GF_Err e; GF_PIFFProtectionSystemHeaderBox *ptr = (GF_PIFFProtectionSystemHeaderBox *) s; if (!s) return GF_BAD_PARAM; e = gf_isom_box_write_header(s, bs); if (e) return e; gf_bs_write_u8(bs, ptr->version); gf_bs_write_u24(bs, ptr->flags); gf_bs_write_data(bs, (char *) ptr->SystemID, 16); gf_bs_write_u32(bs, ptr->private_data_size); gf_bs_write_data(bs, (char *) ptr->private_data, ptr->private_data_size); return GF_OK; }
GF_Err gf_isom_rewrite_text_sample(GF_ISOSample *samp, u32 sampleDescriptionIndex, u32 sample_dur) { GF_BitStream *bs; u32 pay_start, txt_size; Bool is_utf_16 = 0; if (!samp || !samp->data || !samp->dataLength) return GF_OK; bs = gf_bs_new(samp->data, samp->dataLength, GF_BITSTREAM_READ); txt_size = gf_bs_read_u16(bs); gf_bs_del(bs); /*remove BOM*/ pay_start = 2; if (txt_size>2) { /*seems 3GP only accepts BE UTF-16 (no LE, no UTF32)*/ if (((u8) samp->data[2]==(u8) 0xFE) && ((u8)samp->data[3]==(u8) 0xFF)) { is_utf_16 = 1; pay_start = 4; txt_size -= 2; } } /*rewrite as TTU(1)*/ bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_int(bs, is_utf_16, 1); gf_bs_write_int(bs, 0, 4); gf_bs_write_int(bs, 1, 3); gf_bs_write_u16(bs, 8 + samp->dataLength - pay_start); gf_bs_write_u8(bs, sampleDescriptionIndex + SAMPLE_INDEX_OFFSET); gf_bs_write_u24(bs, sample_dur); /*write text size*/ gf_bs_write_u16(bs, txt_size); if (txt_size) gf_bs_write_data(bs, samp->data + pay_start, samp->dataLength - pay_start); gf_free(samp->data); samp->data = NULL; gf_bs_get_content(bs, &samp->data, &samp->dataLength); gf_bs_del(bs); return GF_OK; }
GF_Err piff_psec_Write(GF_Box *s, GF_BitStream *bs) { GF_Err e; GF_PIFFSampleEncryptionBox *ptr = (GF_PIFFSampleEncryptionBox *) s; if (!s) return GF_BAD_PARAM; e = gf_isom_box_write_header(s, bs); if (e) return e; gf_bs_write_u8(bs, ptr->version); gf_bs_write_u24(bs, ptr->flags); if (ptr->flags & 1) { gf_bs_write_int(bs, ptr->AlgorithmID, 24); gf_bs_write_u8(bs, ptr->IV_size); gf_bs_write_data(bs, (char *) ptr->KID, 16); } gf_bs_write_u32(bs, ptr->sample_count); if (ptr->cenc_data && ptr->cenc_data_size) { gf_bs_write_data(bs, ptr->cenc_data, ptr->cenc_data_size); } return GF_OK; }
GF_Err piff_psec_Write(GF_Box *s, GF_BitStream *bs) { GF_Err e; u32 sample_count; GF_SampleEncryptionBox *ptr = (GF_SampleEncryptionBox *) s; if (!s) return GF_BAD_PARAM; e = gf_isom_box_write_header(s, bs); if (e) return e; gf_bs_write_u8(bs, ptr->version); gf_bs_write_u24(bs, ptr->flags); if (ptr->flags & 1) { gf_bs_write_int(bs, ptr->AlgorithmID, 24); gf_bs_write_u8(bs, ptr->IV_size); gf_bs_write_data(bs, (char *) ptr->KID, 16); } sample_count = gf_list_count(ptr->samp_aux_info); gf_bs_write_u32(bs, sample_count); if (sample_count) { u32 i, j; e = store_senc_info((GF_SampleEncryptionBox *)ptr, bs); if (e) return e; for (i = 0; i < sample_count; i++) { GF_CENCSampleAuxInfo *sai = (GF_CENCSampleAuxInfo *)gf_list_get(ptr->samp_aux_info, i); if (! sai->IV_size) continue; gf_bs_write_data(bs, (char *)sai->IV, sai->IV_size); gf_bs_write_u16(bs, sai->subsample_count); for (j = 0; j < sai->subsample_count; j++) { gf_bs_write_u16(bs, sai->subsamples[j].bytes_clear_data); gf_bs_write_u32(bs, sai->subsamples[j].bytes_encrypted_data); } } } return GF_OK; }
GF_Err gf_isom_get_ttxt_esd(GF_MediaBox *mdia, GF_ESD **out_esd) { GF_BitStream *bs; u32 count, i; Bool has_v_info; GF_List *sampleDesc; GF_ESD *esd; GF_TrackBox *tk; *out_esd = NULL; sampleDesc = mdia->information->sampleTable->SampleDescription->boxList; count = gf_list_count(sampleDesc); if (!count) return GF_ISOM_INVALID_MEDIA; esd = gf_odf_desc_esd_new(2); esd->decoderConfig->streamType = GF_STREAM_TEXT; esd->decoderConfig->objectTypeIndication = 0x08; bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); /*Base3GPPFormat*/ gf_bs_write_u8(bs, 0x10); /*MPEGExtendedFormat*/ gf_bs_write_u8(bs, 0x10); /*profileLevel*/ gf_bs_write_u8(bs, 0x10); gf_bs_write_u24(bs, mdia->mediaHeader->timeScale); gf_bs_write_int(bs, 0, 1); /*no alt formats*/ gf_bs_write_int(bs, 2, 2); /*only out-of-band-band sample desc*/ gf_bs_write_int(bs, 1, 1); /*we will write sample desc*/ /*write v info if any visual track in this movie*/ has_v_info = 0; i=0; while ((tk = (GF_TrackBox*)gf_list_enum(mdia->mediaTrack->moov->trackList, &i))) { if (tk->Media->handler && (tk->Media->handler->handlerType == GF_ISOM_MEDIA_VISUAL)) { has_v_info = 1; } } gf_bs_write_int(bs, has_v_info, 1); gf_bs_write_int(bs, 0, 3); /*reserved, spec doesn't say the values*/ gf_bs_write_u8(bs, mdia->mediaTrack->Header->layer); gf_bs_write_u16(bs, mdia->mediaTrack->Header->width>>16); gf_bs_write_u16(bs, mdia->mediaTrack->Header->height>>16); /*write desc*/ gf_bs_write_u8(bs, count); for (i=0; i<count; i++) { GF_Tx3gSampleEntryBox *a; a = (GF_Tx3gSampleEntryBox *) gf_list_get(sampleDesc, i); if ((a->type != GF_ISOM_BOX_TYPE_TX3G) && (a->type != GF_ISOM_BOX_TYPE_TEXT) ) continue; gf_isom_write_tx3g(a, bs, i+1, SAMPLE_INDEX_OFFSET); } if (has_v_info) { u32 trans; /*which video shall we pick for MPEG-4, and how is the associations indicated in 3GP ???*/ gf_bs_write_u16(bs, 0); gf_bs_write_u16(bs, 0); trans = mdia->mediaTrack->Header->matrix[6]; trans >>= 16; gf_bs_write_u16(bs, trans); trans = mdia->mediaTrack->Header->matrix[7]; trans >>= 16; gf_bs_write_u16(bs, trans); } gf_bs_get_content(bs, &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength); gf_bs_del(bs); *out_esd = esd; return GF_OK; }
GF_Err gp_rtp_builder_do_tx3g(GP_RTPPacketizer *builder, char *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize, u32 duration, u8 descIndex) { GF_BitStream *bs; char *hdr; u32 samp_size, txt_size, pay_start, hdr_size, txt_done, cur_frag, nb_frag; Bool is_utf_16 = 0; if (!data) { /*flush packet*/ if (builder->bytesInPacket) { builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header); builder->bytesInPacket = 0; } return GF_OK; } /*cfg packet*/ txt_size = data[0]; txt_size <<= 8; txt_size |= (unsigned char) data[1]; /*remove BOM*/ pay_start = 2; if (txt_size>2) { /*seems 3GP only accepts BE UTF-16 (no LE, no UTF32)*/ if (((u8) data[2]==(u8) 0xFE) && ((u8) data[3]==(u8) 0xFF)) { is_utf_16 = 1; pay_start = 4; txt_size -= 2; } } samp_size = data_size - pay_start; /*if TTU does not fit in packet flush packet*/ if (builder->bytesInPacket && (builder->bytesInPacket + 3 + 6 + samp_size > builder->Path_MTU)) { builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header); builder->bytesInPacket = 0; } /*first TTU in packet*/ if (!builder->bytesInPacket) { builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp; builder->rtp_header.Marker = 1; builder->rtp_header.SequenceNumber += 1; builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header); } /*fits entirely*/ if (builder->bytesInPacket + 3 + 6 + samp_size <= builder->Path_MTU) { bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_int(bs, is_utf_16, 1); gf_bs_write_int(bs, 0, 4); gf_bs_write_int(bs, 1, 3); gf_bs_write_u16(bs, 8 + samp_size); gf_bs_write_u8(bs, descIndex); gf_bs_write_u24(bs, duration); gf_bs_write_u16(bs, txt_size); gf_bs_get_content(bs, &hdr, &hdr_size); gf_bs_del(bs); builder->OnData(builder->cbk_obj, (char *) hdr, hdr_size, 0); builder->bytesInPacket += hdr_size; gf_free(hdr); if (txt_size) { if (builder->OnDataReference) { builder->OnDataReference(builder->cbk_obj, samp_size, pay_start); } else { builder->OnData(builder->cbk_obj, data + pay_start, samp_size, 0); } builder->bytesInPacket += samp_size; } /*disable aggregation*/ if (!(builder->flags & GP_RTP_PCK_USE_MULTI)) { builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header); builder->bytesInPacket = 0; } return GF_OK; } /*doesn't fit and already data, flush packet*/ if (builder->bytesInPacket) { builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header); builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp; /*split unit*/ builder->rtp_header.Marker = 0; builder->rtp_header.SequenceNumber += 1; builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header); builder->bytesInPacket = 0; } /*write all type2 units (text only) - FIXME: split at char boundaries, NOT SUPPORTED YET*/ txt_done = 0; nb_frag = 1; /*all fragments needed for Type2 units*/ while (txt_done + (builder->Path_MTU-10) < txt_size) { txt_done += (builder->Path_MTU-10); nb_frag += 1; } /*all fragments needed for Type3/4 units*/ txt_done = txt_size; while (txt_done + (builder->Path_MTU-7) < samp_size) { txt_done += (builder->Path_MTU-7); nb_frag += 1; } cur_frag = 0; txt_done = 0; while (txt_done<txt_size) { u32 size; if (txt_done + (builder->Path_MTU-10) < txt_size) { size = builder->Path_MTU-10; } else { size = txt_size - txt_done; } bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_int(bs, is_utf_16, 1); gf_bs_write_int(bs, 0, 4); gf_bs_write_int(bs, 2, 3); gf_bs_write_u16(bs, 9 + size); gf_bs_write_int(bs, nb_frag, 4); gf_bs_write_int(bs, cur_frag, 4); gf_bs_write_u24(bs, duration); gf_bs_write_u8(bs, descIndex); /*SLEN is the full original length minus text len and BOM (put here for buffer allocation purposes)*/ gf_bs_write_u16(bs, samp_size); gf_bs_get_content(bs, &hdr, &hdr_size); gf_bs_del(bs); builder->OnData(builder->cbk_obj, (char *) hdr, hdr_size, 0); builder->bytesInPacket += hdr_size; gf_free(hdr); if (builder->OnDataReference) { builder->OnDataReference(builder->cbk_obj, size, pay_start + txt_done); } else { builder->OnData(builder->cbk_obj, data + pay_start + txt_done, size, 0); } builder->bytesInPacket += size; cur_frag++; /*flush packet*/ if (cur_frag == nb_frag) { txt_done = txt_size; if (pay_start + txt_done == data_size) { builder->rtp_header.Marker = 1; builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header); builder->bytesInPacket = 0; } } else { txt_done += size; builder->rtp_header.Marker = 0; builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header); builder->rtp_header.SequenceNumber += 1; builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header); builder->bytesInPacket = 0; } } txt_done = txt_size; /*write all modifiers - OPT: split at modifiers boundaries*/ while (txt_done<samp_size) { u32 size, type; type = (txt_done == txt_size) ? 3 : 4; if (txt_done + (builder->Path_MTU-7) < samp_size) { size = builder->Path_MTU-10; } else { size = samp_size - txt_done; } bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_int(bs, is_utf_16, 1); gf_bs_write_int(bs, 0, 4); gf_bs_write_int(bs, type, 3); gf_bs_write_u16(bs, 6 + size); gf_bs_write_int(bs, nb_frag, 4); gf_bs_write_int(bs, cur_frag, 4); gf_bs_write_u24(bs, duration); gf_bs_get_content(bs, &hdr, &hdr_size); gf_bs_del(bs); builder->OnData(builder->cbk_obj, (char *) hdr, hdr_size, 0); builder->bytesInPacket += hdr_size; gf_free(hdr); if (builder->OnDataReference) { builder->OnDataReference(builder->cbk_obj, size, pay_start + txt_done); } else { builder->OnData(builder->cbk_obj, data + pay_start + txt_done, size, 0); } builder->bytesInPacket += size; cur_frag++; if (cur_frag==nb_frag) { builder->rtp_header.Marker = 1; builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header); builder->bytesInPacket = 0; } else { builder->rtp_header.Marker = 0; builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header); builder->rtp_header.SequenceNumber += 1; builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header); builder->bytesInPacket = 0; } txt_done += size; } return GF_OK; }