Exemplo n.º 1
0
GF_Err MergeFragment(GF_MovieFragmentBox *moof, GF_ISOFile *mov)
{
	u32 i, j;
	u64 MaxDur;
	GF_TrackFragmentBox *traf;
	GF_TrackBox *trak;
	
	MaxDur = 0;

	//we shall have a MOOV and its MVEX BEFORE any MOOF
	if (!mov->moov || !mov->moov->mvex) return GF_ISOM_INVALID_FILE;
	//and all fragments must be continous
	if (mov->NextMoofNumber && (mov->NextMoofNumber >= moof->mfhd->sequence_number)) return GF_ISOM_INVALID_FILE;

	i=0;
	while ((traf = (GF_TrackFragmentBox*)gf_list_enum(moof->TrackList, &i))) {
		if (!traf->tfhd) {
			trak = NULL;
			traf->trex = NULL;
		} else {
			trak = gf_isom_get_track_from_id(mov->moov, traf->tfhd->trackID);
			j=0;
			while ((traf->trex = (GF_TrackExtendsBox*)gf_list_enum(mov->moov->mvex->TrackExList, &j))) {
				if (traf->trex->trackID == traf->tfhd->trackID) break;
				traf->trex = NULL;
			}
		}
		if (!trak || !traf->trex) return GF_ISOM_INVALID_FILE;

		MergeTrack(trak, traf, mov->current_top_box_start, !mov->first_moof_merged);

		//update trak duration
		SetTrackDuration(trak);
		if (trak->Header->duration > MaxDur) 
			MaxDur = trak->Header->duration;
	}

	mov->first_moof_merged = 1;
	mov->NextMoofNumber = moof->mfhd->sequence_number;
	//update movie duration
	if (mov->moov->mvhd->duration < MaxDur) mov->moov->mvhd->duration = MaxDur;
	return GF_OK;
}
Exemplo n.º 2
0
GF_Err MergeFragment(GF_MovieFragmentBox *moof, GF_ISOFile *mov)
{
    GF_Err e;
    u32 i, j;
    u64 MaxDur;
    GF_TrackFragmentBox *traf;
    GF_TrackBox *trak;

    MaxDur = 0;

    //we shall have a MOOV and its MVEX BEFORE any MOOF
    if (!mov->moov || !mov->moov->mvex) {
        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Error: %s not received before merging fragment\n", mov->moov ? "mvex" : "moov" ));
        return GF_ISOM_INVALID_FILE;
    }
    //and all fragments must be continous - we do not throw an error as we may still want to be able to concatenate dependent representations in DASH and
    //we will likely a-have R1(moofSN 1, 3, 5, 7) plus R2(moofSN 2, 4, 6, 8)
    if (mov->NextMoofNumber && (mov->NextMoofNumber >= moof->mfhd->sequence_number)) {
        GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Warning: wrong sequence number: got %d but last one was %d\n", moof->mfhd->sequence_number, mov->NextMoofNumber));
//		return GF_ISOM_INVALID_FILE;
    }

    i=0;
    while ((traf = (GF_TrackFragmentBox*)gf_list_enum(moof->TrackList, &i))) {
        if (!traf->tfhd) {
            trak = NULL;
            traf->trex = NULL;
        } else {
            trak = gf_isom_get_track_from_id(mov->moov, traf->tfhd->trackID);
            j=0;
            while ((traf->trex = (GF_TrackExtendsBox*)gf_list_enum(mov->moov->mvex->TrackExList, &j))) {
                if (traf->trex->trackID == traf->tfhd->trackID) break;
                traf->trex = NULL;
            }
        }

        if (!trak || !traf->trex) {
            GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Error: Cannot find fragment track with ID %d\n", traf->tfhd->trackID));
            return GF_ISOM_INVALID_FILE;
        }

        e = MergeTrack(trak, traf, mov->current_top_box_start, !trak->first_traf_merged);
        if (e) return e;

        trak->present_in_scalable_segment = 1;

        //update trak duration
        SetTrackDuration(trak);
        if (trak->Header->duration > MaxDur)
            MaxDur = trak->Header->duration;

        trak->first_traf_merged = 1;
    }

    if (moof->other_boxes) {
        GF_Box *a;
        i = 0;
        while ((a = (GF_Box *)gf_list_enum(moof->other_boxes, &i))) {
            if (a->type == GF_ISOM_BOX_TYPE_PSSH) {
                GF_ProtectionSystemHeaderBox *pssh = (GF_ProtectionSystemHeaderBox *)pssh_New();
                memmove(pssh->SystemID, ((GF_ProtectionSystemHeaderBox *)a)->SystemID, 16);
                pssh->KID_count = ((GF_ProtectionSystemHeaderBox *)a)->KID_count;
                pssh->KIDs = (bin128 *)gf_malloc(pssh->KID_count*sizeof(bin128));
                memmove(pssh->KIDs, ((GF_ProtectionSystemHeaderBox *)a)->KIDs, pssh->KID_count*sizeof(bin128));
                pssh->private_data_size = ((GF_ProtectionSystemHeaderBox *)a)->private_data_size;
                pssh->private_data = (u8 *)gf_malloc(pssh->private_data_size*sizeof(char));
                memmove(pssh->private_data, ((GF_ProtectionSystemHeaderBox *)a)->private_data, pssh->private_data_size);

                if (!mov->moov->other_boxes) mov->moov->other_boxes = gf_list_new();
                gf_list_add(mov->moov->other_boxes, pssh);
            }
        }
    }

    mov->NextMoofNumber = moof->mfhd->sequence_number;
    //update movie duration
    if (mov->moov->mvhd->duration < MaxDur) mov->moov->mvhd->duration = MaxDur;
    return GF_OK;
}
Exemplo n.º 3
0
GF_Err gf_isom_parse_movie_boxes(GF_ISOFile *mov, u64 *bytesMissing, Bool progressive_mode)
{
    GF_Box *a;
    u64 totSize;
    GF_Err e = GF_OK;

    totSize = 0;


#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
    if (mov->single_moof_mode && mov->single_moof_state == 2) {
        return e;
    }

    /*restart from where we stopped last*/
    totSize = mov->current_top_box_start;
    gf_bs_seek(mov->movieFileMap->bs, mov->current_top_box_start);

#endif


    /*while we have some data, parse our boxes*/
    while (gf_bs_available(mov->movieFileMap->bs)) {
        *bytesMissing = 0;
#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
        mov->current_top_box_start = gf_bs_get_position(mov->movieFileMap->bs);
        GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[iso file] Current top box start before parsing %d\n", mov->current_top_box_start));
#endif

        e = gf_isom_parse_root_box(&a, mov->movieFileMap->bs, bytesMissing, progressive_mode);

        if (e >= 0) {
            e = GF_OK;
        } else if (e == GF_ISOM_INCOMPLETE_FILE) {
            /*our mdat is uncomplete, only valid for READ ONLY files...*/
            if (mov->openMode != GF_ISOM_OPEN_READ) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Incomplete MDAT while file is not read-only\n"));
                return GF_ISOM_INVALID_FILE;
            }
            return e;
        } else {
            return e;
        }

        switch (a->type) {
        /*MOOV box*/
        case GF_ISOM_BOX_TYPE_MOOV:
            if (mov->moov) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Duplicate MOOV detected!\n"));
                return GF_ISOM_INVALID_FILE;
            }
            mov->moov = (GF_MovieBox *)a;
            /*set our pointer to the movie*/
            mov->moov->mov = mov;
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
            if (mov->moov->mvex) mov->moov->mvex->mov = mov;
#endif
            e = gf_list_add(mov->TopBoxes, a);
            if (e) {
                return e;
            }
            totSize += a->size;
            break;

        /*META box*/
        case GF_ISOM_BOX_TYPE_META:
            if (mov->meta) {
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Duplicate META detected!\n"));
                return GF_ISOM_INVALID_FILE;
            }
            mov->meta = (GF_MetaBox *)a;
            e = gf_list_add(mov->TopBoxes, a);
            if (e) {
                return e;
            }
            totSize += a->size;
            break;

        /*we only keep the MDAT in READ for dump purposes*/
        case GF_ISOM_BOX_TYPE_MDAT:
            totSize += a->size;
            if (mov->openMode == GF_ISOM_OPEN_READ) {
                if (!mov->mdat) {
                    mov->mdat = (GF_MediaDataBox *) a;
                    e = gf_list_add(mov->TopBoxes, mov->mdat);
                    if (e) {
                        return e;
                    }
                }
#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
                else if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) gf_list_add(mov->TopBoxes, a);
#endif
                else gf_isom_box_del(a);
            }
            /*if we don't have any MDAT yet, create one (edit-write mode)
            We only work with one mdat, but we're puting it at the place
            of the first mdat found when opening a file for editing*/
            else if (!mov->mdat && (mov->openMode != GF_ISOM_OPEN_READ) && (mov->openMode != GF_ISOM_OPEN_CAT_FRAGMENTS)) {
                gf_isom_box_del(a);
                mov->mdat = (GF_MediaDataBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MDAT);
                e = gf_list_add(mov->TopBoxes, mov->mdat);
                if (e) {
                    return e;
                }
            } else {
                gf_isom_box_del(a);
            }
            break;
        case GF_ISOM_BOX_TYPE_FTYP:
            /*ONE AND ONLY ONE FTYP*/
            if (mov->brand) {
                gf_isom_box_del(a);
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Duplicate FTYP detected!\n"));
                return GF_ISOM_INVALID_FILE;
            }
            mov->brand = (GF_FileTypeBox *)a;
            totSize += a->size;
            e = gf_list_add(mov->TopBoxes, a);
            break;

        case GF_ISOM_BOX_TYPE_PDIN:
            /*ONE AND ONLY ONE PDIN*/
            if (mov->pdin) {
                gf_isom_box_del(a);
                GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Duplicate PDIN detected!\n"));
                return GF_ISOM_INVALID_FILE;
            }
            mov->pdin = (GF_ProgressiveDownloadBox *) a;
            totSize += a->size;
            e = gf_list_add(mov->TopBoxes, a);
            break;


#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
        case GF_ISOM_BOX_TYPE_STYP:
        {
            u32 brand = ((GF_SegmentTypeBox *)a)->majorBrand;
            switch (brand) {
            case GF_4CC('s', 'i', 's', 'x'):
            case GF_4CC('r', 'i', 's', 'x'):
            case GF_4CC('s', 's', 's', 's'):
                mov->is_index_segment = GF_TRUE;
                break;
            default:
                break;
            }
        }
        /*fall-through*/

        case GF_ISOM_BOX_TYPE_SIDX:
            totSize += a->size;
            if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) {
                e = gf_list_add(mov->TopBoxes, a);
            } else {
                gf_isom_box_del(a);
            }
            break;

        case GF_ISOM_BOX_TYPE_MOOF:
            if (!mov->moov) {
                GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] Movie fragment but no moov (yet) - possibly broken parsing!\n"));
            }
            if (mov->single_moof_mode) {
                mov->single_moof_state++;
                if (mov->single_moof_state > 1) {
                    gf_isom_box_del(a);
                    return GF_OK;
                }
            }
            ((GF_MovieFragmentBox *)a)->mov = mov;

            totSize += a->size;
            mov->moof = (GF_MovieFragmentBox *) a;
            /*read & debug: store at root level*/
            if (mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG) {
                u32 k;
                gf_list_add(mov->TopBoxes, a);
                /*also update pointers to trex for debug*/
                if (mov->moov) {
                    for (k=0; k<gf_list_count(mov->moof->TrackList); k++) {
                        GF_TrackFragmentBox *traf = gf_list_get(mov->moof->TrackList, k);
                        if (traf->tfhd) {
                            GF_TrackBox *trak = gf_isom_get_track_from_id(mov->moov, traf->tfhd->trackID);
                            u32 j=0;
                            while ((traf->trex = (GF_TrackExtendsBox*)gf_list_enum(mov->moov->mvex->TrackExList, &j))) {
                                if (traf->trex->trackID == traf->tfhd->trackID) {
                                    if (!traf->trex->track) traf->trex->track = trak;
                                    break;
                                }
                                traf->trex = NULL;
                            }
                        }
                        //we should only parse senc/psec when no saiz/saio is present, otherwise we fetch the info directly
                        if (traf->trex && traf->trex->track && (traf->piff_sample_encryption || traf->sample_encryption)) {
                            GF_TrackBox *trak = GetTrackbyID(mov->moov, traf->tfhd->trackID);
                            e = senc_Parse(mov->movieFileMap->bs, trak, traf, traf->piff_sample_encryption ? (GF_SampleEncryptionBox *) traf->piff_sample_encryption : traf->sample_encryption);
                        }
                    }
                }
            } else if (mov->openMode==GF_ISOM_OPEN_CAT_FRAGMENTS) {
                mov->NextMoofNumber = mov->moof->mfhd->sequence_number+1;
                mov->moof = NULL;
                gf_isom_box_del(a);
            } else {
                /*merge all info*/
                e = MergeFragment((GF_MovieFragmentBox *)a, mov);
                gf_isom_box_del(a);
            }
            break;
#endif
        case GF_4CC('j','P',' ',' '):
        {
            GF_UnknownBox *box = (GF_UnknownBox*)a;
            u8 *c = (u8 *) box->data;
            if ((box->dataSize==4)
                    && (GF_4CC(c[0],c[1],c[2],c[3])==(u32)0x0D0A870A))
                mov->is_jp2 = 1;

            gf_isom_box_del(a);
        }
        break;

        case GF_ISOM_BOX_TYPE_PRFT:
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
            if (!(mov->FragmentsFlags & GF_ISOM_FRAG_READ_DEBUG)) {
                //keep the last one read
                if (mov->last_producer_ref_time)
                    gf_isom_box_del(a);
                else
                    mov->last_producer_ref_time = (GF_ProducerReferenceTimeBox *)a;
                break;
            }
#endif
        //fallthrough

        default:
            totSize += a->size;
            e = gf_list_add(mov->TopBoxes, a);
            break;
        }

#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
        /*remember where we left, in case we append an entire number of movie fragments*/
        mov->current_top_box_start = gf_bs_get_position(mov->movieFileMap->bs);
#endif
    }

    /*we need at least moov or meta*/
    if (!mov->moov && !mov->meta
#ifndef GPAC_DISABLE_ISOM_FRAGMENTS
            && !mov->moof && !mov->is_index_segment
#endif
       ) {
        return GF_ISOM_INCOMPLETE_FILE;
    }
    /*we MUST have movie header*/
    if (mov->moov && !mov->moov->mvhd) {
        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing MVHD in MOOV!\n"));
        return GF_ISOM_INVALID_FILE;
    }
    /*we MUST have meta handler*/
    if (mov->meta && !mov->meta->handler) {
        GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[iso file] Missing handler in META!\n"));
        return GF_ISOM_INVALID_FILE;
    }

#ifndef GPAC_DISABLE_ISOM_WRITE

    if (mov->moov) {
        /*set the default interleaving time*/
        mov->interleavingTime = mov->moov->mvhd->timeScale;

#ifndef	GPAC_DISABLE_ISOM_FRAGMENTS
        /*in edit mode with successfully loaded fragments, delete all fragment signaling since
        file is no longer fragmented*/
        if ((mov->openMode > GF_ISOM_OPEN_READ) && (mov->openMode != GF_ISOM_OPEN_CAT_FRAGMENTS) && mov->moov->mvex) {
            gf_isom_box_del((GF_Box *)mov->moov->mvex);
            mov->moov->mvex = NULL;
        }
#endif

    }

    //create a default mdat if none was found
    if (!mov->mdat && (mov->openMode != GF_ISOM_OPEN_READ) && (mov->openMode != GF_ISOM_OPEN_CAT_FRAGMENTS)) {
        mov->mdat = (GF_MediaDataBox *) gf_isom_box_new(GF_ISOM_BOX_TYPE_MDAT);
        e = gf_list_add(mov->TopBoxes, mov->mdat);
        if (e) return e;
    }
#endif /*GPAC_DISABLE_ISOM_WRITE*/

    return GF_OK;
}
Exemplo n.º 4
0
//extraction of the ESD from the track
GF_Err GetESD(GF_MovieBox *moov, u32 trackID, u32 StreamDescIndex, GF_ESD **outESD)
{
    GF_Err e;
    GF_ESD *esd;
    u32 track_num = 0;
    GF_SampleTableBox *stbl;
    GF_TrackBox *trak, *OCRTrack;
    GF_TrackReferenceTypeBox *dpnd;
    GF_SLConfig *slc;
    GF_MPEGSampleEntryBox *entry;

    track_num = gf_isom_get_tracknum_from_id(moov, trackID);
    dpnd = NULL;
    *outESD = NULL;

    trak = gf_isom_get_track(moov, track_num);
    if (!trak) return GF_ISOM_INVALID_FILE;

    e = Media_GetESD(trak->Media, StreamDescIndex, &esd, 0);
    if (e) return e;

    e = Media_GetSampleDesc(trak->Media, StreamDescIndex, (GF_SampleEntryBox **) &entry, NULL);
    if (e) return e;
    //set the ID
    esd->ESID = trackID;

    //find stream dependencies
    e = Track_FindRef(trak, GF_ISOM_BOX_TYPE_DPND , &dpnd);
    if (e) return e;
    if (dpnd) {
        //ONLY ONE STREAM DEPENDENCY IS ALLOWED
        if (dpnd->trackIDCount != 1) return GF_ISOM_INVALID_MEDIA;
        //fix the spec: where is the index located ??
        esd->dependsOnESID = dpnd->trackIDs[0];
    } else {
        esd->dependsOnESID = 0;
    }

    if (trak->udta) {
        GF_UserDataMap *map;
        u32 i = 0;
        while ((map = (GF_UserDataMap*)gf_list_enum(trak->udta->recordList, &i))) {
            if (map->boxType == GF_4CC('A','U','X','V')) {
                GF_Descriptor *d = gf_odf_desc_new(GF_ODF_AUX_VIDEO_DATA);
                gf_list_add(esd->extensionDescriptors, d);
                break;
            }
        }
    }

    //OK, get the OCR (in a REAL MP4File, OCR is 0 in ESD and is specified through track reference
    dpnd = NULL;
    OCRTrack = NULL;
    //find OCR dependencies
    e = Track_FindRef(trak, GF_ISOM_BOX_TYPE_SYNC, &dpnd);
    if (e) return e;
    if (dpnd) {
        if (dpnd->trackIDCount != 1) return GF_ISOM_INVALID_MEDIA;
        esd->OCRESID = dpnd->trackIDs[0];
        OCRTrack = gf_isom_get_track_from_id(trak->moov, dpnd->trackIDs[0]);

        while (OCRTrack) {
            /*if we have a dependency on a track that doesn't have OCR dep, remove that dependency*/
            e = Track_FindRef(OCRTrack, GF_ISOM_BOX_TYPE_SYNC, &dpnd);
            if (e || !dpnd || !dpnd->trackIDCount) {
                OCRTrack = NULL;
                goto default_sync;
            }
            /*this is explicit desync*/
            if (dpnd && ((dpnd->trackIDs[0]==0) || (dpnd->trackIDs[0]==OCRTrack->Header->trackID))) break;
            /*loop in OCRs, break it*/
            if (esd->ESID == OCRTrack->Header->trackID) {
                OCRTrack = NULL;
                goto default_sync;
            }
            /*check next*/
            OCRTrack = gf_isom_get_track_from_id(trak->moov, dpnd->trackIDs[0]);
        }
        if (!OCRTrack) goto default_sync;
    } else {
default_sync:
        /*all tracks are sync'ed by default*/
        if (trak->moov->mov->es_id_default_sync<0) {
            if (esd->OCRESID)
                trak->moov->mov->es_id_default_sync = esd->OCRESID;
            else
                trak->moov->mov->es_id_default_sync = esd->ESID;
        }
        if (trak->moov->mov->es_id_default_sync) esd->OCRESID = (u16) trak->moov->mov->es_id_default_sync;
        /*cf ESD writer*/
        if (esd->OCRESID == esd->ESID) esd->OCRESID = 0;
    }



    //update the IPI stuff if needed
    if (esd->ipiPtr != NULL) {
        dpnd = NULL;
        e = Track_FindRef(trak, GF_ISOM_BOX_TYPE_IPIR, &dpnd);
        if (e) return e;
        if (dpnd) {
            if (esd->ipiPtr->tag != GF_ODF_ISOM_IPI_PTR_TAG) return GF_ISOM_INVALID_FILE;
            //OK, retrieve the ID: the IPI_ES_Id is currently the ref track
            esd->ipiPtr->IPI_ES_Id = dpnd->trackIDs[esd->ipiPtr->IPI_ES_Id - 1];
            //and change the tag
            esd->ipiPtr->tag = GF_ODF_IPI_PTR_TAG;
        } else {
            return GF_ISOM_INVALID_FILE;
        }
    }

    if ((trak->Media->mediaHeader->packedLanguage[0] != 'u')
            || (trak->Media->mediaHeader->packedLanguage[1] != 'n')
            || (trak->Media->mediaHeader->packedLanguage[2] != 'd') ) {
        if (!esd->langDesc) esd->langDesc = (GF_Language *) gf_odf_desc_new(GF_ODF_LANG_TAG);

        esd->langDesc->langCode = trak->Media->mediaHeader->packedLanguage[0];
        esd->langDesc->langCode <<= 8;
        esd->langDesc->langCode |= trak->Media->mediaHeader->packedLanguage[1];
        esd->langDesc->langCode <<= 8;
        esd->langDesc->langCode |= trak->Media->mediaHeader->packedLanguage[2];
    }


    {
        u16 rvc_predefined;
        char *rvc_cfg_data;
        const char *mime_type;
        u32 rvc_cfg_size;
        e = gf_isom_get_rvc_config(moov->mov, track_num, 1, &rvc_predefined, &rvc_cfg_data, &rvc_cfg_size, &mime_type);
        if (e==GF_OK) {
            if (rvc_predefined) {
                esd->decoderConfig->predefined_rvc_config = rvc_predefined;
            } else {
                esd->decoderConfig->rvc_config = (GF_DefaultDescriptor *) gf_odf_desc_new(GF_ODF_DSI_TAG);
                if (mime_type && !strcmp(mime_type, "application/rvc-config+xml+gz") ) {
#if !defined(GPAC_DISABLE_CORE_TOOLS) && !defined(GPAC_DISABLE_ZLIB)
                    gf_gz_decompress_payload(rvc_cfg_data, rvc_cfg_size, &esd->decoderConfig->rvc_config->data, &esd->decoderConfig->rvc_config->dataLength);
                    gf_free(rvc_cfg_data);
#endif
                } else {
                    esd->decoderConfig->rvc_config->data = rvc_cfg_data;
                    esd->decoderConfig->rvc_config->dataLength = rvc_cfg_size;
                }
            }
        }
    }


    /*normally all files shall be stored with predefined=SLPredef_MP4, but of course some are broken (philips)
    so we just check the ESD_URL. If set, use the given cfg, otherwise always rewrite it*/
    if (esd->URLString != NULL) {
        *outESD = esd;
        return GF_OK;
    }

    //if we are in publishing mode and we have an SLConfig specified, use it as is
    switch (entry->type) {
    case GF_ISOM_BOX_TYPE_MP4V:
        slc = ((GF_MPEGVisualSampleEntryBox *)entry)->slc;
        break;
    case GF_ISOM_BOX_TYPE_MP4A:
        slc = ((GF_MPEGAudioSampleEntryBox *)entry)->slc;
        break;
    case GF_ISOM_BOX_TYPE_MP4S:
        slc = entry->slc;
        break;
    default:
        slc = NULL;
        break;
    }
    if (slc) {
        gf_odf_desc_del((GF_Descriptor *)esd->slConfig);
        gf_odf_desc_copy((GF_Descriptor *)slc, (GF_Descriptor **)&esd->slConfig);
        *outESD = esd;
        return GF_OK;
    }
    //otherwise use the regular mapping

    //this is a desc for a media in the file, let's rewrite some param
    esd->slConfig->timestampLength = 32;
    esd->slConfig->timestampResolution = trak->Media->mediaHeader->timeScale;
    //NO OCR from MP4File streams (eg, constant OC Res one)
    esd->slConfig->OCRLength = 0;
    esd->slConfig->OCRResolution = 0;
//	if (OCRTrack) esd->slConfig->OCRResolution = OCRTrack->Media->mediaHeader->timeScale;

    stbl = trak->Media->information->sampleTable;
    // a little optimization here: if all our samples are sync,
    //set the RAPOnly to true... for external users...
    if (! stbl->SyncSample) {
        esd->slConfig->hasRandomAccessUnitsOnlyFlag = 1;
        esd->slConfig->useRandomAccessPointFlag = 0;
    } else {
        esd->slConfig->hasRandomAccessUnitsOnlyFlag = 0;
        //signal we are NOT using sync points if no info is present in the table
        esd->slConfig->useRandomAccessPointFlag = stbl->SyncSample->nb_entries ? 1 : 0;
    }
    //do we have DegradationPriority ?
    if (stbl->DegradationPriority) {
        esd->slConfig->degradationPriorityLength = 15;
    } else {
        esd->slConfig->degradationPriorityLength = 0;
    }
    //paddingBits
    if (stbl->PaddingBits) {
        esd->slConfig->usePaddingFlag = 1;
    }
    //change to support reflecting OD streams
    esd->slConfig->useAccessUnitEndFlag = 1;
    esd->slConfig->useAccessUnitStartFlag = 1;

    //signal we do have padding flag (since we only use logical SL packet
    //the user can decide whether to use the info or not
    esd->slConfig->usePaddingFlag = stbl->PaddingBits ? 1 : 0;

    //same with degradation priority
    esd->slConfig->degradationPriorityLength = stbl->DegradationPriority ? 32 : 0;

    //this new SL will be OUT OF THE FILE. Let's set its predefined to 0
    esd->slConfig->predefined = 0;


    *outESD = esd;
    return GF_OK;
}
Exemplo n.º 5
0
// Rewrite the good dependancies when an OD AU is extracted from the file
GF_Err Media_RewriteODFrame(GF_MediaBox *mdia, GF_ISOSample *sample)
{
	GF_Err e;
	GF_ODCodec *ODdecode;
	GF_ODCodec *ODencode;
	GF_ODCom *com;
	
	//the commands we proceed
	GF_ESDUpdate *esdU, *esdU2;
	GF_ESDRemove *esdR, *esdR2;
	GF_ODUpdate *odU, *odU2;

	//the desc they contain
	GF_ObjectDescriptor *od;
	GF_IsomObjectDescriptor *isom_od;
	GF_ESD *esd;
	GF_ES_ID_Ref *ref;
	GF_Descriptor *desc;
	GF_TrackReferenceTypeBox *mpod;
	u32 i, j, skipped;

	if (!mdia || !sample || !sample->data || !sample->dataLength) return GF_BAD_PARAM;

	mpod = NULL;
	e = Track_FindRef(mdia->mediaTrack, GF_ISOM_BOX_TYPE_MPOD, &mpod);
	if (e) return e;
	//no references, nothing to do...
	if (!mpod) return GF_OK;

	ODdecode = gf_odf_codec_new();
	if (!ODdecode) return GF_OUT_OF_MEM;
	ODencode = gf_odf_codec_new();
	if (!ODencode) {
		gf_odf_codec_del(ODdecode);
		return GF_OUT_OF_MEM;
	}
	e = gf_odf_codec_set_au(ODdecode, sample->data, sample->dataLength);
	if (e) goto err_exit;
	e = gf_odf_codec_decode(ODdecode);
	if (e) goto err_exit;

	while (1) {
		com = gf_odf_codec_get_com(ODdecode);
		if (!com) break;

		//we only need to rewrite commands with ESDs inside: ESDUpdate and ODUpdate
		switch (com->tag) {
		case GF_ODF_OD_UPDATE_TAG:
			odU = (GF_ODUpdate *) com;
			odU2 = (GF_ODUpdate *) gf_odf_com_new(GF_ODF_OD_UPDATE_TAG);

			i=0;
			while ((desc = (GF_Descriptor*)gf_list_enum(odU->objectDescriptors, &i))) {
				switch (desc->tag) {
				case GF_ODF_OD_TAG:
				case GF_ODF_ISOM_OD_TAG:
				//IOD can be used in OD streams
				case GF_ODF_ISOM_IOD_TAG:
					break;
				default:
					return GF_ISOM_INVALID_FILE;
				}
				e = gf_odf_desc_copy(desc, (GF_Descriptor **)&isom_od);
				if (e) goto err_exit;
					
				//create our OD...
				if (desc->tag == GF_ODF_ISOM_IOD_TAG) {
					od = (GF_ObjectDescriptor *) gf_malloc(sizeof(GF_InitialObjectDescriptor));
				} else {
					od = (GF_ObjectDescriptor *) gf_malloc(sizeof(GF_ObjectDescriptor));
				}
				if (!od) {
					e = GF_OUT_OF_MEM;
					goto err_exit;
				}
				od->ESDescriptors = gf_list_new();
				//and duplicate...
				od->objectDescriptorID = isom_od->objectDescriptorID;
				od->tag = GF_ODF_OD_TAG;
				od->URLString = isom_od->URLString;
				isom_od->URLString = NULL;
				od->extensionDescriptors = isom_od->extensionDescriptors;
				isom_od->extensionDescriptors = NULL;
				od->IPMP_Descriptors = isom_od->IPMP_Descriptors;
				isom_od->IPMP_Descriptors = NULL;
				od->OCIDescriptors = isom_od->OCIDescriptors;
				isom_od->OCIDescriptors = NULL;
				
				//init as IOD
				if (isom_od->tag == GF_ODF_ISOM_IOD_TAG) {
					((GF_InitialObjectDescriptor *)od)->audio_profileAndLevel = ((GF_IsomInitialObjectDescriptor *)isom_od)->audio_profileAndLevel;
					((GF_InitialObjectDescriptor *)od)->inlineProfileFlag = ((GF_IsomInitialObjectDescriptor *)isom_od)->inlineProfileFlag;
					((GF_InitialObjectDescriptor *)od)->graphics_profileAndLevel = ((GF_IsomInitialObjectDescriptor *)isom_od)->graphics_profileAndLevel;
					((GF_InitialObjectDescriptor *)od)->OD_profileAndLevel = ((GF_IsomInitialObjectDescriptor *)isom_od)->OD_profileAndLevel;
					((GF_InitialObjectDescriptor *)od)->scene_profileAndLevel = ((GF_IsomInitialObjectDescriptor *)isom_od)->scene_profileAndLevel;
					((GF_InitialObjectDescriptor *)od)->visual_profileAndLevel = ((GF_IsomInitialObjectDescriptor *)isom_od)->visual_profileAndLevel;
					((GF_InitialObjectDescriptor *)od)->IPMPToolList = ((GF_IsomInitialObjectDescriptor *)isom_od)->IPMPToolList;
					((GF_IsomInitialObjectDescriptor *)isom_od)->IPMPToolList = NULL;
				}
				
				//then rewrite the ESDesc
				j=0;
				while ((ref = (GF_ES_ID_Ref*)gf_list_enum(isom_od->ES_ID_RefDescriptors, &j))){
					//if the ref index is not valid, skip this desc...
					if (!mpod->trackIDs || gf_isom_get_track_from_id(mdia->mediaTrack->moov, mpod->trackIDs[ref->trackRef - 1]) == NULL) continue;
					//OK, get the esd
					e = GetESDForTime(mdia->mediaTrack->moov, mpod->trackIDs[ref->trackRef - 1], sample->DTS, &esd);
					if (!e) e = gf_odf_desc_add_desc((GF_Descriptor *) od, (GF_Descriptor *) esd);
					if (e) {
						gf_odf_desc_del((GF_Descriptor *)od);
						gf_odf_com_del((GF_ODCom **)&odU2);
						gf_odf_desc_del((GF_Descriptor *)isom_od);
						gf_odf_com_del((GF_ODCom **)&odU);
						goto err_exit;
					}

				}
				//delete our desc
				gf_odf_desc_del((GF_Descriptor *)isom_od);
				gf_list_add(odU2->objectDescriptors, od);
			}
			//clean a bit
			gf_odf_com_del((GF_ODCom **)&odU);
			gf_odf_codec_add_com(ODencode, (GF_ODCom *)odU2);
			break;

		case GF_ODF_ESD_UPDATE_TAG:
			esdU = (GF_ESDUpdate *) com;
			esdU2 = (GF_ESDUpdate *) gf_odf_com_new(GF_ODF_ESD_UPDATE_TAG);
			esdU2->ODID = esdU->ODID;
			i=0;
			while ((ref = (GF_ES_ID_Ref*)gf_list_enum(esdU->ESDescriptors, &i))) {
				//if the ref index is not valid, skip this desc...
				if (gf_isom_get_track_from_id(mdia->mediaTrack->moov, mpod->trackIDs[ref->trackRef - 1]) == NULL) continue;
				//OK, get the esd
				e = GetESDForTime(mdia->mediaTrack->moov, mpod->trackIDs[ref->trackRef - 1], sample->DTS, &esd);
				if (e) goto err_exit;
				gf_list_add(esdU2->ESDescriptors, esd);
			}
			gf_odf_com_del((GF_ODCom **)&esdU);
			gf_odf_codec_add_com(ODencode, (GF_ODCom *)esdU2);
			break;

		//brand new case: the ESRemove follows the same principle according to the spec...
		case GF_ODF_ESD_REMOVE_REF_TAG:
			//both commands have the same structure, only the tags change
			esdR = (GF_ESDRemove *) com;
			esdR2 = (GF_ESDRemove *) gf_odf_com_new(GF_ODF_ESD_REMOVE_TAG);
			esdR2->ODID = esdR->ODID;
			esdR2->NbESDs = esdR->NbESDs;
			//alloc our stuff
			esdR2->ES_ID = (unsigned short*)gf_malloc(sizeof(u32) * esdR->NbESDs);
			if (!esdR2->ES_ID) {
				e = GF_OUT_OF_MEM;
				goto err_exit;
			}
			skipped = 0;
			//get the ES_ID in the mpod indicated in the ES_ID[]
			for (i = 0; i < esdR->NbESDs; i++) {
				//if the ref index is not valid, remove this desc...
				if (gf_isom_get_track_from_id(mdia->mediaTrack->moov, mpod->trackIDs[esdR->ES_ID[i] - 1]) == NULL) {
					skipped ++;
				} else {
					//the command in the file has the ref index of the trackID in the mpod
					esdR2->ES_ID[i - skipped] = mpod->trackIDs[esdR->ES_ID[i] - 1];
				}
			}
			//gf_realloc...
			if (skipped && (skipped != esdR2->NbESDs) ) {
				esdR2->NbESDs -= skipped;
				esdR2->ES_ID = (unsigned short*)gf_realloc(esdR2->ES_ID, sizeof(u32) * esdR2->NbESDs);
			}
			gf_odf_com_del((GF_ODCom **)&esdR);
			gf_odf_codec_add_com(ODencode, (GF_ODCom *)esdR2);
			break;

		default:
			e = gf_odf_codec_add_com(ODencode, com);
			if (e) goto err_exit;
		}
	}
	//encode our new AU
	e = gf_odf_codec_encode(ODencode, 1);
	if (e) goto err_exit;

	//and set the buffer in the sample
	gf_free(sample->data);
	sample->data = NULL;
	sample->dataLength = 0;
	e = gf_odf_codec_get_au(ODencode, &sample->data, &sample->dataLength);

err_exit:
	gf_odf_codec_del(ODdecode);
	gf_odf_codec_del(ODencode);
	return e;
}
Exemplo n.º 6
0
GF_EXPORT
GF_Err gf_isom_next_hint_packet(GF_ISOFile *the_file, u32 trackNumber, char **pck_data, u32 *pck_size, Bool *disposable, Bool *repeated, u32 *trans_ts, u32 *sample_num)
{
	GF_RTPPacket *pck;
	GF_Err e;
	GF_BitStream *bs;
	GF_TrackBox *trak, *ref_trak;
	GF_HintSampleEntryBox *entry;
	u32 i, count, ts;
	s32 cts_off;

	*pck_data = NULL;
	*pck_size = 0;
	if (trans_ts) *trans_ts = 0;
	if (disposable) *disposable = 0;
	if (repeated) *repeated = 0;
	if (sample_num) *sample_num = 0;

	trak = gf_isom_get_track_from_file(the_file, trackNumber);
	if (!trak) return GF_BAD_PARAM;
	e = Media_GetSampleDesc(trak->Media, 1, (GF_SampleEntryBox **) &entry, NULL);
	if (e) return e;
	switch (entry->type) {
	case GF_ISOM_BOX_TYPE_RTP_STSD:
	case GF_ISOM_BOX_TYPE_SRTP_STSD:
	case GF_ISOM_BOX_TYPE_RRTP_STSD:
		break;
	default:
		return GF_NOT_SUPPORTED;
	}

	if (!entry->hint_sample) {
		e = gf_isom_load_next_hint_sample(the_file, trackNumber, trak, entry);
		if (e) return e;
	}
	pck = (GF_RTPPacket *)gf_list_get(entry->hint_sample->packetTable, 0);
	gf_list_rem(entry->hint_sample->packetTable, 0);
	if (!pck) return GF_BAD_PARAM;

	bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
	/*write RTP header*/
	gf_bs_write_int(bs, 2, 2);	/*version*/
	gf_bs_write_int(bs, pck->P_bit, 1);	/*P bit*/
	gf_bs_write_int(bs, pck->X_bit, 1);	/*X bit*/
	gf_bs_write_int(bs, 0, 4);	/*CSRC count*/
	gf_bs_write_int(bs, pck->M_bit, 1);	/*M bit*/
	gf_bs_write_int(bs, pck->payloadType, 7);	/*payt*/
	gf_bs_write_u16(bs, entry->pck_sn);	/*seq num*/
	entry->pck_sn++;

	/*look for CTS offset in TLV*/
	cts_off = 0;
	count = gf_list_count(pck->TLV);
	for (i=0; i<count; i++) {
		GF_RTPOBox *rtpo = (GF_RTPOBox *)gf_list_get(pck->TLV, i);
		if (rtpo->type == GF_ISOM_BOX_TYPE_RTPO) {
			cts_off = rtpo->timeOffset;
			break;
		}
	}
	/*TS - TODO check TS wrapping*/
	ts = (u32) (entry->hint_sample->TransmissionTime + pck->relativeTransTime + entry->ts_offset + cts_off);
	gf_bs_write_u32(bs, ts );
	gf_bs_write_u32(bs, entry->ssrc);	/*SSRC*/

	/*then build all data*/
	count = gf_list_count(pck->DataTable);
	for (i=0; i<count; i++) {
		GF_GenericDTE *dte = (GF_GenericDTE *)gf_list_get(pck->DataTable, i);
		switch (dte->source) {
		/*empty*/
		case 0:
			break;
		/*immediate data*/
		case 1:
			gf_bs_write_data(bs, ((GF_ImmediateDTE *)dte)->data, ((GF_ImmediateDTE *)dte)->dataLength);
			break;
		/*sample data*/
		case 2:
		{
			GF_ISOSample *samp;
			GF_SampleDTE *sdte = (GF_SampleDTE *)dte;
			/*get track if not this one*/
			if (sdte->trackRefIndex != (s8) -1) {
				if (!entry->hint_ref || !entry->hint_ref->trackIDs) {
					gf_isom_hint_rtp_del(pck);
					gf_bs_del(bs);
					return GF_ISOM_INVALID_FILE;
				}
				ref_trak = gf_isom_get_track_from_id(trak->moov, entry->hint_ref->trackIDs[(u32)sdte->trackRefIndex]);
			} else {
				ref_trak = trak;
			}
			samp = gf_isom_get_data_sample(entry->hint_sample, ref_trak, sdte->sampleNumber);
			if (!samp) {
				gf_isom_hint_rtp_del(pck);
				gf_bs_del(bs);
				return GF_IO_ERR;
			}
			gf_bs_write_data(bs, samp->data + sdte->byteOffset, sdte->dataLength);
		}
		break;
		/*sample desc data - currently NOT SUPPORTED !!!*/
		case 3:
			break;
		}
	}
	if (trans_ts) *trans_ts = ts;
	if (disposable) *disposable = pck->B_bit;
	if (repeated) *repeated = pck->R_bit;
	if (sample_num) *sample_num = entry->cur_sample-1;

	gf_bs_get_content(bs, pck_data, pck_size);
	gf_bs_del(bs);
	gf_isom_hint_rtp_del(pck);
	if (!gf_list_count(entry->hint_sample->packetTable)) {
		gf_isom_hint_sample_del(entry->hint_sample);
		entry->hint_sample = NULL;
	}
	return GF_OK;
}