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);
        }
}