📄 media_export.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/internal/media_dev.h>#include <gpac/mpegts.h>#include <gpac/constants.h>#ifndef GPAC_READ_ONLY#include <gpac/internal/avilib.h>#include <gpac/internal/ogg.h>#include <gpac/internal/vobsub.h>static GF_Err gf_export_message(GF_MediaExporter *dumper, GF_Err e, char *format, ...){ if (dumper->flags & GF_EXPORT_PROBE_ONLY) return e;#ifndef GPAC_DISABLE_LOG if (gf_log_get_level() && (gf_log_get_tools() & GF_LOG_AUTHOR)) { va_list args; char szMsg[1024]; va_start(args, format); vsprintf(szMsg, format, args); va_end(args); GF_LOG((u32) (e ? GF_LOG_ERROR : GF_LOG_WARNING), GF_LOG_AUTHOR, ("%s\n", szMsg) ); }#endif return e;}/*that's very very crude, we only support vorbis & theora in MP4 - this will need cleanup as soon as possible*/static GF_Err gf_dump_to_ogg(GF_MediaExporter *dumper, char *szName, u32 track){ FILE *out; ogg_stream_state os; ogg_packet op; ogg_page og; u32 count, i, di, theora_kgs, nb_i, nb_p; GF_BitStream *bs; GF_ISOSample *samp; GF_ESD *esd = gf_isom_get_esd(dumper->file, track, 1); gf_rand_init(1); ogg_stream_init(&os, gf_rand()); op.granulepos = 0; op.packetno = 0; op.b_o_s = 1; op.e_o_s = 0; out = gf_f64_open(szName, "wb"); if (!out) return gf_export_message(dumper, GF_IO_ERR, "Error opening %s for writing - check disk access & permissions", szName); theora_kgs = 0; bs = gf_bs_new(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, GF_BITSTREAM_READ); while (gf_bs_available(bs)) { op.bytes = gf_bs_read_u16(bs); op.packet = (unsigned char*)malloc(sizeof(char) * op.bytes); gf_bs_read_data(bs, (char*)op.packet, op.bytes); ogg_stream_packetin(&os, &op); if (op.b_o_s) { ogg_stream_pageout(&os, &og); fwrite(og.header, 1, og.header_len, out); fwrite(og.body, 1, og.body_len, out); op.b_o_s = 0; if (esd->decoderConfig->objectTypeIndication==0xDF) { u32 kff; GF_BitStream *vbs = gf_bs_new((char*)op.packet, op.bytes, GF_BITSTREAM_READ); gf_bs_skip_bytes(vbs, 40); gf_bs_read_int(vbs, 6); /* quality */ kff = 1 << gf_bs_read_int(vbs, 5); gf_bs_del(vbs); theora_kgs = 0; kff--; while (kff) { theora_kgs ++; kff >>= 1; } } } free(op.packet); op.packetno ++; } gf_bs_del(bs); gf_odf_desc_del((GF_Descriptor *)esd); while (ogg_stream_pageout(&os, &og)>0) { fwrite(og.header, 1, og.header_len, out); fwrite(og.body, 1, og.body_len, out); } op.granulepos = -1; count = gf_isom_get_sample_count(dumper->file, track); nb_i = nb_p = 0; samp = gf_isom_get_sample(dumper->file, track, 1, &di); for (i=0; i<count; i++) { GF_ISOSample *next_samp = gf_isom_get_sample(dumper->file, track, i+2, &di); if (!samp) break; op.bytes = samp->dataLength; op.packet = (unsigned char*)samp->data; op.packetno ++; if (theora_kgs) { if (samp->IsRAP) { if (i) nb_i+=nb_p+1; nb_p = 0; } else { nb_p++; } op.granulepos = nb_i; op.granulepos <<= theora_kgs; op.granulepos |= nb_p; } else { if (next_samp) op.granulepos = next_samp->DTS; } if (!next_samp) op.e_o_s = 1; ogg_stream_packetin(&os, &op); gf_isom_sample_del(&samp); samp = next_samp; next_samp = NULL; gf_set_progress("OGG Export", i+1, count); if (dumper->flags & GF_EXPORT_DO_ABORT) break; while (ogg_stream_pageout(&os, &og)>0) { fwrite(og.header, 1, og.header_len, out); fwrite(og.body, 1, og.body_len, out); } } if (samp) gf_isom_sample_del(&samp); while (ogg_stream_flush(&os, &og)>0) { fwrite(og.header, 1, og.header_len, out); fwrite(og.body, 1, og.body_len, out); } ogg_stream_clear(&os); fclose(out); return GF_OK;}GF_Err gf_export_hint(GF_MediaExporter *dumper){ GF_Err e; char szName[1000], szType[5]; char *pck; FILE *out; u32 track, i, size, m_stype, sn, count; track = gf_isom_get_track_by_id(dumper->file, dumper->trackID); m_stype = gf_isom_get_media_subtype(dumper->file, track, 1); e = gf_isom_reset_hint_reader(dumper->file, track, dumper->sample_num ? dumper->sample_num : 1, 0, 0, 0); if (e) return gf_export_message(dumper, e, "Error initializing hint reader"); gf_export_message(dumper, GF_OK, "Extracting hint track samples - type %s", szType); count = gf_isom_get_sample_count(dumper->file, track); if (dumper->sample_num) count = 0; i = 1; while (1) { e = gf_isom_next_hint_packet(dumper->file, track, &pck, &size, NULL, NULL, NULL, &sn); if (e==GF_EOS) break; if (dumper->sample_num && (dumper->sample_num != sn)) { free(pck); break; } if (e) return gf_export_message(dumper, e, "Error fetching hint packet %d", i); sprintf(szName, "%s_pck_%04d.%s", dumper->out_name, i, gf_4cc_to_str(m_stype)); out = fopen(szName, "wb"); fwrite(pck, size, 1, out); fclose(out); free(pck); i++; if (count) gf_set_progress("Hint Export", sn, count); } if (count) gf_set_progress("Hint Export", count, count); return GF_OK;}static void write_jp2_file(GF_BitStream *bs, char *data, u32 data_size, char *dsi, u32 dsi_size){ gf_bs_write_u32(bs, 12); gf_bs_write_u32(bs, GF_4CC('j','P',' ',' ')); gf_bs_write_u32(bs, 0x0D0A870A); gf_bs_write_u32(bs, 20); gf_bs_write_u32(bs, GF_4CC('f','t','y','p')); gf_bs_write_u32(bs, GF_4CC('j','p','2',' ')); gf_bs_write_u32(bs, 0); gf_bs_write_u32(bs, GF_4CC('j','p','2',' ')); gf_bs_write_data(bs, dsi, dsi_size); gf_bs_write_data(bs, data, data_size);}GF_Err gf_media_export_samples(GF_MediaExporter *dumper){ GF_DecoderConfig *dcfg; GF_GenericSampleDescription *udesc; char szName[1000], szEXT[10], szNum[1000], *dsi; FILE *out; GF_BitStream *bs; u32 track, i, di, count, m_type, m_stype, dsi_size, is_mj2k; track = gf_isom_get_track_by_id(dumper->file, dumper->trackID); m_type = gf_isom_get_media_type(dumper->file, track); m_stype = gf_isom_get_media_subtype(dumper->file, track, 1); dsi_size = 0; if (dumper->sample_num) sprintf(szNum, " %d", dumper->sample_num); else strcpy(szNum, "s"); is_mj2k = 0; dsi = NULL; udesc = NULL; dcfg = NULL; if ((m_stype==GF_ISOM_SUBTYPE_MPEG4) || (m_stype==GF_ISOM_SUBTYPE_MPEG4_CRYP)) dcfg = gf_isom_get_decoder_config(dumper->file, track, 1); strcpy(szName, dumper->out_name ? dumper->out_name : ""); if (dcfg) { switch (dcfg->streamType) { case GF_STREAM_VISUAL: switch (dcfg->objectTypeIndication) { case 0x20: strcpy(szEXT, ".cmp"); gf_export_message(dumper, GF_OK, "Dumping MPEG-4 Visual sample%s", szNum); break; case 0x21: strcpy(szEXT, ".h264"); gf_export_message(dumper, GF_OK, "Dumping MPEG-4 AVC-H264 Visual sample%s", szNum); break; case 0x6C: strcpy(szEXT, ".jpg"); gf_export_message(dumper, GF_OK, "Dumping JPEG image%s", szNum); break; case 0x6D: strcpy(szEXT, ".png"); gf_export_message(dumper, GF_OK, "Dumping PNG image%s", szNum); break; case 0x6E: strcpy(szEXT, ".jp2"); gf_export_message(dumper, GF_OK, "Dumping JPEG 2000 image%s", szNum); break; case GPAC_OGG_MEDIA_OTI: strcpy(szEXT, ".theo"); gf_export_message(dumper, GF_OK, "Dumping Theora video sample%s", szNum); break; default: strcpy(szEXT, ".raw"); gf_export_message(dumper, GF_OK, "Dumping Unknown video sample%s (OTI %d)", szNum, dcfg->objectTypeIndication); break; } break; case GF_STREAM_AUDIO: switch (dcfg->objectTypeIndication) { case 0x66: case 0x67: case 0x68: case 0x40: strcpy(szEXT, ".aac"); gf_export_message(dumper, GF_OK, "Dumping MPEG-%d AAC sample%s", (dcfg->objectTypeIndication==0x40) ? 4 : 2, szNum); break; case 0x69: case 0x6B: strcpy(szEXT, ".mp3"); gf_export_message(dumper, GF_OK, "Dumping MPEG-1/2 Audio (MP3) sample%s", szNum); break; case GPAC_OGG_MEDIA_OTI: strcpy(szEXT, ".vorb"); gf_export_message(dumper, GF_OK, "Dumping Vorbis audio sample%s", szNum); break; default: strcpy(szEXT, ".raw"); gf_export_message(dumper, GF_OK, "Dumping Unknown audio sample%s (OTI %d)", szNum, dcfg->objectTypeIndication); break; } break; case GF_STREAM_SCENE: strcpy(szEXT, ".bifs"); gf_export_message(dumper, GF_OK, "Dumping BIFS sample%s", szNum); break; case GF_STREAM_OD: strcpy(szEXT, ".od"); gf_export_message(dumper, GF_OK, "Dumping OD sample%s", szNum); break; case GF_STREAM_MPEGJ: strcpy(szEXT, ".mpj"); gf_export_message(dumper, GF_OK, "Dumping MPEG-J sample%s", szNum); break; case GF_STREAM_OCI: strcpy(szEXT, ".oci"); gf_export_message(dumper, GF_OK, "Dumping OCI sample%s", szNum); break; case GF_STREAM_MPEG7: strcpy(szEXT, ".mp7"); gf_export_message(dumper, GF_OK, "Dumping MPEG7 sample%s", szNum); break; case GF_STREAM_IPMP: strcpy(szEXT, ".ipmp"); gf_export_message(dumper, GF_OK, "Dumping IPMP sample%s", szNum); break; case GF_STREAM_TEXT: strcpy(szEXT, ".tx3g"); gf_export_message(dumper, GF_OK, "Dumping 3GP Text sample%s", szNum); break; default: gf_odf_desc_del((GF_Descriptor *) dcfg); return gf_export_message(dumper, GF_NOT_SUPPORTED, "Cannot dump systems track ID %d sample%s - use NHNT", dumper->trackID, szNum); } gf_odf_desc_del((GF_Descriptor *) dcfg); } else if ((m_stype==GF_ISOM_SUBTYPE_3GP_AMR) || (m_stype==GF_ISOM_SUBTYPE_3GP_AMR_WB)) { strcpy(szEXT, ".amr"); gf_export_message(dumper, GF_OK, "Extracting AMR Audio sample%s", szNum); } else if (m_stype==GF_ISOM_SUBTYPE_3GP_H263) { gf_export_message(dumper, GF_OK, "Extracting H263 Video sample%s", szNum); strcpy(szEXT, ".263"); } else if (m_stype==GF_ISOM_SUBTYPE_AVC_H264) { strcpy(szEXT, ".h264"); gf_export_message(dumper, GF_OK, "Dumping MPEG-4 AVC-H264 Visual sample%s", szNum); } else if (m_type==GF_ISOM_MEDIA_FLASH) { gf_export_message(dumper, GF_OK, "Extracting Macromedia Flash Movie sample%s", szNum); strcpy(szEXT, ".swf"); } else if (m_type==GF_ISOM_MEDIA_HINT) { return gf_export_hint(dumper); } else if (m_stype==GF_4CC('m','j','p','2')) { strcpy(szEXT, ".jp2"); gf_export_message(dumper, GF_OK, "Dumping JPEG 2000 sample%s", szNum); udesc = gf_isom_get_generic_sample_description(dumper->file, track, 1); dsi = udesc->extension_buf; dsi_size = udesc->extension_buf_size; free(udesc); is_mj2k = 1; } else { strcpy(szEXT, "."); strcat(szEXT, gf_4cc_to_str(m_stype)); udesc = gf_isom_get_generic_sample_description(dumper->file, track, 1); switch (m_type) { case GF_ISOM_MEDIA_VISUAL: gf_export_message(dumper, GF_OK, "Extracting \'%s\' Video - Compressor %s", szEXT, udesc ? udesc->compressor_name: "Unknown"); break; case GF_ISOM_MEDIA_AUDIO: gf_export_message(dumper, GF_OK, "Extracting \'%s\' Audio - Compressor %s", szEXT, udesc ? udesc->compressor_name : "Unknown"); break; default: gf_export_message(dumper, GF_OK, "Extracting \'%s\' Track (type '%s') - Compressor %s sample%s", szEXT, gf_4cc_to_str(m_type), udesc ? udesc->compressor_name : "Unknown", szNum); break; } if (udesc->extension_buf) free(udesc->extension_buf); if (udesc) free(udesc); } if (dumper->flags & GF_EXPORT_PROBE_ONLY) return GF_OK; if (dumper->sample_num) { GF_ISOSample *samp = gf_isom_get_sample(dumper->file, track, dumper->sample_num, &di); if (!samp) return GF_BAD_PARAM;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -