M4Err M4H_RTP_NewPacket(M4File *the_file, u32 trackNumber, s32 relativeTime, u8 PackingBit, u8 eXtensionBit, u8 MarkerBit, u8 PayloadType, u8 B_frame, u8 IsRepeatedPacket, u16 SequenceNumber) { TrackAtom *trak; HintSampleEntryAtom *entry; RTPPacket *pck; u32 dataRefIndex; M4Err e; trak = GetTrackFromFile(the_file, trackNumber); if (!trak || !CheckHintFormat(trak, M4_Hint_RTP)) return M4BadParam; e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (SampleEntryAtom **) &entry, &dataRefIndex); if (e) return e; if (!entry->w_sample) return M4BadParam; pck = (RTPPacket *) New_HintPacket(entry->w_sample->HintType); pck->P_bit = PackingBit ? 1 : 0; pck->X_bit = eXtensionBit ? 1 : 0; pck->M_bit = MarkerBit ? 1 : 0; pck->payloadType = PayloadType; pck->SequenceNumber = SequenceNumber; pck->B_bit = B_frame ? 1 : 0; pck->R_bit = IsRepeatedPacket ? 1 : 0; pck->relativeTransTime = relativeTime; return ChainAddEntry(entry->w_sample->packetTable, pck); }
//set the time offset of this packet. This enables packets to be placed in the hint track //in decoding order, but have their presentation time-stamp in the transmitted //packet be in a different order. Typically used for MPEG video with B-frames GF_Err gf_isom_rtp_packet_set_offset(GF_ISOFile *the_file, u32 trackNumber, s32 timeOffset) { GF_RTPOBox *rtpo; GF_TrackBox *trak; GF_HintSampleEntryBox *entry; GF_RTPPacket *pck; u32 dataRefIndex, i; GF_Err e; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak || !CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM; e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &dataRefIndex); if (e) return e; if (!entry->hint_sample) return GF_BAD_PARAM; pck = (GF_RTPPacket *)gf_list_get(entry->hint_sample->packetTable, gf_list_count(entry->hint_sample->packetTable) - 1); if (!pck) return GF_BAD_PARAM; //look in the TLV i=0; while ((rtpo = (GF_RTPOBox *)gf_list_enum(pck->TLV, &i))) { if (rtpo->type == GF_ISOM_BOX_TYPE_RTPO) { rtpo->timeOffset = timeOffset; return GF_OK; } } //not found, add it rtpo = (GF_RTPOBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_RTPO); rtpo->timeOffset = timeOffset; return gf_list_add(pck->TLV, rtpo); }
//set the time offset of this packet. This enables packets to be placed in the hint track //in decoding order, but have their presentation time-stamp in the transmitted //packet be in a different order. Typically used for MPEG video with B-frames M4Err M4H_RTP_SetPacketTimeOffset(M4File *the_file, u32 trackNumber, s32 timeOffset) { RtpoAtom *rtpo; TrackAtom *trak; HintSampleEntryAtom *entry; RTPPacket *pck; u32 dataRefIndex, i; M4Err e; trak = GetTrackFromFile(the_file, trackNumber); if (!trak || !CheckHintFormat(trak, M4_Hint_RTP)) return M4BadParam; e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (SampleEntryAtom **) &entry, &dataRefIndex); if (e) return e; if (!entry->w_sample) return M4BadParam; pck = ChainGetEntry(entry->w_sample->packetTable, ChainGetCount(entry->w_sample->packetTable) - 1); if (!pck) return M4BadParam; //look in the TLV for (i=0; i<ChainGetCount(pck->TLV); i++) { rtpo = ChainGetEntry(pck->TLV, i); if (rtpo->type == rtpoAtomType) { rtpo->timeOffset = timeOffset; return M4OK; } } //not found, add it rtpo = (RtpoAtom *) CreateAtom(rtpoAtomType); rtpo->timeOffset = timeOffset; return ChainAddEntry(pck->TLV, rtpo); }
M4Err M4H_RTP_SetPacketFlags(M4File *the_file, u32 trackNumber, u8 PackingBit, u8 eXtensionBit, u8 MarkerBit, u8 B_frame, u8 IsRepeatedPacket) { TrackAtom *trak; HintSampleEntryAtom *entry; RTPPacket *pck; u32 dataRefIndex, ind; M4Err e; trak = GetTrackFromFile(the_file, trackNumber); if (!trak || !CheckHintFormat(trak, M4_Hint_RTP)) return M4BadParam; e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (SampleEntryAtom **) &entry, &dataRefIndex); if (e) return e; if (!entry->w_sample) return M4BadParam; ind = ChainGetCount(entry->w_sample->packetTable); if (!ind) return M4BadParam; pck = ChainGetEntry(entry->w_sample->packetTable, ind-1); pck->P_bit = PackingBit ? 1 : 0; pck->X_bit = eXtensionBit ? 1 : 0; pck->M_bit = MarkerBit ? 1 : 0; pck->B_bit = B_frame ? 1 : 0; pck->R_bit = IsRepeatedPacket ? 1 : 0; return M4OK; }
//adds a chunk of data (max 14 bytes) in the packet that is directly copied //while streaming M4Err M4H_AddDirectData(M4File *the_file, u32 trackNumber, char *data, u32 dataLength, u8 AtBegin) { TrackAtom *trak; HintSampleEntryAtom *entry; u32 count; HintPacket *pck; ImmediateDTE *dte; M4Err e; u32 offset = 0; trak = GetTrackFromFile(the_file, trackNumber); if (!trak || !IsHintTrack(trak) || (dataLength > 14)) return M4BadParam; e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (SampleEntryAtom **) &entry, &count); if (e) return e; if (!entry->w_sample) return M4BadParam; count = ChainGetCount(entry->w_sample->packetTable); if (!count) return M4BadParam; pck = ChainGetEntry(entry->w_sample->packetTable, count - 1); dte = (ImmediateDTE *) NewDTE(1); memcpy(dte->data, data + offset, dataLength); dte->dataLength = dataLength; return AddDTE_HintPacket(entry->w_sample->HintType, pck, (GenericDTE *)dte, AtBegin); }
M4Err Media_UpdateSampleReference(MediaAtom *mdia, u32 sampleNumber, M4Sample *sample, u64 data_offset) { M4Err e; u32 drefIndex, DTS, chunkNum, descIndex; u64 off; u8 isEdited; DataEntryURLAtom *Dentry; SampleTableAtom *stbl; M4Err stbl_AddAtom(SampleTableAtom *ptr, Atom *a); if (!mdia) return M4BadParam; stbl = mdia->information->sampleTable; //check we have the sampe dts e = stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &DTS); if (e) return e; if (DTS != sample->DTS) return M4BadParam; //get our infos stbl_GetSampleInfos(stbl, sampleNumber, &off, &chunkNum, &descIndex, &isEdited); //then check the data ref e = Media_GetSampleDesc(mdia, descIndex, NULL, &drefIndex); if (e) return e; Dentry = (DataEntryURLAtom*)ChainGetEntry(mdia->information->dataInformation->dref->atomList, drefIndex - 1); if (!Dentry) return M4InvalidMP4File; //we only modify self-contained data if (Dentry->flags == 1) return M4InvalidMP4Mode; //and we don't modify the media data return UpdateSample(mdia, sampleNumber, sample->dataLength, sample->CTS_Offset, data_offset, sample->IsRAP); }
//adds a chunk of data (max 14 bytes) in the packet that is directly copied //while streaming GF_Err gf_isom_hint_direct_data(GF_ISOFile *the_file, u32 trackNumber, char *data, u32 dataLength, u8 AtBegin) { GF_TrackBox *trak; GF_HintSampleEntryBox *entry; u32 count; GF_HintPacket *pck; GF_ImmediateDTE *dte; GF_Err e; u32 offset = 0; if (!dataLength) return GF_OK; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak || !IsHintTrack(trak) || (dataLength > 14)) return GF_BAD_PARAM; e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &count); if (e) return e; if (!entry->hint_sample) return GF_BAD_PARAM; count = gf_list_count(entry->hint_sample->packetTable); if (!count) return GF_BAD_PARAM; pck = (GF_HintPacket *)gf_list_get(entry->hint_sample->packetTable, count - 1); dte = (GF_ImmediateDTE *) NewDTE(1); memcpy(dte->data, data + offset, dataLength); dte->dataLength = dataLength; return gf_isom_hint_pck_add_dte(entry->hint_sample->HintType, pck, (GF_GenericDTE *)dte, AtBegin); }
GF_Err Media_UpdateSampleReference(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample *sample, u64 data_offset) { GF_Err e; u32 drefIndex, chunkNum, descIndex; u64 off, DTS; u8 isEdited; GF_DataEntryURLBox *Dentry; GF_SampleTableBox *stbl; if (!mdia) return GF_BAD_PARAM; stbl = mdia->information->sampleTable; //check we have the sampe dts e = stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &DTS); if (e) return e; if (DTS != sample->DTS) return GF_BAD_PARAM; //get our infos stbl_GetSampleInfos(stbl, sampleNumber, &off, &chunkNum, &descIndex, &isEdited); //then check the data ref e = Media_GetSampleDesc(mdia, descIndex, NULL, &drefIndex); if (e) return e; Dentry = (GF_DataEntryURLBox*)gf_list_get(mdia->information->dataInformation->dref->other_boxes, drefIndex - 1); if (!Dentry) return GF_ISOM_INVALID_FILE; //we only modify self-contained data if (Dentry->flags == 1) return GF_ISOM_INVALID_MODE; //and we don't modify the media data return UpdateSample(mdia, sampleNumber, sample->dataLength, sample->CTS_Offset, data_offset, sample->IsRAP); }
GF_Err gf_isom_change_ismacryp_protection(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex, char *scheme_uri, char *kms_uri) { GF_TrackBox *trak; GF_Err e; GF_SampleEntryBox *sea; e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE); if (e) return e; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak || !trak->Media || !StreamDescriptionIndex) return GF_BAD_PARAM; Media_GetSampleDesc(trak->Media, StreamDescriptionIndex, &sea, NULL); /*non-encrypted or non-ISMA*/ if (!sea || !sea->protection_info) return GF_BAD_PARAM; if (!sea->protection_info->scheme_type || !sea->protection_info->original_format) return GF_NON_COMPLIANT_BITSTREAM; if (scheme_uri) { free(sea->protection_info->scheme_type->URI); sea->protection_info->scheme_type->URI = strdup(scheme_uri); } if (kms_uri) { free(sea->protection_info->info->ikms->URI); sea->protection_info->info->ikms->URI = strdup(kms_uri); } return GF_OK; }
GF_Err gf_isom_rtp_packet_set_flags(GF_ISOFile *the_file, u32 trackNumber, u8 PackingBit, u8 eXtensionBit, u8 MarkerBit, u8 disposable_packet, u8 IsRepeatedPacket) { GF_TrackBox *trak; GF_HintSampleEntryBox *entry; GF_RTPPacket *pck; u32 dataRefIndex, ind; GF_Err e; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak || !CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM; e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &dataRefIndex); if (e) return e; if (!entry->hint_sample) return GF_BAD_PARAM; ind = gf_list_count(entry->hint_sample->packetTable); if (!ind) return GF_BAD_PARAM; pck = (GF_RTPPacket *)gf_list_get(entry->hint_sample->packetTable, ind-1); pck->P_bit = PackingBit ? 1 : 0; pck->X_bit = eXtensionBit ? 1 : 0; pck->M_bit = MarkerBit ? 1 : 0; pck->B_bit = disposable_packet ? 1 : 0; pck->R_bit = IsRepeatedPacket ? 1 : 0; return GF_OK; }
GF_Err gf_isom_rtp_packet_begin(GF_ISOFile *the_file, u32 trackNumber, s32 relativeTime, u8 PackingBit, u8 eXtensionBit, u8 MarkerBit, u8 PayloadType, u8 B_frame, u8 IsRepeatedPacket, u16 SequenceNumber) { GF_TrackBox *trak; GF_HintSampleEntryBox *entry; GF_RTPPacket *pck; u32 dataRefIndex; GF_Err e; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak || !CheckHintFormat(trak, GF_ISOM_HINT_RTP)) return GF_BAD_PARAM; e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &dataRefIndex); if (e) return e; if (!entry->hint_sample) return GF_BAD_PARAM; pck = (GF_RTPPacket *) gf_isom_hint_pck_new(entry->hint_sample->HintType); pck->P_bit = PackingBit ? 1 : 0; pck->X_bit = eXtensionBit ? 1 : 0; pck->M_bit = MarkerBit ? 1 : 0; pck->payloadType = PayloadType; pck->SequenceNumber = SequenceNumber; pck->B_bit = B_frame ? 1 : 0; pck->R_bit = IsRepeatedPacket ? 1 : 0; pck->relativeTransTime = relativeTime; return gf_list_add(entry->hint_sample->packetTable, pck); }
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: 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; }
GF_EXPORT u32 gf_isom_is_media_encrypted(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex) { GF_TrackBox *trak; GF_SampleEntryBox *sea; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak) return 0; Media_GetSampleDesc(trak->Media, sampleDescriptionIndex, &sea, NULL); /*non-encrypted or non-ISMA*/ if (!sea || !sea->protection_info || !sea->protection_info->scheme_type) return 0; return sea->protection_info->scheme_type->scheme_type; }
Bool Media_IsSelfContained(MediaAtom *mdia, u32 StreamDescIndex) { u32 drefIndex; FullAtom *a; SampleEntryAtom *se = NULL; Media_GetSampleDesc(mdia, StreamDescIndex, &se, &drefIndex); if (!drefIndex) return 0; a = (FullAtom*)ChainGetEntry(mdia->information->dataInformation->dref->atomList, drefIndex - 1); if (a->flags & 1) return 1; /*QT specific*/ if (a->type == FOUR_CHAR_INT('a', 'l', 'i', 's')) return 1; return 0; }
//stores the hint sample in the file //set IsRandomAccessPoint if you want to indicate that this is a random access point //in the stream M4Err M4H_EndHintSample(M4File *the_file, u32 trackNumber, u8 IsRandomAccessPoint) { TrackAtom *trak; HintSampleEntryAtom *entry; u32 dataRefIndex; M4Err e; BitStream *bs; M4Sample *samp; trak = GetTrackFromFile(the_file, trackNumber); if (!trak || !IsHintTrack(trak)) return M4BadParam; e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (SampleEntryAtom **) &entry, &dataRefIndex); if (e) return e; if (!entry->w_sample) return M4BadParam; //first of all, we need to adjust the offset for data referenced IN THIS hint sample //and get some PckSize e = AdjustHintInfo(entry, trak->Media->information->sampleTable->SampleSize->sampleCount + 1); if (e) return e; //ok, let's write the sample bs = NewBitStream(NULL, 0, BS_WRITE); e = Write_HintSample(entry->w_sample, bs); if (e) { DeleteBitStream(bs); return e; } BS_CutBuffer(bs); samp = M4_NewSample(); samp->CTS_Offset = 0; samp->IsRAP = IsRandomAccessPoint; samp->DTS = entry->w_sample->TransmissionTime; //get the sample BS_GetContent(bs, (unsigned char **) &samp->data, &samp->dataLength); DeleteBitStream(bs); //finally add the sample e = M4_AddSample(the_file, trackNumber, trak->Media->information->sampleTable->currentEntryIndex, samp); M4_DeleteSample(&samp); //and delete the sample in our entry ... Del_HintSample(entry->w_sample); entry->w_sample = NULL; return e; }
GF_Err Media_UpdateSample(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample *sample, Bool data_only) { GF_Err e; u32 drefIndex, chunkNum, descIndex; u64 newOffset, DTS; u8 isEdited; GF_DataEntryURLBox *Dentry; GF_SampleTableBox *stbl; if (!mdia || !sample || !sampleNumber || !mdia->mediaTrack->moov->mov->editFileMap) return GF_BAD_PARAM; stbl = mdia->information->sampleTable; if (!data_only) { //check we have the sampe dts e = stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &DTS); if (e) return e; if (DTS != sample->DTS) return GF_BAD_PARAM; } //get our infos stbl_GetSampleInfos(stbl, sampleNumber, &newOffset, &chunkNum, &descIndex, &isEdited); //then check the data ref e = Media_GetSampleDesc(mdia, descIndex, NULL, &drefIndex); if (e) return e; Dentry = (GF_DataEntryURLBox*)gf_list_get(mdia->information->dataInformation->dref->other_boxes, drefIndex - 1); if (!Dentry) return GF_ISOM_INVALID_FILE; if (Dentry->flags != 1) return GF_BAD_PARAM; //MEDIA DATA EDIT: write this new sample to the edit temp file newOffset = gf_isom_datamap_get_offset(mdia->mediaTrack->moov->mov->editFileMap); if (sample->dataLength) { e = gf_isom_datamap_add_data(mdia->mediaTrack->moov->mov->editFileMap, sample->data, sample->dataLength); if (e) return e; } if (data_only) { stbl_SetSampleSize(stbl->SampleSize, sampleNumber, sample->dataLength); return stbl_SetChunkOffset(mdia, sampleNumber, newOffset); } return UpdateSample(mdia, sampleNumber, sample->dataLength, sample->CTS_Offset, newOffset, sample->IsRAP); }
//stores the hint sample in the file //set IsRandomAccessPoint if you want to indicate that this is a random access point //in the stream GF_Err gf_isom_end_hint_sample(GF_ISOFile *the_file, u32 trackNumber, u8 IsRandomAccessPoint) { GF_TrackBox *trak; GF_HintSampleEntryBox *entry; u32 dataRefIndex; GF_Err e; GF_BitStream *bs; GF_ISOSample *samp; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM; e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &dataRefIndex); if (e) return e; if (!entry->hint_sample) return GF_BAD_PARAM; //first of all, we need to adjust the offset for data referenced IN THIS hint sample //and get some PckSize e = AdjustHintInfo(entry, trak->Media->information->sampleTable->SampleSize->sampleCount + 1); if (e) return e; //ok, let's write the sample bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); e = gf_isom_hint_sample_write(entry->hint_sample, bs); if (e) { gf_bs_del(bs); return e; } samp = gf_isom_sample_new(); samp->CTS_Offset = 0; samp->IsRAP = IsRandomAccessPoint; samp->DTS = entry->hint_sample->TransmissionTime; //get the sample gf_bs_get_content(bs, &samp->data, &samp->dataLength); gf_bs_del(bs); //finally add the sample e = gf_isom_add_sample(the_file, trackNumber, trak->Media->information->sampleTable->currentEntryIndex, samp); gf_isom_sample_del(&samp); //and delete the sample in our entry ... gf_isom_hint_sample_del(entry->hint_sample); entry->hint_sample = NULL; return e; }
Bool Media_IsSelfContained(GF_MediaBox *mdia, u32 StreamDescIndex) { u32 drefIndex=0; GF_FullBox *a; GF_SampleEntryBox *se = NULL; Media_GetSampleDesc(mdia, StreamDescIndex, &se, &drefIndex); if (!drefIndex) return 0; a = (GF_FullBox*)gf_list_get(mdia->information->dataInformation->dref->other_boxes, drefIndex - 1); if (!a) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] broken file: Data reference index set to %d but no data reference entry found\n", drefIndex)); return 0; } if (a->flags & 1) return 1; /*QT specific*/ if (a->type == GF_4CC('a', 'l', 'i', 's')) return 1; return 0; }
/*retrieves ISMACryp info for the given track & SDI*/ GF_EXPORT GF_Err gf_isom_get_omadrm_info(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *outOriginalFormat, u32 *outSchemeType, u32 *outSchemeVersion, const char **outContentID, const char **outRightsIssuerURL, const char **outTextualHeaders, u32 *outTextualHeadersLen, u64 *outPlaintextLength, u32 *outEncryptionType, Bool *outSelectiveEncryption, u32 *outIVLength, u32 *outKeyIndicationLength) { GF_TrackBox *trak; GF_SampleEntryBox *sea; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak) return GF_BAD_PARAM; Media_GetSampleDesc(trak->Media, sampleDescriptionIndex, &sea, NULL); /*non-encrypted or non-ISMA*/ if (!sea || !sea->protection_info) return GF_BAD_PARAM; if (!sea->protection_info->scheme_type || !sea->protection_info->original_format) return GF_NON_COMPLIANT_BITSTREAM; if (!sea->protection_info->info || !sea->protection_info->info->okms || !sea->protection_info->info->okms->hdr) return GF_NON_COMPLIANT_BITSTREAM; if (outOriginalFormat) { *outOriginalFormat = sea->protection_info->original_format->data_format; if (IsMP4Description(sea->protection_info->original_format->data_format)) *outOriginalFormat = GF_ISOM_SUBTYPE_MPEG4; } if (outSchemeType) *outSchemeType = sea->protection_info->scheme_type->scheme_type; if (outSchemeVersion) *outSchemeVersion = sea->protection_info->scheme_type->scheme_version; if (outContentID) *outContentID = sea->protection_info->info->okms->hdr->ContentID; if (outRightsIssuerURL) *outRightsIssuerURL = sea->protection_info->info->okms->hdr->RightsIssuerURL; if (outTextualHeaders) { *outTextualHeaders = sea->protection_info->info->okms->hdr->TextualHeaders; if (outTextualHeadersLen) *outTextualHeadersLen = sea->protection_info->info->okms->hdr->TextualHeadersLen; } if (outPlaintextLength) *outPlaintextLength = sea->protection_info->info->okms->hdr->PlaintextLength; if (outEncryptionType) *outEncryptionType = sea->protection_info->info->okms->hdr->EncryptionMethod; if (sea->protection_info->info && sea->protection_info->info->okms && sea->protection_info->info->okms->fmt) { if (outSelectiveEncryption) *outSelectiveEncryption = sea->protection_info->info->okms->fmt->selective_encryption; if (outIVLength) *outIVLength = sea->protection_info->info->okms->fmt->IV_length; if (outKeyIndicationLength) *outKeyIndicationLength = sea->protection_info->info->okms->fmt->key_indicator_length; } else { if (outSelectiveEncryption) *outSelectiveEncryption = 0; if (outIVLength) *outIVLength = 0; if (outKeyIndicationLength) *outKeyIndicationLength = 0; } return GF_OK; }
GF_EXPORT GF_Err gf_isom_get_original_format_type(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *outOriginalFormat) { GF_TrackBox *trak; GF_SampleEntryBox *sea; GF_ProtectionInfoBox *sinf; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak) return GF_BAD_PARAM; Media_GetSampleDesc(trak->Media, sampleDescriptionIndex, &sea, NULL); if (!sea) return GF_BAD_PARAM; sinf = (GF_ProtectionInfoBox*)gf_list_get(sea->protections, 0); if (outOriginalFormat && sinf->original_format) { *outOriginalFormat = sinf->original_format->data_format; } return GF_OK; }
static GF_ProtectionInfoBox *gf_isom_get_sinf_entry(GF_TrackBox *trak, u32 sampleDescriptionIndex, u32 scheme_type, GF_SampleEntryBox **out_sea) { u32 i=0; GF_SampleEntryBox *sea=NULL; GF_ProtectionInfoBox *sinf; Media_GetSampleDesc(trak->Media, sampleDescriptionIndex, &sea, NULL); if (!sea) return NULL; i = 0; while ((sinf = (GF_ProtectionInfoBox*)gf_list_enum(sea->protections, &i))) { if (sinf->original_format && sinf->scheme_type && sinf->info) { if (!scheme_type || (sinf->scheme_type->scheme_type == scheme_type)) { if (out_sea) *out_sea = sea; return sinf; } } } return NULL; }
M4Err M4H_AddStreamDescriptionData(M4File *the_file, u32 trackNumber, u32 SourceTrackID, u32 StreamDescriptionIndex, u16 DataLength, u32 offsetInDescription, u8 AtBegin) { TrackAtom *trak; HintSampleEntryAtom *entry; u32 count; u16 refIndex; HintPacket *pck; StreamDescDTE *dte; M4Err e; TrackReferenceTypeAtom *hint; M4Err reftype_AddRefTrack(TrackReferenceTypeAtom *ref, u32 trackID, u16 *outRefIndex); trak = GetTrackFromFile(the_file, trackNumber); if (!trak || !IsHintTrack(trak)) return M4BadParam; e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (SampleEntryAtom **) &entry, &count); if (e) return e; if (!entry->w_sample) return M4BadParam; count = ChainGetCount(entry->w_sample->packetTable); if (!count) return M4BadParam; pck = ChainGetEntry(entry->w_sample->packetTable, count - 1); dte = (StreamDescDTE *) NewDTE(3); dte->byteOffset = offsetInDescription; dte->dataLength = DataLength; dte->streamDescIndex = StreamDescriptionIndex; if (SourceTrackID == trak->Header->trackID) { dte->trackRefIndex = -1; } else { //get (or set) the track reference index e = Track_FindRef(trak, M4_HintTrack_Ref, &hint); if (e) return e; e = reftype_AddRefTrack(hint, SourceTrackID, &refIndex); if (e) return e; //WARNING: IN QT, MUST BE 0-based !!! dte->trackRefIndex = (u8) (refIndex - 1); } return AddDTE_HintPacket(entry->w_sample->HintType, pck, (GenericDTE *)dte, AtBegin); }
M4Err M4_SetExtractionSLConfig(M4File *the_file, u32 trackNumber, u32 StreamDescriptionIndex, SLConfigDescriptor *slConfig) { TrackAtom *trak; SampleEntryAtom *entry; M4Err e; SLConfigDescriptor **slc; trak = GetTrackFromFile(the_file, trackNumber); if (!trak) return M4BadParam; e = Media_GetSampleDesc(trak->Media, StreamDescriptionIndex, &entry, NULL); if (e) return e; //we must be sure we are not using a remote ESD switch (entry->type) { case MPEGSampleEntryAtomType: if (((MPEGSampleEntryAtom *)entry)->esd->desc->slConfig->predefined != SLPredef_MP4) return M4BadParam; slc = & ((MPEGSampleEntryAtom *)entry)->slc; break; case MPEGAudioSampleEntryAtomType: if (((MPEGAudioSampleEntryAtom *)entry)->esd->desc->slConfig->predefined != SLPredef_MP4) return M4BadParam; slc = & ((MPEGAudioSampleEntryAtom *)entry)->slc; break; case MPEGVisualSampleEntryAtomType: if (((MPEGVisualSampleEntryAtom *)entry)->esd->desc->slConfig->predefined != SLPredef_MP4) return M4BadParam; slc = & ((MPEGVisualSampleEntryAtom *)entry)->slc; break; default: return M4BadParam; } if (*slc) { OD_DeleteDescriptor((Descriptor **)slc); *slc = NULL; } if (!slConfig) return M4OK; //finally duplicate the SL return OD_DuplicateDescriptor((Descriptor *) slConfig, (Descriptor **) slc); }
//adds a blank chunk of data in the sample that is skipped while streaming GF_Err gf_isom_hint_blank_data(GF_ISOFile *the_file, u32 trackNumber, u8 AtBegin) { GF_TrackBox *trak; GF_HintSampleEntryBox *entry; u32 count; GF_HintPacket *pck; GF_EmptyDTE *dte; GF_Err e; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM; e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &count); if (e) return e; if (!entry->hint_sample) return GF_BAD_PARAM; count = gf_list_count(entry->hint_sample->packetTable); if (!count) return GF_BAD_PARAM; pck = (GF_HintPacket *)gf_list_get(entry->hint_sample->packetTable, count - 1); dte = (GF_EmptyDTE *) NewDTE(0); return gf_isom_hint_pck_add_dte(entry->hint_sample->HintType, pck, (GF_GenericDTE *)dte, AtBegin); }
//adds a blank chunk of data in the sample that is skipped while streaming M4Err M4H_AddBlankData(M4File *the_file, u32 trackNumber, u8 AtBegin) { TrackAtom *trak; HintSampleEntryAtom *entry; u32 count; HintPacket *pck; EmptyDTE *dte; M4Err e; trak = GetTrackFromFile(the_file, trackNumber); if (!trak || !IsHintTrack(trak)) return M4BadParam; e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (SampleEntryAtom **) &entry, &count); if (e) return e; if (!entry->w_sample) return M4BadParam; count = ChainGetCount(entry->w_sample->packetTable); if (!count) return M4BadParam; pck = ChainGetEntry(entry->w_sample->packetTable, count - 1); dte = (EmptyDTE *) NewDTE(0); return AddDTE_HintPacket(entry->w_sample->HintType, pck, (GenericDTE *)dte, AtBegin); }
M4Err Media_UpdateSample(MediaAtom *mdia, u32 sampleNumber, M4Sample *sample) { M4Err e; u32 drefIndex, chunkNum, descIndex, DTS; u64 newOffset; u8 isEdited; DataEntryURLAtom *Dentry; SampleTableAtom *stbl; M4Err stbl_AddAtom(SampleTableAtom *ptr, Atom *a); if (!mdia || !sample || !sampleNumber || !mdia->mediaTrack->moov->mov->editFileMap) return M4BadParam; stbl = mdia->information->sampleTable; //check we have the sampe dts e = stbl_GetSampleDTS(stbl->TimeToSample, sampleNumber, &DTS); if (e) return e; if (DTS != sample->DTS) return M4BadParam; //get our infos stbl_GetSampleInfos(stbl, sampleNumber, &newOffset, &chunkNum, &descIndex, &isEdited); //then check the data ref e = Media_GetSampleDesc(mdia, descIndex, NULL, &drefIndex); if (e) return e; Dentry = (DataEntryURLAtom*)ChainGetEntry(mdia->information->dataInformation->dref->atomList, drefIndex - 1); if (!Dentry) return M4InvalidMP4File; if (Dentry->flags != 1) return M4BadParam; //MEDIA DATA EDIT: write this new sample to the edit temp file newOffset = DataMap_GetTotalOffset(mdia->mediaTrack->moov->mov->editFileMap); e = DataMap_AddData(mdia->mediaTrack->moov->mov->editFileMap, sample->data, sample->dataLength); if (e) return e; return UpdateSample(mdia, sampleNumber, sample->dataLength, sample->CTS_Offset, newOffset, sample->IsRAP); }
/*retrieves ISMACryp info for the given track & SDI*/ GF_EXPORT GF_Err gf_isom_get_ismacryp_info(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex, u32 *outOriginalFormat, u32 *outSchemeType, u32 *outSchemeVersion, const char **outSchemeURI, const char **outKMS_URI, Bool *outSelectiveEncryption, u32 *outIVLength, u32 *outKeyIndicationLength) { GF_TrackBox *trak; GF_SampleEntryBox *sea; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak) return GF_BAD_PARAM; Media_GetSampleDesc(trak->Media, sampleDescriptionIndex, &sea, NULL); /*non-encrypted or non-ISMA*/ if (!sea || !sea->protection_info) return GF_BAD_PARAM; if (!sea->protection_info->scheme_type || !sea->protection_info->original_format) return GF_NON_COMPLIANT_BITSTREAM; if (outOriginalFormat) { *outOriginalFormat = sea->protection_info->original_format->data_format; if (IsMP4Description(sea->protection_info->original_format->data_format)) *outOriginalFormat = GF_ISOM_SUBTYPE_MPEG4; } if (outSchemeType) *outSchemeType = sea->protection_info->scheme_type->scheme_type; if (outSchemeVersion) *outSchemeVersion = sea->protection_info->scheme_type->scheme_version; if (outSchemeURI) *outSchemeURI = sea->protection_info->scheme_type->URI; if (sea->protection_info->info && sea->protection_info->info->ikms) { if (outKMS_URI) *outKMS_URI = sea->protection_info->info->ikms->URI; } else { if (outKMS_URI) *outKMS_URI = NULL; } if (sea->protection_info->info && sea->protection_info->info->isfm) { if (outSelectiveEncryption) *outSelectiveEncryption = sea->protection_info->info->isfm->selective_encryption; if (outIVLength) *outIVLength = sea->protection_info->info->isfm->IV_length; if (outKeyIndicationLength) *outKeyIndicationLength = sea->protection_info->info->isfm->key_indicator_length; } else { if (outSelectiveEncryption) *outSelectiveEncryption = 0; if (outIVLength) *outIVLength = 0; if (outKeyIndicationLength) *outKeyIndicationLength = 0; } return GF_OK; }
GF_Err gf_isom_hint_sample_description_data(GF_ISOFile *the_file, u32 trackNumber, u32 SourceTrackID, u32 StreamDescriptionIndex, u16 DataLength, u32 offsetInDescription, u8 AtBegin) { GF_TrackBox *trak; GF_HintSampleEntryBox *entry; u32 count; u16 refIndex; GF_HintPacket *pck; GF_StreamDescDTE *dte; GF_Err e; GF_TrackReferenceTypeBox *hint; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak || !IsHintTrack(trak)) return GF_BAD_PARAM; e = Media_GetSampleDesc(trak->Media, trak->Media->information->sampleTable->currentEntryIndex, (GF_SampleEntryBox **) &entry, &count); if (e) return e; if (!entry->hint_sample) return GF_BAD_PARAM; count = gf_list_count(entry->hint_sample->packetTable); if (!count) return GF_BAD_PARAM; pck = (GF_HintPacket *)gf_list_get(entry->hint_sample->packetTable, count - 1); dte = (GF_StreamDescDTE *) NewDTE(3); dte->byteOffset = offsetInDescription; dte->dataLength = DataLength; dte->streamDescIndex = StreamDescriptionIndex; if (SourceTrackID == trak->Header->trackID) { dte->trackRefIndex = (s8) -1; } else { //get (or set) the track reference index e = Track_FindRef(trak, GF_ISOM_REF_HINT, &hint); if (e) return e; e = reftype_AddRefTrack(hint, SourceTrackID, &refIndex); if (e) return e; //WARNING: IN QT, MUST BE 0-based !!! dte->trackRefIndex = (u8) (refIndex - 1); } return gf_isom_hint_pck_add_dte(entry->hint_sample->HintType, pck, (GF_GenericDTE *)dte, AtBegin); }
GF_EXPORT Bool gf_isom_is_omadrm_media(GF_ISOFile *the_file, u32 trackNumber, u32 sampleDescriptionIndex) { GF_TrackBox *trak; GF_SampleEntryBox *sea; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak) return 0; Media_GetSampleDesc(trak->Media, sampleDescriptionIndex, &sea, NULL); /*non-encrypted or non-ISMA*/ if (!sea || !sea->protection_info || !sea->protection_info->scheme_type || (sea->protection_info->scheme_type->scheme_type != GF_4CC('o','d','k','m') ) || !sea->protection_info->info || !sea->protection_info->info->okms || !sea->protection_info->info->okms->hdr ) return 0; return 1; }
GF_Err gf_isom_remove_ismacryp_protection(GF_ISOFile *the_file, u32 trackNumber, u32 StreamDescriptionIndex) { GF_TrackBox *trak; GF_Err e; GF_SampleEntryBox *sea; e = CanAccessMovie(the_file, GF_ISOM_OPEN_WRITE); if (e) return e; trak = gf_isom_get_track_from_file(the_file, trackNumber); if (!trak || !trak->Media || !StreamDescriptionIndex) return GF_BAD_PARAM; Media_GetSampleDesc(trak->Media, StreamDescriptionIndex, &sea, NULL); /*non-encrypted or non-ISMA*/ if (!sea || !sea->protection_info) return GF_BAD_PARAM; if (!sea->protection_info->scheme_type || !sea->protection_info->original_format) return GF_NON_COMPLIANT_BITSTREAM; sea->type = sea->protection_info->original_format->data_format; gf_isom_box_del((GF_Box *)sea->protection_info); sea->protection_info = NULL; if (sea->type == GF_4CC('2','6','4','b')) sea->type = GF_ISOM_BOX_TYPE_AVC1; return GF_OK; }