📄 encode_isom.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / Scene Management 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/scene_manager.h>#include <gpac/constants.h>#include <gpac/media_tools.h>#include <gpac/bifs.h>#ifndef GPAC_DISABLE_SVG#include <gpac/laser.h>#include <gpac/nodes_svg_da.h>#endif#include <gpac/internal/scenegraph_dev.h>#ifndef GPAC_READ_ONLYstatic GF_MuxInfo *gf_sm_get_mux_info(GF_ESD *src){ u32 i; GF_MuxInfo *mux; i=0; while ((mux = (GF_MuxInfo *)gf_list_enum(src->extensionDescriptors, &i))) { if (mux->tag == GF_ODF_MUXINFO_TAG) return mux; } return NULL;}static void gf_sm_remove_mux_info(GF_ESD *src){ u32 i; GF_MuxInfo *mux; i=0; while ((mux = (GF_MuxInfo *)gf_list_enum(src->extensionDescriptors, &i))) { if (mux->tag == GF_ODF_MUXINFO_TAG) { gf_odf_desc_del((GF_Descriptor *)mux); gf_list_rem(src->extensionDescriptors, i-1); return; } }}static void gf_sm_finalize_mux(GF_ISOFile *mp4, GF_ESD *src, u32 offset_ts){ u32 track, mts, ts; GF_MuxInfo *mux = gf_sm_get_mux_info(src); if (!mux && !offset_ts) return; track = gf_isom_get_track_by_id(mp4, src->ESID); if (!track) return; mts = gf_isom_get_media_timescale(mp4, track); ts = gf_isom_get_timescale(mp4); /*set track time offset*/ if (mux) offset_ts += mux->startTime * mts / 1000; if (offset_ts) { u32 off = offset_ts * ts / mts; u64 dur = gf_isom_get_media_duration(mp4, track); dur = dur * ts / mts; gf_isom_set_edit_segment(mp4, track, 0, off, 0, GF_ISOM_EDIT_EMPTY); gf_isom_set_edit_segment(mp4, track, off, dur, 0, GF_ISOM_EDIT_NORMAL); } /*set track interleaving ID*/ if (mux) { if (mux->GroupID) gf_isom_set_track_group(mp4, track, mux->GroupID); if (mux->import_flags & GF_IMPORT_USE_COMPACT_SIZE) gf_isom_use_compact_size(mp4, track, 1); }}static GF_Err gf_sm_import_ui_stream(GF_ISOFile *mp4, GF_ESD *src){ GF_UIConfig *cfg; u32 len, i; GF_Err e; if (!src->slConfig) src->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); src->slConfig->predefined = 2; src->slConfig->timestampResolution = 1000; if (!src->decoderConfig || !src->decoderConfig->decoderSpecificInfo) return GF_ODF_INVALID_DESCRIPTOR; if (src->decoderConfig->decoderSpecificInfo->tag == GF_ODF_UI_CFG_TAG) { cfg = (GF_UIConfig *) src->decoderConfig->decoderSpecificInfo; e = gf_odf_encode_ui_config(cfg, &src->decoderConfig->decoderSpecificInfo); gf_odf_desc_del((GF_Descriptor *) cfg); if (e) return e; } else if (src->decoderConfig->decoderSpecificInfo->tag != GF_ODF_DSI_TAG) { return GF_ODF_INVALID_DESCRIPTOR; } /*what's the media type for input sensor ??*/ len = gf_isom_new_track(mp4, src->ESID, GF_ISOM_MEDIA_SCENE, 1000); if (!len) return gf_isom_last_error(mp4); gf_isom_set_track_enabled(mp4, len, 1); if (!src->ESID) src->ESID = gf_isom_get_track_id(mp4, len); return gf_isom_new_mpeg4_description(mp4, len, src, NULL, NULL, &i);}static GF_Err gf_sm_import_stream(GF_SceneManager *ctx, GF_ISOFile *mp4, GF_ESD *src, char *mediaSource){ u32 track, di; GF_Err e; Bool isAudio, isVideo; char szName[1024]; char *ext; GF_MediaImporter import; GF_MuxInfo *mux = NULL; /*no import if URL string*/ if (src->URLString) { u32 mtype, track; if (!src->slConfig) src->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); if (!src->decoderConfig) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISO File Encode] ESD with URL string needs a decoder config with remote stream type to be encoded\n")); return GF_BAD_PARAM; } /*however we still need a track to store the ESD ...*/ switch (src->decoderConfig->streamType) { case GF_STREAM_VISUAL: mtype = GF_ISOM_MEDIA_VISUAL; break; case GF_STREAM_AUDIO: mtype = GF_ISOM_MEDIA_AUDIO; break; case GF_STREAM_MPEG7: mtype = GF_ISOM_MEDIA_MPEG7; break; case GF_STREAM_IPMP: mtype = GF_ISOM_MEDIA_IPMP; break; case GF_STREAM_OCI: mtype = GF_ISOM_MEDIA_OCI; break; case GF_STREAM_MPEGJ: mtype = GF_ISOM_MEDIA_MPEGJ; break; case GF_STREAM_INTERACT: case GF_STREAM_SCENE: mtype = GF_ISOM_MEDIA_SCENE; break; case GF_STREAM_TEXT: mtype = GF_ISOM_MEDIA_TEXT; break; default: GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISO File Encode] Unsupported media type %d for ESD with URL string\n", src->decoderConfig->streamType)); return GF_BAD_PARAM; } track = gf_isom_new_track(mp4, src->ESID, mtype, 1000); if (!src->ESID) src->ESID = gf_isom_get_track_id(mp4, track); return gf_isom_new_mpeg4_description(mp4, track, src, NULL, NULL, &di); } /*look for muxInfo*/ mux = gf_sm_get_mux_info(src); /*special streams*/ if (src->decoderConfig) { /*InputSensor*/ if (src->decoderConfig->decoderSpecificInfo && (src->decoderConfig->decoderSpecificInfo->tag == GF_ODF_UI_CFG_TAG)) src->decoderConfig->streamType = GF_STREAM_INTERACT; if (src->decoderConfig->streamType == GF_STREAM_INTERACT) return gf_sm_import_ui_stream(mp4, src); } /*OCR streams*/ if (src->decoderConfig && src->decoderConfig->streamType == GF_STREAM_OCR) { track = gf_isom_new_track(mp4, src->ESID, GF_ISOM_MEDIA_OCR, 1000); if (!track) return gf_isom_last_error(mp4); gf_isom_set_track_enabled(mp4, track, 1); if (!src->ESID) src->ESID = gf_isom_get_track_id(mp4, track); if (!src->slConfig) src->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); src->slConfig->predefined = 2; e = gf_isom_new_mpeg4_description(mp4, track, src, NULL, NULL, &di); if (e) return e; if (mux && mux->duration) e = gf_isom_set_edit_segment(mp4, track, 0, mux->duration * gf_isom_get_timescale(mp4) / 1000, 0, GF_ISOM_EDIT_NORMAL); return e; } if (!mux) { /*if existing don't import (systems tracks)*/ track = gf_isom_get_track_by_id(mp4, src->ESID); if (track) return GF_OK; if (mediaSource) { memset(&import, 0, sizeof(GF_MediaImporter)); import.dest = mp4; import.trackID = src->ESID; import.orig = gf_isom_open(mediaSource, GF_ISOM_OPEN_READ, NULL); if (import.orig) { e = gf_media_import(&import); gf_isom_delete(import.orig); return e; } } return GF_OK; } if (!mux->file_name) return GF_OK; memset(&import, 0, sizeof(GF_MediaImporter)); strcpy(szName, mux->file_name); ext = strrchr(szName, '.'); /*get track types for AVI*/ if (ext && !strnicmp(ext, ".avi", 4)) { isAudio = isVideo = 0; if (ext && !stricmp(ext, ".avi#video")) isVideo = 1; else if (ext && !stricmp(ext, ".avi#audio")) isAudio = 1; else if (src->decoderConfig) { if (src->decoderConfig->streamType == GF_STREAM_VISUAL) isVideo = 1; else if (src->decoderConfig->streamType == GF_STREAM_AUDIO) isAudio = 1; } if (!isAudio && !isVideo) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[ISO File Encode] missing track specifier for AVI import (file#audio, file#video)\n")); return GF_NOT_SUPPORTED; } if (isVideo) import.trackID = 1; else import.trackID = 2; ext = strchr(ext, '#'); if (ext) ext[0] = 0; } /*get track ID for MP4/others*/ if (ext) { ext = strchr(ext, '#'); if (ext) { import.trackID = atoi(ext+1); ext[0] = 0; } } import.streamFormat = mux->streamFormat; import.dest = mp4; import.esd = src; import.duration = mux->duration; import.flags = mux->import_flags; import.video_fps = mux->frame_rate; import.in_name = szName; e = gf_media_import(&import); if (e) return e; /*if desired delete input*/ if (mux->delete_file) gf_delete_file(mux->file_name); return e;}static GF_Err gf_sm_import_stream_special(GF_SceneManager *ctx, GF_ESD *esd){ GF_Err e; GF_MuxInfo *mux = gf_sm_get_mux_info(esd); if (!mux || !mux->file_name) return GF_OK; if (esd->decoderConfig && esd->decoderConfig->decoderSpecificInfo && (esd->decoderConfig->decoderSpecificInfo->tag==GF_ODF_TEXT_CFG_TAG)) return GF_OK; e = GF_OK; /*SRT/SUB BIFS import if text node unspecified*/ if (mux->textNode) { e = gf_sm_import_bifs_subtitle(ctx, esd, mux); gf_sm_remove_mux_info(esd); } return e;}static GF_Err gf_sm_import_specials(GF_SceneManager *ctx){ GF_Err e; u32 i, j, n, m, k; GF_ESD *esd; GF_AUContext *au; GF_StreamContext *sc; i=0; while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) { if (sc->streamType != GF_STREAM_OD) continue; esd = NULL; j=0; while ((au = (GF_AUContext *)gf_list_enum(sc->AUs, &j))) { GF_ODCom *com; k=0; while ((com = (GF_ODCom *) gf_list_enum(au->commands, &k))) { switch (com->tag) { case GF_ODF_OD_UPDATE_TAG: { GF_ObjectDescriptor *od; GF_ODUpdate *odU = (GF_ODUpdate *)com; n=0; while ((od = (GF_ObjectDescriptor *) gf_list_enum(odU->objectDescriptors, &n))) { GF_ESD *imp_esd; m=0; while ((imp_esd = (GF_ESD*)gf_list_enum(od->ESDescriptors, &m))) { e = gf_sm_import_stream_special(ctx, imp_esd); if (e != GF_OK) return e; } } } break; case GF_ODF_ESD_UPDATE_TAG: { GF_ESD *imp_esd; GF_ESDUpdate *esdU = (GF_ESDUpdate *)com; m=0; while ((imp_esd = (GF_ESD*)gf_list_enum(esdU->ESDescriptors, &m))) { e = gf_sm_import_stream_special(ctx, imp_esd); if (e != GF_OK) return e; } } break; } } } } return GF_OK;}/*locate stream in all OD updates/ESD updates (needed for systems tracks)*/static GF_ESD *gf_sm_locate_esd(GF_SceneManager *ctx, u16 ES_ID){ u32 i, j, n, m, k; GF_ESD *esd; GF_AUContext *au; GF_StreamContext *sc; if (!ES_ID) return NULL; i=0; while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) { if (sc->streamType != GF_STREAM_OD) continue; esd = NULL; j=0; while ((au = (GF_AUContext *)gf_list_enum(sc->AUs, &j))) { GF_ODCom *com; k=0; while ((com = (GF_ODCom *) gf_list_enum(au->commands, &k))) { switch (com->tag) { case GF_ODF_OD_UPDATE_TAG: { GF_ObjectDescriptor *od; GF_ODUpdate *odU = (GF_ODUpdate *)com; n=0; while ((od = (GF_ObjectDescriptor *) gf_list_enum(odU->objectDescriptors, &n))) { GF_ESD *imp_esd; m=0; while ((imp_esd = (GF_ESD*)gf_list_enum(od->ESDescriptors, &m))) { if (imp_esd->ESID == ES_ID) return imp_esd; } } } break; case GF_ODF_ESD_UPDATE_TAG: { GF_ESD *imp_esd; GF_ESDUpdate *esdU = (GF_ESDUpdate *)com; m=0; while ((imp_esd = (GF_ESD*)gf_list_enum(esdU->ESDescriptors, &m))) { if (imp_esd->ESID == ES_ID) return imp_esd; } } break; } } } } return NULL;}static GF_Err gf_sm_encode_scene(GF_SceneManager *ctx, GF_ISOFile *mp4, GF_SMEncodeOptions *opts, u32 scene_type){ char *data; Bool is_in_iod, delete_desc, first_scene_id; u32 i, j, di, rate, init_offset, data_len, count, track, rap_delay, flags, rap_mode; u64 last_rap, dur, time_slice, avg_rate, prev_dts; GF_Err e; GF_InitialObjectDescriptor *iod; GF_AUContext *au; GF_ISOSample *samp; GF_StreamContext *sc; GF_ESD *esd; GF_BifsEncoder *bifs_enc;#ifndef GPAC_DISABLE_SVG GF_LASeRCodec *lsr_enc;#endif rap_mode = 0; if (opts && opts->rap_freq) { if (opts->flags & GF_SM_ENCODE_RAP_INBAND) rap_mode = 3; else if (opts->flags & GF_SM_ENCODE_RAP_SHADOW) rap_mode = 2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -