Beispiel #1
0
M4Err MediaCodec_Process(GenericCodec *codec, u32 TimeAvailable)
{
	LPAUBUFFER AU;
	Channel *ch;
	char *cu_buf;
	u32 cu_buf_size, mmlevel, deltaTS;
	u32 first, entryTime, now, obj_time;
	MediaDecoder *mdec = (MediaDecoder*)codec->decio;
	M4Err e = M4OK;

	/*if video codec muted don't decode
	if audio codec muted we dispatch to keep sync in place*/
	if (codec->Muted && (codec->type==M4ST_VISUAL) ) return M4OK;

	entryTime = Term_GetTime(codec->odm->term);

	/*fetch next AU in DTS order for this codec*/
	Decoder_GetNextAU(codec, &ch, &AU);
	/*no active channel return*/
	if (!AU || !ch) {
		/*if the codec is in EOS state, assume we're done*/
		if (codec->Status == CODEC_EOS) {
			/*if codec is reordering, try to flush it*/
			if (codec->is_reordering) {
				if ( LockCompositionUnit(codec, codec->last_unit_cts+1, &cu_buf, &cu_buf_size) == M4OutOfMem) 
					return M4OK;
				e = mdec->ProcessData(mdec, NULL, 0, 0, cu_buf, &cu_buf_size, 0, 0);
				if (e==M4OK) e = UnlockCompositionUnit(codec, codec->last_unit_cts+1, cu_buf_size);
			}
			MM_StopCodec(codec);
			if (codec->CB) CB_SetEndOfStream(codec->CB);
		}
		/*if no data, and channel not buffering, ABORT CB buffer (data timeout or EOS not detectable)*/
		else if (ch && !ch->BufferOn) 
			CB_AbortBuffering(codec->CB);
		return M4OK;
	}

	/*get the object time*/
	obj_time = CK_GetTime(codec->ck);
	/*Media Time for media codecs is updated in the CB*/

	if (!codec->CB) {
		Channel_DropAU(ch);
		return M4BadParam;
	}
	
	/*try to refill the full buffer*/
	first = 1;
	while (codec->CB->Capacity > codec->CB->UnitCount) {
		/*set media processing level*/
		mmlevel = MM_LEVEL_NORMAL;
		/*SEEK: if the last frame had the same TS, we are seeking. Ask the codec to drop*/
		if (!ch->skip_sl && codec->last_unit_cts && (codec->last_unit_cts == AU->CTS) && !ch->esd->dependsOnESID) {
			mmlevel = MM_LEVEL_SEEK;
		}
		/*only perform drop in normal playback*/
		else if (codec->CB->Status == CB_PLAY) {
			if (!ch->skip_sl && (AU->CTS < obj_time)) {
				/*extremely late, even if we decode the renderer will drop the frame 
				so set the level to drop*/
				mmlevel = MM_LEVEL_DROP;
			}
			/*we are late according to the media manager*/
			else if (codec->PriorityBoost) {
				mmlevel = MM_LEVEL_VERY_LATE;
			}
			/*otherwise we must have an idea of the load in order to set the right level
			use the composition buffer for that, only on the first frame*/
			else if (first) {
				//if the CB is almost empty set to very late
				if (codec->CB->UnitCount <= codec->CB->Min+1) {
					mmlevel = MM_LEVEL_VERY_LATE;
				} else if (codec->CB->UnitCount * 2 <= codec->CB->Capacity) {
					mmlevel = MM_LEVEL_LATE;
				}
				first = 0;
			}
		}

		/*when using temporal scalability make sure we can decode*/
		if (ch->esd->dependsOnESID && (codec->last_unit_dts > AU->DTS)){
//			printf("SCALABLE STREAM DEAD!!\n");
			goto drop;
		}

		if (ch->skip_sl) {
			if (codec->bytes_per_sec) {
				AU->CTS = codec->last_unit_cts + ch->ts_offset + codec->cur_audio_bytes * 1000 / codec->bytes_per_sec;
			} else if (codec->fps) {
				AU->CTS = codec->last_unit_cts + ch->ts_offset + (u32) (codec->cur_video_frames * 1000 / codec->fps);
			}
		}

		if ( LockCompositionUnit(codec, AU->CTS, &cu_buf, &cu_buf_size) == M4OutOfMem) 
			return M4OK;

		now = Term_GetTime(codec->odm->term);

		e = mdec->ProcessData(mdec, AU->data, AU->dataLength, 
			ch->esd->ESID, cu_buf, &cu_buf_size, AU->PaddingBits, mmlevel);
		now = Term_GetTime(codec->odm->term) - now;

		/*input is too small, resize composition memory*/
		switch (e) {
		case M4BufferTooSmall:
			/*release but no dispatch*/
			UnlockCompositionUnit(codec, AU->CTS, 0);
			if (ResizeCompositionBuffer(codec, cu_buf_size)==M4OK) continue;
			break;
		case M4OK:
			/*in seek don't dispatch any output*/
			if (mmlevel == MM_LEVEL_SEEK) cu_buf_size = 0;
			e = UnlockCompositionUnit(codec, AU->CTS, cu_buf_size);
			codec_update_stats(codec, AU->dataLength, now);
			if (ch->skip_sl) {
				if (codec->bytes_per_sec) {
					codec->cur_audio_bytes += cu_buf_size;
					while (codec->cur_audio_bytes>codec->bytes_per_sec) {
						codec->cur_audio_bytes -= codec->bytes_per_sec;
						codec->last_unit_cts += 1000;
					}
				} else if (codec->fps && cu_buf_size) {
					codec->cur_video_frames += 1;
				}
			}
			break;
		/*this happens a lot when using non-MPEG-4 streams (ex: ffmpeg demuxer)*/
		case M4PackedFrames:
			/*in seek don't dispatch any output*/
			if (mmlevel	== MM_LEVEL_SEEK) cu_buf_size = 0;
			e = UnlockCompositionUnit(codec, AU->CTS, cu_buf_size);

			if (ch->skip_sl) {
				if (codec->bytes_per_sec) {
					codec->cur_audio_bytes += cu_buf_size;
				} else if (codec->fps && cu_buf_size) {
					codec->cur_video_frames += 1;
				}
			} else {
				if (codec->bytes_per_sec) {
					deltaTS = cu_buf_size * 1000 / codec->bytes_per_sec;
				} else if (codec->fps && cu_buf_size) {
					deltaTS = (u32) (1000.0f / codec->fps);
				}
				AU->DTS += deltaTS;
				AU->CTS += deltaTS;
			}
			codec_update_stats(codec, 0, now);
			continue;
		default:
			UnlockCompositionUnit(codec, AU->CTS, 0);
			/*error - if the object is in intitial buffering resume it!!*/
			CB_AbortBuffering(codec->CB);
			break;
		}

		codec->last_unit_dts = AU->DTS;
		/*remember base layer timing*/
		if (!ch->esd->dependsOnESID && !ch->skip_sl) codec->last_unit_cts = AU->CTS;

drop:
		Channel_DropAU(ch);
		if (e) return e;

		/*escape from decoding loop only if above critical limit - this is to avoid starvation on audio*/
		if (codec->CB->UnitCount > codec->CB->Min) {
			now = Term_GetTime(codec->odm->term);
			if (now - entryTime >= TimeAvailable - TIME_CHECK) {
				return M4OK;
			}
		}

		Decoder_GetNextAU(codec, &ch, &AU);
		if (!ch || !AU) return M4OK;
	}
	return M4OK;
}
Beispiel #2
0
/*special handling of decoders not using ESM*/
M4Err PrivateScene_Process(GenericCodec *codec, u32 TimeAvailable)
{
	Bool resume_clock;
	u32 now;
	Channel *ch;
	SceneDecoder *sdec = (SceneDecoder *)codec->decio;
	M4Err e = M4OK;
	
	/*muting systems codec means we don't decode until mute is off - likely there will be visible however
	there is no other way to decode system AUs without modifying the content, which is what mute is about on visual...*/
	if (codec->Muted) return M4OK;

	if (codec->Status == CODEC_EOS) {
		MM_StopCodec(codec);
		return M4OK;
	}

	ch = ChainGetEntry(codec->inChannels, 0);
	if (!ch) return M4OK;
	resume_clock = 0;
	/*init channel clock*/
	if (!ch->IsClockInit) {
		Channel_InitDummy(ch);
		if (!CK_IsStarted(ch->clock)) return M4OK;
		/*let's be nice to the scene loader (that usually involves quite some parsing), pause clock while
		parsing*/
		CK_Pause(ch->clock);
		codec->last_unit_dts = 0;
	}

	codec->odm->current_time = codec->last_unit_cts = CK_GetTime(codec->ck);

	/*lock scene*/
	Term_LockScene(codec->odm->term, 1);
	now = Term_GetTime(codec->odm->term);
	e = sdec->ProcessData(sdec, NULL, codec->odm->current_time, ch->esd->ESID, codec->odm->current_time, MM_LEVEL_NORMAL);
	now = Term_GetTime(codec->odm->term) - now;
	codec->last_unit_dts ++;
	/*resume on error*/
	if (e && (codec->last_unit_dts<2) ) {
		CK_Resume(ch->clock);
		codec->last_unit_dts = 2;
	}
	/*resume clock on 2nd decode (we assume parsing is done in 2 steps, one for first frame display, one for complete parse)*/
	else if (codec->last_unit_dts==2) {
		CK_Resume(ch->clock);
	}

	codec_update_stats(codec, 0, now);

	Term_LockScene(codec->odm->term, 0);
	Term_InvalidateScene(codec->odm->term);

	if (e==M4EOF) {
		/*first end of stream, evaluate duration*/
		if (!codec->odm->duration) ODM_SetDuration(codec->odm, ch, codec->odm->current_time);
		Channel_EndOfStream(ch);
		return M4OK;
	}
	return e;
}
Beispiel #3
0
M4Err SystemCodec_Process(GenericCodec *codec, u32 TimeAvailable)
{
	LPAUBUFFER AU;
	Channel *ch;
	u32 now, obj_time;
	Bool scene_locked, invalidate_scene;
	Bool check_next_unit;
	SceneDecoder *sdec = (SceneDecoder *)codec->decio;
	M4Err e = M4OK;

	scene_locked = 0;
	invalidate_scene = 0;
	
	/*for resync, if needed - the logic behind this is that there is no composition memory on sytems codecs so
	"frame dropping" is done by preventing the renderer from redrawing after an update and decoding following AU
	so that the renderer is always woken up once all late systems AUs are decoded. This flag is overriden when 
	seeking*/
	check_next_unit = codec->odm->term->bifs_can_resync;
	
check_unit:

	/*muting systems codec means we don't decode until mute is off - likely there will be visible however
	there is no other way to decode system AUs without modifying the content, which is what mute is about on visual...*/
	if (codec->Muted) goto exit;

	/*fetch next AU in DTS order for this codec*/
	Decoder_GetNextAU(codec, &ch, &AU);

	/*get the object time*/
	obj_time = CK_GetTime(codec->ck);

	/*no active channel return*/
	if (!AU || !ch) {
		/*if the codec is in EOS state, move to STOP*/
		if (codec->Status == CODEC_EOS) {
			CapObject cap;
			cap.CapCode = CAP_MEDIA_NOT_OVER;
			cap.cap.valueINT = 0;
			sdec->GetCapabilities(codec->decio, &cap);
			if (!cap.cap.valueINT) MM_StopCodec(codec);
		}
		goto exit;
	}
	

	/*clock is not started*/
	if (ch->first_au_fetched && !CK_IsStarted(ch->clock)) goto exit;

	/*check timing based on the input channel and main FPS*/
	if ( (AU->DTS > obj_time + codec->odm->term->half_frame_duration) ) goto exit;

	/*check seeking and update timing - do NOT use the base layer, since BIFS streams may depend on other 
	streams not on the same clock*/
	if (codec->last_unit_cts == AU->CTS ) {
		/*hack for RTSP streaming of systems streams, except InputSensor*/
		if (!ch->is_pulling && (codec->type != M4ST_INTERACT) && (AU->dataLength == codec->prev_au_size)) {
			Channel_DropAU(ch);
			goto check_unit;
		}
		/*seeking for systems is done by not releasing the graph until seek is done*/
		check_next_unit = 1;
	} 
	/*set system stream timing*/
	else {
		codec->last_unit_cts = AU->CTS;
	}

	/*lock scene*/
	if (!scene_locked) {
		Term_LockScene(codec->odm->term, 1);
		scene_locked = 1;
	}

	/*current media time for system objects is the clock time, since the media is likely to have random 
	updates in time*/
	codec->odm->current_time = CK_GetTime(codec->ck);

	now = Term_GetTime(codec->odm->term);
	e = sdec->ProcessData(sdec, (unsigned char *) AU->data, AU->dataLength, ch->esd->ESID, codec->odm->current_time, MM_LEVEL_NORMAL);
	now = Term_GetTime(codec->odm->term) - now;

	codec_update_stats(codec, AU->dataLength, now);
	codec->prev_au_size = AU->dataLength;

	/*destroy this AU*/
	Channel_DropAU(ch);

	if (e) goto exit;
	/*dynamic OD stream, regenerate scene*/
	if (codec->flags & COD_IS_STATIC_OD) IS_RegenerateScene(codec->odm->subscene ? codec->odm->subscene : codec->odm->parentscene);

	/*always force redraw for system codecs*/
	invalidate_scene = 1;

	/*if no release restart*/
	if (check_next_unit) goto check_unit;
	
exit:
	if (scene_locked) Term_LockScene(codec->odm->term, 0);
	if (invalidate_scene) Term_InvalidateScene(codec->odm->term);
	return e;
}
Beispiel #4
0
static GF_Err MediaCodec_Process(GF_Codec *codec, u32 TimeAvailable)
{
	GF_CMUnit *CU;
	GF_DBUnit *AU;
	GF_Channel *ch, *prev_ch;
	u32 mmlevel, cts;
	u32 first, entryTime, now, obj_time, unit_size;
	GF_MediaDecoder *mdec = (GF_MediaDecoder*)codec->decio;
	GF_Err e = GF_OK;
	CU = NULL;

	/*if video codec muted don't decode (try to saves ressources)
	if audio codec muted we dispatch to keep sync in place*/
	if (codec->Muted && (codec->type==GF_STREAM_VISUAL) ) return GF_OK;

	entryTime = gf_term_get_time(codec->odm->term);

	/*fetch next AU in DTS order for this codec*/
	Decoder_GetNextAU(codec, &ch, &AU);
	/*no active channel return*/
	if (!AU || !ch) {
		/*if the codec is in EOS state, assume we're done*/
		if (codec->Status == GF_ESM_CODEC_EOS) {
			/*if codec is reordering, try to flush it*/
			if (codec->is_reordering) {
				if ( LockCompositionUnit(codec, codec->last_unit_cts+1, &CU, &unit_size) == GF_OUT_OF_MEM)
					return GF_OK;
				assert( CU );
				e = mdec->ProcessData(mdec, NULL, 0, 0, CU->data, &unit_size, 0, 0);
				if (e==GF_OK) e = UnlockCompositionUnit(codec, CU, unit_size);
			}
			gf_term_stop_codec(codec);
			if (codec->CB) gf_cm_set_eos(codec->CB);
		}
		/*if no data, and channel not buffering, ABORT CB buffer (data timeout or EOS not detectable)*/
		else if (ch && !ch->BufferOn)
			gf_cm_abort_buffering(codec->CB);
		return GF_OK;
	}

	/*get the object time*/
	obj_time = gf_clock_time(codec->ck);
	/*Media Time for media codecs is updated in the CB*/

	if (!codec->CB) {
		gf_es_drop_au(ch);
		return GF_BAD_PARAM;
	}

	/*image codecs*/
	if (codec->CB->Capacity == 1) {
		/*usually only one image is tolerated in the stream, but just in case force reset of CB*/
		if (codec->CB->UnitCount && (obj_time>=AU->CTS)) {
			gf_mx_p(codec->odm->mx);
			codec->CB->output->dataLength = 0;
			codec->CB->UnitCount = 0;
			gf_mx_v(codec->odm->mx);
		}

		/*CB is already full*/
		if (codec->CB->UnitCount)
			return GF_OK;

		/*a SHA signature is computed for each AU. This avoids decoding/recompositing when identical (for instance streaming a carousel)*/
		{
			u8 new_unit_signature[20];
			gf_sha1_csum(AU->data, AU->dataLength, new_unit_signature);
			if (!memcmp(codec->last_unit_signature, new_unit_signature, sizeof(new_unit_signature))) {
				codec->nb_repeted_frames++;
				gf_es_drop_au(ch);
				return GF_OK;
			}
			codec->nb_repeted_frames = 0;
			memcpy(codec->last_unit_signature, new_unit_signature, sizeof(new_unit_signature));
		}
	}

	/*try to refill the full buffer*/
	first = 1;
	while (codec->CB->Capacity > codec->CB->UnitCount) {
	/*set media processing level*/
		mmlevel = GF_CODEC_LEVEL_NORMAL;
		/*SEEK: if the last frame had the same TS, we are seeking. Ask the codec to drop*/
		if (!ch->skip_sl && codec->last_unit_cts && (codec->last_unit_cts == AU->CTS) && !ch->esd->dependsOnESID) {
			mmlevel = GF_CODEC_LEVEL_SEEK;
			/*object clock is paused by media control or terminal is paused: exact frame seek*/
			if (
#ifndef GPAC_DISABLE_VRML
				(codec->ck->mc && codec->ck->mc->paused) || 
#endif
				(codec->odm->term->play_state)
			) {
				gf_cm_rewind_input(codec->CB);
				mmlevel = GF_CODEC_LEVEL_NORMAL;
				/*force staying in step-mode*/
				codec->odm->term->compositor->step_mode=1;
			}
		}
		/*only perform drop in normal playback*/
		else if (codec->CB->Status == CB_PLAY) {
			/*extremely late, set the level to drop
			 NOTE: the 100 ms safety gard is to avoid discarding audio*/
			if (!ch->skip_sl && (AU->CTS + 100 < obj_time) ) {
				mmlevel = GF_CODEC_LEVEL_DROP;
				GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d: frame too late (%d vs %d) - using drop level\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, AU->CTS, obj_time));

				if (ch->resync_drift && (AU->CTS + ch->resync_drift < obj_time)) {
					ch->clock->StartTime += (obj_time - AU->CTS);
					GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[%s] ODM%d: decoder too slow on OCR stream - rewinding clock of %d ms\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, obj_time - AU->CTS));
					obj_time = gf_clock_time(codec->ck);
				}
			}
			/*we are late according to the media manager*/
			else if (codec->PriorityBoost) {
				mmlevel = GF_CODEC_LEVEL_VERY_LATE;
			}
			/*otherwise we must have an idea of the load in order to set the right level
			use the composition buffer for that, only on the first frame*/
			else if (first) {
				//if the CB is almost empty set to very late
				if (codec->CB->UnitCount <= codec->CB->Min+1) {
					mmlevel = GF_CODEC_LEVEL_VERY_LATE;
				} else if (codec->CB->UnitCount * 2 <= codec->CB->Capacity) {
					mmlevel = GF_CODEC_LEVEL_LATE;
				}
				first = 0;
			}
		}

		/*when using temporal scalability make sure we can decode*/
		if (ch->esd->dependsOnESID && (codec->last_unit_dts > AU->DTS)){
//			printf("SCALABLE STREAM DEAD!!\n");
			goto drop;
		}

		if (ch->skip_sl) {
			if (codec->bytes_per_sec) {
				AU->CTS = codec->last_unit_cts + ch->ts_offset + codec->cur_audio_bytes * 1000 / codec->bytes_per_sec;
			} else if (codec->fps) {
				AU->CTS = codec->last_unit_cts + ch->ts_offset + (u32) (codec->cur_video_frames * 1000 / codec->fps);
			}
		}
		if ( LockCompositionUnit(codec, AU->CTS, &CU, &unit_size) == GF_OUT_OF_MEM)
			return GF_OK;

scalable_retry:

		now = gf_term_get_time(codec->odm->term);

		assert( CU );
		if (!CU->data && unit_size)
			e = GF_OUT_OF_MEM;
		else
			e = mdec->ProcessData(mdec, AU->data, AU->dataLength, ch->esd->ESID, CU->data, &unit_size, AU->PaddingBits, mmlevel);
		now = gf_term_get_time(codec->odm->term) - now;
		if (codec->Status == GF_ESM_CODEC_STOP) return GF_OK;

		/*input is too small, resize composition memory*/
		switch (e) {
		case GF_BUFFER_TOO_SMALL:
			/*release but no dispatch*/
			UnlockCompositionUnit(codec, CU, 0);
			ResizeCompositionBuffer(codec, unit_size);
			continue;

		/*this happens a lot when using non-MPEG-4 streams (ex: ffmpeg demuxer)*/
		case GF_PACKED_FRAMES:
			/*in seek don't dispatch any output*/
			if (mmlevel	== GF_CODEC_LEVEL_SEEK)
				unit_size = 0;
			e = UnlockCompositionUnit(codec, CU, unit_size);

			GF_LOG(GF_LOG_DEBUG, GF_LOG_RTI|GF_LOG_CODEC, ("[%s] ODM%d at %d decoded packed frame TS %d in %d ms\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, gf_clock_real_time(ch->clock), AU->CTS, now));
			if (ch->skip_sl) {
				if (codec->bytes_per_sec) {
					codec->cur_audio_bytes += unit_size;
				} else if (codec->fps && unit_size) {
					codec->cur_video_frames += 1;
				}
			} else {
				u32 deltaTS = 0;
				if (codec->bytes_per_sec) {
					deltaTS = unit_size * 1000 / codec->bytes_per_sec;
				} /*else if (0 && codec->fps && unit_size) {
					deltaTS = (u32) (1000.0f / codec->fps);
				} */else {
					deltaTS = (AU->DTS - codec->last_unit_dts);
				}
				AU->CTS += deltaTS;
			}
			codec_update_stats(codec, 0, now);
			continue;

		/*for all cases below, don't release the composition buffer until we are sure we are not
		processing a scalable stream*/
		case GF_OK:
			if (unit_size) {
				GF_LOG(GF_LOG_DEBUG, GF_LOG_RTI|GF_LOG_CODEC, ("[%s] ODM%d at %d decoded frame TS %d in %d ms (DTS %d) - %d in CB\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, gf_clock_real_time(ch->clock), AU->CTS, now, AU->DTS, codec->CB->UnitCount + 1));
			}
			/*if no size the decoder is not using the composition memory - if the object is in intitial buffering resume it!!*/
			else if (codec->CB->Status == CB_BUFFER) {
				gf_cm_abort_buffering(codec->CB);
			}

			codec_update_stats(codec, AU->dataLength, now);
			if (ch->skip_sl) {
				if (codec->bytes_per_sec) {
					codec->cur_audio_bytes += unit_size;
					while (codec->cur_audio_bytes>codec->bytes_per_sec) {
						codec->cur_audio_bytes -= codec->bytes_per_sec;
						codec->last_unit_cts += 1000;
					}
				} else if (codec->fps && unit_size) {
					codec->cur_video_frames += 1;
				}
			}
#ifndef GPAC_DISABLE_LOGS
			if (codec->odm->flags & GF_ODM_PREFETCH) {
				GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] ODM%d At %d decoding frame TS %d in prefetch mode\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, gf_clock_real_time(ch->clock) ));
			}
#endif
			break;
		default:
			unit_size = 0;
			/*error - if the object is in intitial buffering resume it!!*/
			gf_cm_abort_buffering(codec->CB);
			GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d At %d (frame TS %d - %d ms ): decoded error %s\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, gf_clock_real_time(ch->clock), AU->CTS, now, gf_error_to_string(e) ));
			e = GF_OK;
			break;
		}

		codec->last_unit_dts = AU->DTS;
		/*remember base layer timing*/
		if (!ch->esd->dependsOnESID && !ch->skip_sl) codec->last_unit_cts = AU->CTS;


drop:
		/*store current CTS*/
		cts = AU->CTS;
		prev_ch = ch;

		gf_es_drop_au(ch);
		AU = NULL;

		if (e) {
			UnlockCompositionUnit(codec, CU, unit_size);
			return e;
		}

		Decoder_GetNextAU(codec, &ch, &AU);
		/*same CTS: same output, likely scalable stream so don't release the CB*/
		if (AU && (AU->CTS == cts) && (ch !=prev_ch) ) {
			unit_size = codec->CB->UnitSize;
			goto scalable_retry;
		}

		/*in seek don't dispatch any output*/
		if (mmlevel	== GF_CODEC_LEVEL_SEEK)
			unit_size = 0;

		UnlockCompositionUnit(codec, CU, unit_size);
		if (!ch || !AU) return GF_OK;

		/*escape from decoding loop only if above critical limit - this is to avoid starvation on audio*/
		if (!ch->esd->dependsOnESID && (codec->CB->UnitCount > codec->CB->Min)) {
			now = gf_term_get_time(codec->odm->term);
			if (now - entryTime >= TimeAvailable) {
				return GF_OK;
			}
		}
		Decoder_GetNextAU(codec, &ch, &AU);
		if (!ch || !AU) return GF_OK;
	}
	return GF_OK;
}
Beispiel #5
0
/*special handling of decoders not using ESM*/
static GF_Err PrivateScene_Process(GF_Codec *codec, u32 TimeAvailable)
{
	Bool resume_clock;
	u32 now;
	GF_Channel *ch;
	GF_Scene *scene_locked;
	GF_SceneDecoder *sdec = (GF_SceneDecoder *)codec->decio;
	GF_Err e = GF_OK;

	/*muting systems codec means we don't decode until mute is off - likely there will be visible however
	there is no other way to decode system AUs without modifying the content, which is what mute is about on visual...*/
	if (codec->Muted) return GF_OK;

	if (codec->Status == GF_ESM_CODEC_EOS) {
		gf_term_stop_codec(codec);
		return GF_OK;
	}

	scene_locked = codec->odm->subscene ? codec->odm->subscene : codec->odm->parentscene;

	ch = (GF_Channel*)gf_list_get(codec->inChannels, 0);
	if (!ch) return GF_OK;
	resume_clock = 0;
	/*init channel clock*/
	if (!ch->IsClockInit) {
		Bool started;
		/*signal seek*/
		if (!gf_mx_try_lock(scene_locked->root_od->term->compositor->mx)) return GF_OK;
		gf_es_init_dummy(ch);

		sdec->ProcessData(sdec, NULL, 0, ch->esd->ESID, -1, GF_CODEC_LEVEL_NORMAL);
		gf_mx_v(scene_locked->root_od->term->compositor->mx);
		started = gf_clock_is_started(ch->clock);
		/*let's be nice to the scene loader (that usually involves quite some parsing), pause clock while
		parsing*/
		gf_clock_pause(ch->clock);
		codec->last_unit_dts = 0;
		if (!started) return GF_OK;
	}

	codec->odm->current_time = codec->last_unit_cts = gf_clock_time(codec->ck);

	/*lock scene*/
	GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[PrivateDec] Codec %s Processing at %d\n", sdec->module_name , codec->odm->current_time));

	if (!gf_mx_try_lock(scene_locked->root_od->term->compositor->mx)) return GF_OK;
	now = gf_term_get_time(codec->odm->term);
	e = sdec->ProcessData(sdec, NULL, 0, ch->esd->ESID, codec->odm->current_time, GF_CODEC_LEVEL_NORMAL);
	now = gf_term_get_time(codec->odm->term) - now;
	codec->last_unit_dts ++;
	/*resume on error*/
	if (e && (codec->last_unit_dts<2) ) {
		gf_clock_resume(ch->clock);
		codec->last_unit_dts = 2;
	}
	/*resume clock on 2nd decode (we assume parsing is done in 2 steps, one for first frame display, one for complete parse)*/
	else if (codec->last_unit_dts==2) {
		gf_clock_resume(ch->clock);
	}

	codec_update_stats(codec, 0, now);

	gf_mx_v(scene_locked->root_od->term->compositor->mx);

	if (e==GF_EOS) {
		/*first end of stream, evaluate duration*/
		//if (!codec->odm->duration) gf_odm_set_duration(codec->odm, ch, codec->odm->current_time);
		gf_es_on_eos(ch);
		return GF_OK;
	}
	return e;
}
Beispiel #6
0
static GF_Err SystemCodec_Process(GF_Codec *codec, u32 TimeAvailable)
{
	GF_DBUnit *AU;
	GF_Channel *ch;
	u32 now, obj_time, mm_level, au_time, cts;
	GF_Scene *scene_locked;
	Bool check_next_unit;
	GF_SceneDecoder *sdec = (GF_SceneDecoder *)codec->decio;
	GF_Err e = GF_OK;

	scene_locked = NULL;

	/*for resync, if needed - the logic behind this is that there is no composition memory on sytems codecs so
	"frame dropping" is done by preventing the compositor from redrawing after an update and decoding following AU
	so that the compositor is always woken up once all late systems AUs are decoded. This flag is overriden when
	seeking*/
	check_next_unit = (codec->odm->term->flags & GF_TERM_SYSDEC_RESYNC) ? 1 : 0;

check_unit:

	/*muting systems codec means we don't decode until mute is off - likely there will be visible however
	there is no other way to decode system AUs without modifying the content, which is what mute is about on visual...*/
	if (codec->Muted) goto exit;

	/*fetch next AU in DTS order for this codec*/
	Decoder_GetNextAU(codec, &ch, &AU);

	/*no active channel return*/
	if (!AU || !ch) {
		/*if the codec is in EOS state, move to STOP*/
		if (codec->Status == GF_ESM_CODEC_EOS) {
			GF_CodecCapability cap;
			cap.CapCode = GF_CODEC_MEDIA_NOT_OVER;
			cap.cap.valueInt = 0;
			sdec->GetCapabilities(codec->decio, &cap);
			if (!cap.cap.valueInt) {
				gf_term_stop_codec(codec);
				if ((codec->type==GF_STREAM_OD) && (codec->nb_dec_frames==1)) {
					/*this is just by safety, since seeking is only allowed when a single clock is present
					in the scene*/
					if (gf_list_count(codec->odm->net_service->Clocks)==1)
						codec->odm->subscene->static_media_ressources=1;
				}
			}
		}
		goto exit;
	}

#ifndef GPAC_DISABLE_VRML
	if (ch && ch->odm->media_ctrl && !ch->odm->media_ctrl->media_speed)
		goto exit;
#endif

	/*get the object time*/
	obj_time = gf_clock_time(codec->ck);

	/*clock is not started*/
//	if (ch->first_au_fetched && !gf_clock_is_started(ch->clock)) goto exit;

	/*check timing based on the input channel and main FPS*/
	if (AU->DTS > obj_time /*+ codec->odm->term->half_frame_duration*/) goto exit;

	cts = AU->CTS;
	/*in cases where no CTS was set for the BIFS (which may be interpreted as "now", although not compliant), use the object clock*/
	if (AU->flags & GF_DB_AU_NO_TIMESTAMPS) au_time = obj_time;
	/*case where CTS is in the past (carousels) */
	else if (AU->flags & GF_DB_AU_CTS_IN_PAST) {
		au_time = - (s32) AU->CTS;
		cts = AU->DTS;
	}
	/*regular case, SFTime will be from CTS (since DTS == CTS)*/
	else au_time = AU->DTS;

	/*check seeking and update timing - do NOT use the base layer, since BIFS streams may depend on other
	streams not on the same clock*/
	if (codec->last_unit_cts == cts) {
		/*seeking for systems is done by not releasing the graph until seek is done*/
		check_next_unit = 1;
		mm_level = GF_CODEC_LEVEL_SEEK;

	}
	/*set system stream timing*/
	else {
		codec->last_unit_cts = AU->CTS;
		/*we're droping the frame*/
		if (scene_locked) codec->nb_droped ++;
		mm_level = GF_CODEC_LEVEL_NORMAL;
	}

	/*lock scene*/
	if (!scene_locked) {
		scene_locked = codec->odm->subscene ? codec->odm->subscene : codec->odm->parentscene;
		if (!gf_mx_try_lock(scene_locked->root_od->term->compositor->mx)) 
			return GF_OK;
		/*if terminal is paused, force step-mode: it won't hurt in regular pause/play and ensures proper frame dumping*/
		if (codec->odm->term->play_state) codec->odm->term->compositor->step_mode=1;
	}

	/*current media time for system objects is the clock time, since the media is likely to have random
	updates in time*/
	codec->odm->current_time = gf_clock_time(codec->ck);

	now = gf_term_get_time(codec->odm->term);
	e = sdec->ProcessData(sdec, AU->data, AU->dataLength, ch->esd->ESID, au_time, mm_level);
	now = gf_term_get_time(codec->odm->term) - now;

	GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d#CH%d at %d decoded AU TS %d in %d ms\n", sdec->module_name, codec->odm->OD->objectDescriptorID, ch->esd->ESID, codec->odm->current_time, AU->CTS, now));

	codec_update_stats(codec, AU->dataLength, now);
	codec->prev_au_size = AU->dataLength;

	/*destroy this AU*/
	gf_es_drop_au(ch);

	if (e) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[SysDec] Codec %s AU CTS %d Decode error %s\n", sdec->module_name , cts, gf_error_to_string(e) ));
		if (e<0) ch->stream_state = 2;
		goto exit;
	}

	/*in broadcast mode, generate a scene if none is available*/
	if (codec->ck->no_time_ctrl) {
		GF_Scene *scene = codec->odm->subscene ? codec->odm->subscene : codec->odm->parentscene;

		/*static OD resources (embedded in ESD) in broadcast mode, reset time*/
		if (codec->flags & GF_ESM_CODEC_IS_STATIC_OD) gf_clock_reset(codec->ck);
		/*generate a temp scene if none is in place*/
		if (scene->graph_attached != 1) {
			Bool prev_dyn = scene->is_dynamic_scene;
			scene->is_dynamic_scene = 1;
			gf_scene_regenerate(scene);
			scene->graph_attached = 2;
			scene->is_dynamic_scene = prev_dyn;
			GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[Decoder] Got OD resources before scene - generating temporary scene\n"));
		}
	}

	/*if no release restart*/
	if (check_next_unit) goto check_unit;

exit:
	if (scene_locked) {
		gf_mx_v(scene_locked->root_od->term->compositor->mx);
	}
	return e;
}