GF_Err ISOR_ServiceCommand(GF_InputService *plug, GF_NetworkCommand *com) { Double track_dur, media_dur; ISOMChannel *ch; ISOMReader *read; if (!plug || !plug->priv || !com) return GF_SERVICE_ERROR; read = (ISOMReader *) plug->priv; if (com->command_type==GF_NET_SERVICE_INFO) { u32 tag_len; const char *tag; if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_NAME, &tag, &tag_len)==GF_OK) com->info.name = tag; if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_ARTIST, &tag, &tag_len)==GF_OK) com->info.artist = tag; if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_ALBUM, &tag, &tag_len)==GF_OK) com->info.album = tag; if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_COMMENT, &tag, &tag_len)==GF_OK) com->info.comment = tag; if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_TRACK, &tag, &tag_len)==GF_OK) { com->info.track_info = (((tag[2]<<8)|tag[3]) << 16) | ((tag[4]<<8)|tag[5]); } if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_COMPOSER, &tag, &tag_len)==GF_OK) com->info.composer = tag; if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_WRITER, &tag, &tag_len)==GF_OK) com->info.writer = tag; if (gf_isom_apple_get_tag(read->mov, GF_ISOM_ITUNE_GENRE, &tag, &tag_len)==GF_OK) { if (tag[0]) { com->info.genre = 0; } else { com->info.genre = (tag[0]<<8) | tag[1]; } } return GF_OK; } if (com->command_type==GF_NET_SERVICE_HAS_AUDIO) { u32 i, count; count = gf_isom_get_track_count(read->mov); for (i=0; i<count; i++) { if (gf_isom_get_media_type(read->mov, i+1) == GF_ISOM_MEDIA_AUDIO) return GF_OK; } return GF_NOT_SUPPORTED; } if (!com->base.on_channel) return GF_NOT_SUPPORTED; ch = isor_get_channel(read, com->base.on_channel); if (!ch) return GF_STREAM_NOT_FOUND; switch (com->command_type) { case GF_NET_CHAN_SET_PADDING: if (!ch->track) return GF_OK; gf_isom_set_sample_padding(read->mov, ch->track, com->pad.padding_bytes); return GF_OK; case GF_NET_CHAN_SET_PULL: ch->is_pulling = 1; return GF_OK; case GF_NET_CHAN_INTERACTIVE: return GF_OK; case GF_NET_CHAN_BUFFER: com->buffer.max = com->buffer.min = 0; return GF_OK; case GF_NET_CHAN_DURATION: if (!ch->track) { com->duration.duration = 0; return GF_OK; } ch->duration = gf_isom_get_track_duration(read->mov, ch->track); track_dur = (Double) (s64) ch->duration; track_dur /= read->time_scale; if (gf_isom_get_edit_segment_count(read->mov, ch->track)) { com->duration.duration = (Double) track_dur; ch->duration = (u32) (track_dur * ch->time_scale); } else { /*some file indicate a wrong TrackDuration, get the longest*/ ch->duration = gf_isom_get_media_duration(read->mov, ch->track); media_dur = (Double) (s64) ch->duration; media_dur /= ch->time_scale; com->duration.duration = MAX(track_dur, media_dur); } return GF_OK; case GF_NET_CHAN_PLAY: if (!ch->is_pulling) return GF_NOT_SUPPORTED; assert(!ch->is_playing); isor_reset_reader(ch); ch->speed = com->play.speed; ch->start = ch->end = 0; if (com->play.speed>0) { if (com->play.start_range>=0) { ch->start = (u64) (s64) (com->play.start_range * ch->time_scale); ch->start = check_round(ch, ch->start, com->play.start_range, 1); } if (com->play.end_range >= com->play.start_range) { ch->end = (u64) (s64) (com->play.end_range*ch->time_scale); ch->end = check_round(ch, ch->end, com->play.end_range, 0); } } else if (com->play.speed<0) { if (com->play.end_range>=com->play.start_range) ch->start = (u64) (s64) (com->play.start_range * ch->time_scale); if (com->play.end_range >= 0) ch->end = (u64) (s64) (com->play.end_range*ch->time_scale); } ch->is_playing = 1; if (com->play.dash_segment_switch) ch->wait_for_segment_switch = 1; GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[IsoMedia] Starting channel playback "LLD" to "LLD" (%g to %g)\n", ch->start, ch->end, com->play.start_range, com->play.end_range)); return GF_OK; case GF_NET_CHAN_STOP: isor_reset_reader(ch); return GF_OK; /*nothing to do on MP4 for channel config*/ case GF_NET_CHAN_CONFIG: return GF_OK; case GF_NET_CHAN_GET_PIXEL_AR: return gf_isom_get_pixel_aspect_ratio(read->mov, ch->track, 1, &com->par.hSpacing, &com->par.vSpacing); case GF_NET_CHAN_GET_DSI: { /*it may happen that there are conflicting config when using ESD URLs...*/ GF_DecoderConfig *dcd = gf_isom_get_decoder_config(read->mov, ch->track, 1); com->get_dsi.dsi = NULL; com->get_dsi.dsi_len = 0; if (dcd) { if (dcd->decoderSpecificInfo) { com->get_dsi.dsi = dcd->decoderSpecificInfo->data; com->get_dsi.dsi_len = dcd->decoderSpecificInfo->dataLength; dcd->decoderSpecificInfo->data = NULL; } gf_odf_desc_del((GF_Descriptor *) dcd); } } return GF_OK; } return GF_NOT_SUPPORTED; }
GF_Err gf_sm_load_init_isom(GF_SceneLoader *load) { u32 i; GF_BIFSConfig *bc; GF_ESD *esd; GF_Err e; char *scene_msg = "MPEG-4 BIFS Scene Parsing"; if (!load->isom) return GF_BAD_PARAM; /*load IOD*/ load->ctx->root_od = (GF_ObjectDescriptor *) gf_isom_get_root_od(load->isom); if (!load->ctx->root_od) { e = gf_isom_last_error(load->isom); if (e) return e; } else if ((load->ctx->root_od->tag != GF_ODF_OD_TAG) && (load->ctx->root_od->tag != GF_ODF_IOD_TAG)) { gf_odf_desc_del((GF_Descriptor *) load->ctx->root_od); load->ctx->root_od = NULL; } esd = NULL; /*get root scene stream*/ for (i=0; i<gf_isom_get_track_count(load->isom); i++) { u32 type = gf_isom_get_media_type(load->isom, i+1); if (type != GF_ISOM_MEDIA_SCENE) continue; if (! gf_isom_is_track_in_root_od(load->isom, i+1) ) continue; esd = gf_isom_get_esd(load->isom, i+1, 1); if (esd && esd->URLString) { gf_odf_desc_del((GF_Descriptor *)esd); esd = NULL; continue; } /*make sure we load the root BIFS stream first*/ if (esd && esd->dependsOnESID && (esd->dependsOnESID!=esd->ESID) ) { u32 track = gf_isom_get_track_by_id(load->isom, esd->dependsOnESID); if (gf_isom_get_media_type(load->isom, track) != GF_ISOM_MEDIA_OD) { gf_odf_desc_del((GF_Descriptor *)esd); esd = NULL; continue; } } if (esd->decoderConfig->objectTypeIndication==0x09) scene_msg = "MPEG-4 LASeR Scene Parsing"; break; } if (!esd) return GF_OK; e = GF_OK; GF_LOG(GF_LOG_INFO, GF_LOG_PARSER, ("%s\n", scene_msg)); /*BIFS: update size & pixel metrics info*/ if (esd->decoderConfig->objectTypeIndication<=2) { bc = gf_odf_get_bifs_config(esd->decoderConfig->decoderSpecificInfo, esd->decoderConfig->objectTypeIndication); if (!bc->elementaryMasks && bc->pixelWidth && bc->pixelHeight) { load->ctx->scene_width = bc->pixelWidth; load->ctx->scene_height = bc->pixelHeight; load->ctx->is_pixel_metrics = bc->pixelMetrics; } gf_odf_desc_del((GF_Descriptor *) bc); /*note we don't load the first BIFS AU to avoid storing the BIFS decoder, needed to properly handle quantization*/ } /*LASeR*/ else if (esd->decoderConfig->objectTypeIndication==0x09) { load->ctx->is_pixel_metrics = 1; } gf_odf_desc_del((GF_Descriptor *) esd); esd = NULL; load->process = gf_sm_load_run_isom; load->done = gf_sm_load_done_isom; load->suspend = gf_sm_isom_suspend; return GF_OK; }
static GF_Err OSVC_AttachStream(GF_BaseDecoder *ifcg, GF_ESD *esd) { u32 i, count; s32 res; OPENSVCFRAME Picture; int Layer[4]; OSVCDec *ctx = (OSVCDec*) ifcg->privateStack; /*todo: we should check base layer of this stream is indeed our base layer*/ if (!ctx->ES_ID) { ctx->ES_ID = esd->ESID; ctx->width = ctx->height = ctx->out_size = 0; if (!esd->dependsOnESID) ctx->baseES_ID = esd->ESID; } if (esd->decoderConfig->decoderSpecificInfo && esd->decoderConfig->decoderSpecificInfo->data) { GF_AVCConfig *cfg = gf_odf_avc_cfg_read(esd->decoderConfig->decoderSpecificInfo->data, esd->decoderConfig->decoderSpecificInfo->dataLength); if (!cfg) return GF_NON_COMPLIANT_BITSTREAM; if (!esd->dependsOnESID) { ctx->nalu_size_length = cfg->nal_unit_size; if (SVCDecoder_init(&ctx->codec) == SVC_STATUS_ERROR) return GF_IO_ERR; } /*decode all NALUs*/ count = gf_list_count(cfg->sequenceParameterSets); SetCommandLayer(Layer, 255, 0, &res, 0);//bufindex can be reset without pb for (i=0; i<count; i++) { u32 w=0, h=0, sid; s32 par_n=0, par_d=0; GF_AVCConfigSlot *slc = (GF_AVCConfigSlot*)gf_list_get(cfg->sequenceParameterSets, i); #ifndef GPAC_DISABLE_AV_PARSERS gf_avc_get_sps_info(slc->data, slc->size, &sid, &w, &h, &par_n, &par_d); #endif /*by default use the base layer*/ if (!i) { if ((ctx->width<w) || (ctx->height<h)) { ctx->width = w; ctx->height = h; if ( ((s32)par_n>0) && ((s32)par_d>0) ) ctx->pixel_ar = (par_n<<16) || par_d; } } res = decodeNAL(ctx->codec, (unsigned char *) slc->data, slc->size, &Picture, Layer); if (res<0) { GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[SVC Decoder] Error decoding SPS %d\n", res)); } GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[SVC Decoder] Attach: SPS id=\"%d\" code=\"%d\" size=\"%d\"\n", slc->id, slc->data[0] & 0x1F, slc->size)); } count = gf_list_count(cfg->pictureParameterSets); for (i=0; i<count; i++) { u32 sps_id, pps_id; GF_AVCConfigSlot *slc = (GF_AVCConfigSlot*)gf_list_get(cfg->pictureParameterSets, i); gf_avc_get_pps_info(slc->data, slc->size, &pps_id, &sps_id); res = decodeNAL(ctx->codec, (unsigned char *) slc->data, slc->size, &Picture, Layer); if (res<0) { GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[SVC Decoder] Error decoding PPS %d\n", res)); } GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[SVC Decoder] Attach: PPS id=\"%d\" code=\"%d\" size=\"%d\" sps_id=\"%d\"\n", pps_id, slc->data[0] & 0x1F, slc->size, sps_id)); } ctx->state_found = GF_TRUE; gf_odf_avc_cfg_del(cfg); } else { if (ctx->nalu_size_length) { return GF_NOT_SUPPORTED; } ctx->nalu_size_length = 0; if (!esd->dependsOnESID) { if (SVCDecoder_init(&ctx->codec) == SVC_STATUS_ERROR) return GF_IO_ERR; } ctx->pixel_ar = (1<<16) || 1; } ctx->stride = ctx->width + 32; ctx->CurrentDqId = ctx->MaxDqId = 0; ctx->out_size = ctx->stride * ctx->height * 3 / 2; return GF_OK; }
/*enumerate directories*/ GF_EXPORT GF_Err gf_enum_directory(const char *dir, Bool enum_directory, gf_enum_dir_item enum_dir_fct, void *cbck, const char *filter) { #ifdef WIN32 wchar_t item_path[GF_MAX_PATH]; #else char item_path[GF_MAX_PATH]; #endif GF_FileEnumInfo file_info; #if defined(_WIN32_WCE) char _path[GF_MAX_PATH]; unsigned short path[GF_MAX_PATH]; unsigned short w_filter[GF_MAX_PATH]; char file[GF_MAX_PATH]; #elif defined(WIN32) wchar_t path[GF_MAX_PATH], *file; wchar_t w_filter[GF_MAX_PATH]; wchar_t w_dir[GF_MAX_PATH]; char *mbs_file, *mbs_item_path; #else char path[GF_MAX_PATH], *file; #endif #ifdef WIN32 WIN32_FIND_DATAW FindData; HANDLE SearchH; #else DIR *the_dir; struct dirent* the_file; struct stat st; #endif if (!dir || !enum_dir_fct) return GF_BAD_PARAM; if (filter && (!strcmp(filter, "*") || !filter[0])) filter=NULL; memset(&file_info, 0, sizeof(GF_FileEnumInfo) ); if (!strcmp(dir, "/")) { #if defined(WIN32) && !defined(_WIN32_WCE) u32 len; char *drives, *volume; len = GetLogicalDriveStrings(0, NULL); drives = (char*)gf_malloc(sizeof(char)*(len+1)); drives[0]=0; GetLogicalDriveStrings(len, drives); len = (u32) strlen(drives); volume = drives; file_info.directory = GF_TRUE; file_info.drive = GF_TRUE; while (len) { enum_dir_fct(cbck, volume, "", &file_info); volume += len+1; len = (u32) strlen(volume); } gf_free(drives); return GF_OK; #elif defined(__SYMBIAN32__) RFs iFs; TDriveList aList; iFs.Connect(); iFs.DriveList(aList); for (TInt i=0; i<KMaxDrives; i++) { if (aList[i]) { char szDrive[10]; TChar aDrive; iFs.DriveToChar(i, aDrive); sprintf(szDrive, "%c:", (TUint)aDrive); enum_dir_fct(cbck, szDrive, "", &file_info); } } iFs.Close(); FlushItemList(); return GF_OK; #endif } #if defined (_WIN32_WCE) switch (dir[strlen(dir) - 1]) { case '/': case '\\': sprintf(_path, "%s*", dir); break; default: sprintf(_path, "%s%c*", dir, GF_PATH_SEPARATOR); break; } CE_CharToWide(_path, path); CE_CharToWide((char *)filter, w_filter); #elif defined(WIN32) { const char* tmpdir = dir; gf_utf8_mbstowcs(w_dir, sizeof(w_dir), &tmpdir); } switch (w_dir[wcslen(w_dir) - 1]) { case '/': case '\\': swprintf(path, MAX_PATH, L"%s*", w_dir); break; default: swprintf(path, MAX_PATH, L"%s%c*", w_dir, GF_PATH_SEPARATOR); break; } { const char* tmpfilter = filter; gf_utf8_mbstowcs(w_filter, sizeof(w_filter), &tmpfilter); } #else strcpy(path, dir); if (path[strlen(path)-1] != '/') strcat(path, "/"); #endif #ifdef WIN32 SearchH= FindFirstFileW(path, &FindData); if (SearchH == INVALID_HANDLE_VALUE) return GF_IO_ERR; #if defined (_WIN32_WCE) _path[strlen(_path)-1] = 0; #else path[wcslen(path)-1] = 0; #endif while (SearchH != INVALID_HANDLE_VALUE) { #else the_dir = opendir(path); if (the_dir == NULL) { GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Cannot open directory %s for enumeration: %d\n", path, errno)); return GF_IO_ERR; } the_file = readdir(the_dir); while (the_file) { #endif memset(&file_info, 0, sizeof(GF_FileEnumInfo) ); #if defined (_WIN32_WCE) if (!wcscmp(FindData.cFileName, _T(".") )) goto next; if (!wcscmp(FindData.cFileName, _T("..") )) goto next; #elif defined(WIN32) if (!wcscmp(FindData.cFileName, L".")) goto next; if (!wcscmp(FindData.cFileName, L"..")) goto next; #else if (!strcmp(the_file->d_name, "..")) goto next; if (the_file->d_name[0] == '.') goto next; #endif #ifdef WIN32 file_info.directory = (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? GF_TRUE : GF_FALSE; if (!enum_directory && file_info.directory) goto next; if (enum_directory && !file_info.directory) goto next; #endif if (filter) { #if defined (_WIN32_WCE) short ext[30]; short *sep = wcsrchr(FindData.cFileName, (wchar_t) '.'); if (!sep) goto next; wcscpy(ext, sep+1); wcslwr(ext); if (!wcsstr(w_filter, ext)) goto next; #elif defined(WIN32) wchar_t ext[30]; wchar_t *sep = wcsrchr(FindData.cFileName, L'.'); if (!sep) goto next; wcscpy(ext, sep+1); wcslwr(ext); if (!wcsstr(w_filter, ext)) goto next; #else char ext[30]; char *sep = strrchr(the_file->d_name, '.'); if (!sep) goto next; strcpy(ext, sep+1); strlwr(ext); if (!strstr(filter, sep+1)) goto next; #endif } #if defined(WIN32) file_info.hidden = (FindData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? GF_TRUE : GF_FALSE; file_info.system = (FindData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? GF_TRUE : GF_FALSE; file_info.size = MAXDWORD; file_info.size += 1; file_info.size *= FindData.nFileSizeHigh; file_info.size += FindData.nFileSizeLow; file_info.last_modified = (u64) ((*(LONGLONG *) &FindData.ftLastWriteTime - TIMESPEC_TO_FILETIME_OFFSET) / 10000000); #endif #if defined (_WIN32_WCE) CE_WideToChar(FindData.cFileName, file); strcpy(item_path, _path); strcat(item_path, file); #elif defined(WIN32) wcscpy(item_path, path); wcscat(item_path, FindData.cFileName); file = FindData.cFileName; #else strcpy(item_path, path); strcat(item_path, the_file->d_name); GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Core] Checking file %s for enum\n", item_path)); if (stat( item_path, &st ) != 0) goto next; file_info.directory = ((st.st_mode & S_IFMT) == S_IFDIR) ? GF_TRUE : GF_FALSE; if (enum_directory && !file_info.directory) goto next; if (!enum_directory && file_info.directory) goto next; file_info.size = st.st_size; { struct tm _t = * gmtime(& st.st_mtime); file_info.last_modified = mktime(&_t); } file = the_file->d_name; if (file && file[0]=='.') file_info.hidden = 1; if (file_info.directory) { char * parent_name = strrchr(item_path, '/'); if (!parent_name) { file_info.drive = GF_TRUE; } else { struct stat st_parent; parent_name[0] = 0; if (stat(item_path, &st_parent) == 0) { if ((st.st_dev != st_parent.st_dev) || ((st.st_dev == st_parent.st_dev) && (st.st_ino == st_parent.st_ino))) { file_info.drive = GF_TRUE; } } parent_name[0] = '/'; } } #endif #ifdef WIN32 mbs_file = wcs_to_utf8(file); mbs_item_path = wcs_to_utf8(item_path); if (!mbs_file || !mbs_item_path) { if (mbs_file) gf_free(mbs_file); if (mbs_item_path) gf_free(mbs_item_path); return GF_IO_ERR; } if (enum_dir_fct(cbck, mbs_file, mbs_item_path, &file_info)) { BOOL ret = FindClose(SearchH); if (!ret) { DWORD err = GetLastError(); GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_enum_directory() returned(1) the following error code: %d\n", err)); } #else if (enum_dir_fct(cbck, file, item_path, &file_info)) { #endif break; } #ifdef WIN32 gf_free(mbs_file); gf_free(mbs_item_path); #endif next: #ifdef WIN32 if (!FindNextFileW(SearchH, &FindData)) { BOOL ret = FindClose(SearchH); if (!ret) { DWORD err = GetLastError(); GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_enum_directory() returned(2) the following error code: %d\n", err)); } break; } #else the_file = readdir(the_dir); #endif } #ifndef WIN32 closedir(the_dir); #endif return GF_OK; } GF_EXPORT u64 gf_ftell(FILE *fp) { #if defined(_WIN32_WCE) return (u64) ftell(fp); #elif defined(GPAC_CONFIG_WIN32) && !defined(__CYGWIN__) /* mingw or cygwin */ #if (_FILE_OFFSET_BITS >= 64) return (u64) ftello64(fp); #else return (u64) ftell(fp); #endif #elif defined(WIN32) return (u64) _ftelli64(fp); #elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID) return (u64) ftello64(fp); #elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN)) return (u64) ftello(fp); #else return (u64) ftell(fp); #endif } GF_EXPORT u64 gf_fseek(FILE *fp, s64 offset, s32 whence) { #if defined(_WIN32_WCE) return (u64) fseek(fp, (s32) offset, whence); #elif defined(GPAC_CONFIG_WIN32) && !defined(__CYGWIN__) /* mingw or cygwin */ #if (_FILE_OFFSET_BITS >= 64) return (u64) fseeko64(fp, offset, whence); #else return (u64) fseek(fp, (s32) offset, whence); #endif #elif defined(WIN32) return (u64) _fseeki64(fp, offset, whence); #elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID) return fseeko64(fp, (off64_t) offset, whence); #elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN)) return fseeko(fp, (off_t) offset, whence); #else return fseek(fp, (s32) offset, whence); #endif } GF_EXPORT FILE *gf_fopen(const char *file_name, const char *mode) { FILE *res = NULL; #if defined(WIN32) wchar_t *wname; wchar_t *wmode; wname = utf8_to_wcs(file_name); wmode = utf8_to_wcs(mode); if (!wname || !wmode) { if (wname) gf_free(wname); if (wmode) gf_free(wmode); return NULL; } res = _wfsopen(wname, wmode, _SH_DENYNO); gf_free(wname); gf_free(wmode); #elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID) res = fopen64(file_name, mode); #elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN)) res = fopen(file_name, mode); #else res = fopen(file_name, mode); #endif if (res) { gpac_file_handles++; GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Core] file %s opened in mode %s - %d file handles\n", file_name, mode, gpac_file_handles)); } else { if (strchr(mode, 'w') || strchr(mode, 'a')) { #if defined(WIN32) u32 err = GetLastError(); GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] system failure for file opening of %s in mode %s: 0x%08x\n", file_name, mode, err)); #else GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] system failure for file opening of %s in mode %s: %d\n", file_name, mode, errno)); #endif } } return res; } GF_EXPORT s32 gf_fclose(FILE *file) { if (file) { assert(gpac_file_handles); gpac_file_handles--; } return fclose(file); } #if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! defined(_GNU_SOURCE) && !defined(WIN32) #define HAVE_STRERROR_R 1 #endif GF_EXPORT size_t gf_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { return fread(ptr, size, nmemb, stream); } GF_EXPORT size_t gf_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { size_t result = fwrite(ptr, size, nmemb, stream); if (result != nmemb) { #ifdef _WIN32_WCE GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Error writing data: %d blocks to write but %d blocks written\n", nmemb, result)); #else #if defined WIN32 && !defined(GPAC_CONFIG_WIN32) errno_t errno_save; _get_errno(&errno_save); #else int errno_save = errno; #endif //if (errno_save!=0) { #ifdef HAVE_STRERROR_R #define ERRSTR_BUF_SIZE 256 char errstr[ERRSTR_BUF_SIZE]; if(strerror_r(errno_save, errstr, ERRSTR_BUF_SIZE) != 0) { strerror_r(0, errstr, ERRSTR_BUF_SIZE); } #else char *errstr = (char*)strerror(errno_save); #endif GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Error writing data (%s): %d blocks to write but %d blocks written\n", errstr, nmemb, result)); } #endif } return result; }
void svg_drawable_pick(GF_Node *node, Drawable *drawable, GF_TraverseState *tr_state) { DrawAspect2D asp; GF_Matrix2D inv_2d; Fixed x, y; Bool picked = 0; GF_Compositor *compositor = tr_state->visual->compositor; SVGPropertiesPointers backup_props; GF_Matrix2D backup_matrix; GF_Matrix mx_3d; SVGAllAttributes all_atts; if (!drawable->path) return; gf_svg_flatten_attributes((SVG_Element *)node, &all_atts); memcpy(&backup_props, tr_state->svg_props, sizeof(SVGPropertiesPointers)); gf_svg_apply_inheritance(&all_atts, tr_state->svg_props); if (compositor_svg_is_display_off(tr_state->svg_props)) return; compositor_svg_apply_local_transformation(tr_state, &all_atts, &backup_matrix, &mx_3d); memset(&asp, 0, sizeof(DrawAspect2D)); drawable_get_aspect_2d_svg(node, &asp, tr_state); #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { svg_drawable_3d_pick(drawable, tr_state, &asp); compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers)); return; } #endif gf_mx2d_copy(inv_2d, tr_state->transform); gf_mx2d_inverse(&inv_2d); x = tr_state->ray.orig.x; y = tr_state->ray.orig.y; gf_mx2d_apply_coords(&inv_2d, &x, &y); picked = svg_drawable_is_over(drawable, x, y, &asp, tr_state, NULL); if (picked) { u32 count, i; compositor->hit_local_point.x = x; compositor->hit_local_point.y = y; compositor->hit_local_point.z = 0; gf_mx_from_mx2d(&compositor->hit_world_to_local, &tr_state->transform); gf_mx_from_mx2d(&compositor->hit_local_to_world, &inv_2d); compositor->hit_node = drawable->node; compositor->hit_use_dom_events = 1; compositor->hit_normal.x = compositor->hit_normal.y = 0; compositor->hit_normal.z = FIX_ONE; compositor->hit_texcoords.x = gf_divfix(x, drawable->path->bbox.width) + FIX_ONE/2; compositor->hit_texcoords.y = gf_divfix(y, drawable->path->bbox.height) + FIX_ONE/2; svg_clone_use_stack(compositor, tr_state); /*not use in SVG patterns*/ compositor->hit_appear = NULL; /*also stack any VRML sensors present at the current level. If the event is not catched by a listener in the SVG tree, the event will be forwarded to the VRML tree*/ gf_list_reset(tr_state->visual->compositor->sensors); count = gf_list_count(tr_state->vrml_sensors); for (i=0; i<count; i++) { gf_list_add(tr_state->visual->compositor->sensors, gf_list_get(tr_state->vrml_sensors, i)); } GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SVG Picking] node %s is under mouse - hit %g %g 0\n", gf_node_get_log_name(drawable->node), FIX2FLT(x), FIX2FLT(y))); } compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx_3d); memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers)); }
static GF_Err AC3_ProcessData(GF_MediaDecoder *ifcg, char *inBuffer, u32 inBufferLength, u16 ES_ID, u32 *CTS, char *outBuffer, u32 *outBufferLength, u8 PaddingBits, u32 mmlevel) { short *out_samples; int i, len, bit_rate; sample_t level; A52CTX(); /*check not using scalabilty*/ if (ctx->ES_ID != ES_ID) return GF_BAD_PARAM; /*if late or seeking don't decode*/ switch (mmlevel) { case GF_CODEC_LEVEL_SEEK: case GF_CODEC_LEVEL_DROP: *outBufferLength = 0; return GF_OK; default: break; } if (ctx->out_size > *outBufferLength) { *outBufferLength = ctx->out_size; return GF_BUFFER_TOO_SMALL; } GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[A52] Decoding AU\n")); len = a52_syncinfo(inBuffer, &ctx->flags, &ctx->sample_rate, &bit_rate); if (!len) return GF_NON_COMPLIANT_BITSTREAM; /*init decoder*/ if (!ctx->out_size) { ctx->num_channels = ac3_channels[ctx->flags & 7]; if (ctx->flags & A52_LFE) ctx->num_channels++; ctx->flags |= A52_ADJUST_LEVEL; ctx->out_size = ctx->num_channels * sizeof(short) * 1536; *outBufferLength = ctx->out_size; return GF_BUFFER_TOO_SMALL; } level = 1; if ( a52_frame(ctx->codec, inBuffer, &ctx->flags, &level, 384)) { GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[A52] Error decoding AU\n" )); *outBufferLength = 0; return GF_NON_COMPLIANT_BITSTREAM; } out_samples = (short*)outBuffer; for (i=0; i<6; i++) { if (a52_block(ctx->codec)) return GF_NON_COMPLIANT_BITSTREAM; float_to_int(ctx->samples, out_samples + i * 256 * ctx->num_channels, ctx->num_channels); } *outBufferLength = 6 * ctx->num_channels * 256 * sizeof(short); return GF_OK; }
GF_AbstractTSMuxer * ts_amux_new(GF_AVRedirect * avr, u32 videoBitrateInBitsPerSec, u32 width, u32 height, u32 audioBitRateInBitsPerSec) { GF_AbstractTSMuxer * ts = gf_malloc( sizeof(GF_AbstractTSMuxer)); memset( ts, 0, sizeof( GF_AbstractTSMuxer)); ts->oc = avformat_alloc_context(); ts->destination = avr->destination; av_register_all(); ts->oc->oformat = GUESS_FORMAT(NULL, avr->destination, NULL); if (!ts->oc->oformat) ts->oc->oformat = GUESS_FORMAT("mpegts", NULL, NULL); assert( ts->oc->oformat); #if REDIRECT_AV_AUDIO_ENABLED ts->audio_st = av_new_stream(ts->oc, avr->audioCodec->id); { AVCodecContext * c = ts->audio_st->codec; c->codec_id = avr->audioCodec->id; c->codec_type = AVMEDIA_TYPE_AUDIO; /* put sample parameters */ c->sample_fmt = SAMPLE_FMT_S16; c->bit_rate = audioBitRateInBitsPerSec; c->sample_rate = avr->audioSampleRate; c->channels = 2; c->time_base.num = 1; c->time_base.den = 1000; // some formats want stream headers to be separate if (ts->oc->oformat->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; } #endif ts->video_st = av_new_stream(ts->oc, avr->videoCodec->id); { AVCodecContext * c = ts->video_st->codec; c->codec_id = avr->videoCodec->id; c->codec_type = AVMEDIA_TYPE_VIDEO; /* put sample parameters */ c->bit_rate = videoBitrateInBitsPerSec; /* resolution must be a multiple of two */ c->width = width; c->height = height; /* time base: this is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented. for fixed-fps content, timebase should be 1/framerate and timestamp increments should be identically 1. */ c->time_base.den = STREAM_FRAME_RATE; c->time_base.num = 1; c->gop_size = 12; /* emit one intra frame every twelve frames at most */ c->pix_fmt = STREAM_PIX_FMT; if (c->codec_id == CODEC_ID_MPEG2VIDEO) { /* just for testing, we also add B frames */ c->max_b_frames = 2; } if (c->codec_id == CODEC_ID_MPEG1VIDEO) { /* Needed to avoid using macroblocks in which some coeffs overflow. This does not happen with normal video, it just happens here as the motion of the chroma plane does not match the luma plane. */ c->mb_decision=2; } // some formats want stream headers to be separate if (ts->oc->oformat->flags & AVFMT_GLOBALHEADER) c->flags |= CODEC_FLAG_GLOBAL_HEADER; } //av_set_pts_info(ts->audio_st, 33, 1, audioBitRateInBitsPerSec); #ifndef AVIO_FLAG_WRITE /* set the output parameters (must be done even if no parameters). */ if (av_set_parameters(ts->oc, NULL) < 0) { fprintf(stderr, "Invalid output format parameters\n"); return NULL; } #endif dump_format(ts->oc, 0, avr->destination, 1); GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[AVRedirect] DUMPING to %s...\n", ts->destination)); #if (LIBAVCODEC_VERSION_MAJOR<55) if (avcodec_open(ts->video_st->codec, avr->videoCodec) < 0) { #else if (avcodec_open2(ts->video_st->codec, avr->videoCodec, NULL) < 0) { #endif GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[AVRedirect] failed to open video codec\n")); return NULL; } #if REDIRECT_AV_AUDIO_ENABLED #if (LIBAVCODEC_VERSION_MAJOR<55) if (avcodec_open(ts->audio_st->codec, avr->audioCodec) < 0) { #else if (avcodec_open2(ts->audio_st->codec, avr->audioCodec, NULL) < 0) { #endif GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[AVRedirect] failed to open audio codec\n")); return NULL; } ts->audioMx = gf_mx_new("TS_AudioMx"); #endif ts->videoMx = gf_mx_new("TS_VideoMx"); ts->tsEncodingThread = gf_th_new("ts_interleave_thread_run"); ts->encode = 1; ts->audioPackets = NULL; ts->videoPackets = NULL; gf_th_run(ts->tsEncodingThread, ts_interleave_thread_run, ts); return ts; } void ts_amux_del(GF_AbstractTSMuxer * muxerToDelete) { if (!muxerToDelete) return; muxerToDelete->encode = 0; gf_sleep(100); gf_th_stop(muxerToDelete->tsEncodingThread); muxerToDelete->tsEncodingThread = NULL; #if REDIRECT_AV_AUDIO_ENABLED gf_mx_del(muxerToDelete->audioMx); muxerToDelete->audioMx = NULL; #endif gf_mx_del(muxerToDelete->videoMx); muxerToDelete->videoMx = NULL; if (muxerToDelete->video_st) { avcodec_close(muxerToDelete->video_st->codec); muxerToDelete->video_st = NULL; } #if REDIRECT_AV_AUDIO_ENABLED if (muxerToDelete->audio_st) { avcodec_close(muxerToDelete->audio_st->codec); muxerToDelete->audio_st = NULL; } #endif /* write the trailer, if any. the trailer must be written * before you close the CodecContexts open when you wrote the * header; otherwise write_trailer may try to use memory that * was freed on av_codec_close() */ if (muxerToDelete->oc) { u32 i; /* free the streams */ for (i = 0; i < muxerToDelete->oc->nb_streams; i++) { av_freep(&muxerToDelete->oc->streams[i]->codec); av_freep(&muxerToDelete->oc->streams[i]); } /* free the stream */ av_free(muxerToDelete->oc); muxerToDelete->oc = NULL; } } Bool ts_encode_audio_frame(GF_AbstractTSMuxer * ts, uint8_t * data, int encoded, u64 pts) { AVPacketList *pl; AVPacket * pkt; if (!ts->encode) return 1; pl = gf_malloc(sizeof(AVPacketList)); pl->next = NULL; pkt = &(pl->pkt); av_init_packet(pkt); assert( ts->audio_st); assert( ts->audio_st->codec); pkt->flags = 0; if (ts->audio_st->codec->coded_frame) { if (ts->audio_st->codec->coded_frame->key_frame) pkt->flags = AV_PKT_FLAG_KEY; if (ts->audio_st->codec->coded_frame->pts != AV_NOPTS_VALUE) { pkt->pts = av_rescale_q(ts->audio_st->codec->coded_frame->pts, ts->audio_st->codec->time_base, ts->audio_st->time_base); } else { if (pts == AV_NOPTS_VALUE) pkt->pts = AV_NOPTS_VALUE; else { pkt->pts = av_rescale_q(pts, ts->audio_st->codec->time_base, ts->audio_st->time_base); } } } else { if (pts == AV_NOPTS_VALUE) pkt->pts = AV_NOPTS_VALUE; else pkt->pts = av_rescale_q(pts, ts->audio_st->codec->time_base, ts->audio_st->time_base); } pkt->stream_index= ts->audio_st->index; pkt->data = data; pkt->size = encoded; //fprintf(stderr, "AUDIO PTS="LLU" was: "LLU" (%p)\n", pkt->pts, pts, pl); gf_mx_p(ts->audioMx); if (!ts->audioPackets) ts->audioPackets = pl; else { AVPacketList * px = ts->audioPackets; while (px->next) px = px->next; px->next = pl; } gf_mx_v(ts->audioMx); return 0; } Bool ts_encode_video_frame(GF_AbstractTSMuxer* ts, uint8_t* data, int encoded) { AVPacketList *pl; AVPacket * pkt; if (!ts->encode) return 1; pl = gf_malloc(sizeof(AVPacketList)); pl->next = NULL; pkt = &(pl->pkt); av_init_packet(pkt); if (ts->video_st->codec->coded_frame->pts != AV_NOPTS_VALUE) { //pkt->pts= av_rescale_q(ts->video_st->codec->coded_frame->pts, ts->video_st->codec->time_base, ts->video_st->time_base); pkt->pts = ts->video_st->codec->coded_frame->pts * ts->video_st->time_base.den / ts->video_st->time_base.num / 1000; //pkt->pts = ts->video_st->codec->coded_frame->pts; } if (ts->video_st->codec->coded_frame->key_frame) pkt->flags |= AV_PKT_FLAG_KEY; pkt->stream_index= ts->video_st->index; pkt->data= data; pkt->size= encoded; //fprintf(stderr, "VIDEO PTS="LLU" was: "LLU" (%p)\n", pkt->pts, ts->video_st->codec->coded_frame->pts, pl); gf_mx_p(ts->videoMx); if (!ts->videoPackets) ts->videoPackets = pl; else { AVPacketList * px = ts->videoPackets; while (px->next) px = px->next; px->next = pl; } gf_mx_v(ts->videoMx); return 0; }
int dc_video_decoder_open(VideoInputFile *video_input_file, VideoDataConf *video_data_conf, int mode, int no_loop, int nb_consumers) { s32 ret; u32 i; s32 open_res; AVInputFormat *in_fmt = NULL; AVDictionary *options = NULL; AVCodecContext *codec_ctx; AVCodec *codec; memset(video_input_file, 0, sizeof(VideoInputFile)); if (video_data_conf->width > 0 && video_data_conf->height > 0) { char vres[16]; snprintf(vres, sizeof(vres), "%dx%d", video_data_conf->width, video_data_conf->height); ret = av_dict_set(&options, "video_size", vres, 0); if (ret < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not set video size %s.\n", vres)); return -1; } } if (video_data_conf->framerate > 0) { char vfr[16]; snprintf(vfr, sizeof(vfr), "%d", video_data_conf->framerate); ret = av_dict_set(&options, "framerate", vfr, 0); if (ret < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not set video framerate %s.\n", vfr)); return -1; } } if (strlen(video_data_conf->pixel_format)) { ret = av_dict_set(&options, "pixel_format", video_data_conf->pixel_format, 0); if (ret < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not set pixel format %s.\n", video_data_conf->pixel_format)); return -1; } } #ifndef WIN32 if (strcmp(video_data_conf->v4l2f, "") != 0) { ret = av_dict_set(&options, "input_format", video_data_conf->v4l2f, 0); if (ret < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not set input format %s.\n", video_data_conf->v4l2f)); return -1; } } #endif if (video_data_conf->format && strcmp(video_data_conf->format, "") != 0) { in_fmt = av_find_input_format(video_data_conf->format); if (in_fmt == NULL) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find the format %s.\n", video_data_conf->format)); return -1; } } video_input_file->av_fmt_ctx = NULL; if (video_data_conf->demux_buffer_size) { char szBufSize[100]; sprintf(szBufSize, "%d", video_data_conf->demux_buffer_size); ret = av_dict_set(&options, "buffer_size", szBufSize, 0); if (ret < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Could not set demuxer's input buffer size.\n")); return -1; } } /* Open video */ open_res = avformat_open_input(&video_input_file->av_fmt_ctx, video_data_conf->filename, in_fmt, options ? &options : NULL); if ( (open_res < 0) && !stricmp(video_data_conf->filename, "screen-capture-recorder") ) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Buggy screen capture input (open failed with code %d), retrying without specifying resolution\n", open_res)); av_dict_set(&options, "video_size", NULL, 0); open_res = avformat_open_input(&video_input_file->av_fmt_ctx, video_data_conf->filename, in_fmt, options ? &options : NULL); } if ( (open_res < 0) && options) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error %d opening input - retrying without options\n", open_res)); av_dict_free(&options); open_res = avformat_open_input(&video_input_file->av_fmt_ctx, video_data_conf->filename, in_fmt, NULL); } if (open_res < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open file %s\n", video_data_conf->filename)); return -1; } /* Retrieve stream information */ if (avformat_find_stream_info(video_input_file->av_fmt_ctx, NULL) < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find stream information\n")); return -1; } av_dump_format(video_input_file->av_fmt_ctx, 0, video_data_conf->filename, 0); /* Find the first video stream */ video_input_file->vstream_idx = -1; for (i = 0; i < video_input_file->av_fmt_ctx->nb_streams; i++) { if (video_input_file->av_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { video_input_file->vstream_idx = i; break; } } if (video_input_file->vstream_idx == -1) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot find a video stream\n")); return -1; } /* Get a pointer to the codec context for the video stream */ codec_ctx = video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->codec; /* Find the decoder for the video stream */ codec = avcodec_find_decoder(codec_ctx->codec_id); if (codec == NULL) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Codec is not supported.\n")); if (!video_input_file->av_fmt_ctx_ref_cnt) avformat_close_input(&video_input_file->av_fmt_ctx); return -1; } /* Open codec */ if (avcodec_open2(codec_ctx, codec, NULL) < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot open codec.\n")); if (!video_input_file->av_fmt_ctx_ref_cnt) avformat_close_input(&video_input_file->av_fmt_ctx); return -1; } video_input_file->width = codec_ctx->width; video_input_file->height = codec_ctx->height; video_input_file->sar = codec_ctx->sample_aspect_ratio; video_input_file->pix_fmt = codec_ctx->pix_fmt; if (codec_ctx->time_base.num==1) { GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("AVCTX give frame duration of %d/%d - keeping requested rate %d, but this may result in unexpected behaviour.\n", codec_ctx->time_base.num, codec_ctx->time_base.den, video_data_conf->framerate )); if (codec_ctx->time_base.den==1000000) { codec_ctx->time_base.num = codec_ctx->time_base.den / video_data_conf->framerate; } } else if (video_data_conf->framerate >= 0 && codec_ctx->time_base.num) { video_data_conf->framerate = codec_ctx->time_base.den / codec_ctx->time_base.num; } if (video_data_conf->framerate <= 1 || video_data_conf->framerate > 1000) { const int num = video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->avg_frame_rate.num; const int den = video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->avg_frame_rate.den == 0 ? 1 : video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->avg_frame_rate.den; video_data_conf->framerate = num / den; if (video_data_conf->framerate / 1000 != 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Framerate %d was divided by 1000: %d\n", video_data_conf->framerate, video_data_conf->framerate/1000)); video_data_conf->framerate = video_data_conf->framerate / 1000; } if (video_data_conf->framerate <= 1 || video_data_conf->framerate > 1000) { video_data_conf->framerate = num / den; if (video_data_conf->framerate / 1000 != 0) { video_data_conf->framerate = video_data_conf->framerate / 1000; } } } if (video_data_conf->framerate <= 1 || video_data_conf->framerate > 1000) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Invalid input framerate %d (AVCTX timebase is %d/%d).\n", video_data_conf->framerate, codec_ctx->time_base.num, codec_ctx->time_base.den)); return -1; } video_data_conf->time_base = video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->time_base; video_input_file->mode = mode; video_input_file->no_loop = no_loop; video_input_file->nb_consumers = nb_consumers; return 0; }
static void UpdateComposite2D(GF_TextureHandler *txh) { GF_Err e; u32 i; SensorHandler *hsens; RenderEffect2D *eff; M_CompositeTexture2D *ct2D = (M_CompositeTexture2D *)txh->owner; Composite2DStack *st = (Composite2DStack *) gf_node_get_private(txh->owner); GF_Raster2D *r2d = st->surf->render->compositor->r2d; if (!gf_node_dirty_get(txh->owner)) { txh->needs_refresh = 0; return; } /*rebuild stencil*/ if (!st->surf->the_surface || !txh->hwtx || ((s32) st->width != ct2D->pixelWidth) || ( (s32) st->height != ct2D->pixelHeight) ) { if (txh->hwtx) r2d->stencil_delete(txh->hwtx); txh->hwtx = NULL; if (ct2D->pixelWidth<=0) return; if (ct2D->pixelHeight<=0) return; st->width = ct2D->pixelWidth; st->height = ct2D->pixelHeight; txh->hwtx = r2d->stencil_new(r2d, GF_STENCIL_TEXTURE); e = r2d->stencil_create_texture(txh->hwtx, st->width, st->height, GF_PIXEL_ARGB); if (e) { if (txh->hwtx) r2d->stencil_delete(txh->hwtx); txh->hwtx = NULL; } } if (!txh->hwtx) return; GF_SAFEALLOC(eff, RenderEffect2D); eff->sensors = gf_list_new(); eff->surface = st->surf; if (st->surf->render->top_effect->trav_flags & TF_RENDER_DIRECT) { eff->trav_flags = TF_RENDER_DIRECT; } gf_mx2d_init(eff->transform); gf_cmx_init(&eff->color_mat); st->surf->width = st->width; st->surf->height = st->height; eff->back_stack = st->surf->back_stack; eff->view_stack = st->surf->view_stack; eff->is_pixel_metrics = gf_sg_use_pixel_metrics(gf_node_get_graph(st->txh.owner)); eff->min_hsize = INT2FIX( MIN(st->width, st->height) ) / 2; Composite_CheckBindables(st->txh.owner, eff, st->first); st->first = 0; GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 2D] Entering CompositeTexture2D Render Cycle\n")); e = VS2D_InitDraw(st->surf, eff); if (e) { effect_delete(eff); return; } /*render children*/ if (gf_node_dirty_get(st->txh.owner) & GF_SG_NODE_DIRTY) { GF_ChildNodeItem *l = ct2D->children; /*rebuild sensor list */ if (gf_list_count(st->sensors)) { gf_list_del(st->sensors); st->sensors = gf_list_new(); } while (l) { if (l->node && is_sensor_node(l->node) ) { hsens = get_sensor_handler(l->node); if (hsens) gf_list_add(st->sensors, hsens); } l = l->next; } /*if we have an active sensor at this level discard all sensors in current render context (cf VRML)*/ if (gf_list_count(st->sensors)) { effect_reset_sensors(eff); } } /*add sensor to effects*/ i=0; while ((hsens = (SensorHandler*)gf_list_enum(st->sensors, &i))) { effect_add_sensor(eff, hsens, &eff->transform); } gf_node_dirty_clear(st->txh.owner, 0); /*render*/ gf_node_render_children(st->txh.owner, eff); /*finalize draw*/ txh->needs_refresh = VS2D_TerminateDraw(st->surf, eff); st->txh.transparent = st->surf->last_had_back ? 0 : 1; /* st->txh.active_window.x = 0; st->txh.active_window.y = 0; st->txh.active_window.width = st->width; st->txh.active_window.height = st->height; */ st->txh.width = st->width; st->txh.height = st->height; /*set active viewport in image coordinates top-left=(0, 0), not in BIFS*/ if (gf_list_count(st->surf->view_stack)) { M_Viewport *vp = (M_Viewport *)gf_list_get(st->surf->view_stack, 0); if (vp->isBound) { SFVec2f size = vp->size; if (size.x >=0 && size.y>=0) { /* st->txh.active_window.width = size.x; st->txh.active_window.height = size.y; st->txh.active_window.x = (st->width - size.x) / 2; st->txh.active_window.y = (st->height - size.y) / 2; */ /*FIXME - we need tracking of VP changes*/ txh->needs_refresh = 1; } } } if (txh->needs_refresh) { if (r2d->stencil_texture_modified) r2d->stencil_texture_modified(st->txh.hwtx); gf_sr_invalidate(st->txh.compositor, NULL); } effect_delete(eff); GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 2D] Leaving CompositeTexture2D Render Cycle\n")); }
GF_Err gf_isom_add_meta_item_extended(GF_ISOFile *file, Bool root_meta, u32 track_num, Bool self_reference, char *resource_path, const char *item_name, u32 item_id, u32 item_type, const char *mime_type, const char *content_encoding, GF_ImageItemProperties *image_props, const char *URL, const char *URN, char *data, u32 data_len, GF_List *item_extent_refs) { u32 i; GF_Err e; GF_ItemLocationEntry *location_entry; GF_ItemInfoEntryBox *infe; GF_MetaBox *meta; u32 lastItemID = 0; if (!self_reference && !resource_path && !data) return GF_BAD_PARAM; e = CanAccessMovie(file, GF_ISOM_OPEN_WRITE); if (e) return e; meta = gf_isom_get_meta(file, root_meta, track_num); if (!meta) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("Trying to add item, but missing meta box")); return GF_BAD_PARAM; } e = FlushCaptureMode(file); if (e) return e; /*check file exists */ if (!URN && !URL && !self_reference && !data) { FILE *src = gf_fopen(resource_path, "rb"); if (!src) return GF_URL_ERROR; gf_fclose(src); } if (meta->item_infos) { u32 item_count = gf_list_count(meta->item_infos->item_infos); for (i = 0; i < item_count; i++) { GF_ItemInfoEntryBox *e = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, i); if (e->item_ID > lastItemID) lastItemID = e->item_ID; if (item_id == e->item_ID) { GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[IsoMedia] Item with id %d already exists, ignoring id\n", item_id)); item_id = 0; } } } infe = (GF_ItemInfoEntryBox *)infe_New(); if (item_id) { infe->item_ID = item_id; } else { infe->item_ID = ++lastItemID; } /*get relative name*/ if (item_name) { infe->item_name = gf_strdup(item_name); } else if (resource_path) { if (strrchr(resource_path, GF_PATH_SEPARATOR)) { infe->item_name = gf_strdup(strrchr(resource_path, GF_PATH_SEPARATOR) + 1); } else { infe->item_name = gf_strdup(resource_path); } } infe->item_type = item_type; if (mime_type) { infe->content_type = gf_strdup(mime_type); } else { infe->content_type = gf_strdup("application/octet-stream"); } if (content_encoding) infe->content_encoding = gf_strdup(content_encoding); /*Creation of the ItemLocation */ location_entry = (GF_ItemLocationEntry*)gf_malloc(sizeof(GF_ItemLocationEntry)); if (!location_entry) { gf_isom_box_del((GF_Box *)infe); return GF_OUT_OF_MEM; } memset(location_entry, 0, sizeof(GF_ItemLocationEntry)); location_entry->extent_entries = gf_list_new(); /*Creates an mdat if it does not exist*/ if (!file->mdat) { file->mdat = (GF_MediaDataBox *)mdat_New(); gf_list_add(file->TopBoxes, file->mdat); } /*Creation an ItemLocation Box if it does not exist*/ if (!meta->item_locations) meta->item_locations = (GF_ItemLocationBox *)iloc_New(); gf_list_add(meta->item_locations->location_entries, location_entry); location_entry->item_ID = infe->item_ID; if (!meta->item_infos) meta->item_infos = (GF_ItemInfoBox *)iinf_New(); e = gf_list_add(meta->item_infos->item_infos, infe); if (e) return e; if (image_props) { if (image_props->hidden) { infe->flags = 0x1; } } /*0: the current file*/ location_entry->data_reference_index = 0; if (self_reference) { GF_ItemExtentEntry *entry; GF_SAFEALLOC(entry, GF_ItemExtentEntry); gf_list_add(location_entry->extent_entries, entry); if (!infe->item_name) infe->item_name = gf_strdup(""); return GF_OK; } /*file not copied, just referenced*/ if (URL || URN) { u32 dataRefIndex; if (!meta->file_locations) meta->file_locations = (GF_DataInformationBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_DINF); if (!meta->file_locations->dref) meta->file_locations->dref = (GF_DataReferenceBox *)gf_isom_box_new(GF_ISOM_BOX_TYPE_DREF); e = Media_FindDataRef(meta->file_locations->dref, (char *)URL, (char *)URN, &dataRefIndex); if (e) return e; if (!dataRefIndex) { e = Media_CreateDataRef(meta->file_locations->dref, (char *)URL, (char *)URN, &dataRefIndex); if (e) return e; } location_entry->data_reference_index = dataRefIndex; } if (item_extent_refs && gf_list_count(item_extent_refs)) { u32 refs_count; location_entry->construction_method = 2; meta->item_locations->index_size = 4; refs_count = gf_list_count(item_extent_refs); for (i = 0; i < refs_count; i++) { u32 *item_index; GF_ItemExtentEntry *entry; GF_SAFEALLOC(entry, GF_ItemExtentEntry); gf_list_add(location_entry->extent_entries, entry); item_index = (u32 *)gf_list_get(item_extent_refs, i); gf_isom_meta_add_item_ref(file, root_meta, track_num, infe->item_ID, *item_index, GF_4CC('i', 'l', 'o', 'c'), &(entry->extent_index)); } } else { /*capture mode, write to disk*/ if ((file->openMode == GF_ISOM_OPEN_WRITE) && !location_entry->data_reference_index) { FILE *src; GF_ItemExtentEntry *entry; GF_SAFEALLOC(entry, GF_ItemExtentEntry); location_entry->base_offset = gf_bs_get_position(file->editFileMap->bs); /*update base offset size*/ if (location_entry->base_offset > 0xFFFFFFFF) meta->item_locations->base_offset_size = 8; else if (location_entry->base_offset && !meta->item_locations->base_offset_size) meta->item_locations->base_offset_size = 4; entry->extent_length = 0; entry->extent_offset = 0; gf_list_add(location_entry->extent_entries, entry); if (data) { gf_bs_write_data(file->editFileMap->bs, data, data_len); /*update length size*/ if (entry->extent_length > 0xFFFFFFFF) meta->item_locations->length_size = 8; else if (entry->extent_length && !meta->item_locations->length_size) meta->item_locations->length_size = 4; } else if (resource_path) { src = gf_fopen(resource_path, "rb"); if (src) { char cache_data[4096]; u64 remain; gf_fseek(src, 0, SEEK_END); entry->extent_length = gf_ftell(src); gf_fseek(src, 0, SEEK_SET); remain = entry->extent_length; while (remain) { u32 size_cache = (remain > 4096) ? 4096 : (u32)remain; size_t read = fread(cache_data, 1, size_cache, src); if (read == (size_t)-1) break; gf_bs_write_data(file->editFileMap->bs, cache_data, (u32)read); remain -= (u32)read; } gf_fclose(src); /*update length size*/ if (entry->extent_length > 0xFFFFFFFF) meta->item_locations->length_size = 8; else if (entry->extent_length && !meta->item_locations->length_size) meta->item_locations->length_size = 4; } } } /*store full path for info*/ else if (!location_entry->data_reference_index) { if (data) { infe->full_path = (char *)gf_malloc(sizeof(char) * data_len); memcpy(infe->full_path, data, sizeof(char) * data_len); infe->data_len = data_len; } else { infe->full_path = gf_strdup(resource_path); infe->data_len = 0; } } } return GF_OK; }
int dc_video_decoder_read(VideoInputFile *video_input_file, VideoInputData *video_input_data, int source_number, int use_source_timing, int is_live_capture, const int *exit_signal_addr) { #ifdef DASHCAST_DEBUG_TIME_ struct timeval start, end; long elapsed_time; #endif AVPacket packet; int ret, got_frame, already_locked = 0; AVCodecContext *codec_ctx; VideoDataNode *video_data_node; /* Get a pointer to the codec context for the video stream */ codec_ctx = video_input_file->av_fmt_ctx->streams[video_input_file->vstream_idx]->codec; /* Read frames */ while (1) { #ifdef DASHCAST_DEBUG_TIME_ gf_gettimeofday(&start, NULL); #endif memset(&packet, 0, sizeof(AVPacket)); ret = av_read_frame(video_input_file->av_fmt_ctx, &packet); #ifdef DASHCAST_DEBUG_TIME_ gf_gettimeofday(&end, NULL); elapsed_time = (end.tv_sec * 1000000 + end.tv_usec) - (start.tv_sec * 1000000 + start.tv_usec); fprintf(stdout, "fps: %f\n", 1000000.0/elapsed_time); #endif /* If we demux for the audio thread, send the packet to the audio */ if (video_input_file->av_fmt_ctx_ref_cnt && ((packet.stream_index != video_input_file->vstream_idx) || (ret == AVERROR_EOF))) { AVPacket *packet_copy = NULL; if (ret != AVERROR_EOF) { GF_SAFEALLOC(packet_copy, AVPacket); memcpy(packet_copy, &packet, sizeof(AVPacket)); } assert(video_input_file->av_pkt_list); gf_mx_p(video_input_file->av_pkt_list_mutex); gf_list_add(video_input_file->av_pkt_list, packet_copy); gf_mx_v(video_input_file->av_pkt_list_mutex); if (ret != AVERROR_EOF) { continue; } } if (ret == AVERROR_EOF) { if (video_input_file->mode == LIVE_MEDIA && video_input_file->no_loop == 0) { av_seek_frame(video_input_file->av_fmt_ctx, video_input_file->vstream_idx, 0, 0); av_free_packet(&packet); continue; } dc_producer_lock(&video_input_data->producer, &video_input_data->circular_buf); dc_producer_unlock_previous(&video_input_data->producer, &video_input_data->circular_buf); video_data_node = (VideoDataNode *) dc_producer_produce(&video_input_data->producer, &video_input_data->circular_buf); video_data_node->source_number = source_number; /* Flush decoder */ memset(&packet, 0, sizeof(AVPacket)); #ifndef FF_API_AVFRAME_LAVC avcodec_get_frame_defaults(video_data_node->vframe); #else av_frame_unref(video_data_node->vframe); #endif avcodec_decode_video2(codec_ctx, video_data_node->vframe, &got_frame, &packet); if (got_frame) { dc_producer_advance(&video_input_data->producer, &video_input_data->circular_buf); return 0; } dc_producer_end_signal(&video_input_data->producer, &video_input_data->circular_buf); dc_producer_unlock(&video_input_data->producer, &video_input_data->circular_buf); return -2; } else if (ret < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Cannot read video frame.\n")); continue; } /* Is this a packet from the video stream? */ if (packet.stream_index == video_input_file->vstream_idx) { u32 nb_retry = 10; while (!already_locked) { if (dc_producer_lock(&video_input_data->producer, &video_input_data->circular_buf) < 0) { if (!nb_retry) break; gf_sleep(10); nb_retry--; continue; } dc_producer_unlock_previous(&video_input_data->producer, &video_input_data->circular_buf); already_locked = 1; } if (!already_locked) { GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("[dashcast] Live system dropped a video frame\n")); continue; } video_data_node = (VideoDataNode *) dc_producer_produce(&video_input_data->producer, &video_input_data->circular_buf); video_data_node->source_number = source_number; /* Set video frame to default */ #ifndef FF_API_AVFRAME_LAVC avcodec_get_frame_defaults(video_data_node->vframe); #else av_frame_unref(video_data_node->vframe); #endif /* Decode video frame */ if (avcodec_decode_video2(codec_ctx, video_data_node->vframe, &got_frame, &packet) < 0) { av_free_packet(&packet); GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Error while decoding video.\n")); dc_producer_end_signal(&video_input_data->producer, &video_input_data->circular_buf); dc_producer_unlock(&video_input_data->producer, &video_input_data->circular_buf); return -1; } /* Did we get a video frame? */ if (got_frame) { if (use_source_timing && is_live_capture) { u64 pts; if (video_input_file->pts_init == 0) { video_input_file->pts_init = 1; video_input_file->utc_at_init = gf_net_get_utc(); video_input_file->first_pts = packet.pts; video_input_file->prev_pts = 0; video_input_data->frame_duration = 0; } if (video_input_file->pts_init && (video_input_file->pts_init!=3) ) { if (packet.pts==AV_NOPTS_VALUE) { video_input_file->pts_init=1; } else if (video_input_file->pts_init==1) { video_input_file->pts_init=2; video_input_file->pts_dur_estimate = packet.pts; } else if (video_input_file->pts_init==2) { video_input_file->pts_init=3; video_input_data->frame_duration = packet.pts - video_input_file->pts_dur_estimate; video_input_file->sync_tolerance = 9*video_input_data->frame_duration/5; //TODO - check with audio if sync is OK } } //move to 0-based PTS if (packet.pts!=AV_NOPTS_VALUE) { pts = packet.pts - video_input_file->first_pts; } else { pts = video_input_file->prev_pts + video_input_data->frame_duration; } //check for drop frames #ifndef GPAC_DISABLE_LOG if (0 && gf_log_tool_level_on(GF_LOG_DASH, GF_LOG_WARNING)) { if (pts - video_input_file->prev_pts > video_input_file->sync_tolerance) { u32 nb_lost=0; while (video_input_file->prev_pts + video_input_data->frame_duration + video_input_file->sync_tolerance < pts) { video_input_file->prev_pts += video_input_data->frame_duration; nb_lost++; } if (nb_lost) { GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[DashCast] Capture lost %d video frames \n", nb_lost)); } } } #endif video_input_file->prev_pts = pts; video_data_node->vframe->pts = pts; } if (video_data_node->vframe->pts==AV_NOPTS_VALUE) { if (!use_source_timing) { video_data_node->vframe->pts = video_input_file->frame_decoded; } else { video_data_node->vframe->pts = video_data_node->vframe->pkt_pts; } } video_input_file->frame_decoded++; GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[DashCast] Video Frame TS "LLU" decoded at UTC "LLU" ms\n", video_data_node->vframe->pts, gf_net_get_utc() )); // For a decode/encode process we must free this memory. //But if the input is raw and there is no need to decode then // the packet is directly passed for decoded frame. We must wait until rescale is done before freeing it if (codec_ctx->codec->id == CODEC_ID_RAWVIDEO) { video_data_node->nb_raw_frames_ref = video_input_file->nb_consumers; video_data_node->raw_packet = packet; dc_producer_advance(&video_input_data->producer, &video_input_data->circular_buf); while (video_data_node->nb_raw_frames_ref && ! *exit_signal_addr) { gf_sleep(0); } } else { dc_producer_advance(&video_input_data->producer, &video_input_data->circular_buf); av_free_packet(&packet); } return 0; } } /* Free the packet that was allocated by av_read_frame */ av_free_packet(&packet); } GF_LOG(GF_LOG_ERROR, GF_LOG_DASH, ("Unknown error while reading video frame.\n")); return -1; }
GF_EXPORT GF_Err gf_isom_extract_meta_item_extended(GF_ISOFile *file, Bool root_meta, u32 track_num, u32 item_id, const char *dump_file_name, char **out_data, u32 *out_size, const char **out_mime) { GF_BitStream *item_bs; char szPath[1024]; GF_ItemExtentEntry *extent_entry; FILE *resource = NULL; u32 i, count; GF_ItemLocationEntry *location_entry; u32 item_num; char *item_name = NULL; GF_MetaBox *meta = gf_isom_get_meta(file, root_meta, track_num); if (!meta || !meta->item_infos || !meta->item_locations) return GF_BAD_PARAM; if (out_mime) *out_mime = NULL; item_num = gf_isom_get_meta_item_by_id(file, root_meta, track_num, item_id); if (item_num) { GF_ItemInfoEntryBox *item_entry = (GF_ItemInfoEntryBox *)gf_list_get(meta->item_infos->item_infos, item_num - 1); item_name = item_entry->item_name; if (out_mime) *out_mime = item_entry->content_type; } location_entry = NULL; count = gf_list_count(meta->item_locations->location_entries); for (i = 0; i<count; i++) { location_entry = (GF_ItemLocationEntry *)gf_list_get(meta->item_locations->location_entries, i); if (location_entry->item_ID == item_id) break; location_entry = NULL; } if (!location_entry) return GF_BAD_PARAM; /*FIXME*/ if (location_entry->data_reference_index) { char *item_url = NULL, *item_urn = NULL; GF_Box *a = (GF_Box *)gf_list_get(meta->file_locations->dref->other_boxes, location_entry->data_reference_index - 1); if (a->type == GF_ISOM_BOX_TYPE_URL) { item_url = ((GF_DataEntryURLBox*)a)->location; } else if (a->type == GF_ISOM_BOX_TYPE_URN) { item_url = ((GF_DataEntryURNBox*)a)->location; item_urn = ((GF_DataEntryURNBox*)a)->nameURN; } GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[IsoMedia] Item already outside the ISO file at URL: %s, URN: %s\n", (item_url ? item_url : "N/A"), (item_urn ? item_urn : "N/A"))); return GF_OK; } /*don't extract self-reference item*/ count = gf_list_count(location_entry->extent_entries); if (!location_entry->base_offset && (count == 1)) { extent_entry = (GF_ItemExtentEntry *)gf_list_get(location_entry->extent_entries, 0); if (!extent_entry->extent_length #ifndef GPAC_DISABLE_ISOM_WRITE && !extent_entry->original_extent_offset #endif ) return GF_BAD_PARAM; } item_bs = NULL; if (out_data) { item_bs = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); } else if (dump_file_name) { strcpy(szPath, dump_file_name); resource = gf_fopen(szPath, "wb"); item_bs = gf_bs_from_file(resource, GF_BITSTREAM_WRITE); } else { if (item_name) strcpy(szPath, item_name); else sprintf(szPath, "item_id%02d", item_id); resource = gf_fopen(szPath, "wb"); item_bs = gf_bs_from_file(resource, GF_BITSTREAM_WRITE); } for (i = 0; i<count; i++) { char buf_cache[4096]; u64 remain; GF_ItemExtentEntry *extent_entry = (GF_ItemExtentEntry *)gf_list_get(location_entry->extent_entries, i); gf_bs_seek(file->movieFileMap->bs, location_entry->base_offset + extent_entry->extent_offset); remain = extent_entry->extent_length; while (remain) { u32 cache_size = (remain>4096) ? 4096 : (u32)remain; gf_bs_read_data(file->movieFileMap->bs, buf_cache, cache_size); gf_bs_write_data(item_bs, buf_cache, cache_size); remain -= cache_size; } } if (out_data) { gf_bs_get_content(item_bs, out_data, out_size); } if (resource) { gf_fclose(resource); } gf_bs_del(item_bs); return GF_OK; }
GF_EXPORT GF_Err gf_img_jpeg_dec(char *jpg, u32 jpg_size, u32 *width, u32 *height, u32 *pixel_format, char *dst, u32 *dst_size, u32 dst_nb_comp) { s32 i, j, scans, k; u32 stride; char *scan_line, *ptr, *tmp; char *lines[JPEG_MAX_SCAN_BLOCK_HEIGHT]; JPGErr jper; JPGCtx jpx; jpx.cinfo.err = jpeg_std_error(&(jper.pub)); jper.pub.error_exit = gf_jpeg_fatal_error; jper.pub.output_message = gf_jpeg_output_message; jper.pub.emit_message = gf_jpeg_nonfatal_error2; if (setjmp(jper.jmpbuf)) { GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[JPEGDecode] : Failed to decode\n")); jpeg_destroy_decompress(&jpx.cinfo); return GF_IO_ERR; } /*create decompress struct*/ jpeg_create_decompress(&jpx.cinfo); /*prepare IO*/ jpx.src.init_source = gf_jpeg_stub; jpx.src.fill_input_buffer = gf_jpeg_fill_input_buffer; jpx.src.skip_input_data = gf_jpeg_skip_input_data; jpx.src.resync_to_restart = jpeg_resync_to_restart; jpx.src.term_source = gf_jpeg_stub; jpx.skip = 0; jpx.src.next_input_byte = jpg; jpx.src.bytes_in_buffer = jpg_size; jpx.cinfo.src = (void *) &jpx.src; /*read header*/ do { i = jpeg_read_header(&jpx.cinfo, TRUE); } while (i == JPEG_HEADER_TABLES_ONLY); /*we're supposed to have the full image in the buffer, wrong stream*/ if (i == JPEG_SUSPENDED) { jpeg_destroy_decompress(&jpx.cinfo); return GF_NON_COMPLIANT_BITSTREAM; } *width = jpx.cinfo.image_width; *height = jpx.cinfo.image_height; stride = *width * jpx.cinfo.num_components; switch (jpx.cinfo.num_components) { case 1: *pixel_format = GF_PIXEL_GREYSCALE; break; case 3: *pixel_format = GF_PIXEL_RGB_24; break; default: jpeg_destroy_decompress(&jpx.cinfo); return GF_NON_COMPLIANT_BITSTREAM; } if (*dst_size < *height * *width * jpx.cinfo.num_components) { *dst_size = *height * *width * jpx.cinfo.num_components; jpeg_destroy_decompress(&jpx.cinfo); return GF_BUFFER_TOO_SMALL; } if (!dst_nb_comp) dst_nb_comp = jpx.cinfo.num_components; scan_line = NULL; /*decode*/ jpx.cinfo.do_fancy_upsampling = FALSE; jpx.cinfo.do_block_smoothing = FALSE; if (!jpeg_start_decompress(&jpx.cinfo)) { if (scan_line) gf_free(scan_line); jpeg_destroy_decompress(&jpx.cinfo); return GF_NON_COMPLIANT_BITSTREAM; } if (jpx.cinfo.rec_outbuf_height>JPEG_MAX_SCAN_BLOCK_HEIGHT) { if (scan_line) gf_free(scan_line); jpeg_destroy_decompress(&jpx.cinfo); GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[gf_img_jpeg_dec] : jpx.cinfo.rec_outbuf_height>JPEG_MAX_SCAN_BLOCK_HEIGHT\n")); return GF_IO_ERR; } /*read scanlines (the scan is not one line by one line so alloc a placeholder for block scaning) */ scan_line = gf_malloc(sizeof(char) * stride * jpx.cinfo.rec_outbuf_height); for (i = 0; i<jpx.cinfo.rec_outbuf_height;i++) { lines[i] = scan_line + i * stride; } tmp = dst; for (j=0; j< (s32) *height; j += jpx.cinfo.rec_outbuf_height) { jpeg_read_scanlines(&jpx.cinfo, (unsigned char **) lines, jpx.cinfo.rec_outbuf_height); scans = jpx.cinfo.rec_outbuf_height; if (( (s32) *height - j) < scans) scans = *height - j; ptr = scan_line; /*for each line in the scan*/ for (k = 0; k < scans; k++) { if (dst_nb_comp==(u32)jpx.cinfo.num_components) { memcpy(tmp, ptr, sizeof(char) * stride); ptr += stride; tmp += stride; } else { u32 z, c; for (z=0; z<*width; z++) { for (c=0; c<(u32)jpx.cinfo.num_components; c++) { if (c >= dst_nb_comp) break; tmp[c] = ptr[c]; } ptr += jpx.cinfo.num_components; tmp += dst_nb_comp; } } } } /*done*/ jpeg_finish_decompress(&jpx.cinfo); jpeg_destroy_decompress(&jpx.cinfo); gf_free(scan_line); return GF_OK; }
static void gf_jpeg_output_message (j_common_ptr cinfo){ char buffer[JMSG_LENGTH_MAX]; /* Create the message */ (*cinfo->err->format_message) (cinfo, buffer); GF_LOG(GF_LOG_ERROR, GF_LOG_CODEC, ("[JPEG OUTPUT MESSAGE]: %s\n", buffer)); }
GF_Err gf_bifs_enc_sf_field(GF_BifsEncoder *codec, GF_BitStream *bs, GF_Node *node, GF_FieldInfo *field) { GF_Err e; if (node) { e = gf_bifs_enc_quant_field(codec, bs, node, field); if (e != GF_EOS) return e; } switch (field->fieldType) { case GF_SG_VRML_SFBOOL: GF_BIFS_WRITE_INT(codec, bs, * ((SFBool *)field->far_ptr), 1, "SFBool", NULL); break; case GF_SG_VRML_SFCOLOR: BE_WriteSFFloat(codec, ((SFColor *)field->far_ptr)->red, bs, "color.red"); BE_WriteSFFloat(codec, ((SFColor *)field->far_ptr)->green, bs, "color.green"); BE_WriteSFFloat(codec, ((SFColor *)field->far_ptr)->blue, bs, "color.blue"); break; case GF_SG_VRML_SFFLOAT: BE_WriteSFFloat(codec, * ((SFFloat *)field->far_ptr), bs, NULL); break; case GF_SG_VRML_SFINT32: GF_BIFS_WRITE_INT(codec, bs, * ((SFInt32 *)field->far_ptr), 32, "SFInt32", NULL); break; case GF_SG_VRML_SFROTATION: BE_WriteSFFloat(codec, ((SFRotation *)field->far_ptr)->x, bs, "rot.x"); BE_WriteSFFloat(codec, ((SFRotation *)field->far_ptr)->y, bs, "rot.y"); BE_WriteSFFloat(codec, ((SFRotation *)field->far_ptr)->z, bs, "rot.z"); BE_WriteSFFloat(codec, ((SFRotation *)field->far_ptr)->q, bs, "rot.theta"); break; case GF_SG_VRML_SFSTRING: if (node && (node->sgprivate->tag==TAG_MPEG4_CacheTexture) && (field->fieldIndex<=2)) { u32 size, val; char buf[4096]; FILE *f = gf_f64_open(((SFString*)field->far_ptr)->buffer, "rb"); if (!f) return GF_URL_ERROR; gf_f64_seek(f, 0, SEEK_END); size = (u32) gf_f64_tell(f); val = gf_get_bit_size(size); GF_BIFS_WRITE_INT(codec, bs, val, 5, "nbBits", NULL); GF_BIFS_WRITE_INT(codec, bs, size, val, "length", NULL); gf_f64_seek(f, 0, SEEK_SET); while (size) { u32 read = fread(buf, 1, 4096, f); gf_bs_write_data(bs, buf, read); size -= read; } } else { u32 i; char *str = (char *) ((SFString*)field->far_ptr)->buffer; u32 len = str ? strlen(str) : 0; u32 val = gf_get_bit_size(len); GF_BIFS_WRITE_INT(codec, bs, val, 5, "nbBits", NULL); GF_BIFS_WRITE_INT(codec, bs, len, val, "length", NULL); for (i=0; i<len; i++) gf_bs_write_int(bs, str[i], 8); GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[BIFS] string\t\t%d\t\t%s\n", 8*len, str) ); } break; case GF_SG_VRML_SFTIME: gf_bs_write_double(bs, *((SFTime *)field->far_ptr)); GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[BIFS] SFTime\t\t%d\t\t%g\n", 64, *((SFTime *)field->far_ptr))); break; case GF_SG_VRML_SFVEC2F: BE_WriteSFFloat(codec, ((SFVec2f *)field->far_ptr)->x, bs, "vec2f.x"); BE_WriteSFFloat(codec, ((SFVec2f *)field->far_ptr)->y, bs, "vec2f.y"); break; case GF_SG_VRML_SFVEC3F: BE_WriteSFFloat(codec, ((SFVec3f *)field->far_ptr)->x, bs, "vec3f.x"); BE_WriteSFFloat(codec, ((SFVec3f *)field->far_ptr)->y, bs, "vec3f.y"); BE_WriteSFFloat(codec, ((SFVec3f *)field->far_ptr)->z, bs, "vec3f.z"); break; case GF_SG_VRML_SFURL: { SFURL *url = (SFURL *) field->far_ptr; GF_BIFS_WRITE_INT(codec, bs, (url->OD_ID>0) ? 1 : 0, 1, "hasODID", "SFURL"); if (url->OD_ID>0) { GF_BIFS_WRITE_INT(codec, bs, url->OD_ID, 10, "ODID", "SFURL"); } else { u32 i; u32 len = url->url ? strlen(url->url) : 0; u32 val = gf_get_bit_size(len); GF_BIFS_WRITE_INT(codec, bs, val, 5, "nbBits", NULL); GF_BIFS_WRITE_INT(codec, bs, len, val, "length", NULL); for (i=0; i<len; i++) gf_bs_write_int(bs, url->url[i], 8); GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[BIFS] string\t\t%d\t\t%s\t\t//SFURL\n", 8*len, url->url)); } } break; case GF_SG_VRML_SFIMAGE: { u32 size, i; SFImage *img = (SFImage *)field->far_ptr; GF_BIFS_WRITE_INT(codec, bs, img->width, 12, "width", "SFImage"); GF_BIFS_WRITE_INT(codec, bs, img->height, 12, "height", "SFImage"); GF_BIFS_WRITE_INT(codec, bs, img->numComponents - 1, 2, "nbComp", "SFImage"); size = img->width * img->height * img->numComponents; for (i=0; i<size; i++) gf_bs_write_int(bs, img->pixels[i], 8); GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[BIFS] pixels\t\t%d\t\tnot dumped\t\t//SFImage\n", 8*size)); } break; case GF_SG_VRML_SFCOMMANDBUFFER: { SFCommandBuffer *cb = (SFCommandBuffer *) field->far_ptr; if (cb->buffer) gf_free(cb->buffer); cb->buffer = NULL; cb->bufferSize = 0; if (gf_list_count(cb->commandList)) { u32 i, nbBits; GF_BitStream *bs_cond = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE); GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[BIFS] /*SFCommandBuffer*/\n" )); e = gf_bifs_enc_commands(codec, cb->commandList, bs_cond); if (!e) gf_bs_get_content(bs_cond, (char**)&cb->buffer, &cb->bufferSize); gf_bs_del(bs_cond); if (e) return e; GF_LOG(GF_LOG_DEBUG, GF_LOG_CODING, ("[BIFS] /*End SFCommandBuffer*/\n")); nbBits = gf_get_bit_size(cb->bufferSize); GF_BIFS_WRITE_INT(codec, bs, nbBits, 5, "NbBits", NULL); GF_BIFS_WRITE_INT(codec, bs, cb->bufferSize, nbBits, "BufferSize", NULL); for (i=0; i<cb->bufferSize; i++) GF_BIFS_WRITE_INT(codec, bs, cb->buffer[i], 8, "buffer byte", NULL); } /*empty command buffer*/ else { GF_BIFS_WRITE_INT(codec, bs, 0, 5, "NbBits", NULL); } } break; case GF_SG_VRML_SFNODE: return gf_bifs_enc_node(codec, *((GF_Node **)field->far_ptr), field->NDTtype, bs); case GF_SG_VRML_SFSCRIPT: #ifdef GPAC_HAS_SPIDERMONKEY codec->LastError = SFScript_Encode(codec, (SFScript *)field->far_ptr, bs, node); #else return GF_NOT_SUPPORTED; #endif break; case GF_SG_VRML_SFATTRREF: { u32 idx=0; SFAttrRef *ar = (SFAttrRef *)field->far_ptr; u32 nbBitsDEF = gf_get_bit_size(gf_node_get_num_fields_in_mode(ar->node, GF_SG_FIELD_CODING_DEF) - 1); GF_BIFS_WRITE_INT(codec, bs, gf_node_get_id(ar->node) - 1, codec->info->config.NodeIDBits, "NodeID", NULL); gf_bifs_field_index_by_mode(ar->node, ar->fieldIndex, GF_SG_FIELD_CODING_DEF, &idx); GF_BIFS_WRITE_INT(codec, bs, idx, nbBitsDEF, "field", NULL); } break; default: return GF_NOT_SUPPORTED; } return codec->LastError; }
GF_EXPORT void gf_sc_texture_update_frame(GF_TextureHandler *txh, Bool disable_resync) { Bool needs_reload = 0; u32 size, ts; s32 ms_until_pres, ms_until_next; /*already refreshed*/ if ((txh->stream_finished && txh->tx_io) || txh->needs_refresh) return; if (!txh->stream) { txh->data = NULL; return; } /*should never happen!!*/ if (txh->needs_release) gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0); /*check init flag*/ if (!(gf_mo_get_flags(txh->stream) & GF_MO_IS_INIT)) { needs_reload = 1; txh->data = NULL; if (txh->tx_io) { gf_sc_texture_release(txh); } } txh->data = gf_mo_fetch_data(txh->stream, disable_resync ? GF_MO_FETCH : GF_MO_FETCH_RESYNC, &txh->stream_finished, &ts, &size, &ms_until_pres, &ms_until_next); if (!(gf_mo_get_flags(txh->stream) & GF_MO_IS_INIT)) { needs_reload = 1; } else if (size && txh->size && (size != txh->size)) { needs_reload = 1; } if (needs_reload) { /*if we had a texture this means the object has changed - delete texture and resetup. Do not skip texture update as this may lead to an empty rendering pass (blank frame for this object), especially in DASH*/ if (txh->tx_io) { gf_sc_texture_release(txh); txh->needs_refresh = 1; } if (gf_mo_is_private_media(txh->stream)) { setup_texture_object(txh, 1); gf_node_dirty_set(txh->owner, 0, 0); } } /*if no frame or muted don't draw*/ if (!txh->data || !size) { GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Visual Texture] No output frame available \n")); /*TODO - check if this is needed */ if (txh->flags & GF_SR_TEXTURE_PRIVATE_MEDIA) { //txh->needs_refresh = 1; gf_sc_invalidate(txh->compositor, NULL); } return; } if (txh->compositor->frame_delay > ms_until_pres) txh->compositor->frame_delay = ms_until_pres; /*if setup and same frame return*/ if (txh->tx_io && (txh->stream_finished || (txh->last_frame_time==ts)) ) { gf_mo_release_data(txh->stream, 0xFFFFFFFF, 0); txh->needs_release = 0; if (!txh->stream_finished) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual Texture] Same frame fetched (TS %d)\n", ts)); if (txh->compositor->ms_until_next_frame > ms_until_next) txh->compositor->ms_until_next_frame = ms_until_next; } return; } txh->stream_finished = 0; txh->needs_release = 1; txh->last_frame_time = ts; txh->size = size; if (txh->raw_memory) { gf_mo_get_raw_image_planes(txh->stream, (u8 **) &txh->data, (u8 **) &txh->pU, (u8 **) &txh->pV); } if (gf_mo_is_muted(txh->stream)) return; if (txh->nb_frames) { s32 push_delay = txh->upload_time / txh->nb_frames; if (push_delay > ms_until_pres) ms_until_pres = 0; else ms_until_pres -= push_delay; } if (txh->compositor->ms_until_next_frame > ms_until_next) txh->compositor->ms_until_next_frame = ms_until_next; if (!txh->tx_io) { setup_texture_object(txh, 0); } /*try to push texture on graphics but don't complain if failure*/ gf_sc_texture_set_data(txh); txh->needs_refresh = 1; gf_sc_invalidate(txh->compositor, NULL); }
/*this is a quicktime specific box - see apple documentation*/ GF_Err text_Read(GF_Box *s, GF_BitStream *bs) { u16 pSize; GF_TextSampleEntryBox *ptr = (GF_TextSampleEntryBox*)s; gf_bs_read_data(bs, ptr->reserved, 6); ptr->dataReferenceIndex = gf_bs_read_u16(bs); ptr->displayFlags = gf_bs_read_u32(bs); /*Display flags*/ ptr->textJustification = gf_bs_read_u32(bs); /*Text justification*/ gf_bs_read_data(bs, ptr->background_color, 6); /*Background color*/ gpp_read_box(bs, &ptr->default_box); /*Default text box*/ gf_bs_read_data(bs, ptr->reserved1, 8); /*Reserved*/ ptr->fontNumber = gf_bs_read_u16(bs); /*Font number*/ ptr->fontFace = gf_bs_read_u16(bs); /*Font face*/ ptr->reserved2 = gf_bs_read_u8(bs); /*Reserved*/ ptr->reserved3 = gf_bs_read_u16(bs); /*Reserved*/ gf_bs_read_data(bs, ptr->foreground_color, 6); /*Foreground color*/ if (ptr->size < 51) return GF_ISOM_INVALID_FILE; ptr->size -= 51; if (!ptr->size) return GF_OK; /*ffmpeg compatibility with iPod streams: no pascal string*/ pSize = gf_bs_read_u8(bs); /*a Pascal string begins with its size: get textName size*/ ptr->size -= 1; if (ptr->size < pSize) { u32 s = pSize; size_t i = 0; GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[iso file] text box doesn't use a Pascal string: trying to decode anyway.\n")); ptr->textName = (char*)gf_malloc((u32) ptr->size + 1 + 1); do { char c = (char)s; if (c == '\0') { break; } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { ptr->textName[i] = c; } else { gf_free(ptr->textName); ptr->textName = NULL; GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] text box doesn't use a Pascal string and contains non-chars. Abort.\n")); return GF_ISOM_INVALID_FILE; } i++; if (!ptr->size) break; ptr->size--; s = gf_bs_read_u8(bs); } while (s); ptr->textName[i] = '\0'; /*Font name*/ GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[iso file] text box doesn't use a Pascal string: \"%s\" detected.\n", ptr->textName)); return GF_OK; } if (pSize) { ptr->textName = (char*) gf_malloc(pSize+1 * sizeof(char)); if (gf_bs_read_data(bs, ptr->textName, pSize) != pSize) { gf_free(ptr->textName); ptr->textName = NULL; return GF_ISOM_INVALID_FILE; } ptr->textName[pSize] = '\0'; /*Font name*/ } ptr->size -= pSize; return GF_OK; }
static void term_on_media_add(GF_ClientService *service, GF_Descriptor *media_desc, Bool no_scene_check) { u32 i, min_od_id; GF_MediaObject *the_mo; GF_Scene *scene; GF_ObjectManager *odm, *root; GF_ObjectDescriptor *od; GF_Terminal *term = service->term; root = service->owner; if (!root) { GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Service %s] has not root, aborting !\n", service->url)); return; } if (root->flags & GF_ODM_DESTROYED) { GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Service %s] root has been scheduled for destruction - aborting !\n", service->url)); return; } scene = root->subscene ? root->subscene : root->parentscene; if (scene->root_od->addon && (scene->root_od->addon->addon_type == GF_ADDON_TYPE_MAIN)) { no_scene_check = 1; scene->root_od->flags |= GF_ODM_REGENERATE_SCENE; } GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Service %s] %s\n", service->url, media_desc ? "Adding new media object" : "Regenerating scene graph")); if (!media_desc) { if (!no_scene_check) gf_scene_regenerate(scene); return; } switch (media_desc->tag) { case GF_ODF_OD_TAG: case GF_ODF_IOD_TAG: if (root && (root->net_service == service)) { od = (GF_ObjectDescriptor *) media_desc; break; } default: gf_odf_desc_del(media_desc); return; } gf_term_lock_net(term, 1); /*object declared this way are not part of an OD stream and are considered as dynamic*/ /* od->objectDescriptorID = GF_MEDIA_EXTERNAL_ID; */ /*check if we have a mediaObject in the scene not attached and matching this object*/ the_mo = NULL; odm = NULL; min_od_id = 0; for (i=0; i<gf_list_count(scene->scene_objects); i++) { char *frag, *ext; GF_ESD *esd; char *url; u32 match_esid = 0; GF_MediaObject *mo = gf_list_get(scene->scene_objects, i); if ((mo->OD_ID != GF_MEDIA_EXTERNAL_ID) && (min_od_id<mo->OD_ID)) min_od_id = mo->OD_ID; if (!mo->odm) continue; /*if object is attached to a service, don't bother looking in a different one*/ if (mo->odm->net_service && (mo->odm->net_service != service)) continue; /*already assigned object - this may happen since the compositor has no control on when objects are declared by the service, therefore opening file#video and file#audio may result in the objects being declared twice if the service doesn't keep track of declared objects*/ if (mo->odm->OD) { if (od->objectDescriptorID && is_same_od(mo->odm->OD, od)) { /*reassign OD ID*/ if (mo->OD_ID != GF_MEDIA_EXTERNAL_ID) { od->objectDescriptorID = mo->OD_ID; } else { mo->OD_ID = od->objectDescriptorID; } gf_odf_desc_del(media_desc); gf_term_lock_net(term, 0); return; } continue; } if (mo->OD_ID != GF_MEDIA_EXTERNAL_ID) { if (mo->OD_ID == od->objectDescriptorID) { the_mo = mo; odm = mo->odm; break; } continue; } if (!mo->URLs.count || !mo->URLs.vals[0].url) continue; frag = NULL; ext = strrchr(mo->URLs.vals[0].url, '#'); if (ext) { frag = strchr(ext, '='); ext[0] = 0; } url = mo->URLs.vals[0].url; if (!strnicmp(url, "file://localhost", 16)) url += 16; else if (!strnicmp(url, "file://", 7)) url += 7; else if (!strnicmp(url, "gpac://", 7)) url += 7; else if (!strnicmp(url, "pid://", 6)) match_esid = atoi(url+6); if (!match_esid && !strstr(service->url, url)) { if (ext) ext[0] = '#'; continue; } if (ext) ext[0] = '#'; esd = gf_list_get(od->ESDescriptors, 0); if (match_esid && (esd->ESID != match_esid)) continue; /*match type*/ switch (esd->decoderConfig->streamType) { case GF_STREAM_VISUAL: if (mo->type != GF_MEDIA_OBJECT_VIDEO) continue; break; case GF_STREAM_AUDIO: if (mo->type != GF_MEDIA_OBJECT_AUDIO) continue; break; case GF_STREAM_PRIVATE_MEDIA: if ((mo->type != GF_MEDIA_OBJECT_AUDIO) && (mo->type != GF_MEDIA_OBJECT_VIDEO)) continue; break; case GF_STREAM_SCENE: if (mo->type != GF_MEDIA_OBJECT_UPDATES) continue; break; default: continue; } if (frag) { u32 frag_id = 0; u32 ID = od->objectDescriptorID; if (ID==GF_MEDIA_EXTERNAL_ID) ID = esd->ESID; frag++; frag_id = atoi(frag); if (ID!=frag_id) continue; } the_mo = mo; odm = mo->odm; break; } /*add a pass on scene->resource to check for min_od_id, otherwise we may have another modules declaring an object with ID 0 from another thread, which will assert (only one object with a givne OD ID)*/ for (i=0; i<gf_list_count(scene->resources); i++) { GF_ObjectManager *an_odm = gf_list_get(scene->resources, i); if (an_odm->OD && (an_odm->OD->objectDescriptorID != GF_MEDIA_EXTERNAL_ID) && (min_od_id < an_odm->OD->objectDescriptorID)) min_od_id = an_odm->OD->objectDescriptorID; } if (!odm) { odm = gf_odm_new(); odm->term = term; odm->parentscene = scene; gf_mx_p(scene->mx_resources); gf_list_add(scene->resources, odm); gf_mx_v(scene->mx_resources); } odm->flags |= GF_ODM_NOT_SETUP; odm->OD = od; odm->mo = the_mo; odm->flags |= GF_ODM_NOT_IN_OD_STREAM; if (!od->objectDescriptorID) { od->objectDescriptorID = min_od_id + 1; } if (the_mo) the_mo->OD_ID = od->objectDescriptorID; if (!scene->selected_service_id) scene->selected_service_id = od->ServiceID; /*net is unlocked before seting up the object as this might trigger events going into JS and deadlocks with the compositor*/ gf_term_lock_net(term, 0); GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[ODM%d] setup object - MO %08x\n", odm->OD->objectDescriptorID, odm->mo)); gf_odm_setup_object(odm, service); /*OD inserted by service: resetup scene*/ if (!no_scene_check && scene->is_dynamic_scene) gf_scene_regenerate(scene); }
static GF_Err FFD_ConnectService(GF_InputService *plug, GF_ClientService *serv, const char *url) { GF_Err e; s64 last_aud_pts; u32 i; s32 res; Bool is_local; const char *sOpt; char *ext, szName[1024]; FFDemux *ffd = plug->priv; AVInputFormat *av_in = NULL; char szExt[20]; if (ffd->ctx) return GF_SERVICE_ERROR; assert( url && strlen(url) < 1024); strcpy(szName, url); ext = strrchr(szName, '#'); ffd->service_type = 0; e = GF_NOT_SUPPORTED; ffd->service = serv; if (ext) { if (!stricmp(&ext[1], "video")) ffd->service_type = 1; else if (!stricmp(&ext[1], "audio")) ffd->service_type = 2; ext[0] = 0; } /*some extensions not supported by ffmpeg, overload input format*/ ext = strrchr(szName, '.'); strcpy(szExt, ext ? ext+1 : ""); strlwr(szExt); if (!strcmp(szExt, "cmp")) av_in = av_find_input_format("m4v"); is_local = (strnicmp(url, "file://", 7) && strstr(url, "://")) ? 0 : 1; GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[FFMPEG] opening file %s - local %d - av_in %08x\n", url, is_local, av_in)); if (!is_local) { AVProbeData pd; /*setup wraper for FFMPEG I/O*/ ffd->buffer_size = 8192; sOpt = gf_modules_get_option((GF_BaseInterface *)plug, "FFMPEG", "IOBufferSize"); if (sOpt) ffd->buffer_size = atoi(sOpt); ffd->buffer = gf_malloc(sizeof(char)*ffd->buffer_size); #ifdef FFMPEG_DUMP_REMOTE ffd->outdbg = gf_f64_open("ffdeb.raw", "wb"); #endif #ifdef USE_PRE_0_7 init_put_byte(&ffd->io, ffd->buffer, ffd->buffer_size, 0, ffd, ff_url_read, NULL, NULL); ffd->io.is_streamed = 1; #else ffd->io.seekable = 1; #endif ffd->dnload = gf_term_download_new(ffd->service, url, GF_NETIO_SESSION_NOT_THREADED | GF_NETIO_SESSION_NOT_CACHED, NULL, ffd); if (!ffd->dnload) return GF_URL_ERROR; while (1) { u32 read; e = gf_dm_sess_fetch_data(ffd->dnload, ffd->buffer + ffd->buffer_used, ffd->buffer_size - ffd->buffer_used, &read); if (e==GF_EOS) break; /*we're sync!!*/ if (e==GF_IP_NETWORK_EMPTY) continue; if (e) goto err_exit; ffd->buffer_used += read; if (ffd->buffer_used == ffd->buffer_size) break; } if (e==GF_EOS) { const char *cache_file = gf_dm_sess_get_cache_name(ffd->dnload); res = open_file(&ffd->ctx, cache_file, av_in); } else { pd.filename = szName; pd.buf_size = ffd->buffer_used; pd.buf = ffd->buffer; av_in = av_probe_input_format(&pd, 1); if (!av_in) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[FFMPEG] error probing file %s - probe start with %c %c %c %c\n", url, ffd->buffer[0], ffd->buffer[1], ffd->buffer[2], ffd->buffer[3])); return GF_NOT_SUPPORTED; } /*setup downloader*/ av_in->flags |= AVFMT_NOFILE; #if FF_API_FORMAT_PARAMETERS /*commit ffmpeg 603b8bc2a109978c8499b06d2556f1433306eca7*/ res = avformat_open_input(&ffd->ctx, szName, av_in, NULL); #else res = av_open_input_stream(&ffd->ctx, &ffd->io, szName, av_in, NULL); #endif } } else { res = open_file(&ffd->ctx, szName, av_in); } switch (res) { #ifndef _WIN32_WCE case 0: e = GF_OK; break; case AVERROR_IO: e = GF_URL_ERROR; goto err_exit; case AVERROR_INVALIDDATA: e = GF_NON_COMPLIANT_BITSTREAM; goto err_exit; case AVERROR_NOMEM: e = GF_OUT_OF_MEM; goto err_exit; case AVERROR_NOFMT: e = GF_NOT_SUPPORTED; goto err_exit; #endif default: e = GF_SERVICE_ERROR; goto err_exit; } GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[FFMPEG] looking for streams in %s - %d streams - type %s\n", ffd->ctx->filename, ffd->ctx->nb_streams, ffd->ctx->iformat->name)); res = av_find_stream_info(ffd->ctx); if (res <0) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[FFMPEG] cannot locate streams - error %d\n", res)); e = GF_NOT_SUPPORTED; goto err_exit; } GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[FFMPEG] file %s opened - %d streams\n", url, ffd->ctx->nb_streams)); /*figure out if we can use codecs or not*/ ffd->audio_st = ffd->video_st = -1; for (i = 0; i < ffd->ctx->nb_streams; i++) { AVCodecContext *enc = ffd->ctx->streams[i]->codec; switch(enc->codec_type) { case AVMEDIA_TYPE_AUDIO: if ((ffd->audio_st<0) && (ffd->service_type!=1)) { ffd->audio_st = i; ffd->audio_tscale = ffd->ctx->streams[i]->time_base; } break; case AVMEDIA_TYPE_VIDEO: if ((ffd->video_st<0) && (ffd->service_type!=2)) { ffd->video_st = i; ffd->video_tscale = ffd->ctx->streams[i]->time_base; } break; default: break; } } if ((ffd->service_type==1) && (ffd->video_st<0)) goto err_exit; if ((ffd->service_type==2) && (ffd->audio_st<0)) goto err_exit; if ((ffd->video_st<0) && (ffd->audio_st<0)) { GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[FFMPEG] No supported streams in file\n")); goto err_exit; } sOpt = gf_modules_get_option((GF_BaseInterface *)plug, "FFMPEG", "DataBufferMS"); ffd->data_buffer_ms = 0; if (sOpt) ffd->data_buffer_ms = atoi(sOpt); if (!ffd->data_buffer_ms) ffd->data_buffer_ms = FFD_DATA_BUFFER; /*build seek*/ if (is_local) { /*check we do have increasing pts. If not we can't rely on pts, we must skip SL we assume video pts is always present*/ if (ffd->audio_st>=0) { last_aud_pts = 0; for (i=0; i<20; i++) { AVPacket pkt; pkt.stream_index = -1; if (av_read_frame(ffd->ctx, &pkt) <0) break; if (pkt.pts == AV_NOPTS_VALUE) pkt.pts = pkt.dts; if (pkt.stream_index==ffd->audio_st) last_aud_pts = pkt.pts; } if (last_aud_pts*ffd->audio_tscale.den<10*ffd->audio_tscale.num) ffd->unreliable_audio_timing = 1; } ffd->seekable = (av_seek_frame(ffd->ctx, -1, 0, AVSEEK_FLAG_BACKWARD)<0) ? 0 : 1; if (!ffd->seekable) { av_close_input_file(ffd->ctx); open_file(&ffd->ctx, szName, av_in); av_find_stream_info(ffd->ctx); } } /*let's go*/ gf_term_on_connect(serv, NULL, GF_OK); /*if (!ffd->service_type)*/ FFD_SetupObjects(ffd); ffd->service_type = 0; return GF_OK; err_exit: GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[FFMPEG] Error opening file %s: %s\n", url, gf_error_to_string(e))); if (ffd->ctx) av_close_input_file(ffd->ctx); ffd->ctx = NULL; gf_term_on_connect(serv, NULL, e); return GF_OK; }
static void term_on_connect(GF_ClientService *service, LPNETCHANNEL netch, GF_Err err) { GF_Channel *ch; GF_ObjectManager *root; GF_Terminal *term = service->term; GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] %s connection ACK received from %s - %s\n", netch ? "Channel" : "Service", service->url, gf_error_to_string(err) )); root = service->owner; if (root && (root->net_service != service)) { gf_term_message(term, service->url, "Incompatible module type", GF_SERVICE_ERROR); return; } /*this is service connection*/ if (!netch) { gf_term_service_media_event(service->owner, GF_EVENT_MEDIA_SETUP_DONE); if (err) { char msg[5000]; snprintf(msg, sizeof(msg), "Cannot open %s", service->url); gf_term_message(term, service->url, msg, err); gf_term_service_media_event(service->owner, GF_EVENT_ERROR); /*destroy service only if attached*/ if (root) { gf_term_lock_media_queue(term, 1); //notify before disconnecting if (root->subscene) gf_scene_notify_event(root->subscene, GF_EVENT_SCENE_ATTACHED, NULL, NULL, err, GF_FALSE); service->ifce->CloseService(service->ifce); root->net_service = NULL; if (service->owner && service->nb_odm_users) service->nb_odm_users--; service->owner = NULL; /*depends on module: some module could forget to call gf_service_disconnect_ack */ if ( gf_list_del_item(term->net_services, service) >= 0) { /*and queue for destroy*/ gf_list_add(term->net_services_to_remove, service); } gf_term_lock_media_queue(term, 0); if (!root->parentscene) { GF_Event evt; evt.type = GF_EVENT_CONNECT; evt.connect.is_connected = 0; gf_term_send_event(term, &evt); } else { /*try to reinsert OD for VRML/X3D with multiple URLs: 1- first remove from parent scene without destroying object, this will trigger a re-setup if other URLs are present 2- then destroy object*/ gf_scene_remove_object(root->parentscene, root, 0); gf_odm_disconnect(root, 1); } return; } } if (!root) { /*channel service connect*/ u32 i; GF_ChannelSetup *cs; GF_List *ODs; if (!gf_list_count(term->channels_pending)) { return; } ODs = gf_list_new(); gf_term_lock_net(term, 1); i=0; while ((cs = (GF_ChannelSetup*)gf_list_enum(term->channels_pending, &i))) { if (cs->ch->service != service) continue; gf_list_rem(term->channels_pending, i-1); i--; /*even if error do setup (channel needs to be deleted)*/ if (gf_odm_post_es_setup(cs->ch, cs->dec, err) == GF_OK) { if (cs->ch->odm && (gf_list_find(ODs, cs->ch->odm)==-1) ) gf_list_add(ODs, cs->ch->odm); } gf_free(cs); } gf_term_lock_net(term, 0); /*finally setup all ODs concerned (we do this later in case of scalability)*/ while (gf_list_count(ODs)) { GF_ObjectManager *odm = (GF_ObjectManager*)gf_list_get(ODs, 0); gf_list_rem(ODs, 0); /*force re-setup*/ gf_scene_setup_object(odm->parentscene, odm); } gf_list_del(ODs); } else { /*setup od*/ gf_odm_setup_entry_point(root, service->url); } /*load cache if requested*/ if (!err && term->enable_cache) { err = gf_term_service_cache_load(service); /*not a fatal error*/ if (err) gf_term_message(term, "GPAC Cache", "Cannot load cache", err); } return; } /*this is channel connection*/ ch = gf_term_get_channel(service, netch); if (!ch) { GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Terminal] Channel connection ACK error: channel not found\n")); return; } /*confirm channel connection even if error - this allow playback of objects even if not all streams are setup*/ gf_term_lock_net(term, 1); gf_es_on_connect(ch); gf_term_lock_net(term, 0); if (err && ((err!=GF_STREAM_NOT_FOUND) || (ch->esd->decoderConfig->streamType!=GF_STREAM_INTERACT))) { GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Terminal] Channel %d connection error: %s\n", ch->esd->ESID, gf_error_to_string(err) )); ch->es_state = GF_ESM_ES_UNAVAILABLE; /* return;*/ } if (ch->odm->mo) { GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Channel %d connected - %d objects opened\n", ch->esd->ESID, ch->odm->mo->num_open )); } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Channel %d connected - not attached to the scene\n", ch->esd->ESID)); } /*Plays request are skiped until all channels are connected. We send a PLAY on the objecy in case 1-OD user has requested a play 2-this is a channel of the root OD */ if ( (ch->odm->mo && ch->odm->mo->num_open) || !ch->odm->parentscene ) { gf_odm_start(ch->odm, 0); } #if 0 else if (ch->odm->codec && ch->odm->codec->ck && ch->odm->codec->ck->no_time_ctrl) { gf_odm_play(ch->odm); } #endif }
static u32 ts_interleave_thread_run(void *param) { GF_AbstractTSMuxer * mux = (GF_AbstractTSMuxer *) param; AVStream * video_st = mux->video_st; AVStream * audio_st = mux->audio_st; u64 audio_pts, video_pts; u64 audioSize, videoSize, videoKbps, audioKbps; u32 pass; u32 now, start; /* open the output file, if needed */ if (!(mux->oc->oformat->flags & AVFMT_NOFILE)) { if (url_fopen(&mux->oc->pb, mux->destination, URL_WRONLY) < 0) { fprintf(stderr, "Could not open '%s'\n", mux->destination); return 0; } } /* write the stream header, if any */ av_write_header(mux->oc); audio_pts = video_pts = 0; // Buffering... gf_sleep(1000); now = start = gf_sys_clock(); audioSize = videoSize = 0; audioKbps = videoKbps = 0; pass = 0; while ( mux->encode) { pass++; if (0== (pass%16)) { now = gf_sys_clock(); if (now - start > 1000) { videoKbps = videoSize * 8000 / (now-start) / 1024; audioKbps = audioSize * 8000 / (now-start) / 1024; audioSize = videoSize = 0; start = now; GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("\rPTS audio="LLU" ("LLU"kbps), video="LLU" ("LLU"kbps)", audio_pts, audioKbps, video_pts, videoKbps)); } } /* write interleaved audio and video frames */ if (!video_st || (audio_pts == AV_NOPTS_VALUE && has_packet_ready(mux, mux->audioMx, &mux->audioPackets)) || ((audio_st && audio_pts < video_pts && audio_pts!= AV_NOPTS_VALUE))) { AVPacketList * pl = wait_for_packet(mux, mux->audioMx, &mux->audioPackets); if (!pl) goto exit; audio_pts = pl->pkt.pts ; audioSize+=pl->pkt.size; if (pl->pkt.pts == AV_NOPTS_VALUE) { pl->pkt.pts = 0; } if (av_interleaved_write_frame(mux->oc, &(pl->pkt)) < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[AVRedirect] : failed to write audio interleaved frame audio_pts="LLU", video_pts="LLU"\n", audio_pts, video_pts)); } gf_free(pl); } else { AVPacketList * pl = wait_for_packet(mux, mux->videoMx, &mux->videoPackets); if (!pl) goto exit; video_pts = pl->pkt.pts; /* write the compressed frame in the media file */ if (0 && audio_pts != AV_NOPTS_VALUE && audio_pts > video_pts && pl->next) { u32 skipped = 0; u64 first = video_pts; /* We may be too slow... */ gf_mx_p(mux->videoMx); while (video_pts < audio_pts && pl->next) { AVPacketList * old = pl; // We skip frames... pl = pl->next; video_pts = pl->pkt.pts; skipped++; gf_free(old); } mux->videoPackets = pl->next; gf_mx_v(mux->videoMx); if (skipped > 0) GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("Skipped %u video frames, frame was "LLU", but is now "LLU"\n", skipped, first, video_pts)); } videoSize+=pl->pkt.size; video_pts = pl->pkt.pts; // * video_st->time_base.num / video_st->time_base.den; assert( video_pts); if (av_interleaved_write_frame(mux->oc, &(pl->pkt)) < 0) { GF_LOG(GF_LOG_ERROR, GF_LOG_MODULE, ("[AVRedirect] : failed to write video interleaved frame audio_pts="LLU", video_pts="LLU"\n", audio_pts, video_pts)); } gf_free(pl); } gf_sleep(1); } exit: GF_LOG(GF_LOG_INFO, GF_LOG_MODULE, ("[AVRedirect] Ending TS thread...\n")); av_write_trailer(mux->oc); if (!(mux->oc->oformat->flags & AVFMT_NOFILE)) { /* close the output file */ url_fclose(mux->oc->pb); } return 0; }
static void term_on_command(GF_ClientService *service, GF_NetworkCommand *com, GF_Err response) { GF_Channel *ch; GF_Terminal *term = service->term; if (com->command_type==GF_NET_BUFFER_QUERY) { GF_Scene *scene; u32 i, max_buffer_time; GF_ObjectManager *odm; com->buffer.max = 0; com->buffer.min = com->buffer.occupancy = (u32) -1; com->buffer.buffering = GF_FALSE; if (!service->owner) { com->buffer.occupancy = 0; return; } /*browse all channels in the scene, running on this service, and get buffer info*/ scene = NULL; if (service->owner->subscene) { scene = service->owner->subscene; } else if (service->owner->parentscene) { scene = service->owner->parentscene; } if (!scene) { com->buffer.occupancy = 0; return; } /*get exclusive access to scene resources , to make sure ODs are not being inserted/remove*/ gf_mx_p(scene->mx_resources); max_buffer_time=0; if (!gf_list_count(scene->resources)) GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM] No object manager found for the scene (URL: %s), buffer occupancy will remain unchanged\n", service->url)); i=0; while ((odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) { gather_buffer_level(odm, service, com, &max_buffer_time); } gf_mx_v(scene->mx_resources); if (com->buffer.occupancy==(u32) -1) com->buffer.occupancy = 0; //in bench mode return the 1 if one of the buffer is full (eg sleep until all buffers are not full), 0 otherwise if (term->bench_mode) { com->buffer.occupancy = (max_buffer_time>com->buffer.max) ? 2 : 0; com->buffer.max = 1; com->buffer.min = 0; } return; } if (com->command_type==GF_NET_SERVICE_INFO) { GF_Event evt; evt.type = GF_EVENT_METADATA; gf_term_send_event(term, &evt); return; } if (com->command_type==GF_NET_SERVICE_MEDIA_CAP_QUERY) { gf_sc_get_av_caps(term->compositor, &com->mcaps.width, &com->mcaps.height, &com->mcaps.display_bit_depth, &com->mcaps.audio_bpp, &com->mcaps.channels, &com->mcaps.sample_rate); return; } if (com->command_type==GF_NET_SERVICE_EVENT) { /*check for UDP timeout*/ if (com->send_event.evt.message.error == GF_IP_UDP_TIMEOUT) { const char *sOpt = gf_cfg_get_key(term->user->config, "Network", "AutoReconfigUDP"); if (sOpt && !stricmp(sOpt, "yes")) { char szMsg[1024]; sprintf(szMsg, "!! UDP down (%s) - Retrying with TCP !!\n", com->send_event.evt.message.message); gf_term_message(term, service->url, szMsg, GF_IP_NETWORK_FAILURE); /*reload scene - FIXME this shall work on inline nodes, not on the root !*/ if (term->reload_url) gf_free(term->reload_url); term->reload_state = 1; term->reload_url = gf_strdup(term->root_scene->root_od->net_service->url); gf_cfg_set_key(term->user->config, "Network", "UDPNotAvailable", "yes"); return; } } com->send_event.res = 0; gf_term_send_event(term, &com->send_event.evt); return; } if (com->command_type==GF_NET_ASSOCIATED_CONTENT_LOCATION) { GF_Scene *scene = NULL; if (service->owner->subscene) { scene = service->owner->subscene; } else if (service->owner->parentscene) { scene = service->owner->parentscene; } if (scene) gf_scene_register_associated_media(scene, &com->addon_info); return; } if (com->command_type==GF_NET_ASSOCIATED_CONTENT_TIMING) { GF_Scene *scene = NULL; if (service->owner->subscene) { scene = service->owner->subscene; } else if (service->owner->parentscene) { scene = service->owner->parentscene; } if (scene) gf_scene_notify_associated_media_timeline(scene, &com->addon_time); return; } if (com->command_type==GF_NET_SERVICE_SEEK) { GF_Scene *scene = NULL; if (service->owner->subscene) { scene = service->owner->subscene; } else if (service->owner->parentscene) { scene = service->owner->parentscene; } if (scene && scene->is_dynamic_scene) { gf_sc_lock(term->compositor, 1); gf_scene_restart_dynamic(scene, (u64) (com->play.start_range*1000), 0, 0); gf_sc_lock(term->compositor, 0); } return; } if (com->command_type == GF_NET_SERVICE_CODEC_STAT_QUERY) { GF_List *od_list; u32 i; GF_ObjectManager *odm; com->codec_stat.avg_dec_time = 0; com->codec_stat.max_dec_time = 0; com->codec_stat.irap_avg_dec_time = 0; com->codec_stat.irap_max_dec_time = 0; if (!service->owner) return; /*browse all channels in the scene, running on this service, and get codec stat*/ od_list = NULL; if (service->owner->subscene) { od_list = service->owner->subscene->resources; } else if (service->owner->parentscene) { od_list = service->owner->parentscene->resources; } if (!od_list) return; /*get exclusive access to media scheduler, to make sure ODs are not being manipulated*/ i=0; while ((odm = (GF_ObjectManager*)gf_list_enum(od_list, &i))) { u32 avg_dec_time; /*the decoder statistics are reliable only if we decoded at least 1s*/ if (!odm->codec || !odm->codec->nb_dec_frames || (odm->codec->ck->speed > 0 ? odm->codec->stat_start + 1000 > odm->codec->last_unit_dts : odm->codec->stat_start - 1000 < odm->codec->last_unit_dts)) continue; avg_dec_time = (u32) (odm->codec->total_dec_time / odm->codec->nb_dec_frames); if (avg_dec_time > com->codec_stat.avg_dec_time) { com->codec_stat.avg_dec_time = avg_dec_time; com->codec_stat.max_dec_time = odm->codec->max_dec_time; com->codec_stat.irap_avg_dec_time = odm->codec->nb_iframes ? (u32) (odm->codec->total_iframes_time / odm->codec->nb_iframes) : 0; com->codec_stat.irap_max_dec_time = odm->codec->max_iframes_time; } if (odm->codec->codec_reset) { com->codec_stat.codec_reset = GF_TRUE; odm->codec->codec_reset = GF_FALSE; } com->codec_stat.decode_only_rap = odm->codec->decode_only_rap ? GF_TRUE : GF_FALSE; } return; } if (!com->base.on_channel) return; ch = gf_term_get_channel(service, com->base.on_channel); if (!ch) return; switch (com->command_type) { /*SL reconfiguration*/ case GF_NET_CHAN_RECONFIG: gf_term_lock_net(term, 1); gf_es_reconfig_sl(ch, &com->cfg.sl_config, com->cfg.use_m2ts_sections); gf_term_lock_net(term, 0); return; case GF_NET_CHAN_SET_MEDIA_TIME: if (gf_es_owns_clock(ch) || !ch->clock->has_media_time_shift) { Double mtime = com->map_time.media_time; if (ch->clock->clock_init) { Double t = (Double) com->map_time.timestamp; t /= ch->esd->slConfig->timestampResolution; t -= ((Double) ch->clock->init_time) /1000; mtime += t; } ch->clock->media_time_at_init = (u32) (1000*mtime); ch->clock->has_media_time_shift = 1; } return; /*time mapping (TS to media-time)*/ case GF_NET_CHAN_MAP_TIME: if (ch->esd->dependsOnESID) { //ignore everything } else { u32 i; GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: before mapping: seed TS %d - TS offset %d\n", ch->esd->ESID, ch->seed_ts, ch->ts_offset)); ch->seed_ts = com->map_time.timestamp; ch->ts_offset = (u32) (com->map_time.media_time*1000); GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: mapping TS "LLD" to media time %f - current time %d\n", ch->esd->ESID, com->map_time.timestamp, com->map_time.media_time, gf_clock_time(ch->clock))); GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: after mapping: seed TS %d - TS offset %d\n", ch->esd->ESID, ch->seed_ts, ch->ts_offset)); if (com->map_time.reset_buffers) { gf_es_reset_buffers(ch); } /*if we were reassembling an AU, do not perform clock init check when dispatching it since we computed its timestamps according to the previous clock origin*/ else { gf_mx_p(ch->mx); ch->skip_time_check_for_pending = 1; gf_mx_v(ch->mx); } /*if the channel is the clock, force a re-init*/ if (gf_es_owns_clock(ch)) { ch->IsClockInit = 0; gf_clock_reset(ch->clock); } else if (ch->odm->flags & GF_ODM_INHERIT_TIMELINE) { ch->IsClockInit = 0; // ch->ts_offset -= ch->seed_ts*1000/ch->ts_res; } for (i=0; i<gf_list_count(ch->odm->channels); i++) { GF_Channel *a_ch = gf_list_get(ch->odm->channels, i); if (ch==a_ch) continue; if (! a_ch->esd->dependsOnESID) continue; a_ch->seed_ts = ch->seed_ts; a_ch->IsClockInit = 0; a_ch->ts_offset = ch->ts_offset; } } break; /*duration changed*/ case GF_NET_CHAN_DURATION: gf_odm_set_duration(ch->odm, ch, (u32) (1000*com->duration.duration)); break; case GF_NET_CHAN_BUFFER_QUERY: if (ch->IsEndOfStream) { com->buffer.max = com->buffer.min = com->buffer.occupancy = 0; } else { com->buffer.max = ch->MaxBuffer; com->buffer.min = ch->MinBuffer; com->buffer.occupancy = (u32) (ch->BufferTime / FIX2FLT(ch->clock->speed) ); } break; case GF_NET_CHAN_DRM_CFG: gf_term_lock_net(term, 1); gf_es_config_drm(ch, &com->drm_cfg); gf_term_lock_net(term, 0); return; case GF_NET_CHAN_GET_ESD: gf_term_lock_net(term, 1); com->cache_esd.esd = ch->esd; com->cache_esd.is_iod_stream = (ch->odm->subscene /*&& (ch->odm->subscene->root_od==ch->odm)*/) ? 1 : 0; gf_term_lock_net(term, 0); return; case GF_NET_CHAN_RESET: gf_es_reset_buffers(ch); break; case GF_NET_CHAN_PAUSE: ch->MaxBuffer = com->buffer.max; ch->MinBuffer = com->buffer.min; ch->BufferTime = com->buffer.max; gf_es_buffer_on(ch); break; case GF_NET_CHAN_RESUME: ch->BufferTime = ch->MaxBuffer; gf_es_update_buffering(ch, 1); gf_es_buffer_off(ch); break; case GF_NET_CHAN_BUFFER: ch->MaxBuffer = com->buffer.max; ch->MinBuffer = com->buffer.min; ch->BufferTime = com->buffer.occupancy; gf_es_update_buffering(ch, 1); break; default: return; } }
void svg_drawable_3d_pick(Drawable *drawable, GF_TraverseState *tr_state, DrawAspect2D *asp) { SFVec3f local_pt, world_pt, vdiff; SFVec3f hit_normal; SFVec2f text_coords; u32 i, count; Fixed sqdist; Bool node_is_over; GF_Compositor *compositor; GF_Matrix mx; GF_Ray r; compositor = tr_state->visual->compositor; node_is_over = 0; r = tr_state->ray; gf_mx_copy(mx, tr_state->model_matrix); gf_mx_inverse(&mx); gf_mx_apply_ray(&mx, &r); /*if we already have a hit point don't check anything below...*/ if (compositor->hit_square_dist && !compositor->grabbed_sensor && !tr_state->layer3d) { GF_Plane p; GF_BBox box; SFVec3f hit = compositor->hit_world_point; gf_mx_apply_vec(&mx, &hit); p.normal = r.dir; p.d = -1 * gf_vec_dot(p.normal, hit); gf_bbox_from_rect(&box, &drawable->path->bbox); if (gf_bbox_plane_relation(&box, &p) == GF_BBOX_FRONT) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SVG Picking] bounding box of node %s (DEF %s) below current hit point - skipping\n", gf_node_get_class_name(drawable->node), gf_node_get_name(drawable->node))); return; } } node_is_over = 0; if (compositor_get_2d_plane_intersection(&r, &local_pt)) { node_is_over = svg_drawable_is_over(drawable, local_pt.x, local_pt.y, asp, tr_state, NULL); } if (!node_is_over) return; hit_normal.x = hit_normal.y = 0; hit_normal.z = FIX_ONE; text_coords.x = gf_divfix(local_pt.x, drawable->path->bbox.width) + FIX_ONE/2; text_coords.y = gf_divfix(local_pt.y, drawable->path->bbox.height) + FIX_ONE/2; /*check distance from user and keep the closest hitpoint*/ world_pt = local_pt; gf_mx_apply_vec(&tr_state->model_matrix, &world_pt); for (i=0; i<tr_state->num_clip_planes; i++) { if (gf_plane_get_distance(&tr_state->clip_planes[i], &world_pt) < 0) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SVG Picking] node %s (def %s) is not in clipper half space\n", gf_node_get_class_name(drawable->node), gf_node_get_name(drawable->node))); return; } } gf_vec_diff(vdiff, world_pt, tr_state->ray.orig); sqdist = gf_vec_lensq(vdiff); if (compositor->hit_square_dist && (compositor->hit_square_dist+FIX_EPSILON<sqdist)) { GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SVG Picking] node %s (def %s) is farther (%g) than current pick (%g)\n", gf_node_get_class_name(drawable->node), gf_node_get_name(drawable->node), FIX2FLT(sqdist), FIX2FLT(compositor->hit_square_dist))); return; } compositor->hit_square_dist = sqdist; /*also stack any VRML sensors present at the current level. If the event is not catched by a listener in the SVG tree, the event will be forwarded to the VRML tree*/ gf_list_reset(compositor->sensors); count = gf_list_count(tr_state->vrml_sensors); for (i=0; i<count; i++) { gf_list_add(compositor->sensors, gf_list_get(tr_state->vrml_sensors, i)); } gf_mx_copy(compositor->hit_world_to_local, tr_state->model_matrix); gf_mx_copy(compositor->hit_local_to_world, mx); compositor->hit_local_point = local_pt; compositor->hit_world_point = world_pt; compositor->hit_world_ray = tr_state->ray; compositor->hit_normal = hit_normal; compositor->hit_texcoords = text_coords; svg_clone_use_stack(compositor, tr_state); /*not use in SVG patterns*/ compositor->hit_appear = NULL; compositor->hit_node = drawable->node; compositor->hit_text = NULL; compositor->hit_use_dom_events = 1; GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[SVG Picking] node %s (def %s) is under mouse - hit %g %g %g\n", gf_node_get_class_name(drawable->node), gf_node_get_name(drawable->node), FIX2FLT(world_pt.x), FIX2FLT(world_pt.y), FIX2FLT(world_pt.z))); }
static GF_InputService *gf_term_can_handle_service(GF_Terminal *term, const char *url, const char *parent_url, Bool no_mime_check, char **out_url, GF_Err *ret_code, GF_DownloadSession **the_session, char **out_mime_type) { u32 i; GF_Err e; char *sURL, *qm, *frag, *ext, *mime_type, *url_res; char szExt[50]; const char *force_module = NULL; GF_InputService *ifce; Bool skip_mime = 0; memset(szExt, 0, sizeof(szExt)); (*ret_code) = GF_OK; ifce = NULL; mime_type = NULL; GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Looking for plugin for URL %s\n", url)); *out_url = NULL; *out_mime_type = NULL; sURL = NULL; if (!url || !strncmp(url, "\\\\", 2) ) { (*ret_code) = GF_URL_ERROR; goto exit; } if (!strnicmp(url, "libplayer://", 12)) { force_module = "LibPlayer"; } /*used by GUIs scripts to skip URL concatenation*/ if (!strncmp(url, "gpac://", 7)) sURL = gf_strdup(url+7); /*opera-style localhost URLs*/ else if (!strncmp(url, "file://localhost", 16)) sURL = gf_strdup(url+16); else if (parent_url) sURL = gf_url_concatenate(parent_url, url); /*path absolute*/ if (!sURL) sURL = gf_strdup(url); if (gf_url_is_local(sURL)) gf_url_to_fs_path(sURL); if (the_session) *the_session = NULL; if (no_mime_check) { mime_type = NULL; } else { /*fetch a mime type if any. If error don't even attempt to open the service */ mime_type = get_mime_type(term, sURL, &e, the_session); if (e) { (*ret_code) = e; goto exit; } } if (mime_type && (!stricmp(mime_type, "text/plain") || !stricmp(mime_type, "video/quicktime") || !stricmp(mime_type, "application/octet-stream") ) ) { skip_mime = 1; } ifce = NULL; /*load from mime type*/ if (mime_type && !skip_mime) { const char *sPlug = gf_cfg_get_key(term->user->config, "MimeTypes", mime_type); GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Mime type found: %s\n", mime_type)); if (!sPlug) { *out_mime_type = mime_type; mime_type=NULL; } if (sPlug) sPlug = strrchr(sPlug, '"'); if (sPlug) { sPlug += 2; GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("%s:%d FOUND matching module %s\n", __FILE__, __LINE__, sPlug)); ifce = (GF_InputService *) gf_modules_load_interface_by_name(term->user->modules, sPlug, GF_NET_CLIENT_INTERFACE); if (force_module && ifce && !strstr(ifce->module_name, force_module)) { gf_modules_close_interface((GF_BaseInterface *) ifce); ifce = NULL; } if (ifce && !net_check_interface(ifce) ) { gf_modules_close_interface((GF_BaseInterface *) ifce); ifce = NULL; } } } /* The file extension, if any, is before '?' if any or before '#' if any.*/ url_res = strrchr(sURL, '/'); if (!url_res) url_res = strrchr(sURL, '\\'); if (!url_res) url_res = sURL; qm = strchr(url_res, '?'); if (qm) { qm[0] = 0; ext = strrchr(url_res, '.'); qm[0] = '?'; } else { frag = strchr(url_res, '#'); if (frag) { frag[0] = 0; ext = strrchr(url_res, '.'); frag[0] = '#'; } else { ext = strrchr(url_res, '.'); } } if (ext && !stricmp(ext, ".gz")) { char *anext; ext[0] = 0; anext = strrchr(sURL, '.'); ext[0] = '.'; ext = anext; } /*no mime type: either local or streaming. If streaming discard extension checking*/ if (!ifce && !mime_type && strstr(sURL, "://") && strnicmp(sURL, "file://", 7)) ext = NULL; /*browse extensions for prefered module*/ if (!ifce && ext) { u32 keyCount; strncpy(szExt, &ext[1], 49); ext = strrchr(szExt, '?'); if (ext) ext[0] = 0; ext = strrchr(szExt, '#'); if (ext) ext[0] = 0; GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] No mime type found - checking by extension %s\n", szExt)); assert( term && term->user && term->user->modules); keyCount = gf_cfg_get_key_count(term->user->config, "MimeTypes"); for (i=0; i<keyCount; i++) { char *sPlug; const char *sKey; const char *sMime; sMime = gf_cfg_get_key_name(term->user->config, "MimeTypes", i); if (!sMime) continue; sKey = gf_cfg_get_key(term->user->config, "MimeTypes", sMime); if (!sKey) continue; if (!check_extension(sKey, szExt)) continue; sPlug = strrchr(sKey, '"'); if (!sPlug) continue; /*bad format entry*/ sPlug += 2; GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Trying module[%i]=%s, mime=%s\n", i, sPlug, sMime)); ifce = (GF_InputService *) gf_modules_load_interface_by_name(term->user->modules, sPlug, GF_NET_CLIENT_INTERFACE); if (!ifce) { GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] module[%i]=%s, mime=%s, cannot be loaded for GF_NET_CLIENT_INTERFACE.\n", i, sPlug, sMime)); continue; } if (force_module && ifce && !strstr(ifce->module_name, force_module)) { gf_modules_close_interface((GF_BaseInterface *) ifce); ifce = NULL; continue; } if (ifce && !net_check_interface(ifce)) { gf_modules_close_interface((GF_BaseInterface *) ifce); ifce = NULL; continue; } break; } } /*browse all modules*/ if (!ifce) { GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Not found any interface, trying browsing all modules...\n")); for (i=0; i< gf_modules_get_count(term->user->modules); i++) { ifce = (GF_InputService *) gf_modules_load_interface(term->user->modules, i, GF_NET_CLIENT_INTERFACE); if (!ifce) continue; GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Checking if module %s supports URL %s\n", ifce->module_name, sURL)); if (force_module && ifce && !strstr(ifce->module_name, force_module)) { } else if (net_check_interface(ifce) && ifce->CanHandleURL(ifce, sURL)) { break; } gf_modules_close_interface((GF_BaseInterface *) ifce); ifce = NULL; } } exit: if (!ifce) { if (*ret_code) { GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Terminal] Error fetching mime type for URL %s: %s\n", sURL ? sURL : url, gf_error_to_string(*ret_code) )); } else { GF_LOG(GF_LOG_ERROR, GF_LOG_MEDIA, ("[Terminal] Did not find any input plugin for URL %s (%s) \n", sURL ? sURL : url, mime_type ? mime_type : "no mime type")); } if (sURL) gf_free(sURL); if ( (*ret_code) == GF_OK) (*ret_code) = GF_NOT_SUPPORTED; *out_url = NULL; if (the_session && *the_session) { gf_dm_sess_del(*the_session); } if (mime_type) gf_free(mime_type); mime_type = NULL; if (*out_mime_type) gf_free(*out_mime_type); *out_mime_type = NULL; } else { *out_url = sURL; GF_LOG(GF_LOG_INFO, GF_LOG_MEDIA, ("[Terminal] Found input plugin %s for URL %s (%s)\n", ifce->module_name, sURL, mime_type ? mime_type : "no mime type")); } if (mime_type) *out_mime_type = mime_type; return ifce; }
static GF_Err gf_text_import_srt_bifs(GF_SceneManager *ctx, GF_ESD *src, GF_MuxInfo *mux) { GF_Err e; GF_Node *text, *font; GF_StreamContext *srt; FILE *srt_in; GF_FieldInfo string, style; u32 sh, sm, ss, sms, eh, em, es, ems, start, end; GF_AUContext *au; GF_Command *com; SFString *sfstr; GF_CommandField *inf; Bool italic, underlined, bold; u32 state, curLine, line, i, len; char szLine[2048], szText[2048], *ptr; GF_StreamContext *sc = NULL; if (!ctx->scene_graph) { GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] base scene not assigned\n")); return GF_BAD_PARAM; } i=0; while ((sc = (GF_StreamContext*)gf_list_enum(ctx->streams, &i))) { if (sc->streamType==GF_STREAM_SCENE) break; sc = NULL; } if (!sc) { GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] cannot locate base scene\n")); return GF_BAD_PARAM; } if (!mux->textNode) { GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] Target text node unspecified\n")); return GF_BAD_PARAM; } text = gf_sg_find_node_by_name(ctx->scene_graph, mux->textNode); if (!text) { GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] cannot find target text node %s\n", mux->textNode)); return GF_BAD_PARAM; } if (gf_node_get_field_by_name(text, "string", &string) != GF_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] Target text node %s doesn't look like text\n", mux->textNode)); return GF_BAD_PARAM; } font = NULL; if (mux->fontNode) { font = gf_sg_find_node_by_name(ctx->scene_graph, mux->fontNode); if (!font) { GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] cannot find target font node %s\n", mux->fontNode)); return GF_BAD_PARAM; } if (gf_node_get_field_by_name(font, "style", &style) != GF_OK) { GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] Target font node %s doesn't look like font\n", mux->fontNode)); return GF_BAD_PARAM; } } srt_in = gf_f64_open(mux->file_name, "rt"); if (!srt_in) { GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] cannot open input file %s\n", mux->file_name)); return GF_URL_ERROR; } srt = gf_sm_stream_new(ctx, src->ESID, GF_STREAM_SCENE, 1); if (!srt) return GF_OUT_OF_MEM; if (!src->slConfig) src->slConfig = (GF_SLConfig *) gf_odf_desc_new(GF_ODF_SLC_TAG); src->slConfig->timestampResolution = 1000; if (!src->decoderConfig) src->decoderConfig = (GF_DecoderConfig *) gf_odf_desc_new(GF_ODF_DCD_TAG); src->decoderConfig->streamType = GF_STREAM_SCENE; src->decoderConfig->objectTypeIndication = 1; e = GF_OK; state = end = 0; curLine = 0; au = NULL; com = NULL; italic = underlined = bold = 0; inf = NULL; while (1) { char *sOK = fgets(szLine, 2048, srt_in); if (sOK) REM_TRAIL_MARKS(szLine, "\r\n\t ") if (!sOK || !strlen(szLine)) { state = 0; if (au) { /*if italic or underscore do it*/ if (font && (italic || underlined || bold)) { com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE); com->node = font; gf_node_register(font, NULL); inf = gf_sg_command_field_new(com); inf->fieldIndex = style.fieldIndex; inf->fieldType = style.fieldType; inf->field_ptr = gf_sg_vrml_field_pointer_new(style.fieldType); sfstr = (SFString *)inf->field_ptr; if (bold && italic && underlined) sfstr->buffer = gf_strdup("BOLDITALIC UNDERLINED"); else if (italic && underlined) sfstr->buffer = gf_strdup("ITALIC UNDERLINED"); else if (bold && underlined) sfstr->buffer = gf_strdup("BOLD UNDERLINED"); else if (underlined) sfstr->buffer = gf_strdup("UNDERLINED"); else if (bold && italic) sfstr->buffer = gf_strdup("BOLDITALIC"); else if (bold) sfstr->buffer = gf_strdup("BOLD"); else sfstr->buffer = gf_strdup("ITALIC"); gf_list_add(au->commands, com); } au = gf_sm_stream_au_new(srt, end, 0, 1); com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE); com->node = text; gf_node_register(text, NULL); inf = gf_sg_command_field_new(com); inf->fieldIndex = string.fieldIndex; inf->fieldType = string.fieldType; inf->field_ptr = gf_sg_vrml_field_pointer_new(string.fieldType); gf_list_add(au->commands, com); /*reset font styles so that all AUs are true random access*/ if (font) { com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE); com->node = font; gf_node_register(font, NULL); inf = gf_sg_command_field_new(com); inf->fieldIndex = style.fieldIndex; inf->fieldType = style.fieldType; inf->field_ptr = gf_sg_vrml_field_pointer_new(style.fieldType); gf_list_add(au->commands, com); } au = NULL; } inf = NULL; if (!sOK) break; continue; } switch (state) { case 0: if (sscanf(szLine, "%u", &line) != 1) { GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] bad frame format (src: %s)\n", szLine)); e = GF_CORRUPTED_DATA; goto exit; } if (line != curLine + 1) { GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] bad frame: previous %d - current %d (src: %s)\n", curLine, line, szLine)); e = GF_CORRUPTED_DATA; goto exit; } curLine = line; state = 1; break; case 1: if (sscanf(szLine, "%u:%u:%u,%u --> %u:%u:%u,%u", &sh, &sm, &ss, &sms, &eh, &em, &es, &ems) != 8) { GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[srt->bifs] bad frame %u (src: %s)\n", curLine, szLine)); e = GF_CORRUPTED_DATA; goto exit; } start = (3600*sh + 60*sm + ss)*1000 + sms; if (start<end) { GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[srt->bifs] corrupted frame starts before end of previous one (SRT Frame %d) - adjusting time stamps\n", curLine)); start = end; } end = (3600*eh + 60*em + es)*1000 + ems; /*make stream start at 0 by inserting a fake AU*/ if ((curLine==1) && start>0) { au = gf_sm_stream_au_new(srt, 0, 0, 1); com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE); com->node = text; gf_node_register(text, NULL); inf = gf_sg_command_field_new(com); inf->fieldIndex = string.fieldIndex; inf->fieldType = string.fieldType; inf->field_ptr = gf_sg_vrml_field_pointer_new(string.fieldType); gf_list_add(au->commands, com); } au = gf_sm_stream_au_new(srt, start, 0, 1); com = NULL; state = 2; italic = underlined = bold = 0; break; default: ptr = szLine; /*FIXME - other styles posssibles ??*/ while (1) { if (!strnicmp(ptr, "<i>", 3)) { italic = 1; ptr += 3; } else if (!strnicmp(ptr, "<u>", 3)) { underlined = 1; ptr += 3; } else if (!strnicmp(ptr, "<b>", 3)) { bold = 1; ptr += 3; } else break; } /*if style remove end markers*/ while ((strlen(ptr)>4) && (ptr[strlen(ptr) - 4] == '<') && (ptr[strlen(ptr) - 1] == '>')) { ptr[strlen(ptr) - 4] = 0; } if (!com) { com = gf_sg_command_new(ctx->scene_graph, GF_SG_FIELD_REPLACE); com->node = text; gf_node_register(text, NULL); inf = gf_sg_command_field_new(com); inf->fieldIndex = string.fieldIndex; inf->fieldType = string.fieldType; inf->field_ptr = gf_sg_vrml_field_pointer_new(string.fieldType); gf_list_add(au->commands, com); } assert(inf); gf_sg_vrml_mf_append(inf->field_ptr, GF_SG_VRML_MFSTRING, (void **) &sfstr); len = 0; for (i=0; i<strlen(ptr); i++) { /*FIXME - UTF16 support !!*/ if (ptr[i] & 0x80) { /*non UTF8 (likely some win-CP)*/ if ((ptr[i+1] & 0xc0) != 0x80) { szText[len] = 0xc0 | ( (ptr[i] >> 6) & 0x3 ); len++; ptr[i] &= 0xbf; } /*we only handle UTF8 chars on 2 bytes (eg first byte is 0b110xxxxx)*/ else if ((ptr[i] & 0xe0) == 0xc0) { szText[len] = ptr[i]; len++; i++; } } szText[len] = ptr[i]; len++; } szText[len] = 0; sfstr->buffer = gf_strdup(szText); break; }
static void imagetexture_update(GF_TextureHandler *txh) { if (gf_node_get_tag(txh->owner)!=TAG_MPEG4_CacheTexture) { MFURL url = ((M_ImageTexture *) txh->owner)->url; /*setup texture if needed*/ if (!txh->is_open && url.count) { gf_sc_texture_play(txh, &url); } gf_sc_texture_update_frame(txh, 0); if ( /*URL is present but not opened - redraw till fetch*/ /* (txh->stream && !txh->tx_io) && */ /*image has been updated*/ txh->needs_refresh) { /*mark all subtrees using this image as dirty*/ gf_node_dirty_parents(txh->owner); gf_sc_invalidate(txh->compositor, NULL); } return; } /*cache texture case*/ else { M_CacheTexture *ct = (M_CacheTexture *) txh->owner; /*decode cacheTexture data */ if ((ct->data || ct->image.buffer) && !txh->data) { #ifndef GPAC_DISABLE_AV_PARSERS u32 out_size; GF_Err e; /*BT/XMT playback: load to memory*/ if (ct->image.buffer) { char *par = (char *) gf_scene_get_service_url( gf_node_get_graph(txh->owner ) ); char *src_url = gf_url_concatenate(par, ct->image.buffer); FILE *test = gf_fopen( src_url ? src_url : ct->image.buffer, "rb"); if (test) { fseek(test, 0, SEEK_END); ct->data_len = (u32) gf_ftell(test); ct->data = gf_malloc(sizeof(char)*ct->data_len); fseek(test, 0, SEEK_SET); if (ct->data_len != fread(ct->data, 1, ct->data_len, test)) { GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to load CacheTexture data from file %s: IO err\n", src_url ? src_url : ct->image.buffer ) ); gf_free(ct->data); ct->data = NULL; ct->data_len = 0; } gf_fclose(test); } else { GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to load CacheTexture data from file %s: not found\n", src_url ? src_url : ct->image.buffer ) ); } ct->image.buffer = NULL; if (src_url) gf_free(src_url); } /*BIFS decoded playback*/ switch (ct->objectTypeIndication) { case GPAC_OTI_IMAGE_JPEG: out_size = 0; e = gf_img_jpeg_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, NULL, &out_size, 3); if (e==GF_BUFFER_TOO_SMALL) { u32 BPP; txh->data = gf_malloc(sizeof(char) * out_size); if (txh->pixelformat==GF_PIXEL_GREYSCALE) BPP = 1; else BPP = 3; e = gf_img_jpeg_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, txh->data, &out_size, BPP); if (e==GF_OK) { gf_sc_texture_allocate(txh); gf_sc_texture_set_data(txh); txh->needs_refresh = 1; txh->stride = out_size / txh->height; } } break; case GPAC_OTI_IMAGE_PNG: out_size = 0; e = gf_img_png_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, NULL, &out_size); if (e==GF_BUFFER_TOO_SMALL) { txh->data = gf_malloc(sizeof(char) * out_size); e = gf_img_png_dec((char *) ct->data, ct->data_len, &txh->width, &txh->height, &txh->pixelformat, txh->data, &out_size); if (e==GF_OK) { gf_sc_texture_allocate(txh); gf_sc_texture_set_data(txh); txh->needs_refresh = 1; txh->stride = out_size / txh->height; } } break; } #endif // GPAC_DISABLE_AV_PARSERS /*cacheURL is specified, store the image*/ if (ct->cacheURL.buffer) { u32 i; u8 hash[20]; FILE *cached_texture; char szExtractName[GF_MAX_PATH], section[64], *opt, *src_url; opt = (char *) gf_cfg_get_key(txh->compositor->user->config, "General", "CacheDirectory"); if (opt) { strcpy(szExtractName, opt); } else { opt = gf_get_default_cache_directory(); strcpy(szExtractName, opt); gf_free(opt); } strcat(szExtractName, "/"); src_url = (char *) gf_scene_get_service_url( gf_node_get_graph(txh->owner ) ); gf_sha1_csum((u8 *)src_url, (u32) strlen(src_url), hash); for (i=0; i<20; i++) { char t[3]; t[2] = 0; sprintf(t, "%02X", hash[i]); strcat(szExtractName, t); } strcat(szExtractName, "_"); strcat(szExtractName, ct->cacheURL.buffer); cached_texture = gf_fopen(szExtractName, "wb"); if (cached_texture) { gf_fwrite(ct->data, 1, ct->data_len, cached_texture); gf_fclose(cached_texture); } /*and write cache info*/ if (ct->expirationDate!=0) { sprintf(section, "@cache=%p", ct); gf_cfg_set_key(txh->compositor->user->config, section, "serviceURL", src_url); gf_cfg_set_key(txh->compositor->user->config, section, "cacheFile", szExtractName); gf_cfg_set_key(txh->compositor->user->config, section, "cacheName", ct->cacheURL.buffer); if (ct->expirationDate>0) { char exp[50]; u32 sec, frac; gf_net_get_ntp(&sec, &frac); sec += ct->expirationDate; sprintf(exp, "%u", sec); gf_cfg_set_key(txh->compositor->user->config, section, "expireAfterNTP", exp); } else { gf_cfg_set_key(txh->compositor->user->config, section, "expireAfterNTP", "0"); } } } /*done with image, destroy buffer*/ if (ct->data) gf_free(ct->data); ct->data = NULL; ct->data_len = 0; } } }
static GF_Err OSVC_ProcessData(GF_MediaDecoder *ifcg, char *inBuffer, u32 inBufferLength, u16 ES_ID, u32 *CTS, char *outBuffer, u32 *outBufferLength, u8 PaddingBits, u32 mmlevel) { s32 got_pic; OPENSVCFRAME pic; int Layer[4]; u32 i, nalu_size, sc_size; u8 *ptr; OSVCDec *ctx = (OSVCDec*) ifcg->privateStack; u32 curMaxDqId = ctx->MaxDqId; if (!ES_ID || !ctx->codec) { *outBufferLength = 0; return GF_OK; } if (*outBufferLength < ctx->out_size) { *outBufferLength = ctx->out_size; return GF_BUFFER_TOO_SMALL; } ctx->MaxDqId = GetDqIdMax((unsigned char *) inBuffer, inBufferLength, ctx->nalu_size_length, ctx->DqIdTable, ctx->nalu_size_length ? 1 : 0); if (!ctx->init_layer_set) { //AVC stream in a h264 file if (ctx->MaxDqId == -1) ctx->MaxDqId = 0; ctx->CurrentDqId = ctx->MaxDqId; ctx->init_layer_set = GF_TRUE; } if (curMaxDqId != ctx->MaxDqId) ctx->CurrentDqId = ctx->MaxDqId; /*decode only current layer*/ SetCommandLayer(Layer, ctx->MaxDqId, ctx->CurrentDqId, &ctx->TemporalCom, ctx->TemporalId); got_pic = 0; nalu_size = 0; ptr = (u8 *) inBuffer; sc_size = 0; if (!ctx->nalu_size_length) { u32 size; size = gf_media_nalu_next_start_code((u8 *) inBuffer, inBufferLength, &sc_size); if (sc_size) { ptr += size+sc_size; assert(inBufferLength >= size+sc_size); inBufferLength -= size+sc_size; } else { /*no annex-B start-code found, discard */ *outBufferLength = 0; return GF_OK; } } while (inBufferLength) { if (ctx->nalu_size_length) { for (i=0; i<ctx->nalu_size_length; i++) { nalu_size = (nalu_size<<8) + ptr[i]; } ptr += ctx->nalu_size_length; } else { nalu_size = gf_media_nalu_next_start_code(ptr, inBufferLength, &sc_size); } #ifndef GPAC_DISABLE_LOG switch (ptr[0] & 0x1F) { case GF_AVC_NALU_SEQ_PARAM: case GF_AVC_NALU_SVC_SUBSEQ_PARAM: { u32 sps_id; gf_avc_get_sps_info((char *)ptr, nalu_size, &sps_id, NULL, NULL, NULL, NULL); GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[SVC Decoder] ES%d: SPS id=\"%d\" code=\"%d\" size=\"%d\"\n", ES_ID, sps_id, ptr[0] & 0x1F, nalu_size)); } break; case GF_AVC_NALU_PIC_PARAM: { u32 sps_id, pps_id; gf_avc_get_pps_info((char *)ptr, nalu_size, &pps_id, &sps_id); GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[SVC Decoder] ES%d: PPS id=\"%d\" code=\"%d\" size=\"%d\" sps_id=\"%d\"\n", ES_ID, pps_id, ptr[0] & 0x1F, nalu_size, sps_id)); } break; default: GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, ("[SVC Decoder] ES%d: NALU code=\"%d\" size=\"%d\"\n", ES_ID, ptr[0] & 0x1F, nalu_size)); } #endif if (!ctx->state_found) { u8 nal_type = (ptr[0] & 0x1F) ; switch (nal_type) { case GF_AVC_NALU_SEQ_PARAM: case GF_AVC_NALU_PIC_PARAM: if (ctx->baseES_ID == ES_ID) ctx->state_found = GF_TRUE; break; } } if (ctx->state_found) { if (!got_pic) got_pic = decodeNAL(ctx->codec, ptr, nalu_size, &pic, Layer); else decodeNAL(ctx->codec, ptr, nalu_size, &pic, Layer); } ptr += nalu_size; if (ctx->nalu_size_length) { if (inBufferLength < nalu_size + ctx->nalu_size_length) break; inBufferLength -= nalu_size + ctx->nalu_size_length; } else { if (!sc_size || (inBufferLength < nalu_size + sc_size)) break; inBufferLength -= nalu_size + sc_size; ptr += sc_size; } } if (got_pic!=1) { *outBufferLength = 0; return GF_OK; } if ((curMaxDqId != ctx->MaxDqId) || (pic.Width != ctx->width) || (pic.Height!=ctx->height)) { GF_LOG(GF_LOG_INFO, GF_LOG_CODEC, ("[SVC Decoder] Resizing from %dx%d to %dx%d\n", ctx->width, ctx->height, pic.Width, pic.Height )); ctx->width = pic.Width; ctx->stride = pic.Width + 32; ctx->height = pic.Height; ctx->out_size = ctx->stride * ctx->height * 3 / 2; /*always force layer resize*/ *outBufferLength = ctx->out_size; return GF_BUFFER_TOO_SMALL; } *outBufferLength = ctx->out_size; memcpy(outBuffer, pic.pY[0], ctx->stride*ctx->height); memcpy(outBuffer + ctx->stride * ctx->height, pic.pU[0], ctx->stride*ctx->height/4); memcpy(outBuffer + 5*ctx->stride * ctx->height/4, pic.pV[0], ctx->stride*ctx->height/4); return GF_OK; }
/*enumerate directories*/ GF_EXPORT GF_Err gf_enum_directory(const char *dir, Bool enum_directory, gf_enum_dir_item enum_dir_fct, void *cbck, const char *filter) { char item_path[GF_MAX_PATH]; GF_FileEnumInfo file_info; #if defined(_WIN32_WCE) char _path[GF_MAX_PATH]; unsigned short path[GF_MAX_PATH]; unsigned short w_filter[GF_MAX_PATH]; char file[GF_MAX_PATH]; #else char path[GF_MAX_PATH], *file; #endif #ifdef WIN32 WIN32_FIND_DATA FindData; HANDLE SearchH; #else DIR *the_dir; struct dirent* the_file; struct stat st; #endif if (!dir || !enum_dir_fct) return GF_BAD_PARAM; if (filter && (!strcmp(filter, "*") || !filter[0])) filter=NULL; memset(&file_info, 0, sizeof(GF_FileEnumInfo) ); if (!strcmp(dir, "/")) { #if defined(WIN32) && !defined(_WIN32_WCE) u32 len; char *drives, *volume; len = GetLogicalDriveStrings(0, NULL); drives = (char*)gf_malloc(sizeof(char)*(len+1)); drives[0]=0; GetLogicalDriveStrings(len, drives); len = (u32) strlen(drives); volume = drives; file_info.directory = GF_TRUE; file_info.drive = GF_TRUE; while (len) { enum_dir_fct(cbck, volume, "", &file_info); volume += len+1; len = (u32) strlen(volume); } gf_free(drives); return GF_OK; #elif defined(__SYMBIAN32__) RFs iFs; TDriveList aList; iFs.Connect(); iFs.DriveList(aList); for (TInt i=0; i<KMaxDrives; i++) { if (aList[i]) { char szDrive[10]; TChar aDrive; iFs.DriveToChar(i, aDrive); sprintf(szDrive, "%c:", (TUint)aDrive); enum_dir_fct(cbck, szDrive, "", &file_info); } } iFs.Close(); FlushItemList(); return GF_OK; #endif } #if defined (_WIN32_WCE) switch (dir[strlen(dir) - 1]) { case '/': case '\\': sprintf(_path, "%s*", dir); break; default: sprintf(_path, "%s%c*", dir, GF_PATH_SEPARATOR); break; } CE_CharToWide(_path, path); CE_CharToWide((char *)filter, w_filter); #elif defined(WIN32) switch (dir[strlen(dir) - 1]) { case '/': case '\\': sprintf(path, "%s*", dir); break; default: sprintf(path, "%s%c*", dir, GF_PATH_SEPARATOR); break; } #else strcpy(path, dir); if (path[strlen(path)-1] != '/') strcat(path, "/"); #endif #ifdef WIN32 SearchH= FindFirstFile(path, &FindData); if (SearchH == INVALID_HANDLE_VALUE) return GF_IO_ERR; #if defined (_WIN32_WCE) _path[strlen(_path)-1] = 0; #else path[strlen(path)-1] = 0; #endif while (SearchH != INVALID_HANDLE_VALUE) { #else the_dir = opendir(path); if (the_dir == NULL) { GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Cannot open directory %s for enumeration: %d\n", path, errno)); return GF_IO_ERR; } the_file = readdir(the_dir); while (the_file) { #endif memset(&file_info, 0, sizeof(GF_FileEnumInfo) ); #if defined (_WIN32_WCE) if (!wcscmp(FindData.cFileName, _T(".") )) goto next; if (!wcscmp(FindData.cFileName, _T("..") )) goto next; #elif defined(WIN32) if (!strcmp(FindData.cFileName, ".")) goto next; if (!strcmp(FindData.cFileName, "..")) goto next; #else if (!strcmp(the_file->d_name, "..")) goto next; if (the_file->d_name[0] == '.') goto next; #endif #ifdef WIN32 file_info.directory = (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? GF_TRUE : GF_FALSE; if (!enum_directory && file_info.directory) goto next; if (enum_directory && !file_info.directory) goto next; #endif if (filter) { #if defined (_WIN32_WCE) short ext[30]; short *sep = wcsrchr(FindData.cFileName, (wchar_t) '.'); if (!sep) goto next; wcscpy(ext, sep+1); wcslwr(ext); if (!wcsstr(w_filter, ext)) goto next; #elif defined(WIN32) char ext[30]; char *sep = strrchr(FindData.cFileName, '.'); if (!sep) goto next; strcpy(ext, sep+1); strlwr(ext); if (!strstr(filter, ext)) goto next; #else char ext[30]; char *sep = strrchr(the_file->d_name, '.'); if (!sep) goto next; strcpy(ext, sep+1); strlwr(ext); if (!strstr(filter, sep+1)) goto next; #endif } #if defined(WIN32) file_info.hidden = (FindData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? GF_TRUE : GF_FALSE; file_info.system = (FindData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? GF_TRUE : GF_FALSE; file_info.size = MAXDWORD; file_info.size += 1; file_info.size *= FindData.nFileSizeHigh; file_info.size += FindData.nFileSizeLow; file_info.last_modified = (u64) ((*(LONGLONG *) &FindData.ftLastWriteTime - TIMESPEC_TO_FILETIME_OFFSET) / 10000000); #endif #if defined (_WIN32_WCE) CE_WideToChar(FindData.cFileName, file); strcpy(item_path, _path); strcat(item_path, file); #elif defined(WIN32) strcpy(item_path, path); strcat(item_path, FindData.cFileName); file = FindData.cFileName; #else strcpy(item_path, path); strcat(item_path, the_file->d_name); GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Core] Checking file %s for enum\n", item_path)); if (stat( item_path, &st ) != 0) goto next; file_info.directory = ((st.st_mode & S_IFMT) == S_IFDIR) ? GF_TRUE : GF_FALSE; if (enum_directory && !file_info.directory) goto next; if (!enum_directory && file_info.directory) goto next; file_info.size = st.st_size; { struct tm _t = * gmtime(& st.st_mtime); file_info.last_modified = mktime(&_t); } file = the_file->d_name; if (file && file[0]=='.') file_info.hidden = 1; if (file_info.directory) { char * parent_name = strrchr(item_path, '/'); if (!parent_name) { file_info.drive = GF_TRUE; } else { struct stat st_parent; parent_name[0] = 0; if (stat(item_path, &st_parent) == 0) { if ((st.st_dev != st_parent.st_dev) || ((st.st_dev == st_parent.st_dev) && (st.st_ino == st_parent.st_ino))) { file_info.drive = GF_TRUE; } } parent_name[0] = '/'; } } #endif if (enum_dir_fct(cbck, file, item_path, &file_info)) { #ifdef WIN32 BOOL ret = FindClose(SearchH); if (!ret) { DWORD err = GetLastError(); GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_enum_directory() returned(1) the following error code: %d\n", err)); } #endif break; } next: #ifdef WIN32 if (!FindNextFile(SearchH, &FindData)) { BOOL ret = FindClose(SearchH); if (!ret) { DWORD err = GetLastError(); GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_enum_directory() returned(2) the following error code: %d\n", err)); } break; } #else the_file = readdir(the_dir); #endif } #ifndef WIN32 closedir(the_dir); #endif return GF_OK; } GF_EXPORT u64 gf_ftell(FILE *fp) { #if defined(_WIN32_WCE) return (u64) ftell(fp); #elif defined(GPAC_CONFIG_WIN32) /* mingw or cygwin */ #if (_FILE_OFFSET_BITS >= 64) return (u64) ftello64(fp); #else return (u64) ftell(fp); #endif #elif defined(WIN32) return (u64) _ftelli64(fp); #elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID) return (u64) ftello64(fp); #elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN)) return (u64) ftello(fp); #else return (u64) ftell(fp); #endif } GF_EXPORT u64 gf_fseek(FILE *fp, s64 offset, s32 whence) { #if defined(_WIN32_WCE) return (u64) fseek(fp, (s32) offset, whence); #elif defined(GPAC_CONFIG_WIN32) /* mingw or cygwin */ #if (_FILE_OFFSET_BITS >= 64) return (u64) fseeko64(fp, offset, whence); #else return (u64) fseek(fp, (s32) offset, whence); #endif #elif defined(WIN32) return (u64) _fseeki64(fp, offset, whence); #elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID) return fseeko64(fp, (off64_t) offset, whence); #elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN)) return fseeko(fp, (off_t) offset, whence); #else return fseek(fp, (s32) offset, whence); #endif } GF_EXPORT FILE *gf_fopen(const char *file_name, const char *mode) { FILE *res = NULL; #if defined(WIN32) Bool is_create; is_create = (strchr(mode, 'w') == NULL) ? GF_FALSE : GF_TRUE; if (!is_create) { if (strchr(mode, 'a')) { res = fopen(file_name, "rb"); if (res) { fclose(res); res = fopen(file_name, mode); } } else { res = fopen(file_name, mode); } } if (!res) { const char *str_src; wchar_t *wname; wchar_t *wmode; size_t len; size_t len_res; if (!is_create) { GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("[Core] Could not open file %s mode %s in UTF-8 mode, trying UTF-16\n", file_name, mode)); } len = (strlen(file_name) + 1)*sizeof(wchar_t); wname = (wchar_t *)gf_malloc(len); str_src = file_name; len_res = gf_utf8_mbstowcs(wname, len, &str_src); if (len_res == -1) { return NULL; } len = (strlen(mode) + 1)*sizeof(wchar_t); wmode = (wchar_t *)gf_malloc(len); str_src = mode; len_res = gf_utf8_mbstowcs(wmode, len, &str_src); if (len_res == -1) { return NULL; } res = _wfsopen(wname, wmode, _SH_DENYNO); gf_free(wname); gf_free(wmode); } #elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID) res = fopen64(file_name, mode); #elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN)) res = fopen(file_name, mode); #else res = fopen(file_name, mode); #endif if (res) { gpac_file_handles++; GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Core] file %s opened in mode %s - %d file handles\n", file_name, mode, gpac_file_handles)); } else { if (strchr(mode, 'w') || strchr(mode, 'a')) { #if defined(WIN32) u32 err = GetLastError(); GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] system failure for file opening of %s in mode %s: 0x%08x\n", file_name, mode, err)); #else GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] system failure for file opening of %s in mode %s: %d\n", file_name, mode, errno)); #endif } } return res; }
Bool enum_modules(void *cbck, char *item_name, char *item_path) { ModuleInstance *inst; #if CHECK_MODULE QueryInterface query_func; LoadInterface load_func; ShutdownInterface del_func; #ifdef WIN32 HMODULE ModuleLib; #else void *ModuleLib; s32 _flags; #endif #endif GF_ModuleManager *pm = (GF_ModuleManager*)cbck; if (strstr(item_name, "nposmozilla")) return 0; if (strncmp(item_name, "gm_", 3) && strncmp(item_name, "libgm_", 6)) return 0; if (gf_module_is_loaded(pm, item_name) ) return 0; #if CHECK_MODULE #ifdef WIN32 ModuleLib = LoadLibrary(item_path); if (!ModuleLib) { GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Cannot load module file %s\n", item_name)); return 0; } #ifdef _WIN32_WCE query_func = (QueryInterface) GetProcAddress(ModuleLib, _T("QueryInterface")); load_func = (LoadInterface) GetProcAddress(ModuleLib, _T("LoadInterface")); del_func = (ShutdownInterface) GetProcAddress(ModuleLib, _T("ShutdownInterface")); #else query_func = (QueryInterface) GetProcAddress(ModuleLib, "QueryInterface"); load_func = (LoadInterface) GetProcAddress(ModuleLib, "LoadInterface"); del_func = (ShutdownInterface) GetProcAddress(ModuleLib, "ShutdownInterface"); #endif FreeLibrary(ModuleLib); #else #ifdef RTLD_GLOBAL _flags =RTLD_LAZY | RTLD_GLOBAL; #else _flags =RTLD_LAZY; #endif ModuleLib = dlopen(item_name, _flags); if (!ModuleLib) { GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Cannot load module file %s, error is %s\n", item_name, dlerror())); goto next; } query_func = (QueryInterface) dlsym(ModuleLib, "QueryInterface"); load_func = (LoadInterface) dlsym(ModuleLib, "LoadInterface"); del_func = (ShutdownInterface) dlsym(ModuleLib, "ShutdownInterface"); dlclose(ModuleLib); #endif if (!load_func || !query_func || !del_func){ GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("[Core] Could not find some signatures in module %s: QueryInterface=%p, LoadInterface=%p, ShutdownInterface=%p\n", item_name, load_func, query_func, del_func)); return 0; } #endif GF_SAFEALLOC(inst, ModuleInstance); inst->interfaces = gf_list_new(); inst->plugman = pm; inst->name = gf_strdup(item_name); inst->dir = gf_strdup(item_path); gf_url_get_resource_path(item_path, inst->dir); GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("[Core] Added module %s.\n", inst->name)); gf_list_add(pm->plug_list, inst); return GF_FALSE; }
/*fixme, this doesn't work properly with respect to @expect_type*/ static GF_Descriptor *ISOR_GetServiceDesc(GF_InputService *plug, u32 expect_type, const char *sub_url) { u32 count, nb_st, i, trackID; GF_ESD *esd; ISOMReader *read; GF_InitialObjectDescriptor *iod; if (!plug || !plug->priv) return NULL; read = (ISOMReader *) plug->priv; if (!read->mov) return NULL; /*no matter what always read text as TTUs*/ gf_isom_text_set_streaming_mode(read->mov, 1); trackID = 0; if (!sub_url) { trackID = read->base_track_id; read->base_track_id = 0; } else { char *ext = strrchr(sub_url, '#'); if (!ext) { trackID = 0; } else { if (!strnicmp(ext, "#trackID=", 9)) trackID = atoi(ext+9); else if (!stricmp(ext, "#video")) trackID = get_track_id(read->mov, GF_ISOM_MEDIA_VISUAL, 0); else if (!strnicmp(ext, "#video", 6)) { trackID = atoi(ext+6); trackID = get_track_id(read->mov, GF_ISOM_MEDIA_VISUAL, trackID); } else if (!stricmp(ext, "#audio")) trackID = get_track_id(read->mov, GF_ISOM_MEDIA_AUDIO, 0); else if (!strnicmp(ext, "#audio", 6)) { trackID = atoi(ext+6); trackID = get_track_id(read->mov, GF_ISOM_MEDIA_AUDIO, trackID); } else trackID = atoi(ext+1); /*if trackID is 0, assume this is a fragment identifier*/ } } if (!trackID && (expect_type!=GF_MEDIA_OBJECT_SCENE) && (expect_type!=GF_MEDIA_OBJECT_UNDEF)) { for (i=0; i<gf_isom_get_track_count(read->mov); i++) { u32 type = gf_isom_get_media_type(read->mov, i+1); if ( ((type==GF_ISOM_MEDIA_VISUAL) && (expect_type==GF_MEDIA_OBJECT_VIDEO)) || ((type==GF_ISOM_MEDIA_AUDIO) && (expect_type==GF_MEDIA_OBJECT_AUDIO)) ) { trackID = gf_isom_get_track_id(read->mov, i+1); break; } } } if (trackID && (expect_type!=GF_MEDIA_OBJECT_SCENE) ) { u32 track = gf_isom_get_track_by_id(read->mov, trackID); if (!track) return NULL; esd = gf_media_map_esd(read->mov, track); esd->OCRESID = 0; iod = (GF_InitialObjectDescriptor *) gf_isom_get_root_od(read->mov); if (!iod) { iod = (GF_InitialObjectDescriptor *) gf_odf_desc_new(GF_ODF_IOD_TAG); iod->OD_profileAndLevel = iod->audio_profileAndLevel = iod->graphics_profileAndLevel = iod->scene_profileAndLevel = iod->visual_profileAndLevel = 0xFE; } else { while (gf_list_count(iod->ESDescriptors)) { GF_ESD *old = (GF_ESD *)gf_list_get(iod->ESDescriptors, 0); gf_odf_desc_del((GF_Descriptor *) old); gf_list_rem(iod->ESDescriptors, 0); } } gf_list_add(iod->ESDescriptors, esd); isor_emulate_chapters(read->mov, iod); return (GF_Descriptor *) iod; } iod = NULL; if (check_mpeg4_systems(plug, read->mov)) { iod = (GF_InitialObjectDescriptor *) gf_isom_get_root_od(read->mov); if (!iod) { #ifndef GPAC_DISABLE_LOG GF_Err e = gf_isom_last_error(read->mov); if (e) { GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[IsoMedia] Cannot fetch MPEG-4 IOD (error %s) - generating one\n", gf_error_to_string(e) )); } else { GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[IsoMedia] No MPEG-4 IOD found in file - generating one\n")); } #endif } } if (!iod) return isor_emulate_iod(read); count = gf_list_count(iod->ESDescriptors); if (!count) { gf_odf_desc_del((GF_Descriptor*) iod); return isor_emulate_iod(read); } if (count==1) { esd = (GF_ESD *)gf_list_get(iod->ESDescriptors, 0); switch (esd->decoderConfig->streamType) { case GF_STREAM_SCENE: case GF_STREAM_PRIVATE_SCENE: break; case GF_STREAM_VISUAL: if (expect_type!=GF_MEDIA_OBJECT_VIDEO) { gf_odf_desc_del((GF_Descriptor*) iod); return isor_emulate_iod(read); } break; case GF_STREAM_AUDIO: /*we need a fake scene graph*/ if (expect_type!=GF_MEDIA_OBJECT_AUDIO) { gf_odf_desc_del((GF_Descriptor*) iod); return isor_emulate_iod(read); } break; default: gf_odf_desc_del((GF_Descriptor*) iod); return NULL; } } /*check IOD is not badly formed (eg mixing audio, video or text streams)*/ nb_st = 0; for (i=0; i<count; i++) { esd = (GF_ESD *)gf_list_get(iod->ESDescriptors, i); switch (esd->decoderConfig->streamType) { case GF_STREAM_VISUAL: nb_st |= 1; break; case GF_STREAM_AUDIO: nb_st |= 2; break; case GF_STREAM_TEXT: nb_st |= 4; break; } } if ( (nb_st & 1) + (nb_st & 2) + (nb_st & 4) > 1) { gf_odf_desc_del((GF_Descriptor*) iod); return isor_emulate_iod(read); } isor_emulate_chapters(read->mov, iod); return (GF_Descriptor *) iod; }