/*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; if (cu->dataLength && cb->odm->raw_frame_sema) { cu->dataLength = 0; gf_sema_notify(cb->odm->raw_frame_sema, 1); } 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->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_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); }
/*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; 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) { cu->dataLength = 0; gf_sema_notify(cb->odm->raw_frame_sema, 1); } } cu = cu->next; while (cu != cb->input) { if (!cb->no_allocation) { my_large_gf_free(cu->data); cu->data = (char*) my_large_alloc(newCapacity); } else { cu->data = NULL; } cu = cu->next; } 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_set_status(GF_CompositionMemory *cb, u32 Status) { if (cb->Status == Status) return; 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: if (cb->odm->disable_buffer_at_next_play) { cb->Status = CB_BUFFER_DONE; } else { 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; /*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] 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_unlock_input(GF_CompositionMemory *cb, GF_CMUnit *cu, u32 cu_size, Bool codec_reordering) { /*nothing dispatched, ignore*/ 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); // assert(cu->frame); if (codec_reordering) { cb->input = cb->input->next; } else { cu = gf_cm_reorder_unit(cb, cu, codec_reordering); assert(cu); } if (cu) { /*FIXME - if the CU already has data, this is spatial scalability so same num buffers*/ if (!cu->dataLength) cb->UnitCount += 1; cu->dataLength = cu_size; cu->RenderedLength = 0; /*turn off buffering for audio - 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*/ cb->Status = CB_BUFFER_DONE; //for audio, turn off buffering now. For video, we will wait for the first frame to be drawn if (cb->odm->codec->type == GF_STREAM_AUDIO) cb_set_buffer_off(cb); } //new FPS regulation doesn't need this signaling #if 0 /*since a new CU is here notify the compositor*/ 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_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); }
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_unlock_input(GF_CompositionMemory *cb, GF_CMUnit *cu, u32 cu_size, Bool codec_reordering) { /*nothing dispatched, ignore*/ if (!cu_size) { cu->dataLength = 0; cu->TS = 0; return; } gf_odm_lock(cb->odm, 1); if (cu->TS < cb->input->TS) cu = cu; if (codec_reordering) { cb->input = cb->input->next; } else { cu = gf_cm_reorder_unit(cb, cu, codec_reordering); assert(cu); } if (cu) { /*FIXME - if the CU already has data, this is spatial scalability so same num buffers*/ if (!cu->dataLength) cb->UnitCount += 1; cu->dataLength = cu_size; 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); cb->odm->codec->ck->data_timeout = 0; 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)); gf_term_service_media_event(cb->odm->parentscene->root_od, GF_EVENT_MEDIA_CANPLAY); } /*since a new CU is here notify the compositor*/ if ((cb->odm->codec->type==GF_STREAM_VISUAL) && cb->odm->mo && cb->odm->mo->num_open) { gf_term_invalidate_compositor(cb->odm->term); } } 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); if (cb->input){ /*break the loop and destroy*/ 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); }
/*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); }
void gf_mo_unload_xlink_resource(GF_Node *node, GF_MediaObject *mo) { if (!mo) return; if (!gf_odm_lock_mo(mo)) return; if (!mo->odm->subscene) { gf_odm_lock(mo->odm, 0); return; } if (mo->num_open) { mo->num_open--; if (!mo->num_open) { /*do we simply stop the associated document or unload it??? to check*/ // gf_mo_stop(mo); gf_odm_disconnect(mo->odm, 2); return; } } /*ODM may be destroyed at this point !!*/ if (mo->odm) gf_odm_lock(mo->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] 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; //in bench mode eos cannot be signaled through flush of composition memory since it is always empty - do it here 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); }
/*re-orders units in case of temporal scalability. Blocking call as it may change the output unit too*/ static GF_CMUnit *gf_cm_reorder_unit(GF_CompositionMemory *cb, GF_CMUnit *unit, Bool codec_reordering) { GF_CMUnit *cu; #if NO_TEMPORAL_SCALABLE cu = cb->input; cb->input = cb->input->next; return cu; #else /*lock the buffer since we may move pointers*/ gf_odm_lock(cb->odm, 1); /*1- unit is next on time axis (no temporal scalability)*/ if (!cb->input->dataLength || cb->input->TS < unit->TS) { if (unit != cb->input) { /*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; } /*2- 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; GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("Swapping CU buffer\n")); 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; } } //check_temporal(cb); /*unlock the buffer*/ gf_odm_lock(cb->odm, 0); return unit; #endif }