GF_Err flxs_Write(GF_Box *s, GF_BitStream *bs) { GF_Err e; GF_AdobeFlashAccessParamsBox *ptr = (GF_AdobeFlashAccessParamsBox *)s; if (!s) return GF_BAD_PARAM; e = gf_isom_box_write_header(s, bs); if (e) return e; if (ptr->metadata) { gf_bs_write_data(bs, ptr->metadata, (u32)strlen(ptr->metadata)); gf_bs_write_u8(bs, 0); //string end } return GF_OK; }
GF_Err tenc_Write(GF_Box *s, GF_BitStream *bs) { GF_Err e; GF_TrackEncryptionBox *ptr = (GF_TrackEncryptionBox *) s; if (!s) return GF_BAD_PARAM; e = gf_isom_full_box_write(s, bs); if (e) return e; gf_bs_write_int(bs, ptr->IsEncrypted, 24); gf_bs_write_u8(bs, ptr->IV_size); gf_bs_write_data(bs, (char *) ptr->KID, 16); return GF_OK; }
GF_Err avcc_Write(GF_Box *s, GF_BitStream *bs) { u32 i, count; GF_Err e; GF_AVCConfigurationBox *ptr = (GF_AVCConfigurationBox *) s; if (!s) return GF_BAD_PARAM; if (!ptr->config) return GF_OK; e = gf_isom_box_write_header(s, bs); if (e) return e; gf_bs_write_u8(bs, ptr->config->configurationVersion); gf_bs_write_u8(bs, ptr->config->AVCProfileIndication); gf_bs_write_u8(bs, ptr->config->profile_compatibility); gf_bs_write_u8(bs, ptr->config->AVCLevelIndication); if (ptr->type==GF_ISOM_BOX_TYPE_AVCC) { gf_bs_write_int(bs, 0x3F, 6); } else { gf_bs_write_int(bs, ptr->config->complete_representation, 1); gf_bs_write_int(bs, 0x1F, 5); } gf_bs_write_int(bs, ptr->config->nal_unit_size - 1, 2); gf_bs_write_int(bs, 0x7, 3); count = gf_list_count(ptr->config->sequenceParameterSets); gf_bs_write_int(bs, count, 5); for (i=0; i<count; i++) { GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *) gf_list_get(ptr->config->sequenceParameterSets, i); gf_bs_write_u16(bs, sl->size); gf_bs_write_data(bs, sl->data, sl->size); } count = gf_list_count(ptr->config->pictureParameterSets); gf_bs_write_u8(bs, count); for (i=0; i<count; i++) { GF_AVCConfigSlot *sl = (GF_AVCConfigSlot *) gf_list_get(ptr->config->pictureParameterSets, i); gf_bs_write_u16(bs, sl->size); gf_bs_write_data(bs, sl->data, sl->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 tenc_Write(GF_Box *s, GF_BitStream *bs) { GF_Err e; GF_TrackEncryptionBox *ptr = (GF_TrackEncryptionBox *) s; if (!s) return GF_BAD_PARAM; e = gf_isom_full_box_write(s, bs); if (e) return e; gf_bs_write_u8(bs, 0x0); //reserved if (!ptr->version) { gf_bs_write_u8(bs, 0x0); //reserved } else { gf_bs_write_int(bs, ptr->crypt_byte_block, 4); gf_bs_write_int(bs, ptr->skip_byte_block, 4); } gf_bs_write_u8(bs, ptr->isProtected); gf_bs_write_u8(bs, ptr->Per_Sample_IV_Size); gf_bs_write_data(bs, (char *) ptr->KID, 16); if ((ptr->isProtected == 1) && !ptr->Per_Sample_IV_Size) { gf_bs_write_u8(bs, ptr->constant_IV_size); gf_bs_write_data(bs,(char *) ptr->constant_IV, ptr->constant_IV_size); } return GF_OK; }
GF_Err ohdr_Write(GF_Box *s, GF_BitStream *bs) { u16 cid_len, ri_len; GF_Err e; GF_OMADRMCommonHeaderBox *ptr = (GF_OMADRMCommonHeaderBox *)s; if (!s) return GF_BAD_PARAM; e = gf_isom_full_box_write(s, bs); if (e) return e; gf_bs_write_u8(bs, ptr->EncryptionMethod); gf_bs_write_u8(bs, ptr->PaddingScheme); gf_bs_write_u64(bs, ptr->PlaintextLength); cid_len = ptr->ContentID ? strlen(ptr->ContentID) : 0; gf_bs_write_u16(bs, cid_len); ri_len = ptr->RightsIssuerURL ? strlen(ptr->RightsIssuerURL) : 0; gf_bs_write_u16(bs, ri_len); gf_bs_write_u16(bs, ptr->TextualHeadersLen); if (cid_len) gf_bs_write_data(bs, ptr->ContentID, strlen(ptr->ContentID)); if (ri_len) gf_bs_write_data(bs, ptr->RightsIssuerURL, strlen(ptr->RightsIssuerURL)); if (ptr->TextualHeadersLen) gf_bs_write_data(bs, ptr->TextualHeaders, ptr->TextualHeadersLen); ptr->size -= cid_len+ri_len+ptr->TextualHeadersLen; return GF_OK; }
GF_Err grpi_Write(GF_Box *s, GF_BitStream *bs) { GF_Err e; u16 gid_len; GF_OMADRMGroupIDBox *ptr = (GF_OMADRMGroupIDBox *)s; if (!s) return GF_BAD_PARAM; e = gf_isom_full_box_write(s, bs); if (e) return e; gid_len = ptr->GroupID ? (u16) strlen(ptr->GroupID) : 0; gf_bs_write_u16(bs, gid_len); gf_bs_write_u8(bs, ptr->GKEncryptionMethod); gf_bs_write_u16(bs, ptr->GKLength); gf_bs_write_data(bs, ptr->GroupID, gid_len); gf_bs_write_data(bs, ptr->GroupKey, ptr->GKLength); 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 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; }
static GF_Err gf_seng_encode_dims_au(GF_SceneEngine *seng, u16 ESID, GF_List *commands, char **data, u32 *size) { #ifndef GPAC_DISABLE_SCENE_DUMP GF_SceneDumper *dumper = NULL; #endif GF_Err e; char rad_name[4096]; char file_name[4096]; FILE *file = NULL; u64 fsize; char *buffer = NULL; GF_BitStream *bs = NULL; u8 dims_header; Bool compress_dims; #ifdef DUMP_DIMS_LOG_WITH_TIME u32 do_dump_with_time = 1; #endif u32 buffer_len; char *cache_dir, *dump_name; if (!data) return GF_BAD_PARAM; e = GF_OK; if (!seng->dump_path) cache_dir = gf_get_default_cache_directory(); else cache_dir = seng->dump_path; dump_name = "gpac_scene_engine_dump"; compress_dims = 1; #ifdef DUMP_DIMS_LOG_WITH_TIME start: #endif if (commands && gf_list_count(commands)) { sprintf(rad_name, "%s%c%s%s", cache_dir, GF_PATH_SEPARATOR, dump_name, "_update"); } else { #ifndef DUMP_DIMS_LOG_WITH_TIME sprintf(rad_name, "%s%c%s%s", cache_dir, GF_PATH_SEPARATOR, "rap_", dump_name); #else char date_str[100], time_str[100]; time_t now; struct tm *tm_tot; now = time(NULL); tm_tot = localtime(&now); strftime(date_str, 100, "%Yy%mm%dd", tm_tot); strftime(time_str, 100, "%Hh%Mm%Ss", tm_tot); sprintf(rad_name, "%s%c%s-%s-%s%s", cache_dir, GF_PATH_SEPARATOR, date_str, time_str, "rap_", dump_name); #endif } #ifndef GPAC_DISABLE_SCENE_DUMP dumper = gf_sm_dumper_new(seng->ctx->scene_graph, rad_name, ' ', GF_SM_DUMP_SVG); if (!dumper) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[SceneEngine] Cannot create SVG dumper for %s.svg\n", rad_name)); e = GF_IO_ERR; goto exit; } if (commands && gf_list_count(commands)) { e = gf_sm_dump_command_list(dumper, commands, 0, 0); } else { e = gf_sm_dump_graph(dumper, 0, 0); } gf_sm_dumper_del(dumper); if(seng->dump_rap){ GF_SceneDumper *dumper = NULL; sprintf(rad_name, "%s%c%s%s", cache_dir, GF_PATH_SEPARATOR, "rap_", dump_name); dumper = gf_sm_dumper_new(seng->ctx->scene_graph, rad_name, ' ', GF_SM_DUMP_SVG); if (!dumper) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[SceneEngine] Cannot create SVG dumper for %s.svg\n", rad_name)); e = GF_IO_ERR; goto exit; } e = gf_sm_dump_graph(dumper, 0, 0); gf_sm_dumper_del(dumper); } if (e) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[SceneEngine] Cannot dump DIMS Commands\n")); goto exit; } #endif #ifdef DUMP_DIMS_LOG_WITH_TIME if (do_dump_with_time) { do_dump_with_time = 0; goto start; } #endif sprintf(file_name, "%s.svg", rad_name); file = gf_f64_open(file_name, "rb"); if (!file) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[SceneEngine] Cannot open SVG dump file %s\n", file_name)); e = GF_IO_ERR; goto exit; } gf_f64_seek(file, 0, SEEK_END); fsize = gf_f64_tell(file); if (fsize == 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[SceneEngine] SVG dump %s is empty\n", file_name)); goto exit; } /* First, read the dump in a buffer */ buffer = gf_malloc((size_t)fsize * sizeof(char)); gf_f64_seek(file, 0, SEEK_SET); fsize = fread(buffer, sizeof(char), (size_t)fsize, file); fclose(file); file = NULL; /* Then, set DIMS unit header - TODO: notify redundant units*/ dims_header = 0; if (commands && gf_list_count(commands)) { dims_header = GF_DIMS_UNIT_P; /* streamer->all_non_rap_critical ? 0 : GF_DIMS_UNIT_P;*/ } else { /*redundant RAP with complete scene*/ dims_header = GF_DIMS_UNIT_M | GF_DIMS_UNIT_S | GF_DIMS_UNIT_I | GF_DIMS_UNIT_P; } /* Then, if compression is asked, we do it */ buffer_len = (u32)fsize; assert(fsize < 1<<31); GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[SceneEngine] Sending DIMS data - sizes: raw (%d)", buffer_len)); if (compress_dims) { dims_header |= GF_DIMS_UNIT_C; e = gf_gz_compress_payload(&buffer, buffer_len, &buffer_len); GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("/ compressed (%d)", buffer_len)); if (e) goto exit; } GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("\n")); /* Then, prepare the DIMS data using a bitstream instead of direct manipulation for endianness The new bitstream size should be: the size of the (compressed) data + 1 bytes for the header + 2 bytes for the size + 4 bytes if the size is greater than 65535 */ bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); if (buffer_len > 65535) { GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[SceneEngine] Warning: DIMS Unit size too big !!!\n")); gf_bs_write_u16(bs, 0); /* internal GPAC hack to indicate that the size is larger than 65535 */ gf_bs_write_u32(bs, buffer_len+1); } else { gf_bs_write_u16(bs, buffer_len+1); } gf_bs_write_u8(bs, dims_header); gf_bs_write_data(bs, buffer, buffer_len); gf_free(buffer); buffer = NULL; gf_bs_get_content(bs, data, size); gf_bs_del(bs); exit: if (!seng->dump_path) gf_free(cache_dir); if (buffer) gf_free(buffer); if (file) fclose(file); return e; }
static GF_Err CENC_ProcessData(ISMAEAPriv *priv, GF_IPMPEvent *evt) { GF_Err e; GF_BitStream *pleintext_bs, *cyphertext_bs, *sai_bs; char IV[17]; bin128 KID; char *buffer; u32 max_size, i, subsample_count; u64 BSO; GF_CENCSampleAuxInfo *sai; e = GF_OK; pleintext_bs = cyphertext_bs = sai_bs = NULL; buffer = NULL; max_size = 4096; if (!priv->crypt) return GF_SERVICE_ERROR; if (!evt->is_encrypted || !evt->IV_size) return GF_OK; cyphertext_bs = gf_bs_new(evt->data, evt->data_size, GF_BITSTREAM_READ); sai_bs = gf_bs_new(evt->sai, evt->saiz, GF_BITSTREAM_READ); pleintext_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); buffer = (char*)gf_malloc(sizeof(char) * max_size); sai = (GF_CENCSampleAuxInfo *)gf_malloc(sizeof(GF_CENCSampleAuxInfo)); if (!sai) { e = GF_IO_ERR; goto exit; } memset(sai, 0, sizeof(GF_CENCSampleAuxInfo)); sai->IV_size = evt->IV_size; /*read sample auxiliary information from bitstream*/ gf_bs_read_data(sai_bs, (char *)KID, 16); gf_bs_read_data(sai_bs, (char *)sai->IV, sai->IV_size); sai->subsample_count = gf_bs_read_u16(sai_bs); if (sai->subsample_count) { sai->subsamples = (GF_CENCSubSampleEntry *)gf_malloc(sai->subsample_count*sizeof(GF_CENCSubSampleEntry)); for (i = 0; i < sai->subsample_count; i++) { sai->subsamples[i].bytes_clear_data = gf_bs_read_u16(sai_bs); sai->subsamples[i].bytes_encrypted_data = gf_bs_read_u32(sai_bs); } } for (i = 0; i < priv->KID_count; i++) { if (!strncmp((const char *)KID, (const char *)priv->KIDs[i], 16)) { memmove(priv->key, priv->keys[i], 16); break; } } if (priv->first_crypted_samp) { memmove(IV, sai->IV, sai->IV_size); if (sai->IV_size == 8) memset(IV+8, 0, sizeof(char)*8); e = gf_crypt_init(priv->crypt, priv->key, 16, IV); if (e) { GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Cannot initialize AES-128 AES-128 %s (%s)\n", priv->is_cenc ? "CTR" : "CBC", gf_error_to_string(e)) ); e = GF_IO_ERR; goto exit; } priv->first_crypted_samp = GF_FALSE; } else { if (priv->is_cenc) { GF_BitStream *bs; bs = gf_bs_new(IV, 17, GF_BITSTREAM_WRITE); gf_bs_write_u8(bs, 0); /*begin of counter*/ gf_bs_write_data(bs,(char *)sai->IV, sai->IV_size); if (sai->IV_size == 8) gf_bs_write_u64(bs, 0); /*0-padded if IV_size == 8*/ gf_bs_del(bs); gf_crypt_set_state(priv->crypt, IV, 17); } e = gf_crypt_set_key(priv->crypt, priv->key, 16, IV); if (e) { GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Cannot set key AES-128 %s (%s)\n", priv->is_cenc ? "CTR" : "CBC", gf_error_to_string(e)) ); e = GF_IO_ERR; goto exit; } } subsample_count = 0; BSO = 0; while (gf_bs_available(cyphertext_bs)) { assert(subsample_count < sai->subsample_count); /*read clear data and write it to pleintext bitstream*/ if (max_size < sai->subsamples[subsample_count].bytes_clear_data) { buffer = (char*)gf_realloc(buffer, sizeof(char)*sai->subsamples[subsample_count].bytes_clear_data); max_size = sai->subsamples[subsample_count].bytes_clear_data; } gf_bs_read_data(cyphertext_bs, buffer, sai->subsamples[subsample_count].bytes_clear_data); gf_bs_write_data(pleintext_bs, buffer, sai->subsamples[subsample_count].bytes_clear_data); /*now read encrypted data, decrypted it and write to pleintext bitstream*/ if (max_size < sai->subsamples[subsample_count].bytes_encrypted_data) { buffer = (char*)gf_realloc(buffer, sizeof(char)*sai->subsamples[subsample_count].bytes_encrypted_data); max_size = sai->subsamples[subsample_count].bytes_encrypted_data; } gf_bs_read_data(cyphertext_bs, buffer, sai->subsamples[subsample_count].bytes_encrypted_data); gf_crypt_decrypt(priv->crypt, buffer, sai->subsamples[subsample_count].bytes_encrypted_data); gf_bs_write_data(pleintext_bs, buffer, sai->subsamples[subsample_count].bytes_encrypted_data); /*update IV for next subsample*/ if (priv->is_cenc) { BSO += sai->subsamples[subsample_count].bytes_encrypted_data; if (gf_bs_available(cyphertext_bs)) { char next_IV[17]; u64 prev_block_count, salt_portion, block_count_portion; u32 remain; GF_BitStream *bs, *tmp; prev_block_count = BSO / 16; remain = BSO % 16; tmp = gf_bs_new((const char *)sai->IV, 16, GF_BITSTREAM_READ); bs = gf_bs_new(next_IV, 17, GF_BITSTREAM_WRITE); gf_bs_write_u8(bs, 0); /*begin of counter*/ salt_portion = gf_bs_read_u64(tmp); block_count_portion = gf_bs_read_u64(tmp); /*reset the block counter to zero without affecting the other 64 bits of the IV*/ if (prev_block_count > 0xFFFFFFFFFFFFFFFFULL - block_count_portion) block_count_portion = prev_block_count - (0xFFFFFFFFFFFFFFFFULL - block_count_portion) - 1; else block_count_portion += prev_block_count; gf_bs_write_u64(bs, salt_portion); gf_bs_write_u64(bs, block_count_portion); gf_crypt_set_state(priv->crypt, next_IV, 17); /*decrypt remain bytes*/ if (remain) { char dummy[20]; gf_crypt_decrypt(priv->crypt, dummy, remain); } gf_bs_del(bs); gf_bs_del(tmp); } } subsample_count++; } if (buffer) gf_free(buffer); gf_bs_get_content(pleintext_bs, &buffer, &evt->data_size); memmove(evt->data, buffer, evt->data_size); exit: if (pleintext_bs) gf_bs_del(pleintext_bs); if (sai_bs) gf_bs_del(sai_bs); if (cyphertext_bs) gf_bs_del(cyphertext_bs); if (buffer) gf_free(buffer); if (sai && sai->subsamples) gf_free(sai->subsamples); if (sai) gf_free(sai); return e; }
static GF_Err gf_isom_get_3gpp_audio_esd(GF_SampleTableBox *stbl, GF_GenericAudioSampleEntryBox *entry, GF_ESD **out_esd) { GF_BitStream *bs; char szName[80]; (*out_esd) = gf_odf_desc_esd_new(2); (*out_esd)->decoderConfig->streamType = GF_STREAM_AUDIO; /*official mapping to MPEG-4*/ switch (entry->type) { case GF_ISOM_SUBTYPE_3GP_EVRC: (*out_esd)->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_EVRC_VOICE; return GF_OK; case GF_ISOM_SUBTYPE_3GP_QCELP: { u32 block_size, sample_rate, sample_size, i; GF_SttsEntry *ent; /*only map CBR*/ sample_size = stbl->SampleSize->sampleSize; (*out_esd)->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_13K_VOICE; bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_data(bs, "QLCMfmt ", 8); gf_bs_write_u32_le(bs, 150);/*fmt chunk size*/ gf_bs_write_u8(bs, 1); gf_bs_write_u8(bs, 0); /*QCELP GUID*/ gf_bs_write_data(bs, "\x41\x6D\x7F\x5E\x15\xB1\xD0\x11\xBA\x91\x00\x80\x5F\xB4\xB9\x7E", 16); gf_bs_write_u16_le(bs, 1); memset(szName, 0, 80); strcpy(szName, "QCELP-13K(GPAC-emulated)"); gf_bs_write_data(bs, szName, 80); ent = &stbl->TimeToSample->entries[0]; sample_rate = entry->samplerate_hi; block_size = ent ? ent->sampleDelta : 160; gf_bs_write_u16_le(bs, 8*sample_size*sample_rate/block_size); gf_bs_write_u16_le(bs, sample_size); gf_bs_write_u16_le(bs, block_size); gf_bs_write_u16_le(bs, sample_rate); gf_bs_write_u16_le(bs, entry->bitspersample); gf_bs_write_u32_le(bs, sample_size ? 0 : 7); /**/ for (i=0; i<7; i++) { static const u32 qcelp_r2s [] = {0, 1, 1, 4, 2, 8, 3, 17, 4, 35, 5, 8, 14, 1}; if (sample_size) { gf_bs_write_u16(bs, 0); } else { gf_bs_write_u8(bs, qcelp_r2s[2*i+1]); gf_bs_write_u8(bs, qcelp_r2s[2*i]); } } gf_bs_write_u16(bs, 0); memset(szName, 0, 80); gf_bs_write_data(bs, szName, 20);/*reserved*/ gf_bs_get_content(bs, & (*out_esd)->decoderConfig->decoderSpecificInfo->data, & (*out_esd)->decoderConfig->decoderSpecificInfo->dataLength); gf_bs_del(bs); } return GF_OK; case GF_ISOM_SUBTYPE_3GP_SMV: (*out_esd)->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_SMV_VOICE; return GF_OK; default: break; } /*this is a user-reserved used in gpac - we need a std OTI for AMR/AMRWB*/ (*out_esd)->decoderConfig->objectTypeIndication = GPAC_OTI_MEDIA_GENERIC; bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_u32(bs, entry->type); gf_bs_write_u16(bs, entry->samplerate_hi); gf_bs_write_u16(bs, (entry->type == GF_ISOM_SUBTYPE_3GP_AMR) ? 160 : 320); gf_bs_write_u8(bs, entry->channel_count); gf_bs_write_u8(bs, entry->bitspersample); gf_bs_write_u8(bs, 0); gf_bs_get_content(bs, & (*out_esd)->decoderConfig->decoderSpecificInfo->data, & (*out_esd)->decoderConfig->decoderSpecificInfo->dataLength); gf_bs_del(bs); 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; }
GF_Err gp_rtp_builder_do_smv(GP_RTPPacketizer *builder, char *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize) { u32 offset, rtp_ts; if (!data) { rtp_evrc_smv_flush(builder); return GF_OK; } rtp_ts = (u32) builder->sl_header.compositionTimeStamp; offset = 0; while (data_size>offset) { u8 frame_type = data[offset]; u8 size = qes_get_rate_size(frame_type, GF_SMV_EVRC_RATE_TO_SIZE, GF_SMV_EVRC_RATE_TO_SIZE_NB); /*reserved, not sent)*/ if (frame_type>=5) { offset += size; continue; } /*packet full or too long*/ if (builder->bytesInPacket + size > builder->Path_MTU) rtp_evrc_smv_flush(builder); /*need new*/ if (!builder->bytesInPacket) { builder->rtp_header.TimeStamp = rtp_ts; builder->rtp_header.Marker = 0; /*never set*/ builder->rtp_header.SequenceNumber += 1; builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header); assert(builder->pck_hdr==NULL); if (builder->auh_size>1) { builder->pck_hdr = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); /*RRLLLNNN (all 0, no interleaving)*/ gf_bs_write_u8(builder->pck_hdr, 0); /*MMM + count-1 : overriden when flushing*/ gf_bs_write_u8(builder->pck_hdr, 0); builder->bytesInPacket = 2; } } /*bundle mode: cat rate byte to TOC, on 4 bits*/ if (builder->auh_size>1) { gf_bs_write_int(builder->pck_hdr, data[offset], 4); if (!(builder->last_au_sn % 2)) builder->bytesInPacket += 1; } /*note that EVEN in header-free format the rate_type byte is removed*/ offset++; size--; /*add frame data without rate_type byte header*/ if (builder->OnDataReference) { builder->OnDataReference(builder->cbk_obj, size, offset); } else { builder->OnData(builder->cbk_obj, data+offset, size, 0); } builder->last_au_sn++; builder->bytesInPacket += size; offset += size; rtp_ts += 160; assert(builder->bytesInPacket<=builder->Path_MTU); /*take care of aggregation, flush if needed*/ if (builder->last_au_sn==builder->auh_size) rtp_evrc_smv_flush(builder); } return GF_OK; }
/* Rewrite mode: * mode = 0: playback * mode = 1: streaming */ GF_Err gf_isom_nalu_sample_rewrite(GF_MediaBox *mdia, GF_ISOSample *sample, u32 sampleNumber, GF_MPEGVisualSampleEntryBox *entry) { Bool is_hevc = 0; GF_Err e = GF_OK; GF_ISOSample *ref_samp; GF_BitStream *src_bs, *ref_bs, *dst_bs; u64 offset; u32 ref_nalu_size, data_offset, data_length, copy_size, nal_size, max_size, di, nal_unit_size_field, cur_extract_mode, extractor_mode; Bool rewrite_ps, rewrite_start_codes; u8 ref_track_ID, ref_track_num; s8 sample_offset, nal_type; u32 nal_hdr; char *buffer; GF_ISOFile *file = mdia->mediaTrack->moov->mov; src_bs = ref_bs = dst_bs = NULL; ref_samp = NULL; buffer = NULL; rewrite_ps = (mdia->mediaTrack->extractor_mode & GF_ISOM_NALU_EXTRACT_INBAND_PS_FLAG) ? 1 : 0; if (! sample->IsRAP) rewrite_ps = 0; rewrite_start_codes = (mdia->mediaTrack->extractor_mode & GF_ISOM_NALU_EXTRACT_ANNEXB_FLAG) ? 1 : 0; extractor_mode = mdia->mediaTrack->extractor_mode&0x0000FFFF; if (extractor_mode == GF_ISOM_NALU_EXTRACT_INSPECT) { if (!rewrite_ps && !rewrite_start_codes) return GF_OK; } if (!entry) return GF_BAD_PARAM; nal_unit_size_field = 0; /*if svc rewrire*/ if (entry->svc_config && entry->svc_config->config) nal_unit_size_field = entry->svc_config->config->nal_unit_size; /*if mvc rewrire*/ /*otherwise do nothing*/ else if (!rewrite_ps && !rewrite_start_codes) { return GF_OK; } if (!nal_unit_size_field) { if (entry->avc_config) nal_unit_size_field = entry->avc_config->config->nal_unit_size; else if (entry->hevc_config) { nal_unit_size_field = entry->hevc_config->config->nal_unit_size; is_hevc = 1; } } if (!nal_unit_size_field) return GF_ISOM_INVALID_FILE; dst_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); src_bs = gf_bs_new(sample->data, sample->dataLength, GF_BITSTREAM_READ); max_size = 4096; /*rewrite start code with NALU delim*/ if (rewrite_start_codes) { gf_bs_write_int(dst_bs, 1, 32); if (is_hevc) { gf_bs_write_int(dst_bs, 0, 1); gf_bs_write_int(dst_bs, GF_HEVC_NALU_ACCESS_UNIT, 6); gf_bs_write_int(dst_bs, 0, 9); /*pic-type - by default we signal all slice types possible*/ gf_bs_write_int(dst_bs, 2, 3); gf_bs_write_int(dst_bs, 0, 5); } else { gf_bs_write_int(dst_bs, (sample->data[0] & 0x60) | GF_AVC_NALU_ACCESS_UNIT, 8); gf_bs_write_int(dst_bs, 0xF0 , 8); /*7 "all supported NALUs" (=111) + rbsp trailing (10000)*/; } } if (rewrite_ps) { if (is_hevc) { u32 i, count; count = gf_list_count(entry->hevc_config->config->param_array); for (i=0; i<count; i++) { GF_HEVCParamArray *ar = gf_list_get(entry->hevc_config->config->param_array, i); rewrite_nalus_list(ar->nalus, dst_bs, rewrite_start_codes, nal_unit_size_field); } /*little optimization if we are not asked to start codes: copy over the sample*/ if (!rewrite_start_codes) { gf_bs_write_data(dst_bs, sample->data, sample->dataLength); gf_free(sample->data); sample->data = NULL; gf_bs_get_content(dst_bs, &sample->data, &sample->dataLength); gf_bs_del(src_bs); gf_bs_del(dst_bs); return GF_OK; } } else { /*this is an SVC track: get all SPS/PPS from this track down to the base layer and rewrite them*/ if (mdia->mediaTrack->has_base_layer) { u32 j; GF_List *nalu_sps = gf_list_new(); GF_List *nalu_pps = gf_list_new(); GF_TrackReferenceTypeBox *dpnd = NULL; Track_FindRef(mdia->mediaTrack, GF_ISOM_REF_SCAL, &dpnd); #if 0 /*get all upper layers with SCAL reference to this track*/ for (j = 0; j < gf_isom_get_track_count(file); j++) { if (gf_isom_has_track_reference(file, j+1, GF_ISOM_REF_SCAL, mdia->mediaTrack->Header->trackID)) { u32 tkID; GF_TrackBox *base_track; GF_MPEGVisualSampleEntryBox *base_entry; gf_isom_get_reference_ID(file, j+1, GF_ISOM_REF_SCAL, 1, &tkID); base_track = GetTrackbyID(mdia->mediaTrack->moov, tkID); base_entry = base_track ? gf_list_get(base_track->Media->information->sampleTable->SampleDescription->other_boxes, 0) : NULL; if (base_entry) merge_nalus(base_entry, nalu_sps, nalu_pps); } } #endif merge_nalus(entry, nalu_sps, nalu_pps); if (dpnd) { for (j=0; j<dpnd->trackIDCount; j++) { GF_TrackBox *base_track = GetTrackbyID(mdia->mediaTrack->moov, dpnd->trackIDs[j]); GF_MPEGVisualSampleEntryBox *base_entry = base_track ? gf_list_get(base_track->Media->information->sampleTable->SampleDescription->other_boxes, 0) : NULL; if (base_entry) merge_nalus(base_entry, nalu_sps, nalu_pps); } } //rewrite nalus rewrite_nalus_list(nalu_sps, dst_bs, rewrite_start_codes, nal_unit_size_field); rewrite_nalus_list(nalu_pps, dst_bs, rewrite_start_codes, nal_unit_size_field); gf_list_del(nalu_sps); gf_list_del(nalu_pps); } else { if (entry->avc_config) { rewrite_nalus_list(entry->avc_config->config->sequenceParameterSets, dst_bs, rewrite_start_codes, nal_unit_size_field); rewrite_nalus_list(entry->avc_config->config->pictureParameterSets, dst_bs, rewrite_start_codes, nal_unit_size_field); rewrite_nalus_list(entry->avc_config->config->sequenceParameterSetExtensions, dst_bs, rewrite_start_codes, nal_unit_size_field); } /*add svc config */ if (entry->svc_config) { rewrite_nalus_list(entry->svc_config->config->sequenceParameterSets, dst_bs, rewrite_start_codes, nal_unit_size_field); rewrite_nalus_list(entry->svc_config->config->pictureParameterSets, dst_bs, rewrite_start_codes, nal_unit_size_field); } /*little optimization if we are not asked to rewrite extractors or start codes: copy over the sample*/ if (!entry->svc_config && !rewrite_start_codes) { gf_bs_write_data(dst_bs, sample->data, sample->dataLength); gf_free(sample->data); sample->data = NULL; gf_bs_get_content(dst_bs, &sample->data, &sample->dataLength); gf_bs_del(src_bs); gf_bs_del(dst_bs); return GF_OK; } } } } buffer = (char *)gf_malloc(sizeof(char)*max_size); while (gf_bs_available(src_bs)) { nal_size = gf_bs_read_int(src_bs, 8*nal_unit_size_field); if (nal_size>max_size) { buffer = (char*) gf_realloc(buffer, sizeof(char)*nal_size); max_size = nal_size; } if (is_hevc) { nal_hdr = gf_bs_read_u16(src_bs); nal_type = (nal_hdr&0x7E00) >> 9; } else { nal_hdr = gf_bs_read_u8(src_bs); nal_type = nal_hdr & 0x1F; } if (is_hevc) { /*we already wrote this stuff*/ if (nal_type==GF_HEVC_NALU_ACCESS_UNIT) { gf_bs_skip_bytes(src_bs, nal_size-2); continue; } /*rewrite nal*/ gf_bs_read_data(src_bs, buffer, nal_size-2); if (rewrite_start_codes) gf_bs_write_u32(dst_bs, 1); else gf_bs_write_int(dst_bs, nal_size, 8*nal_unit_size_field); gf_bs_write_u16(dst_bs, nal_hdr); gf_bs_write_data(dst_bs, buffer, nal_size-2); continue; } /*we already wrote this stuff*/ if (nal_type==GF_AVC_NALU_ACCESS_UNIT) { gf_bs_skip_bytes(src_bs, nal_size-1); continue; } //extractor if (nal_type == 31) { switch (extractor_mode) { case 0: gf_bs_read_int(src_bs, 24); //3 bytes of NALUHeader in extractor ref_track_ID = gf_bs_read_u8(src_bs); sample_offset = (s8) gf_bs_read_int(src_bs, 8); data_offset = gf_bs_read_u32(src_bs); data_length = gf_bs_read_u32(src_bs); ref_track_num = gf_isom_get_track_by_id(file, ref_track_ID); if (!ref_track_num) { e = GF_BAD_PARAM; goto exit; } cur_extract_mode = gf_isom_get_nalu_extract_mode(file, ref_track_num); gf_isom_set_nalu_extract_mode(file, ref_track_num, GF_ISOM_NALU_EXTRACT_INSPECT); ref_samp = gf_isom_get_sample(file, ref_track_num, sampleNumber+sample_offset, &di); if (!ref_samp) { e = GF_IO_ERR; goto exit; } ref_bs = gf_bs_new(ref_samp->data, ref_samp->dataLength, GF_BITSTREAM_READ); offset = 0; while (gf_bs_available(ref_bs)) { if (gf_bs_get_position(ref_bs) < data_offset) { ref_nalu_size = gf_bs_read_int(ref_bs, 8*nal_unit_size_field); offset += ref_nalu_size + nal_unit_size_field; if ((offset > data_offset) || (offset >= gf_bs_get_size(ref_bs))) { e = GF_BAD_PARAM; goto exit; } e = gf_bs_seek(ref_bs, offset); if (e) goto exit; continue; } ref_nalu_size = gf_bs_read_int(ref_bs, 8*nal_unit_size_field); copy_size = data_length ? data_length : ref_nalu_size; assert(copy_size <= ref_nalu_size); nal_hdr = gf_bs_read_u8(ref_bs); //rewrite NAL type if ((copy_size-1)>max_size) { buffer = (char*)gf_realloc(buffer, sizeof(char)*(copy_size-1)); max_size = copy_size-1; } gf_bs_read_data(ref_bs, buffer, copy_size-1); if (rewrite_start_codes) gf_bs_write_u32(dst_bs, 1); else gf_bs_write_int(dst_bs, copy_size, 8*nal_unit_size_field); gf_bs_write_u8(dst_bs, nal_hdr); gf_bs_write_data(dst_bs, buffer, copy_size-1); } gf_isom_sample_del(&ref_samp); ref_samp = NULL; gf_bs_del(ref_bs); ref_bs = NULL; gf_isom_set_nalu_extract_mode(file, ref_track_num, cur_extract_mode); break; default: //skip to end of this NALU gf_bs_skip_bytes(src_bs, nal_size-1); continue; } } else { gf_bs_read_data(src_bs, buffer, nal_size-1); if (rewrite_start_codes) gf_bs_write_u32(dst_bs, 1); else gf_bs_write_int(dst_bs, nal_size, 8*nal_unit_size_field); gf_bs_write_u8(dst_bs, nal_hdr); gf_bs_write_data(dst_bs, buffer, nal_size-1); } }
static GF_ESD *FFD_GetESDescriptor(FFDemux *ffd, Bool for_audio) { GF_BitStream *bs; Bool dont_use_sl; GF_ESD *esd = (GF_ESD *) gf_odf_desc_esd_new(0); esd->ESID = 1 + (for_audio ? ffd->audio_st : ffd->video_st); esd->decoderConfig->streamType = for_audio ? GF_STREAM_AUDIO : GF_STREAM_VISUAL; esd->decoderConfig->avgBitrate = esd->decoderConfig->maxBitrate = 0; /*remap std object types - depending on input formats, FFMPEG may not have separate DSI from initial frame. In this case we have no choice but using FFMPEG decoders*/ if (for_audio) { AVCodecContext *dec = ffd->ctx->streams[ffd->audio_st]->codec; esd->slConfig->timestampResolution = ffd->audio_tscale.den; switch (dec->codec_id) { case CODEC_ID_MP2: esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_MPEG1; break; case CODEC_ID_MP3: esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_MPEG2_PART3; break; case CODEC_ID_AAC: if (!dec->extradata_size) goto opaque_audio; esd->decoderConfig->objectTypeIndication = GPAC_OTI_AUDIO_AAC_MPEG4; esd->decoderConfig->decoderSpecificInfo->dataLength = dec->extradata_size; esd->decoderConfig->decoderSpecificInfo->data = gf_malloc(sizeof(char)*dec->extradata_size); memcpy(esd->decoderConfig->decoderSpecificInfo->data, dec->extradata, sizeof(char)*dec->extradata_size); break; default: opaque_audio: esd->decoderConfig->objectTypeIndication = GPAC_OTI_MEDIA_FFMPEG; bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_u32(bs, dec->codec_id); gf_bs_write_u32(bs, dec->sample_rate); gf_bs_write_u16(bs, dec->channels); gf_bs_write_u16(bs, dec->frame_size); gf_bs_write_u8(bs, 16); gf_bs_write_u8(bs, 0); /*ffmpeg specific*/ gf_bs_write_u16(bs, dec->block_align); gf_bs_write_u32(bs, dec->bit_rate); gf_bs_write_u32(bs, dec->codec_tag); if (dec->extradata_size) { gf_bs_write_data(bs, (char *) dec->extradata, dec->extradata_size); } gf_bs_get_content(bs, (char **) &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength); gf_bs_del(bs); break; } dont_use_sl = ffd->unreliable_audio_timing; } else { AVCodecContext *dec = ffd->ctx->streams[ffd->video_st]->codec; esd->slConfig->timestampResolution = ffd->video_tscale.den; switch (dec->codec_id) { case CODEC_ID_MPEG4: /*there is a bug in fragmentation of raw H264 in ffmpeg, the NALU startcode (0x00000001) is split across two frames - we therefore force internal ffmpeg codec ID to avoid NALU size recompute at the decoder level*/ // case CODEC_ID_H264: /*if dsi not detected force use ffmpeg*/ if (!dec->extradata_size) goto opaque_video; /*otherwise use any MPEG-4 Visual*/ esd->decoderConfig->objectTypeIndication = (dec->codec_id==CODEC_ID_H264) ? GPAC_OTI_VIDEO_AVC : GPAC_OTI_VIDEO_MPEG4_PART2; esd->decoderConfig->decoderSpecificInfo->dataLength = dec->extradata_size; esd->decoderConfig->decoderSpecificInfo->data = gf_malloc(sizeof(char)*dec->extradata_size); memcpy(esd->decoderConfig->decoderSpecificInfo->data, dec->extradata, sizeof(char)*dec->extradata_size); break; case CODEC_ID_MPEG1VIDEO: esd->decoderConfig->objectTypeIndication = GPAC_OTI_VIDEO_MPEG1; break; case CODEC_ID_MPEG2VIDEO: esd->decoderConfig->objectTypeIndication = GPAC_OTI_VIDEO_MPEG2_422; break; default: opaque_video: esd->decoderConfig->objectTypeIndication = GPAC_OTI_MEDIA_FFMPEG; bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_u32(bs, dec->codec_id); gf_bs_write_u16(bs, dec->width); gf_bs_write_u16(bs, dec->height); /*ffmpeg specific*/ gf_bs_write_u32(bs, dec->bit_rate); gf_bs_write_u32(bs, dec->codec_tag); gf_bs_write_u32(bs, dec->pix_fmt); if (dec->extradata_size) { gf_bs_write_data(bs, (char *) dec->extradata, dec->extradata_size); } gf_bs_get_content(bs, (char **) &esd->decoderConfig->decoderSpecificInfo->data, &esd->decoderConfig->decoderSpecificInfo->dataLength); gf_bs_del(bs); break; } dont_use_sl = 0; } if (dont_use_sl) { esd->slConfig->predefined = SLPredef_SkipSL; } else { /*only send full AUs*/ esd->slConfig->useAccessUnitStartFlag = esd->slConfig->useAccessUnitEndFlag = 0; if (for_audio) { esd->slConfig->hasRandomAccessUnitsOnlyFlag = 1; } else { esd->slConfig->useRandomAccessPointFlag = 1; } esd->slConfig->useTimestampsFlag = 1; } return esd; }
static GF_Err CENC_ProcessData(ISMAEAPriv *priv, GF_IPMPEvent *evt) { GF_Err e; GF_BitStream *pleintext_bs, *cyphertext_bs, *sai_bs; char IV[17]; bin128 KID; char *buffer; u32 max_size, i, subsample_count; GF_CENCSampleAuxInfo *sai; pleintext_bs = cyphertext_bs = sai_bs = NULL; buffer = NULL; max_size = 4096; if (!priv->crypt) return GF_SERVICE_ERROR; if (!evt->is_encrypted || !evt->IV_size || !evt->saiz) return GF_OK; cyphertext_bs = gf_bs_new(evt->data, evt->data_size, GF_BITSTREAM_READ); sai_bs = gf_bs_new(evt->sai, evt->saiz, GF_BITSTREAM_READ); pleintext_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); buffer = (char*)gf_malloc(sizeof(char) * max_size); sai = (GF_CENCSampleAuxInfo *)gf_malloc(sizeof(GF_CENCSampleAuxInfo)); if (!sai) { e = GF_IO_ERR; goto exit; } memset(sai, 0, sizeof(GF_CENCSampleAuxInfo)); sai->IV_size = evt->IV_size; /*read sample auxiliary information from bitstream*/ gf_bs_read_data(sai_bs, (char *)KID, 16); gf_bs_read_data(sai_bs, (char *)sai->IV, sai->IV_size); sai->subsample_count = gf_bs_read_u16(sai_bs); if (sai->subsample_count) { sai->subsamples = (GF_CENCSubSampleEntry *)gf_malloc(sai->subsample_count*sizeof(GF_CENCSubSampleEntry)); for (i = 0; i < sai->subsample_count; i++) { sai->subsamples[i].bytes_clear_data = gf_bs_read_u16(sai_bs); sai->subsamples[i].bytes_encrypted_data = gf_bs_read_u32(sai_bs); } } for (i = 0; i < priv->KID_count; i++) { if (!strncmp((const char *)KID, (const char *)priv->KIDs[i], 16)) { memmove(priv->key, priv->keys[i], 16); break; } } if (priv->first_crypted_samp) { memmove(IV, sai->IV, sai->IV_size); if (sai->IV_size == 8) memset(IV+8, 0, sizeof(char)*8); e = gf_crypt_init(priv->crypt, priv->key, 16, IV); if (e) { GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Cannot initialize AES-128 AES-128 %s (%s)\n", priv->is_cenc ? "CTR" : "CBC", gf_error_to_string(e)) ); e = GF_IO_ERR; goto exit; } priv->first_crypted_samp = GF_FALSE; } else { if (priv->is_cenc) { GF_BitStream *bs; bs = gf_bs_new(IV, 17, GF_BITSTREAM_WRITE); gf_bs_write_u8(bs, 0); /*begin of counter*/ gf_bs_write_data(bs,(char *)sai->IV, sai->IV_size); if (sai->IV_size == 8) gf_bs_write_u64(bs, 0); /*0-padded if IV_size == 8*/ gf_bs_del(bs); gf_crypt_set_state(priv->crypt, IV, 17); } e = gf_crypt_set_key(priv->crypt, priv->key, 16, IV); if (e) { GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[CENC] Cannot set key AES-128 %s (%s)\n", priv->is_cenc ? "CTR" : "CBC", gf_error_to_string(e)) ); e = GF_IO_ERR; goto exit; } } //sub-sample encryption if (sai->subsample_count) { subsample_count = 0; while (gf_bs_available(cyphertext_bs)) { if (subsample_count >= sai->subsample_count) break; /*read clear data and write it to pleintext bitstream*/ if (max_size < sai->subsamples[subsample_count].bytes_clear_data) { buffer = (char*)gf_realloc(buffer, sizeof(char)*sai->subsamples[subsample_count].bytes_clear_data); max_size = sai->subsamples[subsample_count].bytes_clear_data; } gf_bs_read_data(cyphertext_bs, buffer, sai->subsamples[subsample_count].bytes_clear_data); gf_bs_write_data(pleintext_bs, buffer, sai->subsamples[subsample_count].bytes_clear_data); /*now read encrypted data, decrypted it and write to pleintext bitstream*/ if (max_size < sai->subsamples[subsample_count].bytes_encrypted_data) { buffer = (char*)gf_realloc(buffer, sizeof(char)*sai->subsamples[subsample_count].bytes_encrypted_data); max_size = sai->subsamples[subsample_count].bytes_encrypted_data; } gf_bs_read_data(cyphertext_bs, buffer, sai->subsamples[subsample_count].bytes_encrypted_data); gf_crypt_decrypt(priv->crypt, buffer, sai->subsamples[subsample_count].bytes_encrypted_data); gf_bs_write_data(pleintext_bs, buffer, sai->subsamples[subsample_count].bytes_encrypted_data); subsample_count++; } if (buffer) gf_free(buffer); gf_bs_get_content(pleintext_bs, &buffer, &evt->data_size); } //full sample encryption else { if (max_size < evt->data_size) { buffer = (char*)gf_realloc(buffer, sizeof(char)*evt->data_size); } gf_bs_read_data(cyphertext_bs, buffer, evt->data_size); gf_crypt_decrypt(priv->crypt, buffer, evt->data_size); } memmove(evt->data, buffer, evt->data_size); exit: if (pleintext_bs) gf_bs_del(pleintext_bs); if (sai_bs) gf_bs_del(sai_bs); if (cyphertext_bs) gf_bs_del(cyphertext_bs); if (buffer) gf_free(buffer); if (sai && sai->subsamples) gf_free(sai->subsamples); if (sai) gf_free(sai); return e; }
GF_Err gf_saf_mux_for_time(GF_SAFMuxer *mux, u32 time_ms, Bool force_end_of_session, char **out_data, u32 *out_size) { u32 i, count, dlen; char *data; GF_SAFStream *str; GF_SAFSample*au; GF_BitStream *bs, *payload; *out_data = NULL; *out_size = 0; gf_mx_p(mux->mx); if (!force_end_of_session && (mux->state!=1)) { gf_mx_v(mux->mx); return GF_OK; } bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); count = gf_list_count(mux->streams); /*1: write all stream headers*/ for (i=0; i<count; i++) { str = (GF_SAFStream *)gf_list_get(mux->streams, i); if (str->state & 1) continue; au = (GF_SAFSample *)gf_list_get(str->aus, 0); /*write stream declaration*/ payload = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_int(payload, str->remote_url ? SAF_REMOTE_STREAM_HEADER : SAF_STREAM_HEADER, 4); gf_bs_write_int(payload, str->stream_id, 12); gf_bs_write_u8(payload, str->object_type); gf_bs_write_u8(payload, str->stream_type); gf_bs_write_int(payload, str->ts_resolution, 24); gf_bs_write_u16(payload, str->buffersize_db); if (str->mime_type) { u32 len = (u32) strlen(str->mime_type); gf_bs_write_u16(payload, len); gf_bs_write_data(payload, str->mime_type, len); } if (str->remote_url) { u32 len = (u32) strlen(str->remote_url); gf_bs_write_u16(payload, len); gf_bs_write_data(payload, str->remote_url, len); } if (str->dsi) { gf_bs_write_data(payload, str->dsi, str->dsi_len); } gf_bs_get_content(payload, &data, &dlen); gf_bs_del(payload); /*write SAF packet header*/ gf_bs_write_int(bs, 1, 1); gf_bs_write_int(bs, 0, 15); gf_bs_write_int(bs, 0, 1); gf_bs_write_int(bs, 1, 1); gf_bs_write_int(bs, au ? au->ts : 0, 30); gf_bs_write_int(bs, dlen, 16); gf_bs_write_data(bs, data, dlen); gf_free(data); /*mark as signaled*/ str->state |= 1; } /*write all pending AUs*/ while (1) { GF_SAFStream *src = NULL; u32 mux_time = time_ms; for (i=0; i<count; i++) { str = (GF_SAFStream*)gf_list_get(mux->streams, i); au = (GF_SAFSample*)gf_list_get(str->aus, 0); if (au && (au->ts*1000 < mux_time*str->ts_resolution)) { mux_time = 1000*au->ts/str->ts_resolution; src = str; } } if (!src) break; au = (GF_SAFSample*)gf_list_get(src->aus, 0); gf_list_rem(src->aus, 0); /*write stream declaration*/ gf_bs_write_int(bs, au->is_rap ? 1 : 0, 1); gf_bs_write_int(bs, src->last_au_sn, 15); gf_bs_write_int(bs, 0, 1); gf_bs_write_int(bs, 1, 1); gf_bs_write_int(bs, au->ts, 30); gf_bs_write_u16(bs, 2+au->data_size); gf_bs_write_int(bs, SAF_ACCESS_UNIT, 4); gf_bs_write_int(bs, src->stream_id, 12); gf_bs_write_data(bs, au->data, au->data_size); src->last_au_sn ++; src->last_au_ts = au->ts; gf_free(au->data); gf_free(au); } /*3: write all end of stream*/ for (i=0; i<count; i++) { str = (GF_SAFStream*)gf_list_get(mux->streams, i); /*mark as signaled*/ if (!(str->state & 2)) continue; if (gf_list_count(str->aus)) continue; /*write stream declaration*/ gf_bs_write_int(bs, 1, 1); gf_bs_write_int(bs, str->last_au_sn, 15); gf_bs_write_int(bs, 0, 1); gf_bs_write_int(bs, 1, 1); gf_bs_write_int(bs, str->last_au_ts, 30); gf_bs_write_int(bs, 2, 16); gf_bs_write_int(bs, SAF_END_OF_STREAM, 4); gf_bs_write_int(bs, str->stream_id, 12); /*remove stream*/ gf_list_rem(mux->streams, i); i--; count--; saf_stream_del(str); } mux->state = 0; if (force_end_of_session) { gf_bs_write_int(bs, 1, 1); gf_bs_write_int(bs, 0, 15); gf_bs_write_int(bs, 0, 1); gf_bs_write_int(bs, 1, 1); gf_bs_write_int(bs, 0, 30); gf_bs_write_int(bs, 2, 16); gf_bs_write_int(bs, SAF_END_OF_SESSION, 4); gf_bs_write_int(bs, 0, 12); mux->state = 2; } gf_bs_get_content(bs, out_data, out_size); gf_bs_del(bs); gf_mx_v(mux->mx); return GF_OK; }
GF_EXPORT void gf_img_parse(GF_BitStream *bs, u8 *OTI, u32 *mtype, u32 *width, u32 *height, char **dsi, u32 *dsi_len) { u8 b1, b2, b3; u32 size, type; u64 pos; pos = gf_bs_get_position(bs); gf_bs_seek(bs, 0); *mtype = *width = *height = 0; *OTI = 0; if (dsi) { *dsi = NULL; *dsi_len = 0; } b1 = gf_bs_read_u8(bs); b2 = gf_bs_read_u8(bs); b3 = gf_bs_read_u8(bs); /*JPEG*/ if ((b1==0xFF) && (b2==0xD8) && (b3==0xFF)) { u32 offset = 0; u32 Xdens, Ydens, nb_comp; gf_bs_read_u8(bs); gf_bs_skip_bytes(bs, 10); /*2 size, 5 JFIF\0, 2 version, 1 units*/ Xdens = gf_bs_read_int(bs, 16); Ydens = gf_bs_read_int(bs, 16); nb_comp = 0; /*get frame header FFC0*/ while (gf_bs_available(bs)) { u32 type, w, h; if (gf_bs_read_u8(bs) != 0xFF) continue; if (!offset) offset = (u32)gf_bs_get_position(bs) - 1; type = gf_bs_read_u8(bs); /*process all Start of Image markers*/ switch (type) { case 0xC0: case 0xC1: case 0xC2: case 0xC3: case 0xC5: case 0xC6: case 0xC7: case 0xC9: case 0xCA: case 0xCB: case 0xCD: case 0xCE: case 0xCF: gf_bs_skip_bytes(bs, 3); h = gf_bs_read_int(bs, 16); w = gf_bs_read_int(bs, 16); if ((w > *width) || (h > *height)) { *width = w; *height = h; } nb_comp = gf_bs_read_int(bs, 8); break; } } *OTI = GPAC_OTI_IMAGE_JPEG; *mtype = GF_4CC('j','p','e','g'); if (dsi) { GF_BitStream *bs_dsi = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_u16(bs_dsi, offset); gf_bs_write_u16(bs_dsi, Xdens); gf_bs_write_u16(bs_dsi, Ydens); gf_bs_write_u8(bs_dsi, nb_comp); gf_bs_get_content(bs_dsi, dsi, dsi_len); gf_bs_del(bs_dsi); } } /*PNG*/ else if ((b1==0x89) && (b2==0x50) && (b3==0x4E)) { /*check for PNG sig*/ if ( (gf_bs_read_u8(bs) != 0x47) || (gf_bs_read_u8(bs) != 0x0D) || (gf_bs_read_u8(bs) != 0x0A) || (gf_bs_read_u8(bs) != 0x1A) || (gf_bs_read_u8(bs) != 0x0A) ) goto exit; gf_bs_read_u32(bs); /*check for PNG IHDR*/ if ( (gf_bs_read_u8(bs) != 'I') || (gf_bs_read_u8(bs) != 'H') || (gf_bs_read_u8(bs) != 'D') || (gf_bs_read_u8(bs) != 'R')) goto exit; *width = gf_bs_read_u32(bs); *height = gf_bs_read_u32(bs); *OTI = GPAC_OTI_IMAGE_PNG; *mtype = GF_4CC('p','n','g',' '); } size = gf_bs_read_u8(bs); type = gf_bs_read_u32(bs); if ( ((size==12) && (type==GF_4CC('j','P',' ',' ') )) || (type==GF_4CC('j','p','2','h') ) ) { if (type==GF_4CC('j','p','2','h')) { *OTI = GPAC_OTI_IMAGE_JPEG_2000; *mtype = GF_4CC('j','p','2',' '); goto j2k_restart; } type = gf_bs_read_u32(bs); if (type!=0x0D0A870A) goto exit; *OTI = GPAC_OTI_IMAGE_JPEG_2000; *mtype = GF_4CC('j','p','2',' '); while (gf_bs_available(bs)) { j2k_restart: size = gf_bs_read_u32(bs); type = gf_bs_read_u32(bs); switch (type) { case GF_4CC('j','p','2','h'): goto j2k_restart; case GF_4CC('i','h','d','r'): { u16 nb_comp; u8 BPC, C, UnkC, IPR; *height = gf_bs_read_u32(bs); *width = gf_bs_read_u32(bs); nb_comp = gf_bs_read_u16(bs); BPC = gf_bs_read_u8(bs); C = gf_bs_read_u8(bs); UnkC = gf_bs_read_u8(bs); IPR = gf_bs_read_u8(bs); if (dsi) { GF_BitStream *bs_dsi = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_u32(bs_dsi, *height); gf_bs_write_u32(bs_dsi, *width); gf_bs_write_u16(bs_dsi, nb_comp); gf_bs_write_u8(bs_dsi, BPC); gf_bs_write_u8(bs_dsi, C); gf_bs_write_u8(bs_dsi, UnkC); gf_bs_write_u8(bs_dsi, IPR); gf_bs_get_content(bs_dsi, dsi, dsi_len); gf_bs_del(bs_dsi); } goto exit; } break; default: gf_bs_skip_bytes(bs, size-8); break; } } } exit: gf_bs_seek(bs, pos); }