📄 saf_in.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Authors: Jean le Feuvre * Copyright (c) 2005-200X ENST * All rights reserved * * This file is part of GPAC / SAF reader module * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <gpac/modules/service.h>#include <gpac/modules/codec.h>#include <gpac/constants.h>#include <gpac/thread.h>typedef struct{ LPNETCHANNEL ch; u32 au_sn, stream_id, ts_res, buffer_min; GF_ESD *esd;} SAFChannel;enum{ SAF_FILE_LOCAL, SAF_FILE_REMOTE, SAF_LIVE_STREAM};typedef struct{ GF_ClientService *service; GF_List *channels; Bool needs_connection; u32 saf_type; /*file downloader*/ GF_DownloadSession * dnload; /*SAF buffer for both lcoal, remote and live streams*/ char *saf_data; u32 saf_size, alloc_size; /*local file playing*/ GF_Thread *th; FILE *stream; u32 run_state; u32 start_range, end_range; Double duration; u32 nb_playing;} SAFIn;static GFINLINE SAFChannel *saf_get_channel(SAFIn *saf, u32 stream_id, LPNETCHANNEL a_ch){ SAFChannel *ch; u32 i=0; while ((ch = (SAFChannel *)gf_list_enum(saf->channels, &i))) { if (ch->stream_id==stream_id) return ch; if (a_ch && (ch->ch==a_ch)) return ch; } return NULL;}static Bool SAF_CanHandleURL(GF_InputService *plug, const char *url){ char *sExt; sExt = strrchr(url, '.'); if (!sExt) return 0; if (gf_term_check_extension(plug, "application/x-saf", "saf lsr", "SAF Rich Media", sExt)) return 1; return 0;}static void SAF_Regulate(SAFIn *read){ GF_NetworkCommand com; SAFChannel *ch; com.command_type = GF_NET_CHAN_BUFFER_QUERY; /*sleep untill the buffer occupancy is too low - note that this work because all streams in this demuxer are synchronized*/ while (read->run_state) { u32 min_occ = (u32) -1; u32 i=0; while ( (ch = (SAFChannel *)gf_list_enum(read->channels, &i))) { com.base.on_channel = ch->ch; gf_term_on_command(read->service, &com, GF_OK); if (com.buffer.occupancy < ch->buffer_min) return; if (com.buffer.occupancy) min_occ = MIN(min_occ, com.buffer.occupancy - ch->buffer_min); } if (min_occ == (u32) -1) break; //fprintf(stdout, "Regulating SAF demux - sleeping for %d ms\n", min_occ); gf_sleep(min_occ); }}static void SAF_NetIO(void *cbk, GF_NETIO_Parameter *param){ GF_Err e; Bool is_rap, go; SAFChannel *ch; u32 cts, au_sn, au_size, bs_pos, type, i, stream_id; GF_BitStream *bs; GF_SLHeader sl_hdr; SAFIn *read = (SAFIn *) cbk; e = param->error; /*done*/ if (param->msg_type==GF_NETIO_DATA_TRANSFERED) { if (read->stream && (read->saf_type==SAF_FILE_REMOTE)) read->saf_type = SAF_FILE_LOCAL; return; } else { /*handle service message*/ gf_term_download_update_stats(read->dnload); if (param->msg_type!=GF_NETIO_DATA_EXCHANGE) { if (e<0) { if (read->needs_connection) { read->needs_connection = 0; gf_term_on_connect(read->service, NULL, e); } return; } if (read->needs_connection) { u32 total_size; gf_dm_sess_get_stats(read->dnload, NULL, NULL, &total_size, NULL, NULL, NULL); if (!total_size) read->saf_type = SAF_LIVE_STREAM; } return; } } if (!param->size) return; if (!read->run_state) return; if (read->alloc_size < read->saf_size + param->size) { read->saf_data = (char*)realloc(read->saf_data, sizeof(char)*(read->saf_size + param->size) ); read->alloc_size = read->saf_size + param->size; } memcpy(read->saf_data + read->saf_size, param->data, sizeof(char)*param->size); read->saf_size += param->size; /*first AU not complete yet*/ if (read->saf_size<10) return; bs = gf_bs_new(read->saf_data, read->saf_size, GF_BITSTREAM_READ); bs_pos = 0; go = 1; while (go) { u32 avail = (u32) gf_bs_available(bs); bs_pos = (u32) gf_bs_get_position(bs); if (avail<10) break; is_rap = gf_bs_read_int(bs, 1); au_sn = gf_bs_read_int(bs, 15); gf_bs_read_int(bs, 2); cts = gf_bs_read_int(bs, 30); au_size = gf_bs_read_int(bs, 16); avail-=8; if (au_size > avail) break; assert(au_size>=2); is_rap = 1; type = gf_bs_read_int(bs, 4); stream_id = gf_bs_read_int(bs, 12); au_size -= 2; ch = saf_get_channel(read, stream_id, NULL); switch (type) { case 1: case 2: case 7: if (ch) { gf_bs_skip_bytes(bs, au_size); } else { SAFChannel *first = (SAFChannel *)gf_list_get(read->channels, 0); GF_SAFEALLOC(ch, SAFChannel); ch->stream_id = stream_id; ch->esd = gf_odf_desc_esd_new(0); ch->esd->ESID = stream_id; ch->esd->OCRESID = first ? first->stream_id : stream_id; ch->esd->slConfig->useRandomAccessPointFlag = 1; ch->esd->slConfig->AUSeqNumLength = 0; ch->esd->decoderConfig->objectTypeIndication = gf_bs_read_u8(bs); ch->esd->decoderConfig->streamType = gf_bs_read_u8(bs); ch->ts_res = ch->esd->slConfig->timestampResolution = gf_bs_read_u24(bs); ch->esd->decoderConfig->bufferSizeDB = gf_bs_read_u16(bs); au_size -= 7; if ((ch->esd->decoderConfig->objectTypeIndication == 0xFF) && (ch->esd->decoderConfig->streamType == 0xFF) ) { u16 mimeLen = gf_bs_read_u16(bs); gf_bs_skip_bytes(bs, mimeLen); au_size -= mimeLen+2; } if (type==7) { u16 urlLen = gf_bs_read_u16(bs); ch->esd->URLString = (char*)malloc(sizeof(char)*(urlLen+1)); gf_bs_read_data(bs, ch->esd->URLString, urlLen); ch->esd->URLString[urlLen] = 0; au_size -= urlLen+2; } if (au_size) { ch->esd->decoderConfig->decoderSpecificInfo->dataLength = au_size; ch->esd->decoderConfig->decoderSpecificInfo->data = (char*)malloc(sizeof(char)*au_size); gf_bs_read_data(bs, ch->esd->decoderConfig->decoderSpecificInfo->data, au_size); } if (ch->esd->decoderConfig->streamType==4) ch->buffer_min=100; else if (ch->esd->decoderConfig->streamType==5) ch->buffer_min=400; else ch->buffer_min=0; if (read->needs_connection && (ch->esd->decoderConfig->streamType==GF_STREAM_SCENE)) { gf_list_add(read->channels, ch); read->needs_connection = 0; gf_term_on_connect(read->service, NULL, GF_OK); } else if (read->needs_connection) { gf_odf_desc_del((GF_Descriptor *) ch->esd); free(ch); ch = NULL; } else { GF_ObjectDescriptor *od; gf_list_add(read->channels, ch); od = (GF_ObjectDescriptor*)gf_odf_desc_new(GF_ODF_OD_TAG); gf_list_add(od->ESDescriptors, ch->esd); ch->esd = NULL; od->objectDescriptorID = ch->stream_id; gf_term_add_media(read->service, (GF_Descriptor*)od, 0); } } break; case 4: if (ch) { bs_pos = (u32) gf_bs_get_position(bs); memset(&sl_hdr, 0, sizeof(GF_SLHeader)); sl_hdr.accessUnitLength = au_size; sl_hdr.AU_sequenceNumber = au_sn; sl_hdr.compositionTimeStampFlag = 1; sl_hdr.compositionTimeStamp = cts; sl_hdr.randomAccessPointFlag = is_rap; if (read->start_range && (read->start_range*ch->ts_res>cts*1000)) { sl_hdr.compositionTimeStamp = read->start_range*ch->ts_res/1000; } gf_term_on_sl_packet(read->service, ch->ch, read->saf_data+bs_pos, au_size, &sl_hdr, GF_OK); } gf_bs_skip_bytes(bs, au_size); break; case 3: if (ch) gf_term_on_sl_packet(read->service, ch->ch, NULL, 0, NULL, GF_EOS); break; case 5: go = 0; read->run_state = 0; i=0; while ((ch = (SAFChannel *)gf_list_enum(read->channels, &i))) { gf_term_on_sl_packet(read->service, ch->ch, NULL, 0, NULL, GF_EOS); } break; } } gf_bs_del(bs); if (bs_pos) { u32 remain = read->saf_size - bs_pos; if (remain) memmove(read->saf_data, read->saf_data+bs_pos, sizeof(char)*remain); read->saf_size = remain; } SAF_Regulate(read);}u32 SAF_Run(void *_p){ GF_NETIO_Parameter par; char data[1024]; SAFIn *read = (SAFIn *)_p; par.msg_type = GF_NETIO_DATA_EXCHANGE; par.data = data;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -