This source file includes following definitions.
- gf_db_unit_new
- gf_db_unit_del
- gf_cm_unit_new
- my_large_alloc
- my_large_gf_free
- gf_cm_unit_del
- gf_cm_new
- gf_cm_del
- gf_cm_rewind_input
- gf_cm_lock_input
- check_temporal
- gf_cm_reorder_unit
- cb_set_buffer_off
- gf_cm_unlock_input
- gf_cm_reset
- gf_cm_reset_timing
- gf_cm_resize
- gf_cm_reinit
- gf_cm_get_output
- gf_cm_output_kept
- gf_cm_drop_output
- gf_cm_set_status
- gf_cm_set_eos
- gf_cm_is_running
- gf_cm_is_eos
- gf_cm_abort_buffering
#include <gpac/internal/terminal_dev.h>
#include <gpac/constants.h>
#include <gpac/network.h>
#include "media_memory.h"
#include "media_control.h"
GF_DBUnit *gf_db_unit_new()
{
GF_DBUnit *tmp;
GF_SAFEALLOC(tmp, GF_DBUnit)
if (tmp) memset(tmp, 0, sizeof(GF_DBUnit));
return tmp;
}
void gf_db_unit_del(GF_DBUnit *db)
{
while (db) {
GF_DBUnit *next = db->next;
if (db->data) gf_free(db->data);
gf_free(db);
db = next;
}
}
static GF_CMUnit *gf_cm_unit_new()
{
GF_CMUnit *tmp;
GF_SAFEALLOC(tmp, GF_CMUnit)
if (tmp) memset(tmp, 0, sizeof(GF_CMUnit));
return tmp;
}
#ifdef _WIN32_WCE
#include <winbase.h>
static GFINLINE void *my_large_alloc(u32 size) {
void *ptr;
if (!size) return NULL;
ptr = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (!ptr) {
DWORD res = GetLastError();
GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("Cannot resize composition buffer to %d bytes - error %d", size, res));
return NULL;
}
return ptr;
}
static GFINLINE void my_large_gf_free(void *ptr) {
if (ptr) VirtualFree(ptr, 0, MEM_RELEASE);
}
#else
#define my_large_alloc(_size) (_size ? gf_malloc(sizeof(char)*_size) : NULL)
#define my_large_gf_free(_ptr) gf_free(_ptr)
#endif
static void gf_cm_unit_del(GF_CMUnit *cb, Bool no_data_allocation)
{
if (!cb)
return;
if (cb->next) gf_cm_unit_del(cb->next, no_data_allocation);
if (cb->data) {
if (!no_data_allocation) {
my_large_gf_free(cb->data);
}
cb->data = NULL;
}
if (cb->frame) {
cb->frame->Release(cb->frame);
cb->frame=NULL;
}
gf_free(cb);
}
GF_CompositionMemory *gf_cm_new(u32 UnitSize, u32 capacity, Bool no_allocation)
{
GF_CompositionMemory *tmp;
GF_CMUnit *cu, *prev;
u32 i;
if (!capacity) return NULL;
GF_SAFEALLOC(tmp, GF_CompositionMemory)
if (!tmp) {
GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Terminal] Failed to allocate composition memory\n"));
return NULL;
}
tmp->Capacity = capacity;
tmp->UnitSize = UnitSize;
tmp->no_allocation = no_allocation;
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;
if (no_allocation) {
cu->data = NULL;
} else {
cu->data = UnitSize ? (char*)my_large_alloc(sizeof(char)*UnitSize) : NULL;
if (cu->data) memset(cu->data, 0, sizeof(char)*UnitSize);
}
prev = cu;
capacity --;
i++;
}
cu->next = tmp->input;
tmp->input->prev = cu;
tmp->output = tmp->input;
tmp->Status = CB_STOP;
return tmp;
}
void gf_cm_del(GF_CompositionMemory *cb)
{
gf_odm_lock(cb->odm, 1);
if (cb->Status == CB_BUFFER) {
gf_clock_buffer_off(cb->odm->codec->ck);
GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] CB destroy - ODM%d: buffering off at OTB %u (STB %d) (nb wait on clock: %d)\n", cb->odm->OD->objectDescriptorID, gf_clock_time(cb->odm->codec->ck), gf_term_get_time(cb->odm->term), cb->odm->codec->ck->Buffering));
}
if (cb->input) {
cb->input->prev->next = NULL;
gf_cm_unit_del(cb->input, cb->no_allocation);
cb->input = NULL;
}
gf_odm_lock(cb->odm, 0);
gf_free(cb);
}
void gf_cm_rewind_input(GF_CompositionMemory *cb)
{
if (cb->UnitCount) {
cb->UnitCount--;
cb->input = cb->input->prev;
cb->input->dataLength = 0;
}
}
GF_CMUnit *gf_cm_lock_input(GF_CompositionMemory *cb, u32 TS, Bool codec_reordering)
{
GF_CMUnit *cu;
if (codec_reordering) {
if (cb->input->dataLength) {
if (cb->input->TS==TS)
return cb->input;
return NULL;
}
cb->input->TS = TS;
return cb->input;
}
cu = cb->input;
while (1) {
if (cu->TS == TS)
return cu;
cu = cu->prev;
if (cu == cb->input) break;
}
cu = cb->input;
while (1) {
if (!cu->dataLength) {
cu->TS = TS;
return cu;
}
cu = cu->next;
if (cu == cb->input) return NULL;
}
return NULL;
}
#if 0
static void check_temporal(GF_CompositionMemory *cb)
{
GF_CMUnit *cu;
cu = cb->output;
while (1) {
if (cu->next==cb->output) break;
assert(!cu->next->dataLength || (cu->TS < cu->next->TS));
assert(!cu(>TS || (cu->TS >= cb->LastRenderedTS));
cu = cu->next;
}
}
#endif
static GF_CMUnit *gf_cm_reorder_unit(GF_CompositionMemory *cb, GF_CMUnit *unit, Bool codec_reordering)
{
GF_CMUnit *cu;
if (codec_reordering) {
cu = cb->input;
cb->input = cb->input->next;
return cu;
}
gf_odm_lock(cb->odm, 1);
if (!cb->input->dataLength || cb->input->TS < unit->TS) {
if (unit != cb->input) {
unit->prev->next = unit->next;
unit->next->prev = unit->prev;
unit->prev = cb->input;
unit->next = cb->input->next;
unit->next->prev = unit;
unit->prev->next = unit;
}
cb->input = unit;
goto exit;
}
cu = cb->input;
while (1) {
if (cu->TS > unit->TS) {
if (!cu->dataLength) {
unit = NULL;
goto exit;
}
if (cu->prev == unit) {
if (!unit->prev->dataLength || (unit->prev->TS < unit->TS))
break;
}
else if (!cu->prev->dataLength || (cu->prev->TS < unit->TS)) {
break;
}
}
cu = cu->prev;
if (cu == cb->input)
goto exit;
}
unit->prev->next = unit->next;
unit->next->prev = unit->prev;
unit->next = cu;
unit->prev = cu->prev;
unit->next->prev = unit;
unit->prev->next = unit;
GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("Swapping CU buffer\n"));
exit:
if (unit) {
if (!cb->output->dataLength) {
cb->output = cb->input;
while (1) {
if (!cb->output->prev->dataLength) break;
cb->output = cb->output->prev;
}
}
else if (cb->output->TS > unit->TS) {
cb->output = unit;
}
}
gf_odm_lock(cb->odm, 0);
return unit;
}
static void cb_set_buffer_off(GF_CompositionMemory *cb)
{
gf_clock_buffer_off(cb->odm->codec->ck);
GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] CB Buffering done ODM%d: buffering off at OTB %u (STB %d) (nb wait on clock: %d)\n", cb->odm->OD->objectDescriptorID, gf_clock_time(cb->odm->codec->ck), gf_term_get_time(cb->odm->term), cb->odm->codec->ck->Buffering));
gf_term_service_media_event(cb->odm->parentscene->root_od, GF_EVENT_MEDIA_CANPLAY);
}
void gf_cm_unlock_input(GF_CompositionMemory *cb, GF_CMUnit *cu, u32 cu_size, Bool codec_reordering)
{
if (!cu_size || (!cu->data && !cu->frame && !cb->pY) ) {
if (cu->frame) {
cu->frame->Release(cu->frame);
cu->frame = NULL;
}
cu->dataLength = 0;
cu->TS = 0;
return;
}
gf_odm_lock(cb->odm, 1);
if (codec_reordering) {
cb->input = cb->input->next;
} else {
cu = gf_cm_reorder_unit(cb, cu, codec_reordering);
assert(cu);
}
if (cu) {
if (!cu->dataLength) cb->UnitCount += 1;
cu->dataLength = cu_size;
cu->RenderedLength = 0;
if ( (cb->Status == CB_BUFFER) && (cb->UnitCount >= cb->Capacity) ) {
cb->Status = CB_BUFFER_DONE;
if (cb->odm->codec->type == GF_STREAM_AUDIO)
cb_set_buffer_off(cb);
}
#if 0
if ((cb->odm->codec->type==GF_STREAM_VISUAL) && cb->odm->mo && cb->odm->mo->num_open) {
gf_term_invalidate_compositor(cb->odm->term);
}
#endif
}
gf_odm_lock(cb->odm, 0);
}
void gf_cm_reset(GF_CompositionMemory *cb)
{
GF_CMUnit *cu;
gf_odm_lock(cb->odm, 1);
cu = cb->input;
cu->RenderedLength = 0;
if (cu->dataLength && cb->odm->raw_frame_sema) {
cu->dataLength = 0;
gf_sema_notify(cb->odm->raw_frame_sema, 1);
}
cu->dataLength = 0;
if (cu->frame) {
cu->frame->Release(cu->frame);
cu->frame = NULL;
}
cu->TS = 0;
cu = cu->next;
while (cu != cb->input) {
cu->RenderedLength = 0;
cu->TS = 0;
cu->dataLength = 0;
if (cu->frame) {
cu->frame->Release(cu->frame);
cu->frame = NULL;
}
cu = cu->next;
}
cb->UnitCount = 0;
cb->HasSeenEOS = 0;
if (cb->odm->mo) cb->odm->mo->timestamp = 0;
cb->output = cb->input;
gf_odm_lock(cb->odm, 0);
}
void gf_cm_reset_timing(GF_CompositionMemory *cb)
{
GF_CMUnit *cu = cb->input;
gf_odm_lock(cb->odm, 1);
cu->TS = 0;
cu = cu->next;
while (cu != cb->input) {
cu->TS = 0;
cu = cu->next;
}
if (cb->odm->mo) cb->odm->mo->timestamp = 0;
gf_odm_lock(cb->odm, 0);
}
void gf_cm_resize(GF_CompositionMemory *cb, u32 newCapacity)
{
GF_CMUnit *cu;
if (!newCapacity) return;
gf_odm_lock(cb->odm, 1);
cu = cb->input;
cb->UnitSize = newCapacity;
while (1) {
if (cu->frame) {
cu->frame->Release(cu->frame);
cu->frame = NULL;
}
if (!cb->no_allocation) {
my_large_gf_free(cu->data);
cu->data = (char*) my_large_alloc(newCapacity);
} else {
cu->data = NULL;
if (cu->dataLength && cb->odm->raw_frame_sema) {
gf_sema_notify(cb->odm->raw_frame_sema, 1);
}
}
cu->dataLength = 0;
cu->TS = 0;
cu = cu->next;
if (cu == cb->input) break;
}
cb->UnitCount = 0;
cb->output = cb->input;
gf_odm_lock(cb->odm, 0);
}
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);
if (cb->input) {
cb->input->prev->next = NULL;
gf_cm_unit_del(cb->input, cb->no_allocation);
cb->input = NULL;
}
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;
if (cb->no_allocation) {
cu->data = NULL;
} else {
cu->data = (char*)my_large_alloc(UnitSize);
}
prev = cu;
Capacity --;
i++;
}
cu->next = cb->input;
cb->input->prev = cu;
cb->output = cb->input;
gf_odm_lock(cb->odm, 0);
}
GF_CMUnit *gf_cm_get_output(GF_CompositionMemory *cb)
{
switch (cb->Status) {
case CB_BUFFER:
case CB_STOP:
if (cb->odm->codec->type != GF_STREAM_VISUAL) return NULL;
break;
case CB_BUFFER_DONE:
if (cb->odm->codec->type != GF_STREAM_VISUAL)
cb->Status = CB_PLAY;
break;
case CB_PAUSE:
break;
}
if (!cb->UnitCount || !cb->output->dataLength) {
if ((cb->Status != CB_STOP) && cb->HasSeenEOS && (cb->odm && cb->odm->codec)) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM%d] Switching composition memory to stop state - time %d\n", cb->odm->OD->objectDescriptorID, (u32) cb->odm->media_stop_time));
if ((cb->Status==CB_BUFFER_DONE) && (cb->odm->codec->type == GF_STREAM_VISUAL) ){
gf_clock_buffer_off(cb->odm->codec->ck);
}
cb->Status = CB_STOP;
cb->odm->media_current_time = (u32) cb->odm->media_stop_time;
#ifndef GPAC_DISABLE_VRML
mediasensor_update_timing(cb->odm, 1);
#endif
gf_odm_signal_eos(cb->odm);
}
return NULL;
}
if ((cb->Status != CB_STOP) && cb->odm && cb->odm->codec) {
if (cb->odm->codec->ck->has_media_time_shift) {
cb->odm->media_current_time = cb->output->TS + cb->odm->codec->ck->media_time_at_init - cb->odm->codec->ck->init_time;
} else {
cb->odm->media_current_time = cb->output->TS;
}
if (cb->HasSeenEOS && (cb->odm->codec->type == GF_STREAM_VISUAL) && (!cb->output->next->dataLength || (cb->Capacity==1))) {
GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[ODM%d] Switching composition memory to stop state - time %d\n", cb->odm->OD->objectDescriptorID, (u32) cb->odm->media_stop_time));
if (cb->Status==CB_BUFFER_DONE) {
gf_clock_buffer_off(cb->odm->codec->ck);
}
cb->Status = CB_STOP;
cb->odm->media_current_time = (u32) cb->odm->media_stop_time;
#ifndef GPAC_DISABLE_VRML
mediasensor_update_timing(cb->odm, 1);
#endif
gf_odm_signal_eos(cb->odm);
}
}
if (cb->output->sender_ntp) {
cb->LastRenderedNTPDiff = gf_net_get_ntp_diff_ms(cb->output->sender_ntp);
cb->LastRenderedNTP = cb->output->sender_ntp;
}
return cb->output;
}
void gf_cm_output_kept(GF_CompositionMemory *cb)
{
assert(cb->UnitCount);
cb->output->RenderedLength = 0;
cb->LastRenderedTS = cb->output->TS;
if ((cb->Status==CB_BUFFER_DONE) && (cb->odm->codec->type == GF_STREAM_VISUAL)) {
cb_set_buffer_off(cb);
cb->Status=CB_PLAY;
}
}
void gf_cm_drop_output(GF_CompositionMemory *cb)
{
gf_cm_output_kept(cb);
if (cb->output->dataLength && (cb->odm->codec->type == GF_STREAM_VISUAL) ) {
if ( !cb->output->next->dataLength || (cb->Capacity == 1) ) {
Bool no_drop = 1;
if (cb->no_allocation ) {
if (cb->odm->term->bench_mode)
no_drop = 0;
else if (gf_clock_time(cb->odm->codec->ck) > cb->output->TS)
no_drop = 0;
}
if (no_drop) {
if (cb->odm->raw_frame_sema) {
cb->output->dataLength = 0;
gf_sema_notify(cb->odm->raw_frame_sema, 1);
}
return;
}
}
}
cb->output->dataLength = 0;
if (cb->output->frame) {
cb->output->frame->Release(cb->output->frame);
cb->output->frame = NULL;
}
cb->output->TS = 0;
cb->output = cb->output->next;
cb->UnitCount -= 1;
if (!cb->HasSeenEOS && cb->UnitCount <= cb->Min) {
cb->odm->codec->PriorityBoost = 1;
}
if (cb->odm->raw_frame_sema) {
gf_sema_notify(cb->odm->raw_frame_sema, 1);
}
}
void gf_cm_set_status(GF_CompositionMemory *cb, u32 Status)
{
if (cb->Status == Status)
return;
gf_odm_lock(cb->odm, 1);
if (Status == CB_PLAY) {
switch (cb->Status) {
case CB_STOP:
cb->Status = CB_BUFFER;
gf_clock_buffer_on(cb->odm->codec->ck);
GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] CB status changed - ODM%d: buffering on at OTB %d (STB %d) (nb wait on clock: %d)\n", cb->odm->OD->objectDescriptorID, gf_clock_time(cb->odm->codec->ck),gf_term_get_time(cb->odm->term), cb->odm->codec->ck->Buffering));
break;
case CB_PAUSE:
cb->Status = CB_PLAY;
break;
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] CB status changed - ODM%d: buffering off at OTB %u (STB %d) (nb wait on clock: %d)\n", cb->odm->OD->objectDescriptorID, gf_clock_time(cb->odm->codec->ck), gf_term_get_time(cb->odm->term), cb->odm->codec->ck->Buffering));
}
if (Status == CB_STOP) {
gf_cm_reset(cb);
cb->LastRenderedTS = 0;
}
cb->Status = Status;
if (Status==CB_BUFFER) {
gf_clock_buffer_on(cb->odm->codec->ck);
GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] CB status changed - ODM%d: buffering on at OTB %d (STB %d) (nb wait on clock: %d)\n", cb->odm->OD->objectDescriptorID, gf_clock_time(cb->odm->codec->ck), gf_term_get_time(cb->odm->term), cb->odm->codec->ck->Buffering));
}
}
gf_odm_lock(cb->odm, 0);
}
void gf_cm_set_eos(GF_CompositionMemory *cb)
{
gf_odm_lock(cb->odm, 1);
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] CB EOS - ODM%d: buffering off at OTB %u (STB %d) (nb wait on clock: %d)\n", cb->odm->OD->objectDescriptorID, gf_clock_time(cb->odm->codec->ck), gf_term_get_time(cb->odm->term), cb->odm->codec->ck->Buffering));
}
cb->HasSeenEOS = 1;
if (cb->odm->term->bench_mode==2) {
cb->Status = CB_STOP;
gf_odm_signal_eos(cb->odm);
}
gf_term_invalidate_compositor(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) ) {
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)
{
if (cb->HasSeenEOS && ((cb->Status == CB_STOP) || (cb->UnitCount==0)) )
return 1;
return 0;
}
void gf_cm_abort_buffering(GF_CompositionMemory *cb)
{
if (cb->Status == CB_BUFFER) {
cb->Status = CB_BUFFER_DONE;
cb_set_buffer_off(cb);
}
}