This source file includes following definitions.
- gf_codec_new
- gf_codec_use_codec
- gf_codec_add_channel
- gf_codec_is_scene_or_image
- gf_codec_remove_channel
- codec_update_stats
- MediaDecoder_GetNextAU
- Decoder_GetNextAU
- SystemCodec_Process
- PrivateScene_Process
- LockCompositionUnit
- UnlockCompositionUnit
- gf_codec_resize_composition_buffer
- MediaCodec_Process
- gf_codec_process_private_media
- gf_codec_process_raw_media_pull
- gf_codec_process_ocr
- gf_codec_process
- gf_codec_get_capability
- gf_codec_set_capability
- gf_codec_set_status
- get_codec_confidence
- decio_blacklisted
- Codec_LoadModule
- gf_codec_change_decoder
- Codec_Load
- gf_codec_del
#include <gpac/internal/terminal_dev.h>
#include <gpac/internal/compositor_dev.h>
#include <gpac/constants.h>
#include <gpac/crypt.h>
#include "media_memory.h"
#include "media_control.h"
#include "input_sensor.h"
GF_Err Codec_Load(GF_Codec *codec, GF_ESD *esd, u32 PL);
GF_Err gf_codec_process_raw_media_pull(GF_Codec *codec, u32 TimeAvailable);
GF_Codec *gf_codec_new(GF_ObjectManager *odm, GF_ESD *base_layer, s32 PL, GF_Err *e)
{
GF_Codec *tmp;
if (odm->parentscene && odm->parentscene->root_od->addon) {
switch (base_layer->decoderConfig->objectTypeIndication) {
case GPAC_OTI_VIDEO_LHVC:
case GPAC_OTI_VIDEO_SVC:
odm->scalable_addon = 1;
odm->parentscene->root_od->addon->addon_type = GF_ADDON_TYPE_SCALABLE;
*e = GF_OK;
base_layer->dependsOnESID = 0xFFFF;
return NULL;
default:
break;
}
}
GF_SAFEALLOC(tmp, GF_Codec);
if (! tmp) {
*e = GF_OUT_OF_MEM;
return NULL;
}
tmp->odm = odm;
if (PL<0) PL = 0xFF;
*e = Codec_Load(tmp, base_layer, PL);
if (*e) {
if (odm->term->bench_mode==2) {
*e = GF_OK;
GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[Codec] ODM%d ES%d: Cannot find decoder for stream type %s - ignoring as running systems bench mode\n", odm->OD->objectDescriptorID, base_layer->ESID, gf_esd_get_textual_description(base_layer) ));
} else {
GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[Codec] ODM%d ES%d: Cannot find decoder for stream type %s\n", odm->OD->objectDescriptorID, base_layer->ESID, gf_esd_get_textual_description(base_layer) ));
gf_free(tmp);
return NULL;
}
}
tmp->type = base_layer->decoderConfig->streamType;
tmp->oti = base_layer->decoderConfig->objectTypeIndication;
tmp->inChannels = gf_list_new();
tmp->Status = GF_ESM_CODEC_STOP;
if (tmp->type==GF_STREAM_PRIVATE_MEDIA) tmp->type = GF_STREAM_VISUAL;
if (tmp->type==GF_STREAM_VISUAL) {
GF_CodecCapability cap;
cap.CapCode = GF_CODEC_DISPLAY_BPP;
cap.cap.valueInt = odm->term->compositor->video_out->max_screen_bpp;
gf_codec_set_capability(tmp, cap);
}
tmp->Priority = base_layer->streamPriority ? base_layer->streamPriority : 1;
GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[Codec] Found decoder %s for stream type %s\n", tmp->decio ? tmp->decio->module_name : "RAW", gf_esd_get_textual_description(base_layer) ));
return tmp;
}
GF_Codec *gf_codec_use_codec(GF_Codec *codec, GF_ObjectManager *odm)
{
GF_Codec *tmp;
if (!codec->decio) return NULL;
GF_SAFEALLOC(tmp, GF_Codec);
if (!tmp) return NULL;
tmp->type = codec->type;
tmp->inChannels = gf_list_new();
tmp->Status = GF_ESM_CODEC_STOP;
tmp->odm = odm;
tmp->flags = codec->flags | GF_ESM_CODEC_IS_USE;
tmp->decio = codec->decio;
tmp->process = codec->process;
return tmp;
}
GF_Err gf_codec_add_channel(GF_Codec *codec, GF_Channel *ch)
{
GF_Err e;
Bool config_decio = GF_FALSE;
GF_NetworkCommand com;
GF_Channel *a_ch;
u32 CUsize, i;
GF_CodecCapability cap;
u32 min, max;
if (!ch || !ch->esd) return GF_BAD_PARAM;
if (ch && ch->odm && !ch->is_pulling && (ch->MaxBuffer <= ch->odm->term->low_latency_buffer_max))
codec->flags |= GF_ESM_CODEC_IS_LOW_LATENCY;
if (codec->decio) config_decio = GF_TRUE;
else if (codec->odm->term->bench_mode==2) {
if (codec->type != GF_STREAM_OCR)
config_decio = GF_TRUE;
}
if (config_decio) {
com.get_dsi.dsi = NULL;
if (ch->esd->decoderConfig && ch->esd->decoderConfig->upstream) codec->flags |= GF_ESM_CODEC_HAS_UPSTREAM;
if (ch->service && ch->odm && !(ch->odm->flags & GF_ODM_NOT_IN_OD_STREAM) ) {
com.command_type = GF_NET_CHAN_GET_DSI;
com.base.on_channel = ch;
e = gf_term_service_command(ch->service, &com);
if (!e && com.get_dsi.dsi) {
if (ch->esd->decoderConfig->decoderSpecificInfo->data) gf_free(ch->esd->decoderConfig->decoderSpecificInfo->data);
ch->esd->decoderConfig->decoderSpecificInfo->data = com.get_dsi.dsi;
ch->esd->decoderConfig->decoderSpecificInfo->dataLength = com.get_dsi.dsi_len;
}
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[Codec] Attaching stream %d to codec %s\n", ch->esd->ESID, codec->decio->module_name));
if (codec->type == GF_STREAM_VISUAL) {
cap.CapCode = GF_CODEC_FRAME_OUTPUT;
gf_codec_get_capability(codec, &cap);
if (cap.cap.valueBool) {
cap.CapCode = GF_CODEC_FRAME_OUTPUT;
cap.cap.valueInt = gf_sc_use_3d(codec->odm->term->compositor) ? 2 : 1;
if ((gf_codec_set_capability(codec, cap)==GF_OK) && (((GF_MediaDecoder*)codec->decio)->GetOutputFrame != NULL))
codec->direct_frame_output = GF_TRUE;
}
if (!codec->direct_frame_output) {
if ( gf_sc_use_raw_texture(codec->odm->term->compositor)) {
cap.CapCode = GF_CODEC_RAW_MEMORY;
gf_codec_get_capability(codec, &cap);
if (cap.cap.valueBool) {
cap.CapCode = GF_CODEC_RAW_MEMORY;
if ((gf_codec_set_capability(codec, cap)==GF_OK) && (((GF_MediaDecoder*)codec->decio)->GetOutputBuffer != NULL))
codec->direct_vout = GF_TRUE;
}
}
}
}
if (codec->odm->term->bench_mode==2) {
e = GF_OK;
} else {
gf_mx_p(ch->mx);
ch->esd->service_url = (ch->odm && ch->odm->net_service) ? ch->odm->net_service->url : NULL;
#if GPAC_ANDROID
{
char *dsi = NULL;
GF_NetworkCommand com;
u32 len = 0;
#if 0
if (ch->esd->decoderConfig->decoderSpecificInfo) {
dsi = ch->esd->decoderConfig->decoderSpecificInfo->data;
ch->esd->decoderConfig->decoderSpecificInfo->data = NULL;
len = ch->esd->decoderConfig->decoderSpecificInfo->dataLength;
ch->esd->decoderConfig->decoderSpecificInfo->dataLength=0;
}
e = codec->decio->AttachStream(codec->decio, ch->esd);
if (ch->esd->decoderConfig->decoderSpecificInfo) {
ch->esd->decoderConfig->decoderSpecificInfo->data = dsi;
ch->esd->decoderConfig->decoderSpecificInfo->dataLength = 0;
}
#endif
cap.CapCode = GF_CODEC_FORCE_ANNEXB;
gf_codec_get_capability(codec, &cap);
if (cap.cap.valueBool) {
memset(&com, 0, sizeof(GF_NetworkCommand));
com.command_type = GF_NET_CHAN_NALU_MODE;
com.nalu_mode.extract_mode = 1;
com.base.on_channel = ch;
gf_term_service_command(ch->service, &com);
}
}
e = codec->decio->AttachStream(codec->decio, ch->esd);
#else
e = codec->decio->AttachStream(codec->decio, ch->esd);
#endif
gf_mx_v(ch->mx);
}
if (ch->esd->decoderConfig && ch->esd->decoderConfig->rvc_config) {
gf_odf_desc_del((GF_Descriptor *)ch->esd->decoderConfig->rvc_config);
ch->esd->decoderConfig->rvc_config = NULL;
}
if (e) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[Codec] Attach Stream failed %s\n", gf_error_to_string(e) ));
return e;
}
cap.CapCode = GF_CODEC_OUTPUT_SIZE;
gf_codec_get_capability(codec, &cap);
if (codec->CB && (cap.cap.valueInt != codec->CB->UnitSize)) {
gf_cm_del(codec->CB);
codec->CB = NULL;
}
CUsize = cap.cap.valueInt;
switch(codec->type) {
case GF_STREAM_VISUAL:
case GF_STREAM_AUDIO:
cap.CapCode = GF_CODEC_BUFFER_MIN;
cap.cap.valueInt = 1;
gf_codec_get_capability(codec, &cap);
min = cap.cap.valueInt;
cap.CapCode = GF_CODEC_BUFFER_MAX;
cap.cap.valueInt = 1;
gf_codec_get_capability(codec, &cap);
max = cap.cap.valueInt;
if (!max) max = 1;
break;
case GF_STREAM_ND_SUBPIC:
max = 1;
min = 0;
break;
default:
min = max = 0;
break;
}
if ((codec->type==GF_STREAM_AUDIO) && (max<2)) max = 2;
if (!codec->CB && max) {
Bool no_alloc = GF_FALSE;
if (codec->flags & GF_ESM_CODEC_IS_RAW_MEDIA) {
max = 1;
codec->odm->raw_frame_sema = gf_sema_new(1, 0);
no_alloc = 1;
}
else if (codec->direct_frame_output) {
no_alloc = 1;
}
else if (codec->direct_vout) {
max = 1;
no_alloc = 1;
}
else if (codec->flags & GF_ESM_CODEC_IS_LOW_LATENCY) {
max = (codec->type==GF_STREAM_AUDIO) ? 4 : 2;
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[ODM] Creating composition buffer for codec %s - %d units %d bytes each\n", codec->decio->module_name, max, CUsize));
codec->CB = gf_cm_new(CUsize, max, no_alloc);
codec->CB->Min = min;
codec->CB->odm = codec->odm;
}
if (codec->CB) {
codec->is_reordering = 1;
cap.CapCode = GF_CODEC_REORDER;
if (gf_codec_get_capability(codec, &cap) == GF_OK)
codec->is_reordering = cap.cap.valueInt;
codec->trusted_cts = 0;
cap.CapCode = GF_CODEC_TRUSTED_CTS;
if (gf_codec_get_capability(codec, &cap) == GF_OK)
codec->trusted_cts = cap.cap.valueInt;
}
if (codec->flags & GF_ESM_CODEC_IS_RAW_MEDIA) {
ch->is_raw_channel = 1;
}
if (ch->service) {
memset(&com, 0, sizeof(GF_NetworkCommand));
com.command_type = GF_NET_CHAN_CONFIG;
com.base.on_channel = ch;
com.cfg.priority = ch->esd->streamPriority;
assert( ch->clock );
com.cfg.sync_id = ch->clock->clockID;
memcpy(&com.cfg.sl_config, ch->esd->slConfig, sizeof(GF_SLConfig));
if (ch->odm->codec && (ch->odm->codec->type==GF_STREAM_AUDIO) ) {
cap.CapCode = GF_CODEC_SAMPLERATE;
gf_codec_get_capability(ch->odm->codec, &cap);
com.cfg.sample_rate = cap.cap.valueInt;
cap.CapCode = GF_CODEC_CU_DURATION;
gf_codec_get_capability(ch->odm->codec, &cap);
com.cfg.frame_duration = cap.cap.valueInt;
}
gf_term_service_command(ch->service, &com);
ch->carousel_type = GF_ESM_CAROUSEL_NONE;
if (com.cfg.use_m2ts_sections) {
ch->carousel_type = GF_ESM_CAROUSEL_MPEG2;
} else {
switch (ch->esd->decoderConfig->streamType) {
case GF_STREAM_OD:
case GF_STREAM_SCENE:
ch->carousel_type = ch->esd->slConfig->AUSeqNumLength ? GF_ESM_CAROUSEL_MPEG4 : GF_ESM_CAROUSEL_NONE;
break;
}
}
}
} else if (codec->flags & GF_ESM_CODEC_IS_RAW_MEDIA) {
cap.CapCode = GF_CODEC_OUTPUT_SIZE;
gf_codec_get_capability(codec, &cap);
if (codec->CB && (cap.cap.valueInt != codec->CB->UnitSize)) {
gf_cm_del(codec->CB);
codec->CB = NULL;
}
CUsize = cap.cap.valueInt;
codec->odm->raw_frame_sema = gf_sema_new(1, 0);
codec->CB = gf_cm_new(CUsize, 1, 1);
codec->CB->Min = 0;
codec->CB->odm = codec->odm;
ch->is_raw_channel = 1;
if (gf_es_owns_clock(ch))
ch->is_raw_channel = 2;
if (ch->is_pulling) {
codec->process = gf_codec_process_raw_media_pull;
}
}
if (!ch->esd->dependsOnESID || !codec->ck) {
codec->ck = ch->clock;
return gf_list_insert(codec->inChannels, ch, 0);
}
else {
i=0;
while ((a_ch = (GF_Channel*)gf_list_enum(codec->inChannels, &i))) {
if (ch->esd->dependsOnESID == a_ch->esd->ESID) {
return gf_list_insert(codec->inChannels, ch, i);
}
if (a_ch->esd->dependsOnESID == ch->esd->ESID) {
return gf_list_insert(codec->inChannels, ch, i-1);
}
}
return gf_list_add(codec->inChannels, ch);
}
}
Bool gf_codec_is_scene_or_image(GF_Codec *codec)
{
if (!codec) return GF_TRUE;
if (!codec->CB) return GF_TRUE;
if (codec->CB->Capacity>1 || codec->CB->no_allocation) return GF_FALSE;
return GF_TRUE;
}
Bool gf_codec_remove_channel(GF_Codec *codec, struct _es_channel *ch)
{
s32 i;
assert( codec );
assert( codec->inChannels);
assert(ch);
i = gf_list_find(codec->inChannels, ch);
if (i>=0) {
if (codec->decio) {
if (codec->odm->term->bench_mode!=2) {
codec->decio->DetachStream(codec->decio, ch->esd->ESID);
}
}
gf_list_rem(codec->inChannels, (u32) i);
return 1;
}
return 0;
}
static void codec_update_stats(GF_Codec *codec, u32 dataLength, u64 dec_time, u32 DTS, Bool is_rap)
{
codec->total_dec_time += dec_time;
codec->last_frame_time = gf_sys_clock();
if (!codec->nb_dec_frames) {
codec->first_frame_time = codec->last_frame_time;
codec->min_frame_dur = (u32) -1;
}
codec->nb_dec_frames++;
if (is_rap) {
codec->nb_iframes ++;
if (dec_time>codec->max_iframes_time) codec->max_iframes_time = (u32) dec_time;
codec->total_iframes_time += dec_time;
}
if (dec_time>codec->max_dec_time) codec->max_dec_time = (u32) dec_time;
if (DTS - codec->last_unit_dts < codec->min_frame_dur) {
if (DTS > codec->last_unit_dts)
codec->min_frame_dur = DTS - codec->last_unit_dts;
}
if (dataLength) {
if (!codec->cur_bit_size || (codec->ck->speed > 0 ? codec->stat_start > DTS : codec->stat_start < DTS)) {
codec->stat_start = DTS;
codec->cur_bit_size = 8*dataLength;
} else {
if (codec->last_stat_start + 2000 <= DTS) {
codec->avg_bit_rate = (u32) (codec->cur_bit_size * (1000.0 / (DTS-codec->last_stat_start) ) );
if (codec->avg_bit_rate > codec->max_bit_rate) codec->max_bit_rate = codec->avg_bit_rate;
codec->last_stat_start = DTS;
codec->cur_bit_size = 0;
}
codec->cur_bit_size += 8*dataLength;
}
}
}
static void MediaDecoder_GetNextAU(GF_Codec *codec, GF_Channel **activeChannel, GF_DBUnit **nextAU)
{
GF_Channel *ch;
GF_DBUnit *AU;
GF_List *src_channels = codec->inChannels;
GF_ObjectManager *current_odm = codec->odm;
u32 count, curCTS, i, stream_state, now=0;
Bool scalable_check = 0;
s32 cts_diff;
Bool no_au_in_enhancement = GF_FALSE;
*nextAU = NULL;
*activeChannel = NULL;
curCTS = 0;
browse_scalable:
count = gf_list_count(src_channels);
if (!count) return;
for (i=0; i<count; i++) {
ch = (GF_Channel*)gf_list_get(src_channels, i);
if ((codec->type==GF_STREAM_OCR) && ch->IsClockInit) {
if (ch->is_pulling && codec->odm->duration) {
if (gf_clock_time(codec->ck) > codec->odm->duration)
gf_es_on_eos(ch);
}
return;
}
refetch_AU:
stream_state = ch->stream_state;
AU = gf_es_get_au(ch);
if (!AU) {
if (scalable_check==1) {
if (*nextAU && ((*nextAU)->flags & GF_DB_AU_REAGGREGATED)) {
scalable_check=2;
} else if (*nextAU) {
no_au_in_enhancement = GF_TRUE;
}
}
if (! (*activeChannel)) *activeChannel = ch;
continue;
}
cts_diff = AU->CTS;
cts_diff -= curCTS;
if (cts_diff < 0) cts_diff = -cts_diff;
if (! *nextAU) {
if (ch->esd->dependsOnESID) {
continue;
}
*nextAU = AU;
*activeChannel = ch;
curCTS = AU->CTS;
now = gf_clock_time(ch->clock);
}
else if (codec->hybrid_layered_coded) {
if (AU->DTS < (*nextAU)->DTS) {
if (AU->DTS>=codec->last_unit_dts) {
*nextAU = AU;
*activeChannel = ch;
curCTS = AU->CTS;
now = gf_clock_time(ch->clock);
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d#CH%d %s AU DTS %u but base DTS %u: frame too late - re-fetch channel\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, ch->esd->ESID, ch->odm->net_service->url, AU->DTS, (*nextAU)->DTS));
gf_es_drop_au(ch);
ch->stream_state = stream_state;
goto refetch_AU;
}
}
}
else if (cts_diff<=1) {
GF_DBUnit *baseAU = *nextAU;
assert(baseAU);
if ((*activeChannel)->is_pulling && !(baseAU->flags & GF_DB_AU_REAGGREGATED)) {
char *base_au = baseAU->data;
baseAU->data = gf_malloc(baseAU->dataLength + AU->dataLength);
memcpy(baseAU->data, base_au, baseAU->dataLength);
memcpy(baseAU->data + baseAU->dataLength , AU->data, AU->dataLength);
} else {
baseAU->data = gf_realloc(baseAU->data, baseAU->dataLength + AU->dataLength);
memcpy(baseAU->data + baseAU->dataLength , AU->data, AU->dataLength);
}
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d#CH%d (%s) AU DTS %u CTS %u size %d reaggregated on base layer %d - base DTS %d size %d\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, ch->esd->ESID, ch->odm->net_service->url, AU->DTS, AU->CTS, AU->dataLength, (*activeChannel)->esd->ESID, baseAU->DTS, baseAU->dataLength));
baseAU->dataLength += AU->dataLength;
gf_es_drop_au(ch);
ch->first_au_fetched = 1;
scalable_check = 2;
(*nextAU)->flags |= GF_DB_AU_REAGGREGATED;
no_au_in_enhancement = GF_FALSE;
}
else {
if (ch->recompute_dts) {
Bool au_match_base_ts = GF_FALSE;
GF_DBUnit *next_unit = AU->next;
while (next_unit) {
if (next_unit->CTS==curCTS) {
au_match_base_ts = GF_TRUE;
break;
}
next_unit = next_unit->next;
}
if (!au_match_base_ts) {
}
else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d#CH%d (%s) AU CTS %d doesn't have the same CTS as the base (%d)- selected as first layer\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, ch->esd->ESID, ch->odm->net_service->url, AU->CTS, (*nextAU)->CTS));
*nextAU = AU;
*activeChannel = ch;
curCTS = AU->CTS;
}
}
else if (AU->DTS < (*nextAU)->DTS) {
if ((AU->DTS <= codec->last_unit_dts)
|| !codec->first_frame_processed) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d#CH%d %s AU DTS %u but base DTS %u: frame too late - re-fetch channel\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, ch->esd->ESID, ch->odm->net_service->url, AU->DTS, (*nextAU)->DTS));
gf_es_drop_au(ch);
ch->stream_state = stream_state;
goto refetch_AU;
}
else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d#CH%d (%s) AU DTS %u selected as first layer (CTS %d)\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, ch->esd->ESID, ch->odm->net_service->url, AU->DTS, AU->CTS));
*nextAU = AU;
*activeChannel = ch;
curCTS = AU->CTS;
}
} else {
if ((*nextAU)->flags & GF_DB_AU_REAGGREGATED) {
scalable_check = 2;
} else {
GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("AU in enhancement layer DTS %u - CTS %d too early for this AU\n", AU->DTS, AU->CTS));
}
}
}
}
if (current_odm->upper_layer_odm) {
if (*nextAU) {
if (gf_scene_check_addon_restart(current_odm->upper_layer_odm->parentscene->root_od->addon, (*nextAU)->CTS, (*nextAU)->DTS)) {
GF_CodecCapability cap;
cap.CapCode = GF_CODEC_WAIT_RAP;
gf_codec_set_capability(codec, cap);
}
}
current_odm = current_odm->upper_layer_odm;
src_channels = current_odm->channels;
scalable_check = 1;
goto browse_scalable;
}
if (*nextAU && no_au_in_enhancement ) {
if (now < (*nextAU)->DTS) {
*nextAU = NULL;
*activeChannel = NULL;
return;
}
GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] Warning: could not find enhancement layer for this AU (DTS %u) at OTB %d - decoding only base\n", codec->decio->module_name, (*nextAU)->DTS, now));
}
if (codec->is_reordering && *nextAU && codec->first_frame_dispatched) {
u32 diff = 0;
if ((*activeChannel)->esd->slConfig->no_dts_signaling==GF_FALSE) {
u32 DTS = (*nextAU)->DTS;
diff = (DTS > codec-> last_unit_dts) ? (DTS - codec->last_unit_dts) : (codec->last_unit_dts - DTS);
} else {
u32 prev_ts_diff;
u32 CTS = (*nextAU)->CTS;
if (codec->recomputed_cts && (codec->recomputed_cts > (*nextAU)->CTS)) {
diff = codec->recomputed_cts - CTS;
if (diff<2) diff=0;
}
prev_ts_diff = (CTS > codec-> last_unit_cts) ? (CTS - codec->last_unit_cts) : (codec->last_unit_cts - CTS);
if (!diff) diff = prev_ts_diff;
else if (prev_ts_diff && (prev_ts_diff < diff) ) diff = prev_ts_diff;
}
if (!codec->min_au_duration || (diff < codec->min_au_duration))
codec->min_au_duration = diff;
if ((*activeChannel)->esd->slConfig->no_dts_signaling==GF_FALSE) {
(*nextAU)->CTS = (*nextAU)->DTS;
}
}
}
static void Decoder_GetNextAU(GF_Codec *codec, GF_Channel **activeChannel, GF_DBUnit **nextAU)
{
GF_Channel *ch;
GF_DBUnit *AU;
u32 count, minDTS, i;
count = gf_list_count(codec->inChannels);
*nextAU = NULL;
*activeChannel = NULL;
if (!count) return;
minDTS = 0;
for (i=count; i>0; i--) {
ch = (GF_Channel*)gf_list_get(codec->inChannels, i-1);
if ((codec->type==GF_STREAM_OCR) && ch->IsClockInit) {
if (ch->is_pulling && codec->odm->duration) {
if (gf_clock_time(codec->ck) > codec->odm->duration)
gf_es_on_eos(ch);
}
return;
}
AU = gf_es_get_au(ch);
if (!AU) {
if (! (*activeChannel)) *activeChannel = ch;
continue;
}
if (!minDTS || (AU->DTS == minDTS)) {
minDTS = AU->DTS;
*activeChannel = ch;
*nextAU = AU;
}
}
}
static GF_Err SystemCodec_Process(GF_Codec *codec, u32 TimeAvailable)
{
GF_DBUnit *AU;
GF_Channel *ch;
u32 obj_time, mm_level, au_time, cts;
u64 now;
GF_Scene *scene_locked;
Bool check_next_unit = GF_FALSE;
GF_SceneDecoder *sdec = (GF_SceneDecoder *)codec->decio;
GF_Err e = GF_OK;
scene_locked = NULL;
if ( (codec->odm->term->flags & GF_TERM_DROP_LATE_FRAMES) || (codec->flags & GF_ESM_CODEC_IS_LOW_LATENCY) )
check_next_unit = GF_TRUE;
check_unit:
if (codec->Muted) goto exit;
Decoder_GetNextAU(codec, &ch, &AU);
if (!AU || !ch) {
if (codec->Status == GF_ESM_CODEC_EOS) {
GF_CodecCapability cap;
cap.CapCode = GF_CODEC_MEDIA_NOT_OVER;
cap.cap.valueInt = 0;
sdec->GetCapabilities(codec->decio, &cap);
if (!cap.cap.valueInt) {
gf_term_stop_codec(codec, 2);
if (ch)
gf_odm_signal_eos(ch->odm);
if ((codec->type==GF_STREAM_OD) && (codec->nb_dec_frames==1)) {
if (gf_list_count(codec->odm->net_service->Clocks)==1)
codec->odm->subscene->static_media_ressources=1;
}
}
}
goto exit;
}
#ifndef GPAC_DISABLE_VRML
if (ch && ch->odm->media_ctrl && !ch->odm->media_ctrl->media_speed)
goto exit;
#endif
obj_time = gf_clock_time(codec->ck);
if (AU->DTS > obj_time) {
gf_sc_set_system_pending_frame(ch->odm->term->compositor, 1);
goto exit;
}
gf_sc_set_system_pending_frame(ch->odm->term->compositor, 0);
cts = AU->CTS;
if (AU->flags & GF_DB_AU_NO_TIMESTAMPS) au_time = obj_time;
else if (AU->flags & GF_DB_AU_CTS_IN_PAST) {
au_time = - (s32) AU->CTS;
cts = AU->DTS;
}
else au_time = AU->DTS;
if (codec->last_unit_cts == cts) {
check_next_unit = 1;
mm_level = GF_CODEC_LEVEL_SEEK;
}
else {
codec->last_unit_cts = AU->CTS;
if (scene_locked) codec->nb_dropped ++;
mm_level = GF_CODEC_LEVEL_NORMAL;
}
if (!scene_locked) {
scene_locked = codec->odm->subscene ? codec->odm->subscene : codec->odm->parentscene;
if (!gf_mx_try_lock(scene_locked->root_od->term->compositor->mx))
return GF_OK;
if (codec->odm->term->play_state) codec->odm->term->compositor->step_mode = GF_TRUE;
}
codec->odm->media_current_time = obj_time - codec->ck->init_time;
now = gf_sys_clock_high_res();
if (codec->odm->term->bench_mode==2) {
e = GF_OK;
} else {
e = sdec->ProcessData(sdec, AU->data, AU->dataLength, ch->esd->ESID, au_time, mm_level);
}
now = gf_sys_clock_high_res() - now;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d#CH%d at %d decoded AU TS %u in "LLU" us\n", sdec->module_name, codec->odm->OD->objectDescriptorID, ch->esd->ESID, obj_time, AU->CTS, now));
codec_update_stats(codec, AU->dataLength, now, AU->DTS, (AU->flags & GF_DB_AU_RAP));
codec->prev_au_size = AU->dataLength;
gf_es_drop_au(ch);
if (e) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[SysDec] Codec %s AU CTS %d Decode error %s\n", sdec->module_name , cts, gf_error_to_string(e) ));
if (e<0) ch->stream_state = 2;
goto exit;
}
if (codec->ck->no_time_ctrl) {
GF_Scene *scene = codec->odm->subscene ? codec->odm->subscene : codec->odm->parentscene;
if (codec->flags & GF_ESM_CODEC_IS_STATIC_OD) gf_clock_reset(codec->ck);
if (scene->graph_attached != 1) {
Bool prev_dyn = scene->is_dynamic_scene;
scene->is_dynamic_scene = 1;
gf_scene_regenerate(scene);
scene->graph_attached = 2;
scene->is_dynamic_scene = prev_dyn;
GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[Decoder] Got OD resources before scene - generating temporary scene\n"));
}
}
if (check_next_unit) goto check_unit;
exit:
if (scene_locked) {
gf_mx_v(scene_locked->root_od->term->compositor->mx);
}
return e;
}
static GF_Err PrivateScene_Process(GF_Codec *codec, u32 TimeAvailable)
{
u64 now;
GF_Channel *ch;
GF_Scene *scene_locked;
GF_SceneDecoder *sdec = (GF_SceneDecoder *)codec->decio;
GF_Err e = GF_OK;
if (codec->Muted) return GF_OK;
if (codec->Status == GF_ESM_CODEC_EOS) {
gf_term_stop_codec(codec, 2);
return GF_OK;
}
scene_locked = codec->odm->subscene ? codec->odm->subscene : codec->odm->parentscene;
ch = (GF_Channel*)gf_list_get(codec->inChannels, 0);
if (!ch) return GF_OK;
if (!ch->IsClockInit) {
Bool started;
if (!gf_mx_try_lock(scene_locked->root_od->term->compositor->mx)) return GF_OK;
gf_es_init_dummy(ch);
if (codec->odm->term->bench_mode != 2) {
sdec->ProcessData(sdec, NULL, 0, ch->esd->ESID, -1, GF_CODEC_LEVEL_NORMAL);
}
gf_mx_v(scene_locked->root_od->term->compositor->mx);
started = gf_clock_is_started(ch->clock);
gf_clock_pause(ch->clock);
codec->last_unit_dts = 0;
if (!started) return GF_OK;
}
codec->odm->media_current_time = codec->last_unit_cts = gf_clock_time(codec->ck);
codec->odm->media_current_time += codec->ck->media_time_at_init;
codec->odm->media_current_time -= codec->ck->init_time;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[PrivateDec] Codec %s Processing at %d\n", sdec->module_name, codec->last_unit_cts));
if (!gf_mx_try_lock(scene_locked->root_od->term->compositor->mx)) return GF_OK;
now = gf_sys_clock_high_res();
if (codec->odm->term->bench_mode == 2) {
e = GF_OK;
} else {
e = sdec->ProcessData(sdec, NULL, 0, ch->esd->ESID, codec->last_unit_cts, GF_CODEC_LEVEL_NORMAL);
}
now = gf_sys_clock_high_res() - now;
codec->last_unit_dts ++;
if (e && (codec->last_unit_dts<2) ) {
gf_clock_resume(ch->clock);
codec->last_unit_dts = 2;
}
else if (codec->last_unit_dts==2) {
gf_clock_resume(ch->clock);
}
codec_update_stats(codec, 0, now, codec->last_unit_cts, 0);
gf_mx_v(scene_locked->root_od->term->compositor->mx);
if (e==GF_EOS) {
gf_es_on_eos(ch);
return GF_OK;
}
return e;
}
static GFINLINE GF_Err LockCompositionUnit(GF_Codec *dec, u32 CU_TS, GF_CMUnit **cu, u32 *cu_size)
{
if (!dec->CB) return GF_BAD_PARAM;
*cu = gf_cm_lock_input(dec->CB, CU_TS, dec->is_reordering);
if (! *cu ) return GF_OUT_OF_MEM;
*cu_size = dec->CB->UnitSize;
return GF_OK;
}
static GFINLINE GF_Err UnlockCompositionUnit(GF_Codec *dec, GF_CMUnit *CU, u32 cu_size)
{
if (cu_size && dec->is_reordering) {
if (dec->trusted_cts && (CU->prev->dataLength && CU->prev->TS > CU->TS) ) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[%s] ODM%d codec is reordering but CTSs are out of order (%u vs %u prev) - forcing CTS recomputing\n", dec->decio->module_name, dec->odm->OD->objectDescriptorID, CU->TS, CU->prev->TS));
dec->trusted_cts = GF_FALSE;
}
if (!dec->trusted_cts) {
if (!dec->first_frame_dispatched) {
dec->recomputed_cts = CU->TS;
dec->first_frame_dispatched = 1;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d reordering mode - first frame dispatch - CTS %d - min TS diff %d\n", dec->decio->module_name, dec->odm->OD->objectDescriptorID, dec->recomputed_cts, dec->min_au_duration));
} else if (dec->min_au_duration) {
dec->recomputed_cts += dec->min_au_duration;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d reordering mode - original CTS %d recomputed CTS %d - min TS diff %d\n", dec->decio->module_name, dec->odm->OD->objectDescriptorID, CU->TS, dec->recomputed_cts, dec->min_au_duration));
CU->TS = dec->recomputed_cts;
}
}
}
gf_cm_unlock_input(dec->CB, CU, cu_size, dec->is_reordering);
return GF_OK;
}
GF_Err gf_codec_resize_composition_buffer(GF_Codec *dec, u32 NewSize)
{
if (!dec || !dec->CB) return GF_BAD_PARAM;
gf_mo_update_caps(dec->odm->mo);
if (!dec->bytes_per_sec) {
if (NewSize && (NewSize != dec->CB->UnitSize) ) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[ODM] Resizing composition buffer for codec %s - %d bytes per unit\n", dec->decio->module_name, NewSize));
gf_cm_resize(dec->CB, NewSize);
}
}
else {
u32 unit_size, audio_buf_len, unit_count;
GF_CodecCapability cap;
unit_size = NewSize;
audio_buf_len = 200;
cap.CapCode = GF_CODEC_BUFFER_MAX;
gf_codec_get_capability(dec, &cap);
unit_count = cap.cap.valueInt;
if (unit_count<2) unit_count = 2;
while (unit_size*unit_count*1000 < dec->bytes_per_sec*audio_buf_len) unit_count++;
#ifdef __SYMBIAN32__
unit_count = 10;
#endif
gf_cm_reinit(dec->CB, unit_size, unit_count);
dec->CB->Min = unit_count/3;
if (!dec->CB->Min) dec->CB->Min = 1;
}
dec->total_dec_time = 0;
dec->nb_dec_frames = 0;
dec->first_frame_time = 0;
dec->last_frame_time = 0;
dec->total_iframes_time = 0;
dec->max_iframes_time = 0;
dec->max_dec_time = 0;
dec->min_frame_dur = (u32) - 1;
dec->codec_reset = GF_TRUE;
dec->cur_bit_size = 0;
dec->last_stat_start = 0;
if ((dec->type==GF_STREAM_VISUAL) && dec->odm->parentscene->is_dynamic_scene) {
gf_scene_force_size_to_video(dec->odm->parentscene, dec->odm->mo);
}
return GF_OK;
}
static GF_Err MediaCodec_Process(GF_Codec *codec, u32 TimeAvailable)
{
GF_CMUnit *CU;
GF_DBUnit *AU;
GF_Channel *ch, *prev_ch;
Bool drop_late_frames = 0;
u64 now, entryTime;
u32 mmlevel, cts;
u32 first, obj_time, unit_size;
GF_MediaDecoder *mdec = (GF_MediaDecoder*)codec->decio;
GF_Err e = GF_OK;
s32 cts_diff;
u32 scal_unit_size=0;
CU = NULL;
if (codec->Muted && (codec->type==GF_STREAM_VISUAL) ) return GF_OK;
if (codec->CB->Capacity == codec->CB->UnitCount) {
if (codec->CB->UnitCount > 1) return GF_OK;
else if (codec->direct_frame_output|| codec->direct_vout) return GF_OK;
}
entryTime = gf_sys_clock_high_res();
if (!codec->odm->term->bench_mode) {
if ((codec->odm->term->flags & GF_TERM_DROP_LATE_FRAMES) || (codec->flags & GF_ESM_CODEC_IS_LOW_LATENCY))
drop_late_frames = GF_TRUE;
}
MediaDecoder_GetNextAU(codec, &ch, &AU);
if (!AU || !ch) {
if (codec->Status == GF_ESM_CODEC_EOS) {
if (codec->is_reordering) {
if ( LockCompositionUnit(codec, codec->last_unit_cts+1, &CU, &unit_size) == GF_OUT_OF_MEM)
return GF_OK;
assert( CU );
unit_size = 0;
if (codec->odm->term->bench_mode != 2) {
e = mdec->ProcessData(mdec, NULL, 0, 0, &CU->TS, CU->data, &unit_size, 0, 0);
if (e==GF_OK) {
UnlockCompositionUnit(codec, CU, unit_size);
if (unit_size) return GF_OK;
}
}
}
gf_term_stop_codec(codec, 2);
}
else if (ch && !ch->is_pulling && !ch->BufferOn && !ch->last_au_was_seek)
gf_cm_abort_buffering(codec->CB);
return GF_OK;
}
obj_time = gf_clock_time(codec->ck);
if (!codec->CB) {
gf_es_drop_au(ch);
return GF_BAD_PARAM;
}
if (codec->force_cb_resize) {
return GF_OK;
}
if (!codec->CB->no_allocation && (codec->CB->Capacity == 1)) {
u8 new_unit_signature[20];
gf_sha1_csum((u8*)AU->data, AU->dataLength, new_unit_signature);
if (!memcmp(codec->last_unit_signature, new_unit_signature, sizeof(new_unit_signature))) {
codec->nb_repeted_frames++;
gf_es_drop_au(ch);
return GF_OK;
}
if (codec->CB->UnitCount && (obj_time>=AU->CTS)) {
gf_mx_p(codec->odm->mx);
codec->CB->output->dataLength = 0;
codec->CB->UnitCount = 0;
gf_mx_v(codec->odm->mx);
}
if (codec->CB->UnitCount)
return GF_OK;
codec->nb_repeted_frames = 0;
memcpy(codec->last_unit_signature, new_unit_signature, sizeof(new_unit_signature));
}
if (codec->ck->speed != codec->check_speed) {
if (ABS(codec->check_speed) > ABS(codec->ck->speed)) {
codec->decode_only_rap = 0;
codec->drop_modulo = 0;
codec->drop_count = 0;
}
codec->check_speed = codec->ck->speed;
codec->consecutive_late_frames = 0;
codec->consecutive_ontime_frames = 0;
if (codec->type==GF_STREAM_AUDIO) {
if (ABS(FIX2FLT(codec->ck->speed)) > 8) {
codec->decode_only_rap = 2;
GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[%s] Speed %g too hight for audio decoder/renderer - skipping decode\n", codec->decio->module_name, FIX2FLT(codec->ck->speed)));
}
} else {
}
}
TimeAvailable*=1000;
first = 1;
while (codec->CB->Capacity > codec->CB->UnitCount) {
Bool force_skip = 0;
if (codec->decode_only_rap) {
if (AU->flags & GF_DB_AU_RAP) {
if (codec->decode_only_rap==2) {
if (AU->CTS > obj_time + 500)
return GF_OK;
force_skip = 1;
} else if (codec->drop_modulo) {
codec->drop_count ++;
if (codec->drop_count >= codec->drop_modulo) {
codec->drop_count = 0;
} else {
force_skip = 1;
}
}
} else {
force_skip = 1;
}
}
ch->last_au_was_seek = 0;
mmlevel = GF_CODEC_LEVEL_NORMAL;
if (AU->flags & GF_DB_AU_IS_SEEK) {
mmlevel = GF_CODEC_LEVEL_SEEK;
ch->last_au_was_seek = 1;
}
else if (!ch->skip_sl && codec->last_unit_cts && (codec->last_unit_cts == AU->CTS) && !ch->esd->dependsOnESID) {
mmlevel = GF_CODEC_LEVEL_SEEK;
ch->last_au_was_seek = 1;
if (
#ifndef GPAC_DISABLE_VRML
(codec->ck->mc && codec->ck->mc->paused) ||
#endif
(codec->odm->term->play_state)
) {
gf_cm_rewind_input(codec->CB);
mmlevel = GF_CODEC_LEVEL_NORMAL;
codec->odm->term->compositor->step_mode = GF_TRUE;
}
}
else if (!force_skip && (codec->ck->speed >= 0) && (codec->CB->Status == CB_PLAY)) {
if (!ch->skip_sl && (AU->CTS + (codec->is_reordering ? 1000 : 100) < obj_time) ) {
mmlevel = GF_CODEC_LEVEL_DROP;
GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] ODM%d: frame too late (CTS %d vs time %d) - using drop level\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, AU->CTS, obj_time));
#define IFRAME_MODE_THRESHOLD 50
codec->consecutive_late_frames++;
codec->consecutive_ontime_frames = 0;
if (codec->check_speed > 1) {
Double speed = (Double) FIX2FLT(codec->ck->speed);
u32 nb_check_frames = codec->decode_only_rap ? 5 : 30;
if (codec->consecutive_late_frames >= nb_check_frames) {
if (!codec->decode_only_rap) {
codec->drop_modulo += 2;
codec->drop_count = 0;
GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] ODM%d: %d consecutive late frames at speed %g - increasing frame drop modulo to %d\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, codec->consecutive_late_frames, speed, codec->drop_modulo));
if (codec->drop_modulo > IFRAME_MODE_THRESHOLD) {
GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] ODM%d: %d consecutive late frames at speed %g with drop modulo %d - moving to I-frame only decoding\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, codec->consecutive_late_frames, speed, codec->drop_modulo));
codec->drop_modulo = 0;
codec->drop_count = 0;
codec->decode_only_rap = 1;
}
} else {
codec->drop_modulo += 2;
codec->drop_count = 0;
GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] ODM%d: %d consecutive late frames at speed %g in I-frame only mode - decoding only one I-frame out of %d\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, codec->consecutive_late_frames, speed, codec->drop_modulo));
}
codec->consecutive_late_frames = 0;
}
else if (codec->decode_only_rap) {
if (obj_time - AU->CTS > 2000) {
force_skip = 1;
}
}
}
if (ch->resync_drift && (AU->CTS + ch->resync_drift < obj_time)) {
ch->clock->StartTime += (obj_time - AU->CTS);
GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[%s] ODM%d: decoder too slow on OCR stream - rewinding clock of %d ms\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, obj_time - AU->CTS));
obj_time = gf_clock_time(codec->ck);
}
}
else if (codec->PriorityBoost) {
mmlevel = GF_CODEC_LEVEL_VERY_LATE;
codec->consecutive_late_frames = 0;
codec->consecutive_ontime_frames ++;
}
else {
codec->consecutive_late_frames = 0;
codec->consecutive_ontime_frames ++;
if (first) {
if (codec->CB->UnitCount <= codec->CB->Min+1) {
mmlevel = GF_CODEC_LEVEL_VERY_LATE;
} else if (codec->CB->UnitCount * 2 <= codec->CB->Capacity) {
mmlevel = GF_CODEC_LEVEL_LATE;
}
first = 0;
}
}
if (codec->check_speed > 1) {
u32 nb_check_frames = codec->decode_only_rap ? 5 : 30;
if (codec->consecutive_ontime_frames > nb_check_frames) {
if (codec->drop_modulo) {
codec->drop_modulo -= 2;
codec->drop_count = 0;
GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] ODM%d: %d consecutive on-time frames - Decreasing drop modulo %d (I-frame only mode %d)\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, codec->consecutive_ontime_frames, codec->drop_modulo, codec->decode_only_rap));
codec->consecutive_late_frames = 0;
codec->consecutive_ontime_frames = 0;
}
}
}
}
if (ch->skip_sl) {
if (codec->bytes_per_sec) {
AU->CTS = codec->last_unit_cts + ch->ts_offset + codec->cur_audio_bytes * 1000 / codec->bytes_per_sec;
} else if (codec->fps) {
AU->CTS = codec->last_unit_cts + ch->ts_offset + (u32) (codec->cur_video_frames * 1000 / codec->fps);
}
}
if ( LockCompositionUnit(codec, AU->CTS, &CU, &unit_size) == GF_OUT_OF_MEM) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] Exit decode loop because no more space in composition buffer\n", codec->decio->module_name ));
return GF_OK;
}
scalable_retry:
now = gf_sys_clock_high_res();
assert( CU );
if (!CU->data && unit_size && !codec->CB->no_allocation) {
e = GF_OUT_OF_MEM;
} else if (codec->odm->term->bench_mode==2) {
unit_size = 0;
gf_cm_abort_buffering(codec->CB);
} else if (force_skip) {
unit_size = 0;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d: force drop requested in fast playback for AU CTS %u\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, AU->CTS));
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] At %u ODM%d ES%d decoding frame DTS %u CTS %u size %d (%d in channels)\n", codec->decio->module_name, gf_clock_real_time(ch->clock), codec->odm->OD->objectDescriptorID, ch->esd->ESID, AU->DTS, AU->CTS, AU->dataLength, ch->AU_Count));
e = mdec->ProcessData(mdec, AU->data, AU->dataLength, ch->esd->ESID, &CU->TS, CU->data, &unit_size, AU->PaddingBits, mmlevel);
}
now = gf_sys_clock_high_res() - now;
if (codec->Status == GF_ESM_CODEC_STOP) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] Exit decode loop because codec has been stopped\n", codec->decio->module_name));
return GF_OK;
}
switch (e) {
case GF_BUFFER_TOO_SMALL:
UnlockCompositionUnit(codec, CU, 0);
if (codec->CB->LastRenderedTS) {
GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] ODM%d ES%d: Resize output buffer requested\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, ch->esd->ESID));
codec->force_cb_resize = unit_size;
return GF_OK;
}
GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] ODM%d ES%d: Resizing output buffer %d -> %d\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, ch->esd->ESID, codec->CB->UnitSize, unit_size));
gf_codec_resize_composition_buffer(codec, unit_size);
continue;
case GF_PACKED_FRAMES:
if (mmlevel == GF_CODEC_LEVEL_DROP) {
if (drop_late_frames && (codec->CB->UnitCount>1) ) {
unit_size = 0;
codec->nb_dropped++;
} else
ch->clock->last_TS_rendered = codec->CB->LastRenderedTS;
}
e = UnlockCompositionUnit(codec, CU, unit_size);
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] ODM%d ES%d at %d decoded packed frame TS %u in "LLU" us\n", codec->decio->module_name, codec->odm->OD->objectDescriptorID, ch->esd->ESID, gf_clock_real_time(ch->clock), AU->CTS, now));
if (ch->skip_sl) {
if (codec->bytes_per_sec) {
codec->cur_audio_bytes += unit_size;
} else if (codec->fps && unit_size) {
codec->cur_video_frames += 1;
}
} else {
u32 deltaTS = 0;
if (codec->bytes_per_sec) {
deltaTS = unit_size * 1000 / codec->bytes_per_sec;
}
else {
deltaTS = (AU->DTS - codec->last_unit_dts);
}
AU->CTS += deltaTS;
}
codec_update_stats(codec, 0, now, 0, 0);
continue;
case GF_OK:
if (unit_size) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] At %u ODM%d ES%d decoded frame DTS %u CTS %u size %d in "LLU" us - %d in CB\n", codec->decio->module_name, gf_clock_real_time(ch->clock), codec->odm->OD->objectDescriptorID, ch->esd->ESID, AU->DTS, AU->CTS, AU->dataLength, now, codec->CB->UnitCount + 1));
if (codec->direct_frame_output) {
Bool needs_resize = 0;
if (CU->frame) {
CU->frame->Release(CU->frame);
CU->frame = NULL;
}
e = mdec->GetOutputFrame(mdec, ch->esd->ESID, &CU->frame, &needs_resize);
if (e!=GF_OK) {
CU->frame=NULL;
}
if (!CU->frame)
unit_size = 0;
else if (needs_resize) {
assert(unit_size);
if ((codec->type==GF_STREAM_VISUAL) && codec->odm->parentscene->is_dynamic_scene) {
gf_mo_update_caps(codec->odm->mo);
gf_scene_force_size_to_video(codec->odm->parentscene, codec->odm->mo);
}
}
}
else if (codec->direct_vout) {
e = mdec->GetOutputBuffer(mdec, ch->esd->ESID, &codec->CB->pY, &codec->CB->pU, &codec->CB->pV);
if (e==GF_OK) {
gf_sc_set_video_pending_frame(codec->odm->term->compositor);
}
}
CU->sender_ntp = AU->sender_ntp;
}
#if 0
else if ( (!codec->CB->UnitSize && !codec->CB->Capacity) && (codec->CB->Status == CB_BUFFER)) {
codec->nb_dispatch_skipped++;
if (codec->nb_dispatch_skipped==codec->CB->UnitCount)
gf_cm_abort_buffering(codec->CB);
}
#endif
codec_update_stats(codec, AU->dataLength, now, AU->DTS, (AU->flags & GF_DB_AU_RAP));
if (ch->skip_sl) {
if (codec->bytes_per_sec) {
codec->cur_audio_bytes += unit_size;
while (codec->cur_audio_bytes>codec->bytes_per_sec) {
codec->cur_audio_bytes -= codec->bytes_per_sec;
codec->last_unit_cts += 1000;
}
} else if (codec->fps && unit_size) {
codec->cur_video_frames += 1;
}
}
#ifndef GPAC_DISABLE_LOGS
if (codec->odm->flags & GF_ODM_PREFETCH) {
GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] At %d ODM%d ES%d decoding frame TS %u in prefetch mode\n", codec->decio->module_name, gf_clock_real_time(ch->clock), codec->odm->OD->objectDescriptorID, ch->esd->ESID, AU->CTS));
}
#endif
break;
case GF_PROFILE_NOT_SUPPORTED:
UnlockCompositionUnit(codec, CU, 0);
GF_LOG(GF_LOG_WARNING, GF_LOG_CODEC, ("[%s] Unsupported profile detected, blacklisting decoder for this stream and changing decoder\n", codec->decio->module_name ));
return gf_codec_change_decoder(codec);
case GF_CODEC_BUFFER_UNAVAILABLE:
if (unit_size) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] At %u ODM%d ES%d decoded frame DTS %u CTS %u size %d in "LLU" us - %d in CB\n", codec->decio->module_name, gf_clock_real_time(ch->clock), codec->odm->OD->objectDescriptorID, ch->esd->ESID, AU->DTS, AU->CTS, AU->dataLength, now, codec->CB->UnitCount + 1));
if (codec->direct_frame_output) {
Bool needs_resize = 0;
if (CU->frame) {
CU->frame->Release(CU->frame);
CU->frame = NULL;
}
e = mdec->GetOutputFrame(mdec, ch->esd->ESID, &CU->frame, &needs_resize);
if (e!=GF_OK) {
CU->frame=NULL;
}
if (!CU->frame)
unit_size = 0;
else if (needs_resize) {
assert(unit_size);
if ((codec->type==GF_STREAM_VISUAL) && codec->odm->parentscene->is_dynamic_scene) {
gf_mo_update_caps(codec->odm->mo);
gf_scene_force_size_to_video(codec->odm->parentscene, codec->odm->mo);
}
}
}
else if (codec->direct_vout) {
e = mdec->GetOutputBuffer(mdec, ch->esd->ESID, &codec->CB->pY, &codec->CB->pU, &codec->CB->pV);
if (e==GF_OK) {
gf_sc_set_video_pending_frame(codec->odm->term->compositor);
}
}
CU->sender_ntp = AU->sender_ntp;
}
codec_update_stats(codec, AU->dataLength, now, AU->DTS, (AU->flags & GF_DB_AU_RAP));
UnlockCompositionUnit(codec, CU, unit_size);
continue;
default:
unit_size = 0;
gf_cm_abort_buffering(codec->CB);
GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[%s] At %d ODM%d ES%d (frame TS %u - "LLU" us ): decoded error %s\n", codec->decio->module_name, gf_clock_real_time(ch->clock), codec->odm->OD->objectDescriptorID, ch->esd->ESID, AU->CTS, now, gf_error_to_string(e) ));
e = GF_OK;
break;
}
codec->last_unit_dts = AU->DTS;
if (!ch->esd->dependsOnESID && !ch->skip_sl) {
codec->last_unit_cts = AU->CTS;
codec->first_frame_processed = 1;
}
#ifndef GPAC_DISABLE_LOG
if (unit_size) {
if (ch->is_pulling) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[%s] at %u decoded frame DTS %u CTS %u in "LLU" us\n", codec->decio->module_name, gf_clock_real_time(ch->clock), AU->DTS,AU->CTS, now));
} else {
GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[%s] at %u decoded frame DTS %u CTS %u in "LLU" us - %d AU in channel\n", codec->decio->module_name, gf_clock_real_time(ch->clock), AU->DTS, AU->CTS, now, ch->AU_Count));
}
}
#endif
gf_es_lock(ch, GF_TRUE);
cts = AU->CTS;
prev_ch = ch;
gf_es_drop_au(ch);
gf_es_lock(ch, GF_FALSE);
AU = NULL;
if (e) {
UnlockCompositionUnit(codec, CU, unit_size);
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] Exit decode loop because error %s\n", codec->decio->module_name, gf_error_to_string(e) ));
return e;
}
MediaDecoder_GetNextAU(codec, &ch, &AU);
if (AU && (AU->CTS == cts) && (ch != prev_ch) ) {
if (scal_unit_size < unit_size) scal_unit_size = unit_size;
unit_size = codec->CB->UnitSize;
goto scalable_retry;
}
if (!unit_size && scal_unit_size)
unit_size = scal_unit_size;
if (mmlevel >= GF_CODEC_LEVEL_DROP) {
if (drop_late_frames || (mmlevel == GF_CODEC_LEVEL_SEEK) ) {
unit_size = 0;
if (drop_late_frames) codec->nb_dropped++;
} else
prev_ch->clock->last_TS_rendered = codec->CB->LastRenderedTS;
} else {
prev_ch->clock->last_TS_rendered = 0;
}
if (!codec->decode_only_rap && codec->drop_modulo) {
codec->drop_count++;
if (codec->drop_count==codec->drop_modulo) {
codec->drop_count = 0;
} else {
unit_size = 0;
}
}
cts_diff = (s32) cts;
cts_diff -= (s32) CU->TS;
if (cts_diff < 0) cts_diff = -cts_diff;
if (cts_diff > 20000 ) {
GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[%s] decoded frame CTS %d but input frame CTS %d, lilely due to clock discontinuity\n", codec->decio->module_name, CU->TS, cts));
CU->TS = cts;
}
UnlockCompositionUnit(codec, CU, unit_size);
if (unit_size) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[%s] at %u dispatched frame CTS %u in CB\n", codec->decio->module_name, gf_clock_real_time(prev_ch->clock), CU->TS));
}
if (!ch || !AU) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] Exit decode loop because no more input data\n", codec->decio->module_name));
return GF_OK;
}
if (force_skip) continue;
now = gf_sys_clock_high_res() - entryTime;
if (!ch->esd->dependsOnESID && (codec->CB->UnitCount > codec->CB->Min)) {
if (now >= TimeAvailable) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] Exit decode loop because time is up: %d vs %d us available\n", codec->decio->module_name, now, TimeAvailable));
return GF_OK;
}
} else if (now >= TimeAvailable) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[%s] Exit decode loop because running for too long: %d vs %d us available\n", codec->decio->module_name, now, TimeAvailable));
return GF_OK;
} else if (codec->odm->term->bench_mode) {
return GF_OK;
}
}
return GF_OK;
}
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;
}
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);
}
Decoder_GetNextAU(codec, &ch, &db);
if (!db) return GF_OK;
gf_es_dispatch_raw_media_au(ch, db->data, db->dataLength, db->CTS);
gf_term_channel_release_sl_packet(ch->service, ch);
return GF_OK;
}
GF_Err gf_codec_process_ocr(GF_Codec *codec, u32 TimeAvailable)
{
GF_DBUnit *AU;
GF_Channel *ch;
Decoder_GetNextAU(codec, &ch, &AU);
if (!AU || !ch) {
if (codec->Status == GF_ESM_CODEC_EOS) {
gf_term_stop_codec(codec, 2);
#ifndef GPAC_DISABLE_VRML
if (codec->odm->media_ctrl && codec->odm->media_ctrl->control->loop) mediacontrol_restart(codec->odm);
#endif
}
}
return GF_OK;
}
GF_Err gf_codec_process(GF_Codec *codec, u32 TimeAvailable)
{
if (codec->Status == GF_ESM_CODEC_STOP) return GF_OK;
#ifndef GPAC_DISABLE_VRML
codec->Muted = (codec->odm->media_ctrl && codec->odm->media_ctrl->control->mute) ? 1 : 0;
#else
codec->Muted = 0;
#endif
return codec->process(codec, TimeAvailable);
}
GF_Err gf_codec_get_capability(GF_Codec *codec, GF_CodecCapability *cap)
{
cap->cap.valueInt = 0;
if (codec->decio) {
return codec->decio->GetCapabilities(codec->decio, cap);
}
if (codec->flags & GF_ESM_CODEC_IS_RAW_MEDIA) {
GF_BitStream *bs;
u32 pf, w, h, stride=0, out_size, sr, nb_ch, bpp, ch_cfg, is_flipped = 0;
GF_Channel *ch = gf_list_get(codec->odm->channels, 0);
if (!ch || !ch->esd->decoderConfig->decoderSpecificInfo || !ch->esd->decoderConfig->decoderSpecificInfo->data) return 0;
bs = gf_bs_new(ch->esd->decoderConfig->decoderSpecificInfo->data, ch->esd->decoderConfig->decoderSpecificInfo->dataLength, GF_BITSTREAM_READ);
pf = w = h = sr = nb_ch = bpp = ch_cfg = 0;
if (codec->type==GF_STREAM_VISUAL) {
pf = gf_bs_read_u32(bs);
w = gf_bs_read_u16(bs);
h = gf_bs_read_u16(bs);
out_size = gf_bs_read_u32(bs);
stride = gf_bs_read_u32(bs);
is_flipped = gf_bs_read_u8(bs);
} else {
sr = gf_bs_read_u32(bs);
nb_ch = gf_bs_read_u16(bs);
bpp = gf_bs_read_u16(bs);
out_size = gf_bs_read_u32(bs);
ch_cfg = gf_bs_read_u32(bs);
}
gf_bs_del(bs);
switch (cap->CapCode) {
case GF_CODEC_WIDTH:
cap->cap.valueInt = w;
return GF_OK;
case GF_CODEC_HEIGHT:
cap->cap.valueInt = h;
return GF_OK;
case GF_CODEC_STRIDE:
cap->cap.valueInt = stride;
return GF_OK;
case GF_CODEC_PIXEL_FORMAT:
cap->cap.valueInt = pf;
return GF_OK;
case GF_CODEC_FLIP:
cap->cap.valueInt = is_flipped;
return GF_OK;
case GF_CODEC_OUTPUT_SIZE:
cap->cap.valueInt = out_size;
return GF_OK;
case GF_CODEC_SAMPLERATE:
cap->cap.valueInt = sr;
return GF_OK;
case GF_CODEC_NB_CHAN:
cap->cap.valueInt = nb_ch;
return GF_OK;
case GF_CODEC_BITS_PER_SAMPLE:
cap->cap.valueInt = bpp;
return GF_OK;
case GF_CODEC_CHANNEL_CONFIG:
cap->cap.valueInt = ch_cfg;
return GF_OK;
case GF_CODEC_PAR:
cap->cap.valueInt = 0;
return GF_OK;
case GF_CODEC_PADDING_BYTES:
cap->cap.valueInt = 0;
return GF_OK;
case GF_CODEC_RESILIENT:
cap->cap.valueInt = 1;
return GF_OK;
}
}
return GF_BAD_PARAM;
}
GF_Err gf_codec_set_capability(GF_Codec *codec, GF_CodecCapability cap)
{
if (!codec->decio) return GF_OK;
return codec->decio->SetCapabilities(codec->decio, cap);
}
void gf_codec_set_status(GF_Codec *codec, u32 Status)
{
if (!codec) return;
if (Status == GF_ESM_CODEC_PAUSE) {
codec->Status = codec->CB ? GF_ESM_CODEC_PAUSE : GF_ESM_CODEC_STOP;
}
else if (Status == GF_ESM_CODEC_BUFFER) codec->Status = GF_ESM_CODEC_PLAY;
else if (Status == GF_ESM_CODEC_PLAY) {
codec->last_unit_cts = 0;
codec->prev_au_size = 0;
codec->Status = Status;
codec->last_stat_start = codec->cur_bit_size = codec->max_bit_rate = codec->avg_bit_rate = 0;
codec->nb_dec_frames = 0;
codec->nb_iframes = 0;
codec->max_iframes_time = 0;
codec->total_iframes_time = 0;
codec->total_dec_time = 0;
codec->max_dec_time = 0;
codec->cur_audio_bytes = codec->cur_video_frames = 0;
codec->nb_dropped = 0;
codec->nb_repeted_frames = 0;
codec->recomputed_cts = 0;
codec->first_frame_dispatched = 0;
codec->first_frame_processed = 0;
codec->nb_dispatch_skipped = 0;
memset(codec->last_unit_signature, 0, sizeof(codec->last_unit_signature));
}
else
codec->Status = Status;
if (!codec->CB) return;
switch (Status) {
case GF_ESM_CODEC_PLAY:
gf_cm_set_status(codec->CB, CB_PLAY);
if (codec->flags & GF_ESM_CODEC_IS_LOW_LATENCY) {
gf_cm_abort_buffering(codec->CB);
}
return;
case GF_ESM_CODEC_PAUSE:
gf_cm_set_status(codec->CB, CB_PAUSE);
return;
case GF_ESM_CODEC_STOP:
gf_cm_set_status(codec->CB, CB_STOP);
return;
case GF_ESM_CODEC_EOS:
return;
case GF_ESM_CODEC_BUFFER:
default:
return;
}
}
static u32 get_codec_confidence(GF_Codec *codec, GF_BaseDecoder *ifce, GF_ESD *esd, u32 PL)
{
u32 conf = 0;
u32 i_es;
for (i_es=0; i_es<gf_list_count(codec->odm->OD->ESDescriptors); i_es++) {
GF_ESD *an_esd = gf_list_get(codec->odm->OD->ESDescriptors, i_es);
u32 c;
if (an_esd->decoderConfig->streamType != esd->decoderConfig->streamType) continue;
if (an_esd->dependsOnESID && (an_esd->decoderConfig->objectTypeIndication != esd->decoderConfig->objectTypeIndication)) {
codec->hybrid_layered_coded = 1;
}
c = ifce->CanHandleStream(ifce, an_esd->decoderConfig->streamType, an_esd, PL);
if (!conf || (c<conf) ) conf=c;
}
return conf;
}
Bool decio_blacklisted(GF_Codec *codec, const char *ifce_name)
{
u32 i, count;
if (!codec->blacklisted) return GF_FALSE;
count = gf_list_count(codec->blacklisted);
for (i=0; i<count; i++) {
const char *name = gf_list_get(codec->blacklisted, i);
if (!stricmp(name, ifce_name)) return GF_TRUE;
}
return GF_FALSE;
}
static GF_Err Codec_LoadModule(GF_Codec *codec, GF_ESD *esd, u32 PL)
{
char szPrefDec[500];
const char *sOpt;
GF_BaseDecoder *ifce, *dec_ifce;
u32 i, plugCount;
u32 ifce_type;
Bool do_dec_switch = GF_TRUE;
u32 dec_confidence;
GF_Terminal *term = codec->odm->term;
codec->profile_level = PL;
switch (esd->decoderConfig->streamType) {
case GF_STREAM_AUDIO:
case GF_STREAM_VISUAL:
case GF_STREAM_ND_SUBPIC:
ifce_type = GF_MEDIA_DECODER_INTERFACE;
codec->process = MediaCodec_Process;
break;
case GF_STREAM_PRIVATE_MEDIA:
ifce_type = GF_PRIVATE_MEDIA_DECODER_INTERFACE;
codec->process = gf_codec_process_private_media;
break;
case GF_STREAM_PRIVATE_SCENE:
ifce_type = GF_SCENE_DECODER_INTERFACE;
codec->process = PrivateScene_Process;
break;
default:
ifce_type = GF_SCENE_DECODER_INTERFACE;
codec->process = SystemCodec_Process;
if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_SCENE_AFX) {
ifce_type = GF_NODE_DECODER_INTERFACE;
}
break;
}
if (0 && !stricmp(codec->odm->net_service->ifce->module_name, "FFMPEG demuxer")) {
sOpt = "FFMPEG decoder";
} else {
sOpt = NULL;
switch (esd->decoderConfig->streamType) {
case GF_STREAM_VISUAL:
if ((esd->decoderConfig->objectTypeIndication==GPAC_OTI_IMAGE_JPEG) || (esd->decoderConfig->objectTypeIndication==GPAC_OTI_IMAGE_PNG))
sOpt = gf_cfg_get_key(term->user->config, "Systems", "DefImageDec");
else
sOpt = gf_cfg_get_key(term->user->config, "Systems", "DefVideoDec");
break;
case GF_STREAM_AUDIO:
sOpt = gf_cfg_get_key(term->user->config, "Systems", "DefAudioDec");
break;
default:
break;
}
}
dec_confidence = 0;
ifce = NULL;
if (sOpt && decio_blacklisted(codec, sOpt))
sOpt = NULL;
if (sOpt) {
ifce = (GF_BaseDecoder *) gf_modules_load_interface_by_name(term->user->modules, sOpt, ifce_type);
if (ifce) {
if (ifce->CanHandleStream) {
dec_confidence = get_codec_confidence(codec, ifce, esd, PL);
if (dec_confidence==GF_CODEC_SUPPORTED) {
codec->decio = ifce;
return GF_OK;
}
if (dec_confidence==GF_CODEC_NOT_SUPPORTED) {
gf_modules_close_interface((GF_BaseInterface *) ifce);
ifce = NULL;
}
} else {
gf_modules_close_interface((GF_BaseInterface *) ifce);
}
}
}
dec_ifce = ifce;
sprintf(szPrefDec, "codec_%02X_%02X", esd->decoderConfig->streamType, esd->decoderConfig->objectTypeIndication);
sOpt = gf_cfg_get_key(term->user->config, "Systems", szPrefDec);
if (!sOpt && (esd->decoderConfig->streamType==GF_STREAM_AUDIO)) {
switch (esd->decoderConfig->objectTypeIndication) {
case GPAC_OTI_AUDIO_MPEG2_PART3:
case GPAC_OTI_AUDIO_MPEG1:
sOpt = "MAD Decoder";
gf_cfg_set_key(term->user->config, "Systems", szPrefDec, sOpt);
}
}
if (sOpt) {
ifce = (GF_BaseDecoder *) gf_modules_load_interface_by_name(term->user->modules, sOpt, ifce_type);
if (ifce) {
if (ifce->CanHandleStream && !decio_blacklisted(codec, ifce->module_name)) {
u32 conf = get_codec_confidence(codec, ifce, esd, PL);
if ((conf!=GF_CODEC_NOT_SUPPORTED) && (conf>=dec_confidence)) {
if (dec_ifce) gf_modules_close_interface((GF_BaseInterface *) dec_ifce);
dec_confidence = conf;
dec_ifce = ifce;
ifce = NULL;
if (dec_confidence>=GF_CODEC_MAYBE_SUPPORTED) {
codec->decio = dec_ifce;
return GF_OK;
}
}
}
if (ifce)
gf_modules_close_interface((GF_BaseInterface *) ifce);
}
}
plugCount = gf_modules_get_count(term->user->modules);
for (i = 0; i < plugCount ; i++) {
ifce = (GF_BaseDecoder *) gf_modules_load_interface(term->user->modules, i, ifce_type);
if (!ifce) continue;
if (ifce->CanHandleStream && !decio_blacklisted(codec, ifce->module_name)) {
u32 conf = get_codec_confidence(codec, ifce, esd, PL);
if (conf==GF_CODEC_PROFILE_NOT_SUPPORTED) do_dec_switch = GF_FALSE;
if ((conf!=GF_CODEC_NOT_SUPPORTED) && (conf>dec_confidence)) {
if (dec_ifce) gf_modules_close_interface((GF_BaseInterface *) dec_ifce);
dec_confidence = conf;
dec_ifce = ifce;
ifce = NULL;
}
}
if (ifce)
gf_modules_close_interface((GF_BaseInterface *) ifce);
}
if (dec_ifce) {
codec->decio = dec_ifce;
if (do_dec_switch && !codec->blacklisted) {
sprintf(szPrefDec, "codec_%02X_%02X", esd->decoderConfig->streamType, esd->decoderConfig->objectTypeIndication);
gf_cfg_set_key(term->user->config, "Systems", szPrefDec, dec_ifce->module_name);
}
return GF_OK;
}
return GF_CODEC_NOT_FOUND;
}
GF_Err gf_codec_change_decoder(GF_Codec *codec)
{
GF_Err e;
u32 i, count;
GF_ESD *esd=NULL;
if (!codec || !codec->decio) return GF_CODEC_NOT_FOUND;
if (!codec->blacklisted) codec->blacklisted = gf_list_new();
gf_list_add(codec->blacklisted, gf_strdup(codec->decio->module_name) );
count = gf_list_count(codec->inChannels);
for (i=0; i<count; i++) {
GF_Channel *ch = gf_list_get(codec->inChannels, i);
if (ch && ch->esd) {
codec->decio->DetachStream(codec->decio, ch->esd->ESID);
if (!esd) esd = ch->esd;
}
}
gf_modules_close_interface((GF_BaseInterface *) codec->decio);
codec->decio = NULL;
if (!esd) return GF_CODEC_NOT_FOUND;
e = Codec_LoadModule(codec, esd, codec->profile_level);
if (e) return e;
if (!codec->decio) return GF_CODEC_NOT_FOUND;
for (i=0; i<count; i++) {
GF_Channel *ch = gf_list_get(codec->inChannels, i);
if (ch && ch->esd) {
codec->decio->AttachStream(codec->decio, ch->esd);
}
}
return GF_OK;
}
GF_Err Codec_Load(GF_Codec *codec, GF_ESD *esd, u32 PL)
{
switch (esd->decoderConfig->streamType) {
case GF_STREAM_OCR:
codec->decio = NULL;
codec->process = gf_codec_process_ocr;
return GF_OK;
#ifndef GPAC_DISABLE_VRML
case GF_STREAM_INTERACT:
codec->decio = (GF_BaseDecoder *) gf_isdec_new(esd, PL);
assert(codec->decio->InterfaceType == GF_SCENE_DECODER_INTERFACE);
codec->process = SystemCodec_Process;
return GF_OK;
#endif
case GF_STREAM_VISUAL:
case GF_STREAM_AUDIO:
if (!esd->decoderConfig->objectTypeIndication)
return GF_NON_COMPLIANT_BITSTREAM;
if (esd->decoderConfig->objectTypeIndication==GPAC_OTI_RAW_MEDIA_STREAM) {
codec->flags |= GF_ESM_CODEC_IS_RAW_MEDIA;
codec->process = gf_codec_process_private_media;
return GF_OK;
}
default:
return Codec_LoadModule(codec, esd, PL);
}
}
void gf_codec_del(GF_Codec *codec)
{
if (!codec || !codec->inChannels)
return;
if (gf_list_count(codec->inChannels)) return;
if (codec->CB) gf_cm_del(codec->CB);
codec->CB = NULL;
if (!(codec->flags & GF_ESM_CODEC_IS_USE)) {
switch (codec->type) {
#ifndef GPAC_DISABLE_VRML
case GF_STREAM_INTERACT:
gf_mx_p(codec->odm->term->net_mx);
gf_isdec_del(codec->decio);
gf_list_del_item(codec->odm->term->input_streams, codec);
gf_mx_v(codec->odm->term->net_mx);
break;
#endif
default:
if (codec->decio)
gf_modules_close_interface((GF_BaseInterface *) codec->decio);
break;
}
}
if (codec->inChannels) gf_list_del(codec->inChannels);
codec->inChannels = NULL;
if (codec->blacklisted) {
while (gf_list_count(codec->blacklisted)) {
char *name = gf_list_pop_back(codec->blacklisted);
gf_free(name);
}
gf_list_del(codec->blacklisted);
}
gf_free(codec);
}