⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ffmpeg_demux.c

📁 一个用于智能手机的多媒体库适合S60 WinCE的跨平台开发库
💻 C
📖 第 1 页 / 共 2 页
字号:
	return esd;}static void FFD_SetupObjects(FFDemux *ffd){	GF_ESD *esd;	GF_ObjectDescriptor *od;	u32 audio_esid = 0;		if (ffd->audio_st>=0) {		od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);		esd = FFD_GetESDescriptor(ffd, 1);		od->objectDescriptorID = esd->ESID;		audio_esid = esd->ESID;		gf_list_add(od->ESDescriptors, esd);		gf_term_add_media(ffd->service, (GF_Descriptor*)od, (ffd->video_st>=0) ? 1 : 0);	}	if (ffd->video_st>=0) {		od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);		esd = FFD_GetESDescriptor(ffd, 0);		od->objectDescriptorID = esd->ESID;		esd->OCRESID = audio_esid;		gf_list_add(od->ESDescriptors, esd);		gf_term_add_media(ffd->service, (GF_Descriptor*)od, 0);	}}static GF_Err FFD_ConnectService(GF_InputService *plug, GF_ClientService *serv, const char *url){	GF_Err e;	s64 last_aud_pts;	s32 i;	const char *sOpt;	char *ext, szName[1000];	FFDemux *ffd = plug->priv;	AVInputFormat *av_in = NULL;	if (ffd->ctx) return GF_SERVICE_ERROR;	strcpy(szName, url);	ext = strrchr(szName, '#');	ffd->service_type = 0;	e = GF_NOT_SUPPORTED;	ffd->service = serv;	if (ext) {		if (!stricmp(&ext[1], "video")) ffd->service_type = 1;		else if (!stricmp(&ext[1], "audio")) ffd->service_type = 2;		ext[0] = 0;	}	i = av_open_input_file(&ffd->ctx, szName, NULL, 0, NULL);	if (i<0) {		char szExt[20];		ext = strrchr(szName, '.');		strcpy(szExt, ext+1);		strlwr(szExt);		/*some extensions not supported by ffmpeg*/		if (ext && !strcmp(szExt, "cmp")) av_in = av_find_input_format("m4v");		i = av_open_input_file(&ffd->ctx, szName, av_in, 0, NULL);	}	switch (i) {	case 0: e = GF_OK; break;	case AVERROR_IO: e = GF_URL_ERROR; goto err_exit;	case AVERROR_INVALIDDATA: e = GF_NON_COMPLIANT_BITSTREAM; goto err_exit;	case AVERROR_NOMEM: e = GF_OUT_OF_MEM; goto err_exit;	case AVERROR_NOFMT: e = GF_NOT_SUPPORTED; goto err_exit;	default: e = GF_SERVICE_ERROR; goto err_exit;	}    if (av_find_stream_info(ffd->ctx) <0) goto err_exit;	/*figure out if we can use codecs or not*/	ffd->audio_st = ffd->video_st = -1;    for (i = 0; i < ffd->ctx->nb_streams; i++) {        AVCodecContext *enc = ffd->ctx->streams[i]->codec;        switch(enc->codec_type) {        case CODEC_TYPE_AUDIO:            if ((ffd->audio_st<0) && (ffd->service_type!=1)) {				ffd->audio_st = i;				ffd->audio_tscale = ffd->ctx->streams[i]->time_base;			}            break;        case CODEC_TYPE_VIDEO:            if ((ffd->video_st<0) && (ffd->service_type!=2)) {				ffd->video_st = i;				ffd->video_tscale = ffd->ctx->streams[i]->time_base;			}            break;        default:            break;        }    }	if ((ffd->service_type==1) && (ffd->video_st<0)) goto err_exit;	if ((ffd->service_type==2) && (ffd->audio_st<0)) goto err_exit;	if ((ffd->video_st<0) && (ffd->audio_st<0)) goto err_exit;	sOpt = gf_modules_get_option((GF_BaseInterface *)plug, "FFMPEG", "DataBufferMS"); 	ffd->data_buffer_ms = 0;	if (sOpt) ffd->data_buffer_ms = atoi(sOpt);	if (!ffd->data_buffer_ms) ffd->data_buffer_ms = FFD_DATA_BUFFER;	/*check we do have increasing pts. If not we can't rely on pts, we must skip SL	we assume video pts is always present*/	if (ffd->audio_st>=0) {		last_aud_pts = 0;		for (i=0; i<20; i++) {			AVPacket pkt;			pkt.stream_index = -1;			if (av_read_frame(ffd->ctx, &pkt) <0) break;			if (pkt.pts == AV_NOPTS_VALUE) pkt.pts = pkt.dts;			if (pkt.stream_index==ffd->audio_st) last_aud_pts = pkt.pts;		}		if (last_aud_pts*ffd->audio_tscale.den<10*ffd->audio_tscale.num) ffd->unreliable_audio_timing = 1;	}	/*build seek*/	ffd->seekable = (av_seek_frame(ffd->ctx, -1, 0, AVSEEK_FLAG_BACKWARD)<0) ? 0 : 1;	if (!ffd->seekable) {	    av_close_input_file(ffd->ctx);		av_open_input_file(&ffd->ctx, szName, av_in, 0, NULL);	    av_find_stream_info(ffd->ctx);	}	/*let's go*/	gf_term_on_connect(serv, NULL, GF_OK);	if (!ffd->service_type) FFD_SetupObjects(ffd);	ffd->service_type = 0;	return GF_OK;err_exit:    if (ffd->ctx) av_close_input_file(ffd->ctx);	ffd->ctx = NULL;	gf_term_on_connect(serv, NULL, e);	return GF_OK;}static GF_Descriptor *FFD_GetServiceDesc(GF_InputService *plug, u32 expect_type, const char *sub_url){	GF_ObjectDescriptor *od;	GF_ESD *esd;	FFDemux *ffd = plug->priv;	if (!ffd->ctx) return NULL;	if (expect_type==GF_MEDIA_OBJECT_UNDEF) {		if (ffd->video_st>=0) expect_type=GF_MEDIA_OBJECT_VIDEO;		else if (ffd->audio_st>=0) expect_type=GF_MEDIA_OBJECT_AUDIO;	}	/*since we don't handle multitrack in ffmpeg, we don't need to check sub_url, only use expected type*/	if (expect_type==GF_MEDIA_OBJECT_AUDIO) {		od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);		od->objectDescriptorID = 1;		esd = FFD_GetESDescriptor(ffd, 1);		/*if session join, setup sync*/		if (ffd->video_ch) esd->OCRESID = ffd->video_st+1;		gf_list_add(od->ESDescriptors, esd);		ffd->service_type = 2;		return (GF_Descriptor *) od;	}	if (expect_type==GF_MEDIA_OBJECT_VIDEO) {		od = (GF_ObjectDescriptor *) gf_odf_desc_new(GF_ODF_OD_TAG);		od->objectDescriptorID = 1;		esd = FFD_GetESDescriptor(ffd, 0);		/*if session join, setup sync*/		if (ffd->audio_ch) esd->OCRESID = ffd->audio_st+1;		gf_list_add(od->ESDescriptors, esd);		ffd->service_type = 1;		return (GF_Descriptor *) od;	}	return NULL;}static GF_Err FFD_CloseService(GF_InputService *plug){	FFDemux *ffd = plug->priv;	ffd->is_running = 0;	if (ffd->ctx) av_close_input_file(ffd->ctx);	ffd->ctx = NULL;	ffd->audio_ch = ffd->video_ch = NULL;	ffd->audio_run = ffd->video_run = 0;	gf_term_on_disconnect(ffd->service, NULL, GF_OK);	return GF_OK;}static GF_Err FFD_ConnectChannel(GF_InputService *plug, LPNETCHANNEL channel, const char *url, Bool upstream){	GF_Err e;	u32 ESID;	FFDemux *ffd = plug->priv;	e = GF_STREAM_NOT_FOUND;	if (upstream) {		e = GF_ISOM_INVALID_FILE;		goto exit;	}	if (!strstr(url, "ES_ID=")) {		e = GF_NOT_SUPPORTED;		goto exit;	}	sscanf(url, "ES_ID=%d", &ESID);	if ((s32) ESID == 1 + ffd->audio_st) {		if (ffd->audio_ch) {			e = GF_SERVICE_ERROR;			goto exit;		}		ffd->audio_ch = channel;		e = GF_OK;	}	else if ((s32) ESID == 1 + ffd->video_st) {		if (ffd->video_ch) {			e = GF_SERVICE_ERROR;			goto exit;		}		ffd->video_ch = channel;		e = GF_OK;	}exit:	gf_term_on_connect(ffd->service, channel, e);	return GF_OK;}static GF_Err FFD_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel){	GF_Err e;	FFDemux *ffd = plug->priv;	e = GF_STREAM_NOT_FOUND;	if (ffd->audio_ch == channel) {		e = GF_OK;		ffd->audio_ch = NULL;		ffd->audio_run = 0;	}	else if (ffd->video_ch == channel) {		e = GF_OK;		ffd->video_ch = NULL;		ffd->video_run = 0;	}	gf_term_on_disconnect(ffd->service, channel, e);	return GF_OK;}static GF_Err FFD_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com){	FFDemux *ffd = plug->priv;	if (!com->base.on_channel) return GF_NOT_SUPPORTED;	switch (com->command_type) {	/*only BIFS/OD work in pull mode (cf ffmpeg_in.h)*/	case GF_NET_CHAN_SET_PULL:		return GF_NOT_SUPPORTED;	case GF_NET_CHAN_INTERACTIVE:		return ffd->seekable ? GF_OK : GF_NOT_SUPPORTED;	case GF_NET_CHAN_BUFFER:		com->buffer.max = com->buffer.min = 0;		return GF_OK;	case GF_NET_CHAN_DURATION:		if (ffd->ctx->duration == AV_NOPTS_VALUE)			com->duration.duration = -1;		else			com->duration.duration = (Double) ffd->ctx->duration / AV_TIME_BASE;		return GF_OK;	/*fetch start time*/	case GF_NET_CHAN_PLAY:		if (com->play.speed<0) return GF_NOT_SUPPORTED;		gf_mx_p(ffd->mx);		ffd->seek_time = (com->play.start_range>=0) ? com->play.start_range : 0;				if (ffd->audio_ch==com->base.on_channel) ffd->audio_run = 1;		else if (ffd->video_ch==com->base.on_channel) ffd->video_run = 1;		/*play on media stream, start thread*/		if ((ffd->audio_ch==com->base.on_channel) || (ffd->video_ch==com->base.on_channel)) {			if (!ffd->is_running) {				ffd->is_running = 1;				gf_th_run(ffd->thread, FFDemux_Run, ffd);			}		}		gf_mx_v(ffd->mx);		return GF_OK;	case GF_NET_CHAN_STOP:		if (ffd->audio_ch==com->base.on_channel) ffd->audio_run = 0;		else if (ffd->video_ch==com->base.on_channel) ffd->video_run = 0;		return GF_OK;	/*note we don't handle PAUSE/RESUME/SET_SPEED, this is automatically handled by the demuxing thread 	through buffer occupancy queries*/	default:		return GF_OK;	}	return GF_OK;}static Bool FFD_CanHandleURLInService(GF_InputService *plug, const char *url){	char szURL[2048], *sep;	FFDemux *ffd = (FFDemux *)plug->priv;	const char *this_url = gf_term_get_service_url(ffd->service);	if (!this_url || !url) return 0;	strcpy(szURL, this_url);	sep = strrchr(szURL, '#');	if (sep) sep[0] = 0;	if ((url[0] != '#') && strnicmp(szURL, url, sizeof(char)*strlen(szURL))) return 0;	sep = strrchr(url, '#');	if (!stricmp(sep, "#video") && (ffd->video_st>=0)) return 1;	if (!stricmp(sep, "#audio") && (ffd->audio_st>=0)) return 1;	return 0;}void *New_FFMPEG_Demux() {	FFDemux *priv;	GF_InputService *ffd = malloc(sizeof(GF_InputService));	memset(ffd, 0, sizeof(GF_InputService));	priv = malloc(sizeof(FFDemux));	memset(priv, 0, sizeof(FFDemux));    /* register all codecs, demux and protocols */    av_register_all();		ffd->CanHandleURL = FFD_CanHandleURL;	ffd->CloseService = FFD_CloseService;	ffd->ConnectChannel = FFD_ConnectChannel;	ffd->ConnectService = FFD_ConnectService;	ffd->DisconnectChannel = FFD_DisconnectChannel;	ffd->GetServiceDescriptor = FFD_GetServiceDesc;	ffd->ServiceCommand = FFD_ServiceCommand;	ffd->CanHandleURLInService = FFD_CanHandleURLInService;	priv->thread = gf_th_new();	priv->mx = gf_mx_new();	GF_REGISTER_MODULE_INTERFACE(ffd, GF_NET_CLIENT_INTERFACE, "FFMPEG Demuxer", "gpac distribution");	ffd->priv = priv;	return ffd;}void Delete_FFMPEG_Demux(void *ifce){	FFDemux *ffd;	GF_InputService *ptr = (GF_InputService *)ifce;	ffd = ptr->priv;	gf_th_del(ffd->thread);	gf_mx_del(ffd->mx);	free(ffd);	free(ptr);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -