📄 media_export.c
字号:
FILE *med, *inf, *nhml; Bool full_dump; u32 track, i, di, count, pos; track = gf_isom_get_track_by_id(dumper->file, dumper->trackID); if (!track) return gf_export_message(dumper, GF_BAD_PARAM, "Invalid track ID %d", dumper->trackID); if (dumper->flags & GF_EXPORT_PROBE_ONLY) { dumper->flags |= GF_EXPORT_NHML_FULL; return GF_OK; } esd = gf_isom_get_esd(dumper->file, track, 1); full_dump = (dumper->flags & GF_EXPORT_NHML_FULL) ? 1 : 0; sprintf(szMedia, "%s.media", dumper->out_name); med = gf_f64_open(szMedia, "wb"); if (!med) { if (esd) gf_odf_desc_del((GF_Descriptor *) esd); return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szMedia); } sprintf(szName, "%s.nhml", dumper->out_name); nhml = fopen(szName, "wt"); if (!nhml) { fclose(med); if (esd) gf_odf_desc_del((GF_Descriptor *) esd); return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szName); } /*write header*/ fprintf(nhml, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"); fprintf(nhml, "<NHNTStream version=\"1.0\" timeScale=\"%d\" ", gf_isom_get_media_timescale(dumper->file, track) ); if (esd) { fprintf(nhml, "streamType=\"%d\" objectTypeIndication=\"%d\" ", esd->decoderConfig->streamType, esd->decoderConfig->objectTypeIndication); if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) { sprintf(szName, "%s.info", dumper->out_name); inf = fopen(szName, "wb"); if (inf) fwrite(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, 1, inf); fclose(inf); fprintf(nhml, "specificInfoFile=\"%s\" ", szName); } gf_odf_desc_del((GF_Descriptor *) esd); if (gf_isom_get_media_type(dumper->file, track)==GF_ISOM_MEDIA_VISUAL) { u32 w, h; gf_isom_get_visual_info(dumper->file, track, 1, &w, &h); fprintf(nhml, "width=\"%d\" height=\"%d\" ", w, h); } else if (gf_isom_get_media_type(dumper->file, track)==GF_ISOM_MEDIA_AUDIO) { u32 sr, nb_ch; u8 bps; gf_isom_get_audio_info(dumper->file, track, 1, &sr, &nb_ch, &bps); fprintf(nhml, "sampleRate=\"%d\" numChannels=\"%d\" ", sr, nb_ch); } } else { GF_GenericSampleDescription *sdesc = gf_isom_get_generic_sample_description(dumper->file, track, 1); u32 mtype = gf_isom_get_media_type(dumper->file, track); fprintf(nhml, "mediaType=\"%s\" mediaSubType=\"%s\" ", gf_4cc_to_str(mtype), gf_4cc_to_str(sdesc->codec_tag)); if (mtype==GF_ISOM_MEDIA_VISUAL) { fprintf(nhml, "codecVendor=\"%s\" codecVersion=\"%d\" codecRevision=\"%d\" ", gf_4cc_to_str(sdesc->vendor_code), sdesc->version, sdesc->revision); fprintf(nhml, "width=\"%d\" height=\"%d\" compressorName=\"%s\" temporalQuality=\"%d\" spatialQuality=\"%d\" horizontalResolution=\"%d\" verticalResolution=\"%d\" bitDepth=\"%d\" ", sdesc->width, sdesc->height, sdesc->compressor_name, sdesc->temporal_quality, sdesc->spacial_quality, sdesc->h_res, sdesc->v_res, sdesc->depth); } else if (mtype==GF_ISOM_MEDIA_AUDIO) { fprintf(nhml, "codecVendor=\"%s\" codecVersion=\"%d\" codecRevision=\"%d\" ", gf_4cc_to_str(sdesc->vendor_code), sdesc->version, sdesc->revision); fprintf(nhml, "sampleRate=\"%d\" numChannels=\"%d\" bitsPerSample=\"%d\" ", sdesc->samplerate, sdesc->nb_channels, sdesc->bits_per_sample); } if (sdesc->extension_buf) { sprintf(szName, "%s.info", dumper->out_name); inf = fopen(szName, "wb"); if (inf) fwrite(sdesc->extension_buf, sdesc->extension_buf_size, 1, inf); fclose(inf); fprintf(nhml, "specificInfoFile=\"%s\" ", szName); free(sdesc->extension_buf); } free(sdesc); } fprintf(nhml, "baseMediaFile=\"%s\" ", szMedia); if (gf_isom_is_track_in_root_od(dumper->file, track)) fprintf(nhml, "inRootOD=\"yes\" "); fprintf(nhml, "trackID=\"%d\" ", dumper->trackID); fprintf(nhml, ">\n"); pos = 0; count = gf_isom_get_sample_count(dumper->file, track); for (i=0; i<count; i++) { GF_ISOSample *samp = gf_isom_get_sample(dumper->file, track, i+1, &di); if (!samp) break; fwrite(samp->data, samp->dataLength, 1, med); fprintf(nhml, "<NHNTSample DTS=\""LLD"\" dataLength=\"%d\" ", LLD_CAST samp->DTS, samp->dataLength); if (full_dump || samp->CTS_Offset) fprintf(nhml, "CTSOffset=\"%d\" ", samp->CTS_Offset); if (samp->IsRAP==1) fprintf(nhml, "isRAP=\"yes\" "); else if (samp->IsRAP==2) fprintf(nhml, "isSyncShadow=\"yes\" "); else if (full_dump) fprintf(nhml, "isRAP=\"no\" "); if (full_dump) fprintf(nhml, "mediaOffset=\"%d\" ", pos); fprintf(nhml, "/>\n"); pos += samp->dataLength; gf_isom_sample_del(&samp); gf_set_progress("NHML Export", i+1, count); if (dumper->flags & GF_EXPORT_DO_ABORT) break; } fprintf(nhml, "</NHNTStream>\n"); fclose(med); fclose(nhml); return GF_OK;}typedef struct { u32 track_num, stream_id, last_sample, nb_samp;} SAFInfo;GF_Err gf_media_export_saf(GF_MediaExporter *dumper){ u32 count, i, s_count, di, tot_samp, samp_done; char out_file[GF_MAX_PATH]; GF_SAFMuxer *mux; char *data; u32 size; FILE *saf_f; SAFInfo safs[1024]; if (dumper->flags & GF_EXPORT_PROBE_ONLY) return GF_OK; s_count = tot_samp = 0; mux = gf_saf_mux_new(); count = gf_isom_get_track_count(dumper->file); for (i=0; i<count; i++) { u32 time_scale, mtype, stream_id; GF_ESD *esd; mtype = gf_isom_get_media_type(dumper->file, i+1); if (mtype==GF_ISOM_MEDIA_OD) continue; if (mtype==GF_ISOM_MEDIA_HINT) continue; stream_id = 0; time_scale = gf_isom_get_media_timescale(dumper->file, i+1); esd = gf_isom_get_esd(dumper->file, i+1, 1); if (esd) { stream_id = gf_isom_find_od_for_track(dumper->file, i+1); if (!stream_id) stream_id = esd->ESID; /*translate OD IDs to ESIDs !!*/ if (esd->decoderConfig->decoderSpecificInfo) { gf_saf_mux_stream_add(mux, stream_id, time_scale, esd->decoderConfig->bufferSizeDB, esd->decoderConfig->streamType, esd->decoderConfig->objectTypeIndication, NULL, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, esd->URLString); } else { gf_saf_mux_stream_add(mux, stream_id, time_scale, esd->decoderConfig->bufferSizeDB, esd->decoderConfig->streamType, esd->decoderConfig->objectTypeIndication, NULL, NULL, 0, esd->URLString); } gf_odf_desc_del((GF_Descriptor *)esd); } else { char *mime = NULL; switch (gf_isom_get_media_subtype(dumper->file, i+1, 1)) { case GF_ISOM_SUBTYPE_3GP_H263: mime = "video/h263"; break; case GF_ISOM_SUBTYPE_3GP_AMR: mime = "audio/amr"; break; case GF_ISOM_SUBTYPE_3GP_AMR_WB: mime = "audio/amr-wb"; break; case GF_ISOM_SUBTYPE_3GP_EVRC: mime = "audio/evrc"; break; case GF_ISOM_SUBTYPE_3GP_QCELP: mime = "audio/qcelp"; break; case GF_ISOM_SUBTYPE_3GP_SMV: mime = "audio/smv"; break; } if (!mime) continue; stream_id = gf_isom_get_track_id(dumper->file, i+1); gf_saf_mux_stream_add(mux, stream_id, time_scale, 0, 0xFF, 0xFF, mime, NULL, 0, NULL); } safs[s_count].track_num = i+1; safs[s_count].stream_id = stream_id; safs[s_count].nb_samp = gf_isom_get_sample_count(dumper->file, i+1); safs[s_count].last_sample = 0; tot_samp += safs[s_count].nb_samp; s_count++; } if (!s_count) { gf_export_message(dumper, GF_OK, "No tracks available for SAF muxing"); gf_saf_mux_del(mux); return GF_OK; } gf_export_message(dumper, GF_OK, "SAF: Multiplexing %d tracks", s_count); strcpy(out_file, dumper->out_name); strcat(out_file, ".saf"); saf_f = fopen(out_file, "wb"); samp_done = 0; while (samp_done<tot_samp) { for (i=0; i<s_count; i++) { GF_ISOSample *samp; if (safs[i].last_sample==safs[i].nb_samp) continue; samp = gf_isom_get_sample(dumper->file, safs[i].track_num, safs[i].last_sample + 1, &di); gf_saf_mux_add_au(mux, safs[i].stream_id, (u32) (samp->DTS+samp->CTS_Offset), samp->data, samp->dataLength, samp->IsRAP); /*data is kept by muxer!!*/ free(samp); safs[i].last_sample++; samp_done ++; } while (1) { gf_saf_mux_for_time(mux, (u32) -1, 0, &data, &size); if (!data) break; fwrite(data, size, 1, saf_f); free(data); } gf_set_progress("SAF Export", samp_done, tot_samp); if (dumper->flags & GF_EXPORT_DO_ABORT) break; } gf_saf_mux_for_time(mux, (u32) -1, 1, &data, &size); if (data) { fwrite(data, size, 1, saf_f); free(data); } fclose(saf_f); gf_saf_mux_del(mux); return GF_OK;}void m2ts_export_check(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) { if (evt_type == GF_M2TS_EVT_PAT_REPEAT) ts->user = NULL;}void m2ts_export_dump(GF_M2TS_Demuxer *ts, u32 evt_type, void *par) { if (evt_type == GF_M2TS_EVT_PES_PCK) { FILE *dst = (FILE*)ts->user; GF_M2TS_PES_PCK *pck = (GF_M2TS_PES_PCK *)par; fwrite(pck->data, pck->data_len, 1, dst); }}GF_Err gf_media_export_ts_native(GF_MediaExporter *dumper){ char data[188], szFile[GF_MAX_PATH]; GF_M2TS_PES *stream; u32 i, size, fsize, fdone; GF_M2TS_Demuxer *ts; FILE *src, *dst; if (dumper->flags & GF_EXPORT_PROBE_ONLY) return GF_OK; src = fopen(dumper->in_name, "rb"); if (!src) return gf_export_message(dumper, GF_CODEC_NOT_FOUND, "Error opening %s", dumper->in_name); fseek(src, 0, SEEK_END); fsize = ftell(src); fseek(src, 0, SEEK_SET); ts = gf_m2ts_demux_new(); ts->on_event = m2ts_export_check; ts->user = dumper; /*get PAT*/ while (!feof(src)) { size = fread(data, 1, 188, src); if (size<188) break; gf_m2ts_process_data(ts, data, size); if (!ts->user) break; } if (ts->user) { fclose(src); gf_m2ts_demux_del(ts); return gf_export_message(dumper, GF_URL_ERROR, "Cannot locate program association table"); } stream = NULL; for (i=0; i<GF_M2TS_MAX_STREAMS; i++) { GF_M2TS_PES *pes = (GF_M2TS_PES *)ts->ess[i]; if (!pes || (pes->pid==pes->program->pmt_pid)) continue; if (pes->pid == dumper->trackID) { stream = pes; gf_m2ts_set_pes_framing(pes, GF_M2TS_PES_FRAMING_RAW); } else { gf_m2ts_set_pes_framing(pes, GF_M2TS_PES_FRAMING_SKIP); } break; } if (!stream) { fclose(src); gf_m2ts_demux_del(ts); return gf_export_message(dumper, GF_URL_ERROR, "Cannot find PID %d in transport stream", dumper->trackID); } gf_m2ts_reset_parsers(ts); sprintf(szFile, "%s_pid%d", dumper->out_name ? dumper->out_name : "", stream->pid); switch (stream->stream_type) { case GF_M2TS_VIDEO_MPEG1: strcat(szFile, ".m1v"); gf_export_message(dumper, GF_OK, "Extracting MPEG-1 Visual stream to m1v"); break; case GF_M2TS_VIDEO_MPEG2: strcat(szFile, ".m2v"); gf_export_message(dumper, GF_OK, "Extracting MPEG-2 Visual stream to m1v"); break; case GF_M2TS_AUDIO_MPEG1: strcat(szFile, ".mp3"); gf_export_message(dumper, GF_OK, "Extracting MPEG-1 Audio stream to mp3"); break; case GF_M2TS_AUDIO_MPEG2: strcat(szFile, ".mp3"); gf_export_message(dumper, GF_OK, "Extracting MPEG-2 Audio stream to mp3"); break; case GF_M2TS_AUDIO_AAC: strcat(szFile, ".aac"); gf_export_message(dumper, GF_OK, "Extracting MPEG-4 Audio stream to aac"); break; case GF_M2TS_VIDEO_MPEG4: strcat(szFile, ".cmp"); gf_export_message(dumper, GF_OK, "Extracting MPEG-4 Visual stream to cmp"); break; case GF_M2TS_VIDEO_H264: strcat(szFile, ".264"); gf_export_message(dumper, GF_OK, "Extracting MPEG-4 AVC/H264 Visual stream to h264"); break; default: strcat(szFile, ".raw"); gf_export_message(dumper, GF_OK, "Extracting Unknown stream to raw"); break; } dst = fopen(szFile, "wb"); if (!dst) { fclose(src); gf_m2ts_demux_del(ts); return gf_export_message(dumper, GF_IO_ERR, "Cannot open file %s for writing", szFile); } gf_m2ts_reset_parsers(ts); gf_f64_seek(src, 0, SEEK_SET); fdone = 0; ts->user = dst; ts->on_event = m2ts_export_dump; while (!feof(src)) { size = fread(data, 1, 188, src); if (size<188) break; gf_m2ts_process_data(ts, data, size); fdone += size; gf_set_progress("MPEG-2 TS Extract", fdone, fsize); if (dumper->flags & GF_EXPORT_DO_ABORT) break; } gf_set_progress("MPEG-2 TS Extract", fsize, fsize); fclose(dst); fclose(src); gf_m2ts_demux_del(ts); return GF_OK;}GF_EXPORTGF_Err gf_media_export(GF_MediaExporter *dumper){ if (!dumper) return GF_BAD_PARAM; if (!dumper->out_name && !dumper->flags & GF_EXPORT_PROBE_ONLY) return GF_BAD_PARAM; if (dumper->flags & GF_EXPORT_NATIVE) { if (dumper->in_name) { char *ext = strrchr(dumper->in_name, '.'); if (ext && (!strnicmp(ext, ".ts", 3) || !strnicmp(ext, ".m2t", 4)) ) { return gf_media_export_ts_native(dumper); } } return gf_media_export_native(dumper); } else if (dumper->flags & GF_EXPORT_RAW_SAMPLES) return gf_media_export_samples(dumper); else if (dumper->flags & GF_EXPORT_NHNT) return gf_media_export_nhnt(dumper); else if (dumper->flags & GF_EXPORT_AVI) return gf_media_export_avi(dumper); else if (dumper->flags & GF_EXPORT_MP4) return gf_media_export_isom(dumper); else if (dumper->flags & GF_EXPORT_AVI_NATIVE) return gf_media_export_avi_track(dumper); else if (dumper->flags & GF_EXPORT_NHML) return gf_media_export_nhml(dumper); else if (dumper->flags & GF_EXPORT_SAF) return gf_media_export_saf(dumper); else return GF_BAD_PARAM;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -