Пример #1
0
static void MP2TS_SetupProgram(M2TSIn *m2ts, GF_M2TS_Program *prog, Bool regenerate_scene, Bool no_declare)
{
	u32 i, count;

	count = gf_list_count(prog->streams);
#ifdef GPAC_HAS_LINUX_DVB
	if (m2ts->ts->tuner) {
		Bool found = 0;
		for (i=0; i<count; i++) {
			GF_M2TS_PES *pes = gf_list_get(prog->streams, i);
			if (pes->pid==m2ts->ts->tuner->vpid) found = 1;
			else if (pes->pid==m2ts->ts->tuner->apid) found = 1;
		}
		if (!found) return;
	}
#endif

	/*TS is a file, start regulation regardless of how the TS is access (with or without fragment URI)*/
	if (m2ts->ts->file || m2ts->ts->dnload || m2ts->owner->query_proxy)
		m2ts->ts->file_regulate = 1;

	for (i=0; i<count; i++) {
		GF_M2TS_ES *es = gf_list_get(prog->streams, i);
		if (es->pid==prog->pmt_pid) continue;
		if ((es->flags & GF_M2TS_ES_IS_PES) && ((GF_M2TS_PES *)es)->depends_on_pid )
			continue;

		/*move to skip mode for all ES until asked for playback*/
		if (!es->user)
			gf_m2ts_set_pes_framing((GF_M2TS_PES *)es, GF_M2TS_PES_FRAMING_SKIP);

		if (!prog->pmt_iod && !no_declare) {
			MP2TS_DeclareStream(m2ts, (GF_M2TS_PES *)es, NULL, 0);
		}
		/*if IOD, streams not declared through OD framework are refered to by pid:// scheme, and will be declared upon
		request by the terminal through GetServiceDesc*/
	}

	/*force scene regeneration*/
	if (!prog->pmt_iod && regenerate_scene)
		gf_term_add_media(m2ts->service, NULL, 0);
}
Пример #2
0
static void M2TS_OnEvent(GF_M2TS_Demuxer *ts, u32 evt_type, void *param)
{
    GF_Event evt;
    M2TSIn *m2ts = (M2TSIn *) ts->user;

    switch (evt_type) {
    case GF_M2TS_EVT_PAT_UPDATE:
        /*	example code showing how to forward an event from MPEG-2 TS input service to GPAC user*/
#if 0
    {
        GF_Event evt;
        evt.type = GF_EVENT_FORWARDED;
        evt.forwarded_event.forward_type = GF_EVT_FORWARDED_MPEG2;
        evt.forwarded_event.forward_type = GF_EVT_FORWARDED_MPEG2;
        evt.forwarded_event.service_event_type = evt_type;
        evt.forwarded_event.param = param;
        gf_term_on_service_event(m2ts->service, &evt);
    }
#endif
    break;
    case GF_M2TS_EVT_AIT_FOUND:
        evt.type = GF_EVENT_FORWARDED;
        evt.forwarded_event.forward_type = GF_EVT_FORWARDED_MPEG2;
        evt.forwarded_event.service_event_type = evt_type;
        evt.forwarded_event.param = param;
        gf_term_on_service_event(m2ts->service, &evt);
        break;
    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);
            m2ts->is_connected = 1;
        }
        /* Send the TS to the a user if needed. Useful to check the number of received programs*/
        evt.type = GF_EVENT_FORWARDED;
        evt.forwarded_event.forward_type = GF_M2TS_EVT_PAT_FOUND;
        evt.forwarded_event.service_event_type = evt_type;
        evt.forwarded_event.param = ts;
        gf_term_on_service_event(m2ts->service, &evt);
        break;
    case GF_M2TS_EVT_PMT_FOUND:
        if (gf_list_count(m2ts->ts->programs) == 1) {
            gf_term_on_connect(m2ts->service, NULL, GF_OK);
            m2ts->is_connected = 1;
        }

        /*do not declare if  single program was requested for playback*/
        MP2TS_SetupProgram(m2ts, param, m2ts->request_all_pids, m2ts->request_all_pids ? 0 : 1);
        M2TS_FlushRequested(m2ts);
        break;
    case GF_M2TS_EVT_PMT_REPEAT:
//	case GF_M2TS_EVT_PMT_UPDATE:
        M2TS_FlushRequested(m2ts);
        break;
    case GF_M2TS_EVT_SDT_REPEAT:
    case GF_M2TS_EVT_SDT_UPDATE:
    case GF_M2TS_EVT_SDT_FOUND:
        M2TS_FlushRequested(m2ts);
        break;
    case GF_M2TS_EVT_DVB_GENERAL:
        if (m2ts->eit_channel) {
            GF_M2TS_SL_PCK *pck = (GF_M2TS_SL_PCK *)param;
            gf_term_on_sl_packet(m2ts->service, m2ts->eit_channel, pck->data, pck->data_len, NULL, GF_OK);
        }
        break;
    case GF_M2TS_EVT_PES_PCK:
        MP2TS_SendPacket(m2ts, param);
        break;
    case GF_M2TS_EVT_SL_PCK:
        MP2TS_SendSLPacket(m2ts, param);
        break;
    case GF_M2TS_EVT_AAC_CFG:
    {
        GF_M2TS_PES_PCK *pck = (GF_M2TS_PES_PCK*)param;
        if (!pck->stream->first_dts) {
            gf_m2ts_set_pes_framing(pck->stream, GF_M2TS_PES_FRAMING_SKIP_NO_RESET);
            MP2TS_DeclareStream(m2ts, pck->stream, pck->data, pck->data_len);
            if (ts->file || ts->dnload) ts->file_regulate = 1;
            pck->stream->first_dts=1;
            /*force scene regeneration*/
            gf_term_add_media(m2ts->service, NULL, 0);
        }
    }
    break;
    case GF_M2TS_EVT_PES_PCR:
        /*send pcr*/
        if (((GF_M2TS_PES_PCK *) param)->stream && ((GF_M2TS_PES_PCK *) param)->stream->user) {
            GF_SLHeader slh;
            memset(&slh, 0, sizeof(GF_SLHeader) );
            slh.OCRflag = 1;
            slh.m2ts_pcr = ( ((GF_M2TS_PES_PCK *) param)->flags & GF_M2TS_PES_PCK_DISCONTINUITY) ? 2 : 1;
            slh.objectClockReference = ((GF_M2TS_PES_PCK *) param)->PTS;
            gf_term_on_sl_packet(m2ts->service, ((GF_M2TS_PES_PCK *) param)->stream->user, NULL, 0, &slh, GF_OK);
        }
        ((GF_M2TS_PES_PCK *) param)->stream->program->first_dts = 1;

        if ( ((GF_M2TS_PES_PCK *) param)->flags & GF_M2TS_PES_PCK_DISCONTINUITY) {
#if 0
            if (ts->pcr_last) {
                ts->pcr_last = ((GF_M2TS_PES_PCK *) param)->PTS;
                ts->stb_at_last_pcr = gf_sys_clock();
            }
#endif
            GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TS In] PCR discontinuity - switching from old STB "LLD" to new one "LLD"\n", ts->pcr_last, ((GF_M2TS_PES_PCK *) param)->PTS));
            /*FIXME - we need to find a way to treat PCR discontinuities correctly while ignoring broken PCR discontinuities
            seen in many HLS solutions*/
            return;
        }

        if (ts->file_regulate) {
            u64 pcr = ((GF_M2TS_PES_PCK *) param)->PTS;
            u32 stb = gf_sys_clock();

            if (m2ts->regulation_pcr_pid==0) {
                /*we pick the first PCR PID for file regulation - we don't need to make sure this is the PCR of a program being plyaed as we
                only check buffer levels, not DTS/PTS of the streams in the regulation step*/
                m2ts->regulation_pcr_pid = ((GF_M2TS_PES_PCK *) param)->stream->pid;
            } else if (m2ts->regulation_pcr_pid != ((GF_M2TS_PES_PCK *) param)->stream->pid) {
                return;
            }


            if (ts->pcr_last) {
                s32 diff;
                if (pcr < ts->pcr_last) {
                    GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[M2TS In] PCR "LLU" less than previous PCR "LLU"\n", ((GF_M2TS_PES_PCK *) param)->PTS, ts->pcr_last));
                    ts->pcr_last = pcr;
                    ts->stb_at_last_pcr = gf_sys_clock();
                    diff = 0;
                } else {
                    u64 pcr_diff = (pcr - ts->pcr_last);
                    pcr_diff /= 27000;
                    if (pcr_diff>1000) {
                        GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[M2TS In] PCR diff too big: "LLU" ms - PCR "LLU" - previous PCR "LLU" - error in TS ?\n", pcr_diff, ((GF_M2TS_PES_PCK *) param)->PTS, ts->pcr_last));
                        diff = 100;
                    } else {
                        diff = (u32) pcr_diff - (stb - ts->stb_at_last_pcr);
                    }
                }
                if (diff<0) {
                    GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[M2TS In] Demux not going fast enough according to PCR (drift %d, pcr: "LLU", last pcr: "LLU")\n", diff, pcr, ts->pcr_last));
                } else if (diff>0) {
                    u32 sleep_for=1;
#ifndef GPAC_DISABLE_LOG
                    u32 nb_sleep=0;
#endif
                    /*query buffer level, don't sleep if too low*/
                    GF_NetworkCommand com;
                    com.command_type = GF_NET_BUFFER_QUERY;
                    while (ts->run_state) {
                        gf_term_on_command(m2ts->service, &com, GF_OK);
                        if (com.buffer.occupancy < M2TS_BUFFER_MAX) {
                            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[M2TS In] Demux not going to sleep: buffer occupancy %d ms\n", com.buffer.occupancy));
                            break;
                        }
                        /*We don't sleep for the entire buffer occupancy, because we would take
                        the risk of starving the audio chains. We try to keep buffers half full*/
#ifndef GPAC_DISABLE_LOG
                        if (!nb_sleep) {
                            GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[M2TS In] Demux going to sleep (buffer occupancy %d ms)\n", com.buffer.occupancy));
                        }
                        nb_sleep++;
#endif
                        gf_sleep(sleep_for);
                    }
#ifndef GPAC_DISABLE_LOG
                    if (nb_sleep) {
                        GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[M2TS In] Demux resume after %d ms - current buffer occupancy %d ms\n", sleep_for*nb_sleep, com.buffer.occupancy));
                    }
#endif
                    ts->nb_pck = 0;
                    ts->pcr_last = pcr;
                    ts->stb_at_last_pcr = gf_sys_clock();
                } else {
                    GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[M2TS In] Demux drift according to PCR (drift %d, pcr: "LLD", last pcr: "LLD")\n", diff, pcr, ts->pcr_last));
                }
            } else {
                ts->pcr_last = pcr;
                ts->stb_at_last_pcr = gf_sys_clock();
            }
        }
        break;
    case GF_M2TS_EVT_TDT:
        if (m2ts->hybrid_on) {
            u32 i, count;
            GF_M2TS_TDT_TOT *tdt = (GF_M2TS_TDT_TOT *)param;
            GF_NetworkCommand com;
            memset(&com, 0, sizeof(com));
            com.command_type = GF_NET_CHAN_MAP_TIME;
            com.map_time.media_time = tdt->hour*3600+tdt->minute*60+tdt->second;
            com.map_time.reset_buffers = 0;
            count = gf_list_count(ts->programs);
            for (i=0; i<count; i++) {
                GF_M2TS_Program *prog = gf_list_get(ts->programs, i);
                u32 j, count2;
                if (prog->tdt_found || !prog->last_pcr_value) /*map TDT one time, after we received a PCR*/
                    continue;
                prog->tdt_found = 1;
                count2 = gf_list_count(prog->streams);
                com.map_time.timestamp = prog->last_pcr_value/300;
                for (j=0; j<count2; j++) {
                    GF_M2TS_ES * stream = gf_list_get(prog->streams, j);
                    if (stream->user) {
                        com.base.on_channel = stream->user;
                        gf_term_on_command(m2ts->service, &com, GF_OK);
                    }
                }
                GF_LOG(GF_LOG_INFO, GF_LOG_CONTAINER, ("[M2TS In] Mapping TDT Time %04d/%02d/%02d %02d:%02d:%02d and PCR time "LLD" on program %d\n",
                                                       tdt->year, tdt->month, tdt->day, tdt->hour, tdt->minute, tdt->second, com.map_time.timestamp, prog->number));
            }
        }
        break;
    case GF_M2TS_EVT_TOT:
        break;
    }
}
Пример #3
0
static void M2TS_FlushRequested(M2TSIn *m2ts)
{
    u32 i, j, req_prog_count, count, prog_id, found;

    gf_mx_p(m2ts->mx);

    found = 0;
    count = gf_list_count(m2ts->ts->requested_pids);
    for (i=0; i<count; i++) {
        M2TSIn_Prog *req_pid = gf_list_get(m2ts->ts->requested_pids, i);
        GF_M2TS_ES *es = m2ts->ts->ess[req_pid->pid];
        if (es==NULL) continue;

        /*move to skip mode for all PES until asked for playback*/
        if (!(es->flags & GF_M2TS_ES_IS_SECTION) && !es->user)
            gf_m2ts_set_pes_framing((GF_M2TS_PES *)es, GF_M2TS_PES_FRAMING_SKIP);
        MP2TS_DeclareStream(m2ts, (GF_M2TS_PES *)es, NULL, 0);
        gf_list_rem(m2ts->ts->requested_pids, i);
        gf_free(req_pid);
        i--;
        count--;
        found++;
    }
    req_prog_count = gf_list_count(m2ts->ts->requested_progs);
    for (i = 0; i < req_prog_count; i++) {
        M2TSIn_Prog *req_prog = gf_list_get(m2ts->ts->requested_progs, i);
        prog_id = atoi(req_prog->fragment);
        count = gf_list_count(m2ts->ts->SDTs);
        for (j=0; j<count; j++) {
            GF_M2TS_SDT *sdt = gf_list_get(m2ts->ts->SDTs, j);
            if (!stricmp(sdt->service, req_prog->fragment)) req_prog->id = sdt->service_id;
            else if (sdt->service_id==prog_id)  req_prog->id = sdt->service_id;
        }
        if (req_prog->id) {
            GF_M2TS_Program *ts_prog;
            count = gf_list_count(m2ts->ts->programs);
            for (j=0; j<count; j++) {
                ts_prog = gf_list_get(m2ts->ts->programs, j);
                if (ts_prog->number==req_prog->id) {
                    MP2TS_SetupProgram(m2ts, ts_prog, 0, 0);
                    found++;
                    gf_free(req_prog->fragment);
                    gf_free(req_prog);
                    gf_list_rem(m2ts->ts->requested_progs, i);
                    req_prog_count--;
                    i--;
                    break;
                }
            }
        }
    }

    if (m2ts->epg_requested) {
        if (!m2ts->has_eit) {
            GF_ObjectDescriptor *od = M2TS_GenerateEPG_OD(m2ts);
            /*declare but don't regenerate scene*/
            gf_term_add_media(m2ts->service, (GF_Descriptor*)od, 0);
            m2ts->has_eit = 1;
        }
    } else {
        /*force scene regeneration only when EPG is not requested*/
        if (found)
            gf_term_add_media(m2ts->service, NULL, 0);
    }

    gf_mx_v(m2ts->mx);
}