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); }
GF_Err gf_codec_process_raw_media_pull(GF_Codec *codec, u32 TimeAvailable) { GF_Channel *ch; GF_DBUnit *db; if (codec->ck && codec->ck->Paused) { u32 i; for (i=0; i<gf_list_count(codec->odm->channels); i++) { ch = gf_list_get(codec->odm->channels, i); if (ch->BufferOn) { ch->BufferOn = 0; gf_clock_buffer_off(ch->clock); } } if (codec->CB) gf_cm_abort_buffering(codec->CB); } /*this will pull the next AU from the service */ Decoder_GetNextAU(codec, &ch, &db); if (!db) return GF_OK; /*dispatch raw media - this call is blocking untill the cu has been consumed */ gf_es_dispatch_raw_media_au(ch, db->data, db->dataLength, db->CTS); /*release AU from service*/ gf_term_channel_release_sl_packet(ch->service, ch); return GF_OK; }
void gf_es_dispatch_raw_media_au(GF_Channel *ch, char *payload, u32 payload_size, u32 cts) { GF_CompositionMemory *cb; GF_CMUnit *cu; if (!payload || !ch->odm->codec->CB) return; if (!ch->odm->codec->CB->no_allocation) return; cb = ch->odm->codec->CB; cu = gf_cm_lock_input(cb, cts, 1); if (cu) { u32 size = 0; assert(cu->RenderedLength==0); if (cb->UnitSize >= payload_size) { cu->data = payload; size = payload_size; cu->TS = cts; GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM%d] Raw Frame dispatched to CB - TS %d ms\n", ch->odm->OD->objectDescriptorID, cu->TS)); } gf_cm_unlock_input(cb, cu, size, 1); if (ch->BufferOn) { ch->BufferOn = 0; gf_clock_buffer_off(ch->clock); gf_cm_abort_buffering(cb); } /*since the CB is a simple pointer to the input frame, wait until it is released before getting back to the caller module*/ if (size) { gf_sema_wait(ch->odm->raw_frame_sema); assert(cb->output->dataLength == 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); }
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)); } }
static void ch_buffer_off(GF_Channel *ch) { /*just in case*/ if (ch->BufferOn) { ch->BufferOn = 0; gf_clock_buffer_off(ch->clock); GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: buffering off at STB %d (OTB %d) (nb buffering on clock: %d)\n", ch->esd->ESID, gf_term_get_time(ch->odm->term), gf_clock_time(ch->clock), ch->clock->Buffering)); } }
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_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_es_dispatch_raw_media_au(GF_Channel *ch, char *payload, u32 payload_size, u32 cts) { u32 now; GF_CompositionMemory *cb; GF_CMUnit *cu; if (!payload || !ch->odm->codec->CB) return; if (!ch->odm->codec->CB->no_allocation) return; now = gf_clock_real_time(ch->clock); if (cts + ch->MinBuffer < now) { if (ch->MinBuffer && (ch->is_raw_channel==2)) { ch->clock->clock_init = 0; gf_clock_set_time(ch->clock, cts); GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM%d] Raw Frame dispatched at OTB %d but frame TS is %d ms - adjusting clock\n", ch->odm->OD->objectDescriptorID, now, cts)); } else { GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM%d] Raw Frame dispatched at OTB %d but frame TS is %d ms - DROPPING\n", ch->odm->OD->objectDescriptorID, now, cts)); } return; } cb = ch->odm->codec->CB; cu = gf_cm_lock_input(cb, cts, 1); if (cu) { u32 size = 0; assert(cu->RenderedLength==0); if (cb->UnitSize >= payload_size) { cu->data = payload; size = payload_size; cu->TS = cts; GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM%d] Raw Frame dispatched to CB - TS %d ms - OTB %d ms - OTB_drift %d ms\n", ch->odm->OD->objectDescriptorID, cu->TS, gf_clock_real_time(ch->clock), gf_clock_time(ch->clock) )); } gf_cm_unlock_input(cb, cu, size, 1); if (ch->BufferOn) { ch->BufferOn = 0; gf_clock_buffer_off(ch->clock); gf_cm_abort_buffering(cb); } /*since the CB is a simple pointer to the input frame, wait until it is released before getting back to the caller module*/ if (size) { gf_sema_wait(ch->odm->raw_frame_sema); assert(cb->output->dataLength == 0); } } }
GF_Err gf_codec_process_private_media(GF_Codec *codec, u32 TimeAvailable) { if (codec->ck && codec->ck->Paused) { u32 i; for (i=0; i<gf_list_count(codec->odm->channels); i++) { GF_Channel *ch = gf_list_get(codec->odm->channels, i); if (ch->BufferOn) { ch->BufferOn = 0; gf_clock_buffer_off(ch->clock); } } if (codec->CB) gf_cm_abort_buffering(codec->CB); } return GF_OK; }
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); }
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); }
/*access to the first available CU for rendering this is a blocking call since input may change the output (temporal scalability)*/ GF_CMUnit *gf_cm_get_output(GF_CompositionMemory *cb) { /*if paused or stop or buffering, do nothing*/ switch (cb->Status) { case CB_BUFFER: case CB_STOP: /*only visual buffers deliver data when buffering or stop*/ if (cb->odm->codec->type != GF_STREAM_VISUAL) return NULL; break; case CB_BUFFER_DONE: //For non-visual output move to play state upon fetch if (cb->odm->codec->type != GF_STREAM_VISUAL) cb->Status = CB_PLAY; break; //we always deliver in pause, up to the caller to decide to consume or not the frame case CB_PAUSE: break; } /*no output*/ 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 /*force update of media time*/ mediasensor_update_timing(cb->odm, 1); #endif gf_odm_signal_eos(cb->odm); } return NULL; } /*update the timing*/ 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; } /*handle visual object - EOS if no more data (we keep the last CU for rendering, so check next one)*/ 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 /*force update of media time*/ 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; }