📄 isom_tools.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / Media Tools 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/media_tools.h>#include <gpac/constants.h>#ifndef GPAC_READ_ONLYstatic const u32 ISMA_VIDEO_OD_ID = 20;static const u32 ISMA_AUDIO_OD_ID = 10;static const u32 ISMA_VIDEO_ES_ID = 201;static const u32 ISMA_AUDIO_ES_ID = 101;static const char ISMA_BIFS_CONFIG[] = {0x00, 0x00, 0x60 };/*ISMA audio*/static const u8 ISMA_BIFS_AUDIO[] = { 0xC0, 0x10, 0x12, 0x81, 0x30, 0x2A, 0x05, 0x7C};/*ISMA video*/static const u8 ISMA_GF_BIFS_VIDEO[] = { 0xC0, 0x10, 0x12, 0x60, 0x42, 0x82, 0x28, 0x29, 0xD0, 0x4F, 0x00};/*ISMA audio-video*/static const u8 ISMA_BIFS_AV[] = { 0xC0, 0x10, 0x12, 0x81, 0x30, 0x2A, 0x05, 0x72, 0x60, 0x42, 0x82, 0x28, 0x29, 0xD0, 0x4F, 0x00};/*image only - uses same visual OD ID as video*/static const u8 ISMA_BIFS_IMAGE[] = { 0xC0, 0x11, 0xA4, 0xCD, 0x53, 0x6A, 0x0A, 0x44, 0x13, 0x00};/*ISMA audio-image*/static const u8 ISMA_BIFS_AI[] = { 0xC0, 0x11, 0xA5, 0x02, 0x60, 0x54, 0x0A, 0xE4, 0xCD, 0x53, 0x6A, 0x0A, 0x44, 0x13, 0x00};GF_EXPORTGF_Err gf_media_make_isma(GF_ISOFile *mp4file, Bool keepESIDs, Bool keepImage, Bool no_ocr){ u32 AudioTrack, VideoTrack, Tracks, i, mType, bifsT, odT, descIndex, VideoType, VID, AID, bifsID, odID; u32 bifs, w, h; Bool is_image, image_track; GF_ESD *a_esd, *v_esd, *_esd; Bool update_vid_esd; GF_ObjectDescriptor *od; GF_ODUpdate *odU; GF_ODCodec *codec; GF_ISOSample *samp; GF_BitStream *bs; u8 audioPL, visualPL; switch (gf_isom_get_mode(mp4file)) { case GF_ISOM_OPEN_EDIT: case GF_ISOM_OPEN_WRITE: case GF_ISOM_WRITE_EDIT: break; default: return GF_BAD_PARAM; } Tracks = gf_isom_get_track_count(mp4file); AID = VID = 0; is_image = 0; //search for tracks for (i=0; i<Tracks; i++) { GF_ESD *esd = gf_isom_get_esd(mp4file, i+1, 1); //remove from IOD gf_isom_remove_track_from_root_od(mp4file, i+1); mType = gf_isom_get_media_type(mp4file, i+1); switch (mType) { case GF_ISOM_MEDIA_VISUAL: image_track = 0; if (esd && ((esd->decoderConfig->objectTypeIndication==0x6C) || (esd->decoderConfig->objectTypeIndication==0x6D)) ) image_track = 1; /*remove image tracks if wanted*/ if (keepImage || !image_track) { /*only ONE video stream possible with ISMA*/ if (VID) { if (esd) gf_odf_desc_del((GF_Descriptor*)esd); GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[ISMA convert] More than one video track found, cannot convert file - remove extra track(s)\n")); return GF_NOT_SUPPORTED; } VID = gf_isom_get_track_id(mp4file, i+1); is_image = image_track; } else { GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[ISMA convert] Visual track ID %d: only one sample found, assuming image and removing track\n", gf_isom_get_track_id(mp4file, i+1) ) ); gf_isom_remove_track(mp4file, i+1); i -= 1; Tracks = gf_isom_get_track_count(mp4file); } break; case GF_ISOM_MEDIA_AUDIO: if (AID) { if (esd) gf_odf_desc_del((GF_Descriptor*)esd); GF_LOG(GF_LOG_ERROR, GF_LOG_AUTHOR, ("[ISMA convert] More than one audio track found, cannot convert file - remove extra track(s)\n") ); return GF_NOT_SUPPORTED; } AID = gf_isom_get_track_id(mp4file, i+1); break; /*clean file*/ default: if (mType==GF_ISOM_MEDIA_HINT) { GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[ISMA convert] Removing Hint track ID %d\n", gf_isom_get_track_id(mp4file, i+1) )); } else { GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[ISMA convert] Removing track ID %d\n", gf_isom_get_track_id(mp4file, i+1) )); } gf_isom_remove_track(mp4file, i+1); i -= 1; Tracks = gf_isom_get_track_count(mp4file); break; } if (esd) gf_odf_desc_del((GF_Descriptor*)esd); } //no audio no video if (!AID && !VID) return GF_OK; /*reset all PLs*/ visualPL = 0xFE; audioPL = 0xFE; od = (GF_ObjectDescriptor *) gf_isom_get_root_od(mp4file); if (od && (od->tag==GF_ODF_IOD_TAG)) { audioPL = ((GF_InitialObjectDescriptor*)od)->audio_profileAndLevel; visualPL = ((GF_InitialObjectDescriptor*)od)->visual_profileAndLevel; } if (od) gf_odf_desc_del((GF_Descriptor *)od); //create the OD AU bifs = 0; odU = (GF_ODUpdate *) gf_odf_com_new(GF_ODF_OD_UPDATE_TAG); a_esd = v_esd = NULL; update_vid_esd = 0; gf_isom_set_root_od_id(mp4file, 1); bifsID = 1; odID = 2; if (keepESIDs) { bifsID = 1; while ((bifsID==AID) || (bifsID==VID)) bifsID++; odID = 2; while ((odID==AID) || (odID==VID) || (odID==bifsID)) odID++; } VideoTrack = gf_isom_get_track_by_id(mp4file, VID); AudioTrack = gf_isom_get_track_by_id(mp4file, AID); w = h = 0; if (VideoTrack) { bifs = 1; VideoType = 0; od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG); od->objectDescriptorID = ISMA_VIDEO_OD_ID; if (!keepESIDs && (VID != ISMA_VIDEO_ES_ID)) { gf_isom_set_track_id(mp4file, VideoTrack, ISMA_VIDEO_ES_ID); } v_esd = gf_isom_get_esd(mp4file, VideoTrack, 1); if (v_esd) { v_esd->OCRESID = no_ocr ? 0 : bifsID; gf_odf_desc_add_desc((GF_Descriptor *)od, (GF_Descriptor *)v_esd); gf_list_add(odU->objectDescriptors, od); gf_isom_get_track_layout_info(mp4file, VideoTrack, &w, &h, NULL, NULL, NULL); if (!w || !h) { gf_isom_get_visual_info(mp4file, VideoTrack, 1, &w, &h); if ((v_esd->decoderConfig->objectTypeIndication==0x20) && (v_esd->decoderConfig->streamType==GF_STREAM_VISUAL)) { GF_M4VDecSpecInfo dsi; gf_m4v_get_config(v_esd->decoderConfig->decoderSpecificInfo->data, v_esd->decoderConfig->decoderSpecificInfo->dataLength, &dsi); if (!is_image && (!w || !h)) { w = dsi.width; h = dsi.height; gf_isom_set_visual_info(mp4file, VideoTrack, 1, w, h); GF_LOG(GF_LOG_INFO, GF_LOG_AUTHOR, ("[ISMA convert] Adjusting visual track size to %d x %d\n", w, h)); } if (dsi.par_num && (dsi.par_den!=dsi.par_num)) { w *= dsi.par_num; w /= dsi.par_den; } if (dsi.VideoPL) visualPL = dsi.VideoPL; } } } } if (AudioTrack) { od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG); od->objectDescriptorID = ISMA_AUDIO_OD_ID; if (!keepESIDs && (AID != ISMA_AUDIO_ES_ID)) { gf_isom_set_track_id(mp4file, AudioTrack, ISMA_AUDIO_ES_ID); } a_esd = gf_isom_get_esd(mp4file, AudioTrack, 1); if (a_esd) { a_esd->OCRESID = no_ocr ? 0 : bifsID; if (!keepESIDs) a_esd->ESID = ISMA_AUDIO_ES_ID; gf_odf_desc_add_desc((GF_Descriptor *)od, (GF_Descriptor *)a_esd); gf_list_add(odU->objectDescriptors, od); if (!bifs) { bifs = 3; } else { bifs = 2; } if (a_esd->decoderConfig->objectTypeIndication == 0x40) { GF_M4ADecSpecInfo cfg; gf_m4a_get_config(a_esd->decoderConfig->decoderSpecificInfo->data, a_esd->decoderConfig->decoderSpecificInfo->dataLength, &cfg); audioPL = cfg.audioPL; } } } /*update video cfg if needed*/ if (v_esd) gf_isom_change_mpeg4_description(mp4file, VideoTrack, 1, v_esd); if (a_esd) gf_isom_change_mpeg4_description(mp4file, AudioTrack, 1, a_esd); /*likely 3GP or other files...*/ if ((!a_esd && AudioTrack) || (!v_esd && VideoTrack)) return GF_OK; //get the OD sample codec = gf_odf_codec_new(); samp = gf_isom_sample_new(); gf_odf_codec_add_com(codec, (GF_ODCom *)odU); gf_odf_codec_encode(codec, 1); gf_odf_codec_get_au(codec, &samp->data, &samp->dataLength); gf_odf_codec_del(codec); samp->CTS_Offset = 0; samp->DTS = 0; samp->IsRAP = 1; /*create the OD track*/ odT = gf_isom_new_track(mp4file, odID, GF_ISOM_MEDIA_OD, gf_isom_get_timescale(mp4file)); if (!odT) return gf_isom_last_error(mp4file); _esd = gf_odf_desc_esd_new(SLPredef_MP4); _esd->decoderConfig->bufferSizeDB = samp->dataLength; _esd->decoderConfig->objectTypeIndication = 0x01; _esd->decoderConfig->streamType = GF_STREAM_OD; _esd->ESID = odID; _esd->OCRESID = no_ocr ? 0 : bifsID; gf_isom_new_mpeg4_description(mp4file, odT, _esd, NULL, NULL, &descIndex); gf_odf_desc_del((GF_Descriptor *)_esd); gf_isom_add_sample(mp4file, odT, 1, samp); gf_isom_sample_del(&samp); gf_isom_set_track_group(mp4file, odT, 1); /*create the BIFS track*/ bifsT = gf_isom_new_track(mp4file, bifsID, GF_ISOM_MEDIA_SCENE, gf_isom_get_timescale(mp4file)); if (!bifsT) return gf_isom_last_error(mp4file); _esd = gf_odf_desc_esd_new(SLPredef_MP4); _esd->decoderConfig->bufferSizeDB = sizeof(ISMA_BIFS_CONFIG); _esd->decoderConfig->objectTypeIndication = 0x02; _esd->decoderConfig->streamType = GF_STREAM_SCENE; _esd->ESID = bifsID; _esd->OCRESID = 0; /*rewrite ISMA BIFS cfg*/ bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); /*empty bifs stuff*/ gf_bs_write_int(bs, 0, 17); /*command stream*/ gf_bs_write_int(bs, 1, 1); /*in pixel metrics*/ gf_bs_write_int(bs, 1, 1); /*with size*/ gf_bs_write_int(bs, 1, 1); gf_bs_write_int(bs, w, 16); gf_bs_write_int(bs, h, 16); gf_bs_align(bs); gf_bs_get_content(bs, &_esd->decoderConfig->decoderSpecificInfo->data, &_esd->decoderConfig->decoderSpecificInfo->dataLength); gf_isom_new_mpeg4_description(mp4file, bifsT, _esd, NULL, NULL, &descIndex); gf_odf_desc_del((GF_Descriptor *)_esd); gf_bs_del(bs); gf_isom_set_visual_info(mp4file, bifsT, descIndex, w, h); samp = gf_isom_sample_new(); samp->CTS_Offset = 0; samp->DTS = 0; switch (bifs) { case 1: if (is_image) { samp->data = (char *) ISMA_BIFS_IMAGE; samp->dataLength = 10; } else { samp->data = (char *) ISMA_GF_BIFS_VIDEO; samp->dataLength = 11; } break; case 2: if (is_image) { samp->data = (char *) ISMA_BIFS_AI; samp->dataLength = 15; } else { samp->data = (char *) ISMA_BIFS_AV; samp->dataLength = 16; } break; case 3: samp->data = (char *) ISMA_BIFS_AUDIO; samp->dataLength = 8; break; } samp->IsRAP = 1; gf_isom_add_sample(mp4file, bifsT, 1, samp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -