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

📄 media_memory.c

📁 一个用于智能手机的多媒体库适合S60 WinCE的跨平台开发库
💻 C
字号:
/* *			GPAC - Multimedia Framework C SDK * *			Copyright (c) Jean Le Feuvre 2000-2005 *					All rights reserved * *  This file is part of GPAC / Media terminal 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/terminal_dev.h>#include <gpac/constants.h>#include "media_memory.h"#include "media_control.h"#define NO_TEMPORAL_SCALABLE	1GF_DBUnit *gf_db_unit_new(){	GF_DBUnit *tmp;	GF_SAFEALLOC(tmp, GF_DBUnit)	return tmp;}void gf_db_unit_del(GF_DBUnit *db){	if (!db) return;	if (db->next) gf_db_unit_del(db->next);	if (db->data) free(db->data);	free(db);}static GF_CMUnit *gf_cm_unit_new(){	GF_CMUnit *tmp;	GF_SAFEALLOC(tmp, GF_CMUnit)	return tmp;}static void gf_cm_unit_del(GF_CMUnit *cb){	if (cb->next) gf_cm_unit_del(cb->next);	cb->next = NULL;	if (cb->data) {		free(cb->data);		cb->data = NULL;	}	free(cb);}GF_CompositionMemory *gf_cm_new(u32 UnitSize, u32 capacity){	GF_CompositionMemory *tmp;	GF_CMUnit *cu, *prev;	u32 i;	if (!capacity) return NULL;		GF_SAFEALLOC(tmp, GF_CompositionMemory)	tmp->Capacity = capacity;	tmp->UnitSize = UnitSize;	prev = NULL;	i = 1;	while (capacity) {		cu = gf_cm_unit_new();		if (!prev) {			tmp->input = cu;		} else {			prev->next = cu;			cu->prev = prev;		}		cu->dataLength = 0;		cu->data = UnitSize ? (char*)malloc(sizeof(char)*UnitSize) : NULL;		prev = cu;		capacity --;		i++;	}	cu->next = tmp->input;	tmp->input->prev = cu;	/*close the loop. The output is the input as the first item 	that will be ready for composition will be filled in the input*/	tmp->output = tmp->input;	tmp->Status = CB_STOP;	return tmp;}void gf_cm_del(GF_CompositionMemory *cb){	gf_odm_lock(cb->odm, 1);	/*may happen when CB is destroyed right after creation in case*/	if (cb->Status == CB_BUFFER) {		gf_clock_buffer_off(cb->odm->codec->ck);		GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ODM%d: buffering off at %d (nb buffering on clock: %d)\n", cb->odm->OD->objectDescriptorID, gf_term_get_time(cb->odm->term), cb->odm->codec->ck->Buffering));	}		/*break the loop and destroy*/	cb->input->prev->next = NULL;	gf_cm_unit_del(cb->input);	gf_odm_lock(cb->odm, 0);	free(cb);}void gf_cm_rewind_input(GF_CompositionMemory *cb){	if (cb->UnitCount) {		cb->UnitCount--;		cb->input = cb->input->prev;		cb->input->dataLength = 0; 	}}/*access to the input buffer - return NULL if no input is available (buffer full)*/GF_CMUnit *gf_cm_lock_input(GF_CompositionMemory *cb, u32 TS){#if NO_TEMPORAL_SCALABLE	/*there is still something in the input buffer*/	if (cb->input->dataLength) {		if (cb->input->TS==TS) return cb->input;		return NULL;	}	return cb->input;#else		GF_CMUnit *cu;	/*spatial scalable, go backward to fetch same TS*/	cu = cb->input;	while (1) {		if (cu->TS == TS) return cu;		cu = cu->prev;		if (cu == cb->input) break;	}	/*temporal scalable (find empty slot)*/	cu = cb->input;	while (1) {		if (!cu->dataLength) return cu;		cu = cu->next;		if (cu == cb->input) return NULL;	}	return NULL;#endif}/*re-orders units in case of temporal scalability. Blocking call as it may change the output unit too*/static GF_CMUnit *LocateAndOrderUnit(GF_CompositionMemory *cb, u32 TS){	GF_CMUnit *unit;#if NO_TEMPORAL_SCALABLE	unit = cb->input;	cb->input = cb->input->next;	return unit;#else	GF_CMUnit *cu;	/*lock the buffer since we may move pointers*/	gf_cm_lock(cb, 1);	unit = NULL;	/*1- locate cu*/	cu = cb->input;	while (1) {		if (cu->TS == TS) break;		cu = cu->next;		/*done (should never happen)*/		if (cu == cb->input) goto exit;	}	unit = cu;	/*2- spatial scalability or input is our unit, no reordering*/	if (cu->dataLength || (cb->input->TS == TS) ) goto exit;	/*3- unit is next on time axis (no temporal scalability)*/	if (!cb->input->dataLength || cb->input->TS < TS) {		/*remove unit from the list*/		unit->prev->next = unit->next;		unit->next->prev = unit->prev;		/*insert unit after input*/		unit->prev = cb->input;		unit->next = cb->input->next;		unit->next->prev = unit;		unit->prev->next = unit;		/*set input to our unit*/		cb->input = unit;		goto exit;	}	/*4- unit is before our last delivered input - temporal scalability*/	cu = cb->input;	while (1) {		if (cu->TS > unit->TS) {			/*we have a unit after this one that has been consumed - discard our unit*/			if (!cu->dataLength) {				unit = NULL;				goto exit;			}			/*previous unit is the active one - check one further*/			if (cu->prev == unit) {				if (!unit->prev->dataLength || (unit->prev->TS < unit->TS)) 					break;			} 			/*no previous unit or our unit is just after the previous unit*/			else if (!cu->prev->dataLength || (cu->prev->TS < unit->TS)) {				break;			}			/*otherwise need to go one further*/		}		/*go on*/		cu = cu->prev;		/*done (should never happen)*/		if (cu == cb->input) goto exit;	}		/*remove unit from the list*/	unit->prev->next = unit->next;	unit->next->prev = unit->prev;	/*insert active before cu*/	unit->next = cu;	unit->prev = cu->prev;	unit->next->prev = unit;	unit->prev->next = unit;	exit:	/*perform sanity check on output ordering*/	if (unit) {		/*if no more output reset to our min*/		if (!cb->output->dataLength) {			cb->output = cb->input;			while (1) {				if (!cb->output->prev->dataLength) break;				cb->output = cb->output->prev;			}		}		/*otherwise we just inserted a CU that should be the next one to be consumed*/		else if (cb->output->TS > unit->TS) {			cb->output = unit;		}	}	/*unlock the buffer*/	gf_cm_lock(cb, 0);	return unit;#endif}void gf_cm_unlock_input(GF_CompositionMemory *cb, u32 TS, u32 NbBytes){	GF_CMUnit *cu;	/*nothing dispatched, ignore*/	if (!NbBytes) return;	gf_odm_lock(cb->odm, 1);	/*insert/swap this CU*/	cu = LocateAndOrderUnit(cb, TS);	if (cu) {		/*if the CU already has data, this is spatial scalability so same num buffers*/		if (!cu->dataLength) cb->UnitCount += 1;		cu->dataLength = NbBytes;		cu->RenderedLength = 0;		/*turn off buffering - this must be done now rather than when fetching first output frame since we're not 		sure output is fetched (Switch node, ...)*/		if ( (cb->Status == CB_BUFFER) && (cb->UnitCount >= cb->Capacity) ) {			/*done with buffering, signal to the clock (ONLY ONCE !)*/			cb->Status = CB_BUFFER_DONE;			gf_clock_buffer_off(cb->odm->codec->ck);			GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ODM%d: buffering off at %d (nb buffering on clock: %d)\n", cb->odm->OD->objectDescriptorID, gf_term_get_time(cb->odm->term), cb->odm->codec->ck->Buffering));		} 		/*since a new CU is here notify the renderer*/		if ((cb->odm->codec->type==GF_STREAM_VISUAL) && cb->odm->mo && cb->odm->mo->num_open) {			gf_term_invalidate_renderer(cb->odm->term);		}	}	gf_odm_lock(cb->odm, 0);}/*Reset composition memory. Note we don't reset the content of each frame since it would lead to green frames when using bitmap (visual), where data is not cached*/void gf_cm_reset(GF_CompositionMemory *cb){	GF_CMUnit *cu;	gf_odm_lock(cb->odm, 1);	cu = cb->input;	cu->RenderedLength = 0;	cu->dataLength = 0;	cu->TS = 0;	cu = cu->next;	while (cu != cb->input) {		cu->RenderedLength = 0;		cu->TS = 0;		cu->dataLength = 0;		cu = cu->next;	}	cb->output = cb->input;	cb->UnitCount = 0;	cb->HasSeenEOS = 0;	if (cb->odm->mo) cb->odm->mo->timestamp = 0;	gf_odm_lock(cb->odm, 0);}/*resize buffers (blocking)*/void gf_cm_resize(GF_CompositionMemory *cb, u32 newCapacity){	GF_CMUnit *cu;	if (!newCapacity) return;	/*lock buffer*/	gf_odm_lock(cb->odm, 1);	cu = cb->input;	cb->UnitSize = newCapacity;	/*don't touch any existing memory (it may happen on the fly with audio)*/	cu->data = (char*)realloc(cu->data, sizeof(char)*newCapacity);	cu = cu->next;	while (cu != cb->input) {		cu->data = (char*)realloc(cu->data, sizeof(char)*newCapacity);		cu = cu->next;	}	gf_odm_lock(cb->odm, 0);}/*resize buffers (blocking)*/void gf_cm_reinit(GF_CompositionMemory *cb, u32 UnitSize, u32 Capacity){	GF_CMUnit *cu, *prev;	u32 i;	if (!Capacity || !UnitSize) return;	gf_odm_lock(cb->odm, 1);	/*break the loop and destroy*/	cb->input->prev->next = NULL;	gf_cm_unit_del(cb->input);	cu = NULL;	cb->Capacity = Capacity;	cb->UnitSize = UnitSize;	prev = NULL;	i = 1;	while (Capacity) {		cu = gf_cm_unit_new();		if (!prev) {			cb->input = cu;		} else {			prev->next = cu;			cu->prev = prev;		}		cu->dataLength = 0;		cu->data = (char*)malloc(sizeof(char)*UnitSize);		prev = cu;		Capacity --;		i++;	}	cu->next = cb->input;	cb->input->prev = cu;	cb->output = cb->input;	gf_odm_lock(cb->odm, 0);}/*access to the first available CU for renderingthis is a blocking call since input may change the output (temporal scalability)*/GF_CMUnit *gf_cm_get_output(GF_CompositionMemory *cb){	GF_CMUnit *out = NULL;	/*if paused or stop or buffering, do nothing*/	switch (cb->Status) {	case CB_BUFFER:		return NULL;	case CB_STOP:	case CB_PAUSE:		/*only visual buffers deliver data when paused*/		if (cb->odm->codec->type != GF_STREAM_VISUAL) goto exit;		break;	}	/*no output*/	if (!cb->output->dataLength) {		if ((cb->Status != CB_STOP) && cb->HasSeenEOS && (cb->odm && cb->odm->codec)) {			GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[ODM%d] Switching composition memory to stop state - time %d\n", cb->odm->OD->objectDescriptorID, (u32) cb->odm->media_stop_time));			cb->Status = CB_STOP;			cb->odm->current_time = (u32) cb->odm->media_stop_time;			/*force update of media time*/			MS_UpdateTiming(cb->odm, 1);		}		goto exit;	}	/*update the timing*/	if ((cb->Status != CB_STOP) && cb->odm && cb->odm->codec) {		cb->odm->current_time = cb->output->TS;		/*handle visual object - EOS if no more data (we keep the last CU for rendering, so check next one)*/		if (cb->HasSeenEOS && (!cb->output->next->dataLength || (cb->Capacity==1))) {			GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[ODM%d] Switching composition memory to stop state - time %d\n", cb->odm->OD->objectDescriptorID, (u32) cb->odm->media_stop_time));			cb->Status = CB_STOP;			cb->odm->current_time = (u32) cb->odm->media_stop_time;			/*force update of media time*/			MS_UpdateTiming(cb->odm, 1);		}	}	out = cb->output;exit:	return out;}/*drop the output CU*/void gf_cm_drop_output(GF_CompositionMemory *cb){	assert(cb->UnitCount);	/*this allows reuse of the CU*/	cb->output->RenderedLength = 0;	cb->LastRenderedTS = cb->output->TS;	/*on visual streams, always keep the last AU*/	if (cb->output->dataLength && (cb->odm->codec->type == GF_STREAM_VISUAL) ) {		if ( !cb->output->next->dataLength || (cb->Capacity == 1) )  {			return;		}	}		/*reset the output*/	cb->output->dataLength = 0;	cb->output = cb->output->next;	cb->UnitCount -= 1;	if (!cb->HasSeenEOS && cb->UnitCount <= cb->Min) {		cb->odm->codec->PriorityBoost = 1;	}}void gf_cm_set_status(GF_CompositionMemory *cb, u32 Status){	gf_odm_lock(cb->odm, 1);	/*if we're asked for play, trigger on buffering*/	if (Status == CB_PLAY) {		switch (cb->Status) {		case CB_STOP:			cb->Status = CB_BUFFER;			gf_clock_buffer_on(cb->odm->codec->ck);			break;		case CB_PAUSE:			cb->Status = CB_PLAY;			break;		/*this should never happen (calling play while already buffering ...)*/		case CB_BUFFER:			cb->LastRenderedTS = 0;			break;		default:			cb->Status = Status;			break;		}	} else {		cb->LastRenderedTS = 0;		if (cb->Status == CB_BUFFER) {			gf_clock_buffer_off(cb->odm->codec->ck);			GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ODM%d: buffering off at %d (nb buffering on clock: %d)\n", cb->odm->OD->objectDescriptorID, gf_term_get_time(cb->odm->term), cb->odm->codec->ck->Buffering));		}		if (Status == CB_STOP) {			gf_cm_reset(cb);		}		cb->Status = Status;	}	gf_odm_lock(cb->odm, 0);}void gf_cm_set_eos(GF_CompositionMemory *cb){	gf_odm_lock(cb->odm, 1);	/*we may have a pb if the stream is so short that the EOS is signaled 	while we're buffering. In this case we shall turn the clock on and 	keep a trace of the EOS notif*/	if (cb->Status == CB_BUFFER) {		cb->Status = CB_BUFFER_DONE;		gf_clock_buffer_off(cb->odm->codec->ck);		GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ODM%d: buffering off at %d (nb buffering on clock: %d)\n", cb->odm->OD->objectDescriptorID, gf_term_get_time(cb->odm->term), cb->odm->codec->ck->Buffering));	}	cb->HasSeenEOS = 1;	gf_term_invalidate_renderer(cb->odm->term);	gf_odm_lock(cb->odm, 0);}Bool gf_cm_is_running(GF_CompositionMemory *cb){	if (cb->Status == CB_PLAY)		return !cb->odm->codec->ck->Paused;	if ((cb->Status == CB_BUFFER_DONE) && (gf_clock_is_started(cb->odm->codec->ck) || cb->odm->term->play_state) ) {		cb->Status = CB_PLAY;		return 1;	}	if ((cb->odm->codec->type == GF_STREAM_VISUAL)		&& (cb->Status == CB_STOP)		&& cb->output->dataLength) return 1;	return 0;}Bool gf_cm_is_eos(GF_CompositionMemory *cb){	return ( (cb->Status == CB_STOP) && cb->HasSeenEOS);}void gf_cm_abort_buffering(GF_CompositionMemory *cb){	if (cb->Status == CB_BUFFER) {		cb->Status = CB_BUFFER_DONE;		gf_clock_buffer_off(cb->odm->codec->ck);		GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ODM%d: buffering off at %d (nb buffering on clock: %d)\n", cb->odm->OD->objectDescriptorID, gf_term_get_time(cb->odm->term), cb->odm->codec->ck->Buffering));	}}

⌨️ 快捷键说明

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