📄 media.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / ISO Media File Format sub-project * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <gpac/internal/isomedia_dev.h>GF_Err Media_GetSampleDesc(GF_MediaBox *mdia, u32 SampleDescIndex, GF_SampleEntryBox **out_entry, u32 *dataRefIndex){ GF_SampleDescriptionBox *stsd; GF_SampleEntryBox *entry = NULL; if (!mdia) return GF_ISOM_INVALID_FILE; stsd = mdia->information->sampleTable->SampleDescription; if (!stsd) return GF_ISOM_INVALID_FILE; if (!SampleDescIndex || (SampleDescIndex > gf_list_count(stsd->boxList)) ) return GF_BAD_PARAM; entry = (GF_SampleEntryBox*)gf_list_get(stsd->boxList, SampleDescIndex - 1); if (!entry) return GF_ISOM_INVALID_FILE; if (out_entry) *out_entry = entry; if (dataRefIndex) *dataRefIndex = entry->dataReferenceIndex; return GF_OK;}GF_Err Media_GetSampleDescIndex(GF_MediaBox *mdia, u64 DTS, u32 *sampleDescIndex){ GF_Err e; u32 sampleNumber, prevSampleNumber, num; u64 offset; u8 isEdited; if (sampleDescIndex == NULL) return GF_BAD_PARAM; //find the sample for this time e = findEntryForTime(mdia->information->sampleTable, (u32) DTS, 0, &sampleNumber, &prevSampleNumber); if (e) return e; if (!sampleNumber && !prevSampleNumber) { //we have to assume the track was created to be used... If we have a sampleDesc, OK if (gf_list_count(mdia->information->sampleTable->SampleDescription->boxList)) { (*sampleDescIndex) = 1; return GF_OK; } return GF_BAD_PARAM; } return stbl_GetSampleInfos(mdia->information->sampleTable, ( sampleNumber ? sampleNumber : prevSampleNumber), &offset, &num, sampleDescIndex, &isEdited);}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 = 0x05; /*official mapping to MPEG-4*/ switch (entry->type) { case GF_ISOM_SUBTYPE_3GP_EVRC: (*out_esd)->decoderConfig->objectTypeIndication = 0xA0; 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 = 0xE1; 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 = (GF_SttsEntry*)gf_list_get(stbl->TimeToSample->entryList, 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 = 0xA1; 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 = 0x80; 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 Media_GetESD(GF_MediaBox *mdia, u32 sampleDescIndex, GF_ESD **out_esd, Bool true_desc_only){ GF_ESD *esd; GF_MPEGSampleEntryBox *entry = NULL; GF_ESDBox *ESDa; GF_SampleDescriptionBox *stsd = mdia->information->sampleTable->SampleDescription; *out_esd = NULL; if (!stsd || !stsd->boxList || !sampleDescIndex || (sampleDescIndex > gf_list_count(stsd->boxList)) ) return GF_BAD_PARAM; esd = NULL; entry = (GF_MPEGSampleEntryBox*)gf_list_get(stsd->boxList, sampleDescIndex - 1); if (! entry) return GF_ISOM_INVALID_MEDIA; *out_esd = NULL; ESDa = NULL; switch (entry->type) { case GF_ISOM_BOX_TYPE_MP4V: case GF_ISOM_BOX_TYPE_ENCV: ESDa = ((GF_MPEGVisualSampleEntryBox*)entry)->esd; if (ESDa) esd = (GF_ESD *) ESDa->desc; /*avc1 encrypted*/ else esd = ((GF_MPEGVisualSampleEntryBox*) entry)->emul_esd; break; case GF_ISOM_BOX_TYPE_AVC1: esd = ((GF_MPEGVisualSampleEntryBox*) entry)->emul_esd; break; case GF_ISOM_BOX_TYPE_MP4A: case GF_ISOM_BOX_TYPE_ENCA: ESDa = ((GF_MPEGAudioSampleEntryBox*)entry)->esd; if (ESDa) esd = (GF_ESD *) ESDa->desc; break; case GF_ISOM_BOX_TYPE_MP4S: case GF_ISOM_BOX_TYPE_ENCS: ESDa = entry->esd; if (ESDa) esd = (GF_ESD *) ESDa->desc; break; case GF_ISOM_BOX_TYPE_TX3G: if (!true_desc_only && mdia->mediaTrack->moov->mov->convert_streaming_text) { GF_Err e = gf_isom_get_ttxt_esd(mdia, out_esd); if (e) return e; break; } else return GF_ISOM_INVALID_MEDIA; case GF_ISOM_SUBTYPE_3GP_AMR: case GF_ISOM_SUBTYPE_3GP_AMR_WB: case GF_ISOM_SUBTYPE_3GP_EVRC: case GF_ISOM_SUBTYPE_3GP_QCELP: case GF_ISOM_SUBTYPE_3GP_SMV: if (!true_desc_only) { GF_Err e = gf_isom_get_3gpp_audio_esd(mdia->information->sampleTable, (GF_GenericAudioSampleEntryBox*)entry, out_esd); if (e) return e; break; } else return GF_ISOM_INVALID_MEDIA; case GF_ISOM_SUBTYPE_3GP_H263: if (true_desc_only) { return GF_ISOM_INVALID_MEDIA; } else { GF_BitStream *bs; esd = gf_odf_desc_esd_new(2); *out_esd = esd; esd->decoderConfig->streamType = 0x04; esd->decoderConfig->objectTypeIndication = 0x80; bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); gf_bs_write_u32(bs, entry->type); gf_bs_write_u16(bs, ((GF_MPEGVisualSampleEntryBox*)entry)->Width); gf_bs_write_u16(bs, ((GF_MPEGVisualSampleEntryBox*)entry)->Height); gf_bs_get_content(bs, & esd->decoderConfig->decoderSpecificInfo->data, & esd->decoderConfig->decoderSpecificInfo->dataLength); gf_bs_del(bs); return GF_OK; } default: return GF_ISOM_INVALID_MEDIA; } if (true_desc_only) { if (!esd) return GF_ISOM_INVALID_MEDIA; *out_esd = esd; return GF_OK; } else { if (!esd && !*out_esd) return GF_ISOM_INVALID_MEDIA; if (*out_esd == NULL) gf_odf_desc_copy((GF_Descriptor *)esd, (GF_Descriptor **)out_esd); } return GF_OK;}Bool Media_IsSampleSyncShadow(GF_ShadowSyncBox *stsh, u32 sampleNumber){ u32 i; GF_StshEntry *ent; if (!stsh) return 0; i=0; while ((ent = (GF_StshEntry*)gf_list_enum(stsh->entries, &i))) { if ((u32) ent->syncSampleNumber == sampleNumber) return 1; else if ((u32) ent->syncSampleNumber > sampleNumber) return 0; } return 0;}GF_Err Media_GetSample(GF_MediaBox *mdia, u32 sampleNumber, GF_ISOSample **samp, u32 *sIDX, Bool no_data, u64 *out_offset){ GF_Err e; u32 bytesRead; u32 dataRefIndex, chunkNumber; u64 offset, new_size; u8 isEdited; GF_SampleEntryBox *entry; if (!mdia || !mdia->information->sampleTable) return GF_BAD_PARAM; //OK, here we go.... if (sampleNumber > mdia->information->sampleTable->SampleSize->sampleCount) return GF_BAD_PARAM; //get the DTS e = stbl_GetSampleDTS(mdia->information->sampleTable->TimeToSample, sampleNumber, &(*samp)->DTS); if (e) return e; //the CTS offset if (mdia->information->sampleTable->CompositionOffset) { e = stbl_GetSampleCTS(mdia->information->sampleTable->CompositionOffset , sampleNumber, &(*samp)->CTS_Offset); if (e) return e; } else { (*samp)->CTS_Offset = 0; } //the size e = stbl_GetSampleSize(mdia->information->sampleTable->SampleSize, sampleNumber, &(*samp)->dataLength); if (e) return e; //the RAP if (mdia->information->sampleTable->SyncSample) { e = stbl_GetSampleRAP(mdia->information->sampleTable->SyncSample, sampleNumber, &(*samp)->IsRAP, NULL, NULL); if (e) return e; } else { //if no SyncSample, all samples are sync (cf spec) (*samp)->IsRAP = 1; } /*overwrite sync sample with sample dep if any*/ if (mdia->information->sampleTable->SampleDep) { u32 dependsOn, dependedOn, redundant; e = stbl_GetSampleDepType(mdia->information->sampleTable->SampleDep, sampleNumber, &dependsOn, &dependedOn, &redundant); if (!e) { if (dependsOn==1) (*samp)->IsRAP = 0; else if (dependsOn==2) (*samp)->IsRAP = 1; /*if not depended upon and redundant, mark as carousel sample*/ if ((dependedOn==2) && (redundant==1)) (*samp)->IsRAP = 2; /*TODO FIXME - we must enhance the IsRAP semantics to carry disposable info ... */ } } /*get sync shadow*/ if (Media_IsSampleSyncShadow(mdia->information->sampleTable->ShadowSync, sampleNumber)) (*samp)->IsRAP = 2; //the data info if (!sIDX && !no_data) return GF_BAD_PARAM; if (!sIDX && !out_offset) return GF_OK; (*sIDX) = 0; e = stbl_GetSampleInfos(mdia->information->sampleTable, sampleNumber, &offset, &chunkNumber, sIDX, &isEdited); if (e) return e; //then get the DataRef e = Media_GetSampleDesc(mdia, *sIDX, &entry, &dataRefIndex); if (e) return e; // Open the data handler - check our mode, don't reopen in read only if this is //the same entry. In other modes we have no choice because the main data map is //divided into the original and the edition files if (mdia->mediaTrack->moov->mov->openMode == GF_ISOM_OPEN_READ) { //same as last call in read mode if (!mdia->information->dataHandler || (mdia->information->dataEntryIndex != dataRefIndex)) { e = gf_isom_datamap_open(mdia, dataRefIndex, isEdited); if (e) return e; } } else { e = gf_isom_datamap_open(mdia, dataRefIndex, isEdited); if (e) return e; } if (out_offset) *out_offset = offset; if (no_data) return GF_OK; /*and finally get the data, include padding if needed*/ (*samp)->data = (char *) malloc(sizeof(char) * ( (*samp)->dataLength + mdia->mediaTrack->padding_bytes) ); if (mdia->mediaTrack->padding_bytes) memset((*samp)->data + (*samp)->dataLength, 0, sizeof(char) * mdia->mediaTrack->padding_bytes); //check if we can get the sample (make sure we have enougth data...) new_size = gf_bs_get_size(mdia->information->dataHandler->bs); if (offset + (*samp)->dataLength > new_size) { //always refresh the size to avoid wrong info on http/ftp new_size = gf_bs_get_refreshed_size(mdia->information->dataHandler->bs); if (offset + (*samp)->dataLength > new_size) { mdia->BytesMissing = offset + (*samp)->dataLength - new_size; return GF_ISOM_INCOMPLETE_FILE; } } bytesRead = gf_isom_datamap_get_data(mdia->information->dataHandler, (*samp)->data, (*samp)->dataLength, offset); //if bytesRead != sampleSize, we have an IO err if (bytesRead < (*samp)->dataLength) { return GF_IO_ERR; } mdia->BytesMissing = 0; //finally rewrite the sample if this is an OD Access Unit if (mdia->handler->handlerType == GF_ISOM_MEDIA_OD) { e = Media_RewriteODFrame(mdia, *samp); if (e) return e; } else if (mdia->mediaTrack->moov->mov->convert_streaming_text && (mdia->handler->handlerType == GF_ISOM_MEDIA_TEXT) ) { u64 dur; if (sampleNumber == mdia->information->sampleTable->SampleSize->sampleCount) { dur = mdia->mediaHeader->duration - (*samp)->DTS; } else { stbl_GetSampleDTS(mdia->information->sampleTable->TimeToSample, sampleNumber+1, &dur); dur -= (*samp)->DTS; } e = gf_isom_rewrite_text_sample(*samp, *sIDX, (u32) dur); if (e) return e; } return GF_OK;}GF_Err Media_CheckDataEntry(GF_MediaBox *mdia, u32 dataEntryIndex){ GF_DataEntryURLBox *entry; GF_DataMap *map; GF_Err e; if (!mdia || !dataEntryIndex || dataEntryIndex > gf_list_count(mdia->information->dataInformation->dref->boxList)) return GF_BAD_PARAM; entry = (GF_DataEntryURLBox*)gf_list_get(mdia->information->dataInformation->dref->boxList, dataEntryIndex - 1); if (!entry) return GF_ISOM_INVALID_FILE; if (entry->flags == 1) return GF_OK; //ok, not self contained, let's go for it... //we don't know what's a URN yet if (entry->type == GF_ISOM_BOX_TYPE_URN) return GF_NOT_SUPPORTED; if (mdia->mediaTrack->moov->mov->openMode == GF_ISOM_OPEN_WRITE) { e = gf_isom_datamap_new(entry->location, NULL, GF_ISOM_DATA_MAP_READ, &map); } else { e = gf_isom_datamap_new(entry->location, mdia->mediaTrack->moov->mov->fileName, GF_ISOM_DATA_MAP_READ, &map); } if (e) return e; gf_isom_datamap_del(map); return GF_OK;}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->boxList, drefIndex - 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -