예제 #1
0
파일: mp4.c 프로젝트: predmach/x264-devel
static int close_file( hnd_t handle, int64_t largest_pts, int64_t second_largest_pts )
{
    mp4_hnd_t *p_mp4 = handle;

    if( !p_mp4 )
        return 0;

    if( p_mp4->p_config )
        gf_odf_avc_cfg_del( p_mp4->p_config );

    if( p_mp4->p_sample )
    {
        if( p_mp4->p_sample->data )
            free( p_mp4->p_sample->data );

        p_mp4->p_sample->dataLength = 0;
        gf_isom_sample_del( &p_mp4->p_sample );
    }

    if( p_mp4->p_file )
    {
        if( p_mp4->i_track )
        {
            /* The mdhd duration is defined as CTS[final] - CTS[0] + duration of last frame.
             * The mdhd duration (in seconds) should be able to be longer than the tkhd duration since the track is managed by edts.
             * So, if mdhd duration is equal to the last DTS or less, we give the last composition time delta to the last sample duration.
             * And then, the mdhd duration is updated, but it time-wise doesn't give the actual duration.
             * The tkhd duration is the actual track duration. */
            uint64_t mdhd_duration = (2 * largest_pts - second_largest_pts) * p_mp4->i_time_inc;
            if( mdhd_duration != gf_isom_get_media_duration( p_mp4->p_file, p_mp4->i_track ) )
            {
                uint64_t last_dts = gf_isom_get_sample_dts( p_mp4->p_file, p_mp4->i_track, p_mp4->i_numframe );
                uint32_t last_duration = (uint32_t)( mdhd_duration > last_dts ? mdhd_duration - last_dts : (largest_pts - second_largest_pts) * p_mp4->i_time_inc );
                gf_isom_set_last_sample_duration( p_mp4->p_file, p_mp4->i_track, last_duration );
            }

            /* Write an Edit Box if the first CTS offset is positive.
             * A media_time is given by not the mvhd timescale but rather the mdhd timescale.
             * The reason is that an Edit Box maps the presentation time-line to the media time-line.
             * Any demuxers should follow the Edit Box if it exists. */
            GF_ISOSample *sample = gf_isom_get_sample_info( p_mp4->p_file, p_mp4->i_track, 1, NULL, NULL );
            if( sample && sample->CTS_Offset > 0 )
            {
                uint32_t mvhd_timescale = gf_isom_get_timescale( p_mp4->p_file );
                uint64_t tkhd_duration = (uint64_t)( mdhd_duration * ( (double)mvhd_timescale / p_mp4->i_time_res ) );
                gf_isom_append_edit_segment( p_mp4->p_file, p_mp4->i_track, tkhd_duration, sample->CTS_Offset, GF_ISOM_EDIT_NORMAL );
            }
            gf_isom_sample_del( &sample );

            recompute_bitrate_mp4( p_mp4->p_file, p_mp4->i_track );
        }
        gf_isom_set_pl_indication( p_mp4->p_file, GF_ISOM_PL_VISUAL, 0x15 );
        gf_isom_set_storage_mode( p_mp4->p_file, GF_ISOM_STORE_FLAT );
        gf_isom_close( p_mp4->p_file );
    }

    free( p_mp4 );

    return 0;
}
예제 #2
0
파일: read.c 프로젝트: supperlitt/gpac
GF_Err ISOR_ConnectService(GF_InputService *plug, GF_ClientService *serv, const char *url)
{
    char szURL[2048];
    char *tmp;
    ISOMReader *read;
    if (!plug || !plug->priv || !serv) return GF_SERVICE_ERROR;
    read = (ISOMReader *) plug->priv;

    read->input = plug;
    read->service = serv;

    if (read->dnload) gf_term_download_del(read->dnload);
    read->dnload = NULL;

    read->base_track_id = 0;
    strcpy(szURL, url);
    tmp = strrchr(szURL, '.');
    if (tmp) {
        tmp = strchr(tmp, '#');
        if (tmp) {
            if (!strnicmp(tmp, "#trackID=", 9)) {
                read->base_track_id = atoi(tmp+9);
            } else {
                read->base_track_id = atoi(tmp+1);
            }
            tmp[0] = 0;
        }
    }

    if (isor_is_local(szURL)) {
        GF_Err e;
        u64 start_range, end_range;
        start_range = end_range = 0;
        if (plug->query_proxy) {
            GF_NetworkCommand param;
            param.command_type = GF_NET_SERVICE_QUERY_INIT_RANGE;
            if (read->input->query_proxy(read->input, &param)==GF_OK) {
                start_range = param.url_query.start_range;
                end_range = param.url_query.end_range;
            }
        }
        e = gf_isom_open_progressive(szURL, start_range, end_range, &read->mov, &read->missing_bytes);
        if (e != GF_OK) {
            GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[IsoMedia] : error while opening %s, error=%s\n", szURL, gf_error_to_string(e)));
            gf_term_on_connect(serv, NULL, e);
            return GF_OK;
        }
        read->frag_type = gf_isom_is_fragmented(read->mov) ? 1 : 0;

        read->time_scale = gf_isom_get_timescale(read->mov);
        /*reply to user*/
        gf_term_on_connect(serv, NULL, GF_OK);
        if (read->no_service_desc) isor_declare_objects(read);
    } else {
        /*setup downloader*/
        isor_setup_download(plug, szURL);
    }
    return GF_OK;
}
예제 #3
0
파일: load.c 프로젝트: fcsteagu/gpac-1
void isor_emulate_chapters(GF_ISOFile *file, GF_InitialObjectDescriptor *iod)
{
	GF_Segment *prev_seg;
	u64 prev_start;
	u64 start;
	u32 i, count;
	if (!iod || gf_list_count(iod->OCIDescriptors)) return;
	count = gf_isom_get_chapter_count(file, 0);
	if (!count) return;

	prev_seg = NULL;
	start = prev_start = 0;
	for (i=0; i<count; i++) {
		const char *name;
		GF_Segment *seg;
		gf_isom_get_chapter(file, 0, i+1, &start, &name);
		seg = (GF_Segment *) gf_odf_desc_new(GF_ODF_SEGMENT_TAG);
		seg->startTime = (Double) (s64) start;
		seg->startTime /= 1000;
		seg->SegmentName = gf_strdup(name);
		gf_list_add(iod->OCIDescriptors, seg);
		if (prev_seg) {
			prev_seg->Duration = (Double) (s64) (start - prev_start);
			prev_seg->Duration /= 1000;
		} else if (start) {
			prev_seg = (GF_Segment *) gf_odf_desc_new(GF_ODF_SEGMENT_TAG);
			prev_seg->startTime = 0;
			prev_seg->Duration = (Double) (s64) (start);
			prev_seg->Duration /= 1000;
			gf_list_insert(iod->OCIDescriptors, prev_seg, 0);
		}
		prev_seg = seg;
		prev_start = start;
	}
	if (prev_seg) {
		start = 1000*gf_isom_get_duration(file);
		start /= gf_isom_get_timescale(file);
		if (start>prev_start) {
			prev_seg->Duration = (Double) (s64) (start - prev_start);
			prev_seg->Duration /= 1000;
		}
	}
}
예제 #4
0
static void UpdateODCommand(GF_ISOFile *mp4, GF_ODCom *com)
{
	u32 i, j;
	const char *szName;
	char szPath[2048];

	szName = gf_isom_get_filename(mp4);
	if (com->tag == GF_ODF_OD_UPDATE_TAG) {
		GF_ObjectDescriptor *od;
		GF_ODUpdate *odU = (GF_ODUpdate *)com;
		i=0;
		while ((od = (GF_ObjectDescriptor *)gf_list_enum(odU->objectDescriptors, &i))) {
			GF_ESD *esd;
			j=0;
			while ((esd = (GF_ESD *)gf_list_enum(od->ESDescriptors, &j))) {
				Bool import = 1;
				if (esd->URLString) continue;
				switch (esd->decoderConfig->streamType) {
				case GF_STREAM_OD:
					import = 0;
					break;
				case GF_STREAM_SCENE:
					if ((esd->decoderConfig->objectTypeIndication != GPAC_OTI_SCENE_AFX) &&
					        (esd->decoderConfig->objectTypeIndication != GPAC_OTI_SCENE_SYNTHESIZED_TEXTURE)
					   ) {
						import = 0;
					}
					break;
				/*dump the OCR track duration in case the OCR is used by media controls & co*/
				case GF_STREAM_OCR:
				{
					u32 track;
					Double dur;
					GF_MuxInfo *mi = (GF_MuxInfo *) gf_odf_desc_new(GF_ODF_MUXINFO_TAG);
					gf_list_add(esd->extensionDescriptors, mi);
					track = gf_isom_get_track_by_id(mp4, esd->ESID);
					dur = (Double) (s64) gf_isom_get_track_duration(mp4, track);
					dur /= gf_isom_get_timescale(mp4);
					mi->duration = (u32) (dur * 1000);
					import = 0;
				}
				break;
				default:
					break;
				}
				if (import) {
					GF_MuxInfo *mi = (GF_MuxInfo *) gf_odf_desc_new(GF_ODF_MUXINFO_TAG);
					gf_list_add(esd->extensionDescriptors, mi);
					sprintf(szPath, "%s#%d", szName, esd->ESID);
					mi->file_name = gf_strdup(szPath);
					mi->streamFormat = gf_strdup("MP4");
				}
			}
		}
		return;
	}
	if (com->tag == GF_ODF_ESD_UPDATE_TAG) {
		GF_ESD *esd;
		GF_ESDUpdate *esdU = (GF_ESDUpdate *)com;
		i=0;
		while ((esd = (GF_ESD *)gf_list_enum(esdU->ESDescriptors, &i))) {
			Bool import = 1;
			if (esd->URLString) continue;
			switch (esd->decoderConfig->streamType) {
			case GF_STREAM_OD:
				import = 0;
				break;
			case GF_STREAM_SCENE:
				if ((esd->decoderConfig->objectTypeIndication != GPAC_OTI_SCENE_AFX) &&
				        (esd->decoderConfig->objectTypeIndication != GPAC_OTI_SCENE_SYNTHESIZED_TEXTURE)
				   ) {
					import = 0;
				}
				break;
			/*dump the OCR track duration in case the OCR is used by media controls & co*/
			case GF_STREAM_OCR:
			{
				u32 track;
				Double dur;
				GF_MuxInfo *mi = (GF_MuxInfo *) gf_odf_desc_new(GF_ODF_MUXINFO_TAG);
				gf_list_add(esd->extensionDescriptors, mi);
				track = gf_isom_get_track_by_id(mp4, esd->ESID);
				dur = (Double) (s64) gf_isom_get_track_duration(mp4, track);
				dur /= gf_isom_get_timescale(mp4);
				mi->duration = (u32) (dur * 1000);
				import = 0;
			}
			break;
			default:
				break;
			}
			if (import) {
				GF_MuxInfo *mi = (GF_MuxInfo *) gf_odf_desc_new(GF_ODF_MUXINFO_TAG);
				gf_list_add(esd->extensionDescriptors, mi);
				sprintf(szPath, "%s#%d", szName, esd->ESID);
				mi->file_name = gf_strdup(szPath);
				mi->streamFormat = gf_strdup("MP4");
			}
		}
		return;
	}
}
예제 #5
0
static GF_Err gf_sm_load_run_isom(GF_SceneLoader *load)
{
	GF_Err e;
	FILE *logs;
	u32 i, j, di, nbBifs, nbLaser, nb_samp, samp_done, init_offset;
	GF_StreamContext *sc;
	GF_ESD *esd;
	GF_ODCodec *od_dec;
#ifndef GPAC_DISABLE_BIFS
	GF_BifsDecoder *bifs_dec;
#endif
#ifndef GPAC_DISABLE_LASER
	GF_LASeRCodec *lsr_dec;
#endif

	if (!load || !load->isom) return GF_BAD_PARAM;

	nbBifs = nbLaser = 0;
	e = GF_OK;
#ifndef GPAC_DISABLE_BIFS
	bifs_dec = gf_bifs_decoder_new(load->scene_graph, 1);
	gf_bifs_decoder_set_extraction_path(bifs_dec, load->localPath, load->fileName);
#endif
	od_dec = gf_odf_codec_new();
	logs = NULL;
#ifndef GPAC_DISABLE_LASER
	lsr_dec = gf_laser_decoder_new(load->scene_graph);
#endif
	esd = NULL;
	/*load each stream*/
	nb_samp = 0;
	for (i=0; i<gf_isom_get_track_count(load->isom); i++) {
		u32 type = gf_isom_get_media_type(load->isom, i+1);
		switch (type) {
		case GF_ISOM_MEDIA_SCENE:
		case GF_ISOM_MEDIA_OD:
			nb_samp += gf_isom_get_sample_count(load->isom, i+1);
			break;
		default:
			break;
		}
	}
	samp_done = 1;
	gf_isom_text_set_streaming_mode(load->isom, 1);

	for (i=0; i<gf_isom_get_track_count(load->isom); i++) {
		u32 type = gf_isom_get_media_type(load->isom, i+1);
		switch (type) {
		case GF_ISOM_MEDIA_SCENE:
		case GF_ISOM_MEDIA_OD:
			break;
		default:
			continue;
		}
		esd = gf_isom_get_esd(load->isom, i+1, 1);
		if (!esd) continue;


		if ((esd->decoderConfig->objectTypeIndication == GPAC_OTI_SCENE_AFX) ||
		        (esd->decoderConfig->objectTypeIndication == GPAC_OTI_SCENE_SYNTHESIZED_TEXTURE)
		   ) {
			nb_samp += gf_isom_get_sample_count(load->isom, i+1);
			continue;
		}
		sc = gf_sm_stream_new(load->ctx, esd->ESID, esd->decoderConfig->streamType, esd->decoderConfig->objectTypeIndication);
		sc->streamType = esd->decoderConfig->streamType;
		sc->ESID = esd->ESID;
		sc->objectType = esd->decoderConfig->objectTypeIndication;
		sc->timeScale = gf_isom_get_media_timescale(load->isom, i+1);

		/*we still need to reconfig the BIFS*/
		if (esd->decoderConfig->streamType==GF_STREAM_SCENE) {
#ifndef GPAC_DISABLE_BIFS
			/*BIFS*/
			if (esd->decoderConfig->objectTypeIndication<=2) {
				if (!esd->dependsOnESID && nbBifs && !i)
					mp4_report(load, GF_OK, "several scene namespaces used or improper scene dependencies in file - import may be incorrect");
				if (!esd->decoderConfig->decoderSpecificInfo) {
					/* Hack for T-DMB non compliant streams */
					e = gf_bifs_decoder_configure_stream(bifs_dec, esd->ESID, NULL, 0, esd->decoderConfig->objectTypeIndication);
				} else {
					e = gf_bifs_decoder_configure_stream(bifs_dec, esd->ESID, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength, esd->decoderConfig->objectTypeIndication);
				}
				if (e) goto exit;
				nbBifs++;
			}
#endif

#ifndef GPAC_DISABLE_LASER
			/*LASER*/
			if (esd->decoderConfig->objectTypeIndication==0x09) {
				if (!esd->dependsOnESID && nbBifs && !i)
					mp4_report(load, GF_OK, "several scene namespaces used or improper scene dependencies in file - import may be incorrect");
				e = gf_laser_decoder_configure_stream(lsr_dec, esd->ESID, esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength);
				if (e) goto exit;
				nbLaser++;
			}
#endif
		}

		init_offset = 0;
		/*dump all AUs*/
		for (j=0; j<gf_isom_get_sample_count(load->isom, i+1); j++) {
			GF_AUContext *au;
			GF_ISOSample *samp = gf_isom_get_sample(load->isom, i+1, j+1, &di);
			if (!samp) {
				mp4_report(load, gf_isom_last_error(load->isom), "Unable to fetch sample %d from track ID %d - aborting track import", j+1, gf_isom_get_track_id(load->isom, i+1));
				break;
			}
			/*check if track has initial offset*/
			if (!j && gf_isom_get_edit_segment_count(load->isom, i+1)) {
				u64 EditTime, dur, mtime;
				u8 mode;
				gf_isom_get_edit_segment(load->isom, i+1, 1, &EditTime, &dur, &mtime, &mode);
				if (mode==GF_ISOM_EDIT_EMPTY) {
					init_offset = (u32) (dur * sc->timeScale / gf_isom_get_timescale(load->isom) );
				}
			}
			samp->DTS += init_offset;

			au = gf_sm_stream_au_new(sc, samp->DTS, ((Double)(s64) samp->DTS) / sc->timeScale, (samp->IsRAP==RAP) ? 1 : 0);

			if (esd->decoderConfig->streamType==GF_STREAM_SCENE) {
#ifndef GPAC_DISABLE_BIFS
				if (esd->decoderConfig->objectTypeIndication<=2)
					e = gf_bifs_decode_command_list(bifs_dec, esd->ESID, samp->data, samp->dataLength, au->commands);
#endif
#ifndef GPAC_DISABLE_LASER
				if (esd->decoderConfig->objectTypeIndication==0x09)
					e = gf_laser_decode_command_list(lsr_dec, esd->ESID, samp->data, samp->dataLength, au->commands);
#endif
			} else {
				e = gf_odf_codec_set_au(od_dec, samp->data, samp->dataLength);
				if (!e) e = gf_odf_codec_decode(od_dec);
				if (!e) {
					while (1) {
						GF_ODCom *odc = gf_odf_codec_get_com(od_dec);
						if (!odc) break;
						/*update ESDs if any*/
						UpdateODCommand(load->isom, odc);
						gf_list_add(au->commands, odc);
					}
				}
			}
			gf_isom_sample_del(&samp);
			if (e) {
				mp4_report(load, gf_isom_last_error(load->isom), "decoding sample %d from track ID %d failed", j+1, gf_isom_get_track_id(load->isom, i+1));
				goto exit;
			}

			samp_done++;
			gf_set_progress("MP4 Loading", samp_done, nb_samp);
		}
		gf_odf_desc_del((GF_Descriptor *) esd);
		esd = NULL;
	}
	gf_isom_text_set_streaming_mode(load->isom, 0);

exit:
#ifndef GPAC_DISABLE_BIFS
	gf_bifs_decoder_del(bifs_dec);
#endif
	gf_odf_codec_del(od_dec);
#ifndef GPAC_DISABLE_LASER
	gf_laser_decoder_del(lsr_dec);
#endif
	if (esd) gf_odf_desc_del((GF_Descriptor *) esd);
	if (logs) gf_fclose(logs);
	return e;
}
예제 #6
0
파일: read.c 프로젝트: supperlitt/gpac
void isor_net_io(void *cbk, GF_NETIO_Parameter *param)
{
    GF_Err e;
    u32 size = 0;
    char *local_name;
    ISOMReader *read = (ISOMReader *) cbk;

    /*handle service message*/
    gf_term_download_update_stats(read->dnload);

    if (param->msg_type==GF_NETIO_DATA_TRANSFERED) {
        e = GF_EOS;
    } else if (param->msg_type==GF_NETIO_DATA_EXCHANGE) {
        e = GF_OK;
        size = param->size;
    } else {
        e = param->error;
    }

    if (e<GF_OK) {
        /*error opening service*/
        if (!read->mov) gf_term_on_connect(read->service, NULL, e);
        return;
    }

    /*open file if not done yet (bad interleaving)*/
    if (e==GF_EOS) {
        const char *local_name;
        if (read->mov) return;
        local_name = gf_dm_sess_get_cache_name(read->dnload);
        if (!local_name) {
            gf_term_on_connect(read->service, NULL, GF_SERVICE_ERROR);
            return;
        }
        e = GF_OK;
        read->mov = gf_isom_open(local_name, GF_ISOM_OPEN_READ, NULL);
        if (!read->mov) e = gf_isom_last_error(NULL);
        else read->time_scale = gf_isom_get_timescale(read->mov);
        gf_term_on_connect(read->service, NULL, GF_OK);
        if (read->no_service_desc) isor_declare_objects(read);
    }

    if (!size) return;

    /*service is opened, nothing to do*/
    if (read->mov) return;

    /*try to open the service*/
    local_name = (char *)gf_dm_sess_get_cache_name(read->dnload);
    if (!local_name) {
        gf_term_on_connect(read->service, NULL, GF_SERVICE_ERROR);
        return;
    }

    /*not enogh data yet*/
    if (read->missing_bytes && (read->missing_bytes > size) ) {
        read->missing_bytes -= size;
        return;
    }

    e = gf_isom_open_progressive(local_name, 0, 0, &read->mov, &read->missing_bytes);
    switch (e) {
    case GF_ISOM_INCOMPLETE_FILE:
        return;
    case GF_OK:
        break;
    default:
        gf_term_on_connect(read->service, NULL, e);
        return;
    }
    read->frag_type = gf_isom_is_fragmented(read->mov) ? 1 : 0;

    /*ok let's go*/
    read->time_scale = gf_isom_get_timescale(read->mov);
    gf_term_on_connect(read->service, NULL, GF_OK);
    if (read->no_service_desc) isor_declare_objects(read);
}
예제 #7
0
파일: main.c 프로젝트: ARSekkat/gpac
int main(int argc, char **argv)
{
	/********************/
	/*   declarations   */
	/********************/
	char *input, *output, tmpstr[GF_MAX_PATH];
	GF_ISOFile *isom_file_in;
	GF_MediaImporter import;
	AdobeHDSCtx ctx;
	GF_Err e;
	u32 i;

	/*****************/
	/*   gpac init   */
	/*****************/
	gf_sys_init(GF_MemTrackerNone);
	gf_log_set_tool_level(GF_LOG_ALL, GF_LOG_WARNING);

	/***********************/
	/*   initialisations   */
	/***********************/
	input = NULL;
	output = NULL;
	isom_file_in = NULL;
	memset(&import, 0, sizeof(GF_MediaImporter));
	e = GF_OK;
	memset(&ctx, 0, sizeof(ctx));

	ctx.curr_time = 0;
	ctx.segnum = 1;

	/*********************************************/
	/*   parse arguments and build HDS context   */
	/*********************************************/
	if (GF_OK != parse_args(argc, argv, &input, &output, &ctx.curr_time, &ctx.segnum)) {
		usage(argv[0]);
		goto exit;
	}

	ctx.multirate_manifest = adobe_alloc_multirate_manifest(output);

#if 0 /*'moov' conversion tests*/
	{
		char metamoov64[GF_MAX_PATH];
		u32 metamoov64_len;
		unsigned char metamoov[GF_MAX_PATH];
		u32 metamoov_len=GF_MAX_PATH;
		FILE *f = gf_fopen("metamoov64"/*input*/, "rt");
		gf_fseek(f, 0, SEEK_END);
		metamoov64_len = (u32)gf_ftell(f);
		gf_fseek(f, 0, SEEK_SET);
		fread(metamoov64, metamoov64_len, 1, f);
		metamoov_len = gf_base64_decode(metamoov64, metamoov64_len, metamoov, metamoov_len);
		gf_fclose(f);
		f = gf_fopen("metamoov", "wb");
		fwrite(metamoov, metamoov_len, 1, f);
		gf_fclose(f);
		return 0;
	}
#endif

#if 0 /*'abst'conversion tests*/
	{
		char bootstrap64[GF_MAX_PATH];
		u32 bootstrap64_len;
		unsigned char bootstrap[GF_MAX_PATH];
		u32 bootstrap_len=GF_MAX_PATH;
		GF_AdobeBootstrapInfoBox *abst = (GF_AdobeBootstrapInfoBox *)abst_New();
		GF_BitStream *bs;
#if 1 //64
		FILE *f = gf_fopen("bootstrap64"/*input*/, "rt");
		gf_fseek(f, 0, SEEK_END);
		bootstrap64_len = (u32)gf_ftell(f);
		gf_fseek(f, 0, SEEK_SET);
		fread(bootstrap64, bootstrap64_len, 1, f);
		bootstrap_len = gf_base64_decode(bootstrap64, bootstrap64_len, bootstrap, bootstrap_len);
#else //binary bootstrap
		FILE *f = gf_fopen("bootstrap.bin"/*input*/, "rb");
		gf_fseek(f, 0, SEEK_END);
		bootstrap_len = (u32)gf_ftell(f);
		gf_fseek(f, 0, SEEK_SET);
		fread(bootstrap, bootstrap_len, 1, f);
#endif
		bs = gf_bs_new(bootstrap+8, bootstrap_len-8, GF_BITSTREAM_READ);
		abst->size = bootstrap[2]*256+bootstrap[3];
		assert(abst->size<GF_MAX_PATH);
		abst_Read((GF_Box*)abst, bs);
		gf_bs_del(bs);
		//then rewrite with just one 'afrt'
		memset(bootstrap, 0, bootstrap_len);
		bs = gf_bs_new(bootstrap, bootstrap_len, GF_BITSTREAM_WRITE);
		abst_Write((GF_Box*)abst, bs);
		bootstrap_len = (u32)gf_bs_get_position(bs);
		gf_bs_del(bs);
		gf_fclose(f);
		f = gf_fopen("bootstrap", "wt");
		bootstrap64_len = gf_base64_encode(bootstrap, bootstrap_len, bootstrap64, GF_MAX_PATH);
		fwrite(bootstrap64, bootstrap64_len, 1, f);
		fprintf(f, "\n\n");
		abst_dump((GF_Box*)abst, f);
		gf_fclose(f);
		abst_del((GF_Box*)abst);
		return 0;
	}
#endif

	/*****************/
	/*   main loop   */
	/*****************/
	import.trackID = 0;
	import.in_name = input;
	import.flags = GF_IMPORT_PROBE_ONLY;

	//create output or open when recovering from a saved state
	sprintf(tmpstr, "%s_import.mp4", input);
	isom_file_in = gf_isom_open(tmpstr, GF_ISOM_WRITE_EDIT, NULL);
	if (!isom_file_in) {
		fprintf(stderr, "Error opening output file %s: %s\n", tmpstr, gf_error_to_string(e));
		assert(0);
		goto exit;
	}
	import.dest = isom_file_in;

	//probe input
	e = gf_media_import(&import);
	if (e) {
		fprintf(stderr, "Error while importing input file %s: %s\n", input, gf_error_to_string(e));
		assert(0);
		goto exit;
	}

	//import input data
	import.flags = 0;
	for (i=0; i<import.nb_tracks; i++) {
		import.trackID = import.tk_info[i].track_num;
		e = gf_media_import(&import);
		if (e) {
			fprintf(stderr, "Error while importing track number %u, input file %s: %s\n", import.trackID, input, gf_error_to_string(e));
			assert(0);
			goto exit;
		}
	}

	//Adobe specific stuff
	e = adobize_segment(isom_file_in, &ctx);
	if (e) {
		fprintf(stderr, "Couldn't turn the ISOM fragmented file into an Adobe f4v segment: %s\n", gf_error_to_string(e));
		assert(0);
		goto exit;
	}

	//interleave data and remove imported file
	//FIXME: set multiple fragments:
	sprintf(tmpstr, "%s_HD_100_Seg%u-Frag1", output, ctx.segnum); //FIXME: "HD", "100" and fragnum: pass as arg
	//e = gf_media_fragment_file(isom_file_in, tmpstr, 1.0);
	e = gf_media_fragment_file(isom_file_in, tmpstr, 1.0+gf_isom_get_duration(isom_file_in)/gf_isom_get_timescale(isom_file_in));
	if (e) {
		fprintf(stderr, "Error while fragmenting file to output %s: %s\n", output, gf_error_to_string(e));
		assert(0);
		goto exit;
	}
	gf_isom_delete(isom_file_in);
	isom_file_in = NULL;

	e = adobe_gen_multirate_manifest(ctx.multirate_manifest, ctx.bootstrap, ctx.bootstrap_size);
	if (e) {
		fprintf(stderr, "Couldn't generate Adobe f4m manifest: %s\n", gf_error_to_string(e));
		assert(0);
		goto exit;
	}

exit:
	//delete intermediate mp4 file
	if (isom_file_in)
		gf_isom_delete(isom_file_in);

	if (ctx.multirate_manifest)
		adobe_free_multirate_manifest(ctx.multirate_manifest);

	if (ctx.bootstrap) {
		gf_free(ctx.bootstrap);
		//ctx.bootstrap = NULL;
		//ctx.bootstrap_size = 0;
	}

	gf_sys_close();

	return !e ? 0 : 1;
}
예제 #8
0
파일: read.c 프로젝트: dragonlucian/gpac
void isor_net_io(void *cbk, GF_NETIO_Parameter *param)
{
	GF_Err e;
	u32 size = 0;
	char *local_name;
	ISOMReader *read = (ISOMReader *) cbk;

	/*handle service message*/
	if (!read->buffering)
		gf_service_download_update_stats(read->dnload);

	if (param->msg_type==GF_NETIO_DATA_TRANSFERED) {
		e = GF_EOS;
	} else if (param->msg_type==GF_NETIO_DATA_EXCHANGE) {
		e = GF_OK;
		size = param->size;
	} else {
		e = param->error;
	}

	if (e<GF_OK) {
		/*error opening service*/
		if (!read->mov) {
			/* if there is an intermediate between this module and the terminal, report to it */
			if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) {
				send_proxy_command(read, GF_FALSE, GF_FALSE, e, NULL, NULL);
			} else {
				gf_service_connect_ack(read->service, NULL, e);
			}
		}
		return;
	}

	/*open file if not done yet (bad interleaving)*/
	if (e==GF_EOS) {
		const char *local_name;
		if (read->mov) return;
		local_name = gf_dm_sess_get_cache_name(read->dnload);
		if (!local_name) {
			if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) {
				send_proxy_command(read, GF_FALSE, GF_FALSE, GF_SERVICE_ERROR, NULL, NULL);
			} else {
				gf_service_connect_ack(read->service, NULL, GF_SERVICE_ERROR);
			}
			return;
		}
		e = GF_OK;
		read->mov = gf_isom_open(local_name, GF_ISOM_OPEN_READ, NULL);
		if (!read->mov) e = gf_isom_last_error(NULL);
		else read->time_scale = gf_isom_get_timescale(read->mov);
		read->frag_type = gf_isom_is_fragmented(read->mov) ? 1 : 0;
		if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) {
			send_proxy_command(read, GF_FALSE, GF_FALSE, GF_OK, NULL, NULL);
		} else {
			gf_service_connect_ack(read->service, NULL, GF_OK);
		}
		if (read->no_service_desc) isor_declare_objects(read);
	}

	if (!size) return;

	/*service is opened, nothing to do*/
	if (read->mov) {
		isor_check_buffer_level(read);

		/*end of chunk*/
		if (read->frag_type && (param->reply==1) ) {
			u64 bytesMissing = 0;
			gf_mx_p(read->segment_mutex);
			e = gf_isom_refresh_fragmented(read->mov, &bytesMissing, NULL);
			gf_mx_v(read->segment_mutex);
		}
		return;
	}

	/*try to open the service*/
	local_name = (char *)gf_dm_sess_get_cache_name(read->dnload);
	if (!local_name) {
		if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) {
			send_proxy_command(read, GF_FALSE, GF_FALSE, GF_SERVICE_ERROR, NULL, NULL);
		} else {
			gf_service_connect_ack(read->service, NULL, GF_SERVICE_ERROR);
		}
		return;
	}

	/*not enogh data yet*/
	if (read->missing_bytes && (read->missing_bytes > size) ) {
		read->missing_bytes -= size;
		return;
	}

	e = gf_isom_open_progressive(local_name, 0, 0, &read->mov, &read->missing_bytes);
	switch (e) {
	case GF_ISOM_INCOMPLETE_FILE:
		return;
	case GF_OK:
		break;
	default:
		if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) {
			send_proxy_command(read, GF_FALSE, GF_FALSE, e, NULL, NULL);
		} else {
			gf_service_connect_ack(read->service, NULL, e);
		}
		return;
	}
	read->frag_type = gf_isom_is_fragmented(read->mov) ? 1 : 0;

	/*ok let's go, we can setup the decoders */
	read->time_scale = gf_isom_get_timescale(read->mov);
	if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) {
		send_proxy_command(read, GF_FALSE, GF_FALSE, GF_OK, NULL, NULL);
	} else {
		gf_service_connect_ack(read->service, NULL, GF_OK);
	}

	if (read->no_service_desc) isor_declare_objects(read);
}
예제 #9
0
파일: read.c 프로젝트: dragonlucian/gpac
void isor_check_buffer_level(ISOMReader *read)
{
	Double dld_time_remaining, mov_rate;
	GF_NetworkCommand com;
	u32 i, total, done, Bps;
	u64 dur;
	GF_NetIOStatus status;
	Bool do_buffer = GF_FALSE;
	if (!read->dnload) return;
	if (!read->mov) return;

	gf_dm_sess_get_stats(read->dnload, NULL, NULL, &total, &done, &Bps, &status);
	if (!Bps) return;


	gf_mx_p(read->segment_mutex);

	dld_time_remaining = total-done;
	dld_time_remaining /= Bps;

	//we add 30 seconds to smooth out bitrate variations ..;
	dld_time_remaining += 30;

	mov_rate = total;
	dur = gf_isom_get_duration(read->mov);
	if (dur) {
		mov_rate /= dur;
		mov_rate *= gf_isom_get_timescale(read->mov);
	}

	for (i=0; i<gf_list_count(read->channels); i++) {
		ISOMChannel *ch = gf_list_get(read->channels, i);
		Double time_remain_ch = (Double) gf_isom_get_media_duration(read->mov, ch->track);
		u32 buffer_level=0;
		if (total==done) {
			time_remain_ch = 0;
			do_buffer = GF_FALSE;
		} else if (ch->last_state == GF_EOS) {
			time_remain_ch = 0;
			do_buffer = GF_TRUE;
		} else {
			u64 data_offset;
			u32 di, sn = ch->sample_num ? ch->sample_num : 1;
			GF_ISOSample *samp = gf_isom_get_sample_info(read->mov, ch->track, sn, &di, &data_offset);
			if (!samp) continue;

			data_offset += samp->dataLength;

			//we only send buffer on/off based on remainging playback time in channel
#if 0
			//we don't have enough data
			if (((data_offset + ch->buffer_min * mov_rate/1000 > done))) {
				do_buffer = GF_TRUE;
			}
			//we have enough buffer
			else if ((data_offset + ch->buffer_max * mov_rate/1000 <= done)) {
				do_buffer = GF_FALSE;
			}
#endif
			time_remain_ch -= (samp->DTS + samp->CTS_Offset);
			if (time_remain_ch<0) time_remain_ch=0;
			gf_isom_sample_del(&samp);

			time_remain_ch /= ch->time_scale;
			if (time_remain_ch && (time_remain_ch < dld_time_remaining)) {
				do_buffer = GF_TRUE;
				if (!read->remain_at_buffering_start || (read->remain_at_buffering_start < dld_time_remaining)) {
					buffer_level = 0;
					read->remain_at_buffering_start = dld_time_remaining;
				} else {
					buffer_level = (u32) (100 * (read->remain_at_buffering_start - dld_time_remaining) / (read->remain_at_buffering_start - time_remain_ch) );
				}
			} else {
				do_buffer = GF_FALSE;
			}
		}

		if (do_buffer != ch->buffering) {
			GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[IsoMedia] Buffering %s at %d: %g sec still to download and %g sec still to play on track %d (movie rate %g - download rate %g kbps)\n", do_buffer ? "on" : "off", gf_sys_clock(), dld_time_remaining , time_remain_ch, ch->track_id, mov_rate*8/1000, Bps*8.0/1000));

			memset(&com, 0, sizeof(GF_NetworkCommand));
			com.command_type = do_buffer ? GF_NET_CHAN_PAUSE : GF_NET_CHAN_RESUME;
			com.buffer.on_channel = ch->channel;
			com.buffer.min = ch->buffer_min;
			com.buffer.max = ch->buffer_max;
			gf_service_command(read->service, &com, GF_OK);
			ch->buffering = do_buffer;
			read->buffering = do_buffer;
		} else if (ch->buffering) {
			memset(&com, 0, sizeof(GF_NetworkCommand));
			com.command_type = GF_NET_CHAN_BUFFER;
			com.buffer.on_channel = ch->channel;
			com.buffer.min = ch->buffer_min;
			com.buffer.max = ch->buffer_max;
			com.buffer.occupancy = buffer_level;
			gf_service_command(read->service, &com, GF_OK);
		}
	}
	gf_mx_v(read->segment_mutex);
}
예제 #10
0
GF_Err adobize_segment(GF_ISOFile *isom_file, AdobeHDSCtx *ctx)
{
	GF_Err e;
	GF_BitStream *bs;

	GF_AdobeFragRandomAccessBox *afra = (GF_AdobeFragRandomAccessBox*)	afra_New();
	GF_AfraEntry *ae                  = (GF_AfraEntry*)					gf_calloc(1, sizeof(GF_AfraEntry));
	GF_AdobeBootstrapInfoBox *abst    = (GF_AdobeBootstrapInfoBox*)		abst_New();
	GF_AdobeSegmentRunTableBox *asrt  = (GF_AdobeSegmentRunTableBox*)	asrt_New();
	GF_AdobeSegmentRunEntry *asre     = (GF_AdobeSegmentRunEntry*)		gf_calloc(1, sizeof(GF_AdobeSegmentRunEntry));
	GF_AdobeFragmentRunTableBox *afrt = (GF_AdobeFragmentRunTableBox*)	afrt_New();
	GF_AdobeFragmentRunEntry *afre    = (GF_AdobeFragmentRunEntry*)		gf_calloc(1, sizeof(GF_AdobeFragmentRunEntry));

	u64 init_seg_time = ctx->curr_time;
	u32 seg_duration = (u32)gf_isom_get_duration(isom_file);

	//update context
	ctx->curr_time += seg_duration;

	//Adobe specific boxes
	//Random Access
	afra->type = GF_4CC('a', 'f', 'r', 'a');
	afra->version = 0;
	afra->flags = 0;
	afra->long_ids = 1;
	afra->long_offsets = 1;
	afra->global_entries = 0;
	afra->time_scale = gf_isom_get_timescale(isom_file);

	afra->entry_count = 1;
	ae->time = init_seg_time;
	ae->offset = 3999;
	gf_list_add(afra->local_access_entries, ae);

	afra->global_entries = 0;
	afra->global_entry_count = 0;

	e = gf_list_add(isom_file->TopBoxes, afra);
	if (e) {
		fprintf(stderr, "Impossible to write AFRA box: %s\n", gf_error_to_string(e));
		assert(0);
		return e;
	}

	//Bootstrap Info
	abst->type = GF_4CC('a', 'b', 's', 't');
	abst->version = 0;
	abst->flags = 0;
	abst->bootstrapinfo_version = 1;
	abst->profile = 0;
	abst->live = 1;
	abst->update = 0;
	abst->time_scale = gf_isom_get_timescale(isom_file);
	abst->current_media_time = init_seg_time+seg_duration;
	abst->smpte_time_code_offset = 0;

	abst->movie_identifier = NULL;
	abst->drm_data = NULL;
	abst->meta_data = NULL;

	abst->server_entry_count = 0;
	abst->quality_entry_count = 0;

	abst->segment_run_table_count = 1;
	{
		//Segment Run
		asrt->type = GF_4CC('a', 's', 'r', 't');
		asrt->version = 0;
		asrt->flags = 0;
		asrt->segment_run_entry_count = 1;
		{
			asre->first_segment = ctx->segnum;
			asre->fragment_per_segment = 1;
		}
		e = gf_list_add(asrt->segment_run_entry_table, asre);
		if (e) {
			fprintf(stderr, "Impossible to write ASR Entry: %s\n", gf_error_to_string(e));
			assert(0);
			return e;
		}
	}
	e = gf_list_add(abst->segment_run_table_entries, asrt);
	if (e) {
		fprintf(stderr, "Impossible to write ASRT box: %s\n", gf_error_to_string(e));
		assert(0);
		return e;
	}

	abst->fragment_run_table_count = 1;
	{
		//Fragment Run
		afrt->type = GF_4CC('a', 'f', 'r', 't');
		afrt->version = 0;
		afrt->flags = 0;
		afrt->timescale = gf_isom_get_timescale(isom_file);
		afrt->fragment_run_entry_count = 1;
		{
			afre->first_fragment = 1;
			afre->first_fragment_timestamp = 0;
			afre->fragment_duration = seg_duration;
		}
		e = gf_list_add(afrt->fragment_run_entry_table, afre);
		if (e) {
			fprintf(stderr, "Impossible to write AFR Entry: %s\n", gf_error_to_string(e));
			assert(0);
			return e;
		}
	}
	e = gf_list_add(abst->fragment_run_table_entries, afrt);
	if (e) {
		fprintf(stderr, "Impossible to write AFRT box: %s\n", gf_error_to_string(e));
		assert(0);
		return e;
	}

	e = gf_list_add(isom_file->TopBoxes, abst);
	if (e) {
		fprintf(stderr, "Impossible to write ABST box: %s\n", gf_error_to_string(e));
		assert(0);
		return e;
	}

	e = abst_Size((GF_Box*)abst);
	if (e) {
		fprintf(stderr, "Impossible to compute ABST box size: %s\n", gf_error_to_string(e));
		assert(0);
		return e;
	}
	ctx->bootstrap_size = (size_t)abst->size;
	ctx->bootstrap = gf_malloc(ctx->bootstrap_size);
	bs = gf_bs_new(ctx->bootstrap, ctx->bootstrap_size, GF_BITSTREAM_WRITE);
	e = abst_Write((GF_Box*)abst, bs);
	if (e) {
		fprintf(stderr, "Impossible to code the ABST box: %s\n", gf_error_to_string(e));
		assert(0);
		gf_bs_del(bs);
		return e;
	}
	gf_bs_del(bs);

	//set brands as reversed engineered from f4v files
	/*e = gf_isom_reset_alt_brands(isom_file);
	if (e) {
		fprintf(stderr, "Warning: couldn't reset ISOM brands: %s\n", gf_error_to_string(e));
		assert(0);
	}*/
	gf_isom_set_brand_info(isom_file, GF_4CC('f','4','v',' '), 1);
	gf_isom_modify_alternate_brand(isom_file, GF_4CC('i','s','o','m'), 1);
	gf_isom_modify_alternate_brand(isom_file, GF_4CC('m','p','4','2'), 1);
	gf_isom_modify_alternate_brand(isom_file, GF_4CC('m','4','v',' '), 1);

	return GF_OK;
}