📄 mpegts_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 / M2TS 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/mpegts.h>#include <gpac/thread.h>#include <gpac/network.h>#include <gpac/constants.h>#ifdef GPAC_HAS_LINUX_DVB#include <fcntl.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <linux/dvb/dmx.h>#include <linux/dvb/frontend.h>// DVB devices definition// TODO: using adapter0/..0 by default; multi-frontend to be done#define DMX "/dev/dvb/adapter0/demux0"#define FRONT "/dev/dvb/adapter0/frontend0"#define DVR "/dev/dvb/adapter0/dvr0"typedef struct { u32 freq; u16 vpid; u16 apid; fe_spectral_inversion_t specInv; fe_modulation_t modulation; fe_bandwidth_t bandwidth; fe_transmit_mode_t TransmissionMode; fe_guard_interval_t guardInterval; fe_code_rate_t HP_CodeRate; fe_code_rate_t LP_CodeRate; fe_hierarchy_t hierarchy; int ts_fd;} GF_Tuner;#define DVB_BUFFER_SIZE 3760 // DVB buffer size 188x20#endif#define UDP_BUFFER_SIZE 0x40000typedef struct{ GF_ClientService *service; Bool do_regulate; GF_M2TS_Demuxer *ts; char *program; u32 prog_id; /*demuxer thread*/ GF_Thread *th; u32 run_state; /*net playing*/ GF_Socket *sock; #ifdef GPAC_HAS_LINUX_DVB /*dvb playing*/ GF_Tuner *tuner;#endif /*local file playing*/ FILE *file; u32 start_range, end_range; u32 file_size; Double duration; u32 nb_playing;} M2TSIn;#ifdef GPAC_HAS_LINUX_DVBstatic GF_Err gf_dvb_tune(GF_Tuner *tuner, char *url, const char *chan_path) { struct dmx_pes_filter_params pesFilterParams; struct dvb_frontend_parameters frp; int demux1, front1; FILE *chanfile; char line[255], chan_name_t[255]; char freq_str[255], inv[255], bw[255], lcr[255], hier[255], cr[255], mod[255], transm[255], gi[255], apid_str[255], vpid_str[255]; const char *chan_conf = ":%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:%255[^:]:"; char *chan_name; if((chanfile=fopen(chan_path, "r"))==NULL) { return GF_BAD_PARAM; } chan_name=url+6; while(!feof(chanfile)) { if ( fgets(line, 255, chanfile) != NULL) { if (line[0]=='#') continue; if (line[0]=='\r') continue; if (line[0]=='\n') continue; strncpy(chan_name_t, line, index(line, ':')-line); if (strncmp(chan_name,chan_name_t,strlen(chan_name))==0) { sscanf(strstr(line,":"), chan_conf, freq_str, inv, bw, lcr, cr, mod, transm, gi, hier, apid_str, vpid_str); tuner->freq = (uint32_t) atoi(freq_str); tuner->apid = (uint16_t) atoi(apid_str); tuner->vpid = (uint16_t) atoi(vpid_str); //Inversion if(! strcmp(inv, "INVERSION_ON")) tuner->specInv = INVERSION_ON; else if(! strcmp(inv, "INVERSION_OFF")) tuner->specInv = INVERSION_OFF; else tuner->specInv = INVERSION_AUTO; //LP Code Rate if(! strcmp(lcr, "FEC_1_2")) tuner->LP_CodeRate =FEC_1_2; else if(! strcmp(lcr, "FEC_2_3")) tuner->LP_CodeRate =FEC_2_3; else if(! strcmp(lcr, "FEC_3_4")) tuner->LP_CodeRate =FEC_3_4; else if(! strcmp(lcr, "FEC_4_5")) tuner->LP_CodeRate =FEC_4_5; else if(! strcmp(lcr, "FEC_6_7")) tuner->LP_CodeRate =FEC_6_7; else if(! strcmp(lcr, "FEC_8_9")) tuner->LP_CodeRate =FEC_8_9; else if(! strcmp(lcr, "FEC_5_6")) tuner->LP_CodeRate =FEC_5_6; else if(! strcmp(lcr, "FEC_7_8")) tuner->LP_CodeRate =FEC_7_8; else if(! strcmp(lcr, "FEC_NONE")) tuner->LP_CodeRate =FEC_NONE; else tuner->LP_CodeRate =FEC_AUTO; //HP Code Rate if(! strcmp(cr, "FEC_1_2")) tuner->HP_CodeRate =FEC_1_2; else if(! strcmp(cr, "FEC_2_3")) tuner->HP_CodeRate =FEC_2_3; else if(! strcmp(cr, "FEC_3_4")) tuner->HP_CodeRate =FEC_3_4; else if(! strcmp(cr, "FEC_4_5")) tuner->HP_CodeRate =FEC_4_5; else if(! strcmp(cr, "FEC_6_7")) tuner->HP_CodeRate =FEC_6_7; else if(! strcmp(cr, "FEC_8_9")) tuner->HP_CodeRate =FEC_8_9; else if(! strcmp(cr, "FEC_5_6")) tuner->HP_CodeRate =FEC_5_6; else if(! strcmp(cr, "FEC_7_8")) tuner->HP_CodeRate =FEC_7_8; else if(! strcmp(cr, "FEC_NONE")) tuner->HP_CodeRate =FEC_NONE; else tuner->HP_CodeRate =FEC_AUTO; //Modulation if(! strcmp(mod, "QAM_128")) tuner->modulation = QAM_128; else if(! strcmp(mod, "QAM_256")) tuner->modulation = QAM_256; else if(! strcmp(mod, "QAM_64")) tuner->modulation = QAM_64; else if(! strcmp(mod, "QAM_32")) tuner->modulation = QAM_32; else if(! strcmp(mod, "QAM_16")) tuner->modulation = QAM_16; //Bandwidth if(! strcmp(bw, "BANDWIDTH_6_MHZ")) tuner->bandwidth = BANDWIDTH_6_MHZ; else if(! strcmp(bw, "BANDWIDTH_7_MHZ")) tuner->bandwidth = BANDWIDTH_7_MHZ; else if(! strcmp(bw, "BANDWIDTH_8_MHZ")) tuner->bandwidth = BANDWIDTH_8_MHZ; //Transmission Mode if(! strcmp(transm, "TRANSMISSION_MODE_2K")) tuner->TransmissionMode = TRANSMISSION_MODE_2K; else if(! strcmp(transm, "TRANSMISSION_MODE_8K")) tuner->TransmissionMode = TRANSMISSION_MODE_8K; //Guard Interval if(! strcmp(gi, "GUARD_INTERVAL_1_32")) tuner->guardInterval = GUARD_INTERVAL_1_32; else if(! strcmp(gi, "GUARD_INTERVAL_1_16")) tuner->guardInterval = GUARD_INTERVAL_1_16; else if(! strcmp(gi, "GUARD_INTERVAL_1_8")) tuner->guardInterval = GUARD_INTERVAL_1_8; else tuner->guardInterval = GUARD_INTERVAL_1_4; //Hierarchy if(! strcmp(hier, "HIERARCHY_1")) tuner->hierarchy = HIERARCHY_1; else if(! strcmp(hier, "HIERARCHY_2")) tuner->hierarchy = HIERARCHY_2; else if(! strcmp(hier, "HIERARCHY_4")) tuner->hierarchy = HIERARCHY_4; else if(! strcmp(hier, "HIERARCHY_AUTO")) tuner->hierarchy = HIERARCHY_AUTO; else tuner->hierarchy = HIERARCHY_NONE; break; } } } fclose(chanfile); // Open frontend if((front1 = open(FRONT,O_RDWR)) < 0){ return GF_IO_ERR; } // Open demuxes if ((demux1=open(DMX, O_RDWR|O_NONBLOCK)) < 0){ return GF_IO_ERR; } // Set FrontendParameters - DVB-T frp.frequency = tuner->freq; frp.inversion = tuner->specInv; frp.u.ofdm.bandwidth = tuner->bandwidth; frp.u.ofdm.code_rate_HP = tuner->HP_CodeRate; frp.u.ofdm.code_rate_LP = tuner->LP_CodeRate; frp.u.ofdm.constellation = tuner->modulation; frp.u.ofdm.transmission_mode = tuner->TransmissionMode; frp.u.ofdm.guard_interval = tuner->guardInterval; frp.u.ofdm.hierarchy_information = tuner->hierarchy; // Set frontend if (ioctl(front1, FE_SET_FRONTEND, &frp) < 0){ return GF_IO_ERR; } // Set dumex pesFilterParams.pid = 0x2000; // Linux-DVB API take PID=2000 for FULL/RAW TS flag pesFilterParams.input = DMX_IN_FRONTEND; pesFilterParams.output = DMX_OUT_TS_TAP; pesFilterParams.pes_type = DMX_PES_OTHER; pesFilterParams.flags = DMX_IMMEDIATE_START; if (ioctl(demux1, DMX_SET_PES_FILTER, &pesFilterParams) < 0){ return GF_IO_ERR; } if ((tuner->ts_fd = open(DVR, O_RDONLY/*|O_NONBLOCK*/)) < 0){ return GF_IO_ERR; } return GF_OK;}#endifstatic Bool M2TS_CanHandleURL(GF_InputService *plug, const char *url){ char *sExt; if (!strnicmp(url, "udp://", 6) || !strnicmp(url, "mpegts-udp://", 13) || !strnicmp(url, "mpegts-tcp://", 13) #ifdef GPAC_HAS_LINUX_DVB || !strnicmp(url, "dvb://", 6) #endif ) { return 1; } sExt = strrchr(url, '.'); if (!sExt) return 0; if (gf_term_check_extension(plug, "video/mpeg-2", "ts m2t", "MPEG-2 TS", sExt)) return 1; return 0;}#define REGULATE_TIME_SLOT 200/*!! FIXME - THIS IS PLAIN WRONG AND UGLY - WE NEED TO ESTIMATE THE TS BITRATE AND REGULATE BASED ON THAT !!!*/static void M2TS_Regulate(M2TSIn *m2ts){ u32 to_sleep; GF_NetworkCommand com; com.command_type = GF_NET_BUFFER_QUERY; /*sleep untill the buffer occupancy is too low - note that this work because all streams in this demuxer are synchronized*/ while (m2ts->run_state) { /*wait for a connected channel !!*/ if (!m2ts->nb_playing && m2ts->do_regulate) { gf_sleep(50); } else { gf_term_on_command(m2ts->service, &com, GF_OK); if (com.buffer.occupancy < REGULATE_TIME_SLOT) { //gf_sleep(1); return; } to_sleep = com.buffer.occupancy - REGULATE_TIME_SLOT; //fprintf(stdout, "MPEG-2 TS regulate: %d ms in buffers - sleeping %d ms\n", com.buffer.occupancy, to_sleep); while (m2ts->run_state && (to_sleep>REGULATE_TIME_SLOT)) { gf_sleep(REGULATE_TIME_SLOT); to_sleep -= REGULATE_TIME_SLOT; } } }}static void MP2TS_DeclareStream(M2TSIn *m2ts, GF_M2TS_PES *stream){ GF_ObjectDescriptor *od; GF_ESD *esd; /*create a stream description for this channel*/ esd = gf_odf_desc_esd_new(0); esd->ESID = stream->pid; /*ASSIGN PCR here*/ esd->OCRESID = stream->program->pcr_pid; switch (stream->stream_type) { case GF_M2TS_VIDEO_MPEG1: esd->decoderConfig->streamType = GF_STREAM_VISUAL; esd->decoderConfig->objectTypeIndication = 0x6A; break; case GF_M2TS_VIDEO_MPEG2: esd->decoderConfig->streamType = GF_STREAM_VISUAL; esd->decoderConfig->objectTypeIndication = 0x65; break; case GF_M2TS_VIDEO_MPEG4: esd->decoderConfig->streamType = GF_STREAM_VISUAL; esd->decoderConfig->objectTypeIndication = 0x20; break; case GF_M2TS_VIDEO_H264: esd->decoderConfig->streamType = GF_STREAM_VISUAL; esd->decoderConfig->objectTypeIndication = 0x21; break; case GF_M2TS_AUDIO_MPEG1: esd->decoderConfig->streamType = GF_STREAM_AUDIO; esd->decoderConfig->objectTypeIndication = 0x6B; break; case GF_M2TS_AUDIO_MPEG2: esd->decoderConfig->streamType = GF_STREAM_AUDIO; esd->decoderConfig->objectTypeIndication = 0x69; break; case GF_M2TS_AUDIO_AAC: esd->decoderConfig->streamType = GF_STREAM_AUDIO; esd->decoderConfig->objectTypeIndication = 0x40; break; default: gf_odf_desc_del((GF_Descriptor *)esd); return; } esd->decoderConfig->bufferSizeDB = 0; /*we only use AUstart indicator*/ esd->slConfig->useAccessUnitStartFlag = 1; esd->slConfig->useAccessUnitEndFlag = 0; esd->slConfig->useRandomAccessPointFlag = 1; esd->slConfig->AUSeqNumLength = 0; esd->slConfig->timestampResolution = 90000; /*decoder config*/ if (0) { esd->decoderConfig->decoderSpecificInfo->dataLength = 0; } /*declare object to terminal*/ od = (GF_ObjectDescriptor*)gf_odf_desc_new(GF_ODF_OD_TAG); gf_list_add(od->ESDescriptors, esd); od->objectDescriptorID = stream->pid; /*declare but don't regenerate scene*/ gf_term_add_media(m2ts->service, (GF_Descriptor*)od, 1); m2ts->do_regulate = 1; /*wait for connection*/ while (!stream->user) gf_sleep(0);}static void MP2TS_SetupProgram(M2TSIn *m2ts, GF_M2TS_Program *prog){ u32 i, count; count = gf_list_count(prog->streams);#ifdef GPAC_HAS_LINUX_DVB if (m2ts->tuner) { Bool found = 0; for (i=0; i<count; i++) { GF_M2TS_PES *pes = gf_list_get(prog->streams, i); if (pes->pid==m2ts->tuner->vpid) found = 1; else if (pes->pid==m2ts->tuner->apid) found = 1; } if (!found) return; }#endif for (i=0; i<count; i++) { GF_M2TS_PES *pes = gf_list_get(prog->streams, i); if (pes->pid==prog->pmt_pid) continue; gf_m2ts_set_pes_framing(pes, GF_M2TS_PES_FRAMING_SKIP); MP2TS_DeclareStream(m2ts, pes); } /*force scene regeneration*/ gf_term_add_media(m2ts->service, NULL, 0);}static void MP2TS_SendPacket(M2TSIn *m2ts, GF_M2TS_PES_PCK *pck){ GF_SLHeader slh; if (!pck->stream->user) return; if (!pck->stream->program->first_dts && pck->PTS) { pck->stream->program->first_dts = (pck->DTS ? pck->DTS : pck->PTS) - m2ts->start_range * 90; } memset(&slh, 0, sizeof(GF_SLHeader)); slh.accessUnitStartFlag = (pck->flags & GF_M2TS_PES_PCK_AU_START) ? 1 : 0; if (slh.accessUnitStartFlag) { if (pck->PTS < pck->stream->program->first_dts) return; slh.compositionTimeStampFlag = 1; slh.compositionTimeStamp = pck->PTS - pck->stream->program->first_dts; if (pck->DTS) { slh.decodingTimeStampFlag = 1; slh.decodingTimeStamp = pck->DTS - pck->stream->program->first_dts; } slh.randomAccessPointFlag = (pck->flags & GF_M2TS_PES_PCK_RAP) ? 1 : 0; } gf_term_on_sl_packet(m2ts->service, pck->stream->user, pck->data, pck->data_len, &slh, GF_OK);}static GFINLINE void MP2TS_SendSLPacket(M2TSIn *m2ts, GF_M2TS_SL_PCK *pck){ gf_term_on_sl_packet(m2ts->service, pck->stream->user, pck->data, pck->data_len, NULL, GF_OK);}static void M2TS_OnEvent(GF_M2TS_Demuxer *ts, u32 evt_type, void *param){ M2TSIn *m2ts = (M2TSIn *) ts->user; switch (evt_type) { case GF_M2TS_EVT_PAT_FOUND: /* In case the TS has one program, wait for the PMT to send connect, in case of IOD in PMT */ if (gf_list_count(m2ts->ts->programs) != 1) gf_term_on_connect(m2ts->service, NULL, GF_OK); break; case GF_M2TS_EVT_PMT_FOUND: if (gf_list_count(m2ts->ts->programs) == 1) gf_term_on_connect(m2ts->service, NULL, GF_OK); /*do not setup if we've been asked for a dedicated program*/ if (!m2ts->program) MP2TS_SetupProgram(m2ts, param); break; case GF_M2TS_EVT_PAT_UPDATE: case GF_M2TS_EVT_PMT_UPDATE: case GF_M2TS_EVT_SDT_UPDATE: break; case GF_M2TS_EVT_SDT_FOUND: if (m2ts->program) { u32 i, count, prog_id; prog_id = atoi(m2ts->program); count = gf_list_count(ts->SDTs); for (i=0; i<count; i++) { GF_M2TS_SDT *sdt = gf_list_get(ts->SDTs, i); if (!stricmp(sdt->service, m2ts->program)) m2ts->prog_id = sdt->service_id; else if (sdt->service_id==prog_id) m2ts->prog_id = sdt->service_id; } if (m2ts->prog_id) { GF_M2TS_Program *prog; free(m2ts->program); m2ts->program = NULL; count = gf_list_count(ts->programs); for (i=0; i<count; i++) { prog = gf_list_get(ts->programs, i); if (prog->number==m2ts->prog_id) { MP2TS_SetupProgram(m2ts, prog); break; } } } } break; case GF_M2TS_EVT_PES_PCK: MP2TS_SendPacket(m2ts, param); break; case GF_M2TS_EVT_SL_PCK: MP2TS_SendSLPacket(m2ts, param); break; }}u32 M2TS_Run(void *_p){ GF_Err e; char data[UDP_BUFFER_SIZE];#ifdef GPAC_HAS_LINUX_DVB char dvbts[DVB_BUFFER_SIZE];#endif u32 size, i; M2TSIn *m2ts = _p; m2ts->run_state = 1; m2ts->ts->on_event = M2TS_OnEvent; gf_m2ts_reset_parsers(m2ts->ts);#ifdef GPAC_HAS_LINUX_DVB if (m2ts->tuner) { // in case of DVB while (m2ts->run_state) { s32 ts_size = read(m2ts->tuner->ts_fd, dvbts, DVB_BUFFER_SIZE); if (ts_size>0) gf_m2ts_process_data(m2ts->ts, dvbts, (u32) ts_size); } } else#endif if (m2ts->sock) { Bool first_run, is_rtp; first_run = 1; is_rtp = 0; while (m2ts->run_state) { size = 0; /*m2ts chunks by chunks*/ e = gf_sk_receive(m2ts->sock, data, UDP_BUFFER_SIZE, 0, &size); if (!size || e) { gf_sleep(1); continue; } if (first_run) { first_run = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -