MpegTSBaseProgram * mpegts_base_add_program (MpegTSBase * base, gint program_number, guint16 pmt_pid) { MpegTSBaseProgram *program; GST_DEBUG_OBJECT (base, "program_number : %d, pmt_pid : %d", program_number, pmt_pid); program = mpegts_base_new_program (base, program_number, pmt_pid); /* Mark the PMT PID as being a known PSI PID */ if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->known_psi, pmt_pid))) { GST_FIXME ("Refcounting. Setting twice a PID (0x%04x) as known PSI", pmt_pid); } MPEGTS_BIT_SET (base->known_psi, pmt_pid); g_hash_table_insert (base->programs, GINT_TO_POINTER (program_number), program); return program; }
static gboolean mpegts_base_apply_pat (MpegTSBase * base, GstMpegtsSection * section) { GPtrArray *pat = gst_mpegts_section_get_pat (section); GPtrArray *old_pat; MpegTSBaseProgram *program; gint i; if (G_UNLIKELY (pat == NULL)) return FALSE; GST_INFO_OBJECT (base, "PAT"); /* Applying a new PAT does two things: * * It adds the new programs to the list of programs this element handles * and increments at the same time the number of times a program is referenced. * * * If there was a previously active PAT, It decrements the reference count * of all program it used. If a program is no longer needed, it is removed. */ old_pat = base->pat; base->pat = pat; GST_LOG ("Activating new Program Association Table"); /* activate the new table */ for (i = 0; i < pat->len; ++i) { GstMpegtsPatProgram *patp = g_ptr_array_index (pat, i); program = mpegts_base_get_program (base, patp->program_number); if (program) { /* IF the program already existed, just check if the PMT PID changed */ if (program->pmt_pid != patp->network_or_program_map_PID) { if (program->pmt_pid != G_MAXUINT16) { /* pmt pid changed */ /* FIXME: when this happens it may still be pmt pid of another * program, so setting to False may make it go through expensive * path in is_psi unnecessarily */ MPEGTS_BIT_UNSET (base->known_psi, program->pmt_pid); } program->pmt_pid = patp->network_or_program_map_PID; if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->known_psi, program->pmt_pid))) GST_FIXME ("Refcounting issue. Setting twice a PMT PID (0x%04x) as know PSI", program->pmt_pid); MPEGTS_BIT_SET (base->known_psi, patp->network_or_program_map_PID); } } else { /* Create a new program */ program = mpegts_base_add_program (base, patp->program_number, patp->network_or_program_map_PID); } /* We mark this program as being referenced by one PAT */ program->patcount += 1; } if (old_pat) { MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base); /* deactivate the old table */ GST_LOG ("Deactivating old Program Association Table"); for (i = 0; i < old_pat->len; ++i) { GstMpegtsPatProgram *patp = g_ptr_array_index (old_pat, i); program = mpegts_base_get_program (base, patp->program_number); if (G_UNLIKELY (program == NULL)) { GST_DEBUG_OBJECT (base, "broken PAT, duplicated entry for program %d", patp->program_number); continue; } if (--program->patcount > 0) /* the program has been referenced by the new pat, keep it */ continue; GST_INFO_OBJECT (base, "PAT removing program 0x%04x 0x%04x", patp->program_number, patp->network_or_program_map_PID); if (klass->can_remove_program (base, program)) { mpegts_base_deactivate_program (base, program); mpegts_base_remove_program (base, patp->program_number); } /* FIXME: when this happens it may still be pmt pid of another * program, so setting to False may make it go through expensive * path in is_psi unnecessarily */ if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->known_psi, patp->network_or_program_map_PID))) { GST_FIXME ("Program refcounting : Setting twice a pid (0x%04x) as known PSI", patp->network_or_program_map_PID); } MPEGTS_BIT_SET (base->known_psi, patp->network_or_program_map_PID); mpegts_packetizer_remove_stream (base->packetizer, patp->network_or_program_map_PID); } g_ptr_array_unref (old_pat); } return TRUE; }
static void mpegts_base_activate_program (MpegTSBase * base, MpegTSBaseProgram * program, guint16 pmt_pid, GstMpegtsSection * section, const GstMpegtsPMT * pmt, gboolean initial_program) { guint i; MpegTSBaseClass *klass; if (G_UNLIKELY (program->active)) return; GST_DEBUG ("Activating program %d", program->program_number); /* activate new pmt */ if (program->section) gst_mpegts_section_unref (program->section); program->section = gst_mpegts_section_ref (section); program->pmt = pmt; program->pmt_pid = pmt_pid; program->pcr_pid = pmt->pcr_pid; /* extract top-level registration_id if present */ program->registration_id = get_registration_from_descriptors (pmt->descriptors); GST_DEBUG ("program 0x%04x, registration_id %" SAFE_FOURCC_FORMAT, program->program_number, SAFE_FOURCC_ARGS (program->registration_id)); for (i = 0; i < pmt->streams->len; ++i) { GstMpegtsPMTStream *stream = g_ptr_array_index (pmt->streams, i); switch (stream->stream_type) { case GST_MPEGTS_STREAM_TYPE_SCTE_DSMCC_DCB: case GST_MPEGTS_STREAM_TYPE_SCTE_SIGNALING: { guint32 registration_id = get_registration_from_descriptors (stream->descriptors); /* Not a private section stream */ if (registration_id != DRF_ID_CUEI && registration_id != DRF_ID_ETV1) break; /* Fall through on purpose - remove this PID from known_psi */ } case GST_MPEGTS_STREAM_TYPE_PRIVATE_SECTIONS: case GST_MPEGTS_STREAM_TYPE_MHEG: case GST_MPEGTS_STREAM_TYPE_DSM_CC: case GST_MPEGTS_STREAM_TYPE_DSMCC_A: case GST_MPEGTS_STREAM_TYPE_DSMCC_B: case GST_MPEGTS_STREAM_TYPE_DSMCC_C: case GST_MPEGTS_STREAM_TYPE_DSMCC_D: case GST_MPEGTS_STREAM_TYPE_SL_FLEXMUX_SECTIONS: case GST_MPEGTS_STREAM_TYPE_METADATA_SECTIONS: /* Set known PSI streams */ if (base->parse_private_sections) MPEGTS_BIT_SET (base->known_psi, stream->pid); break; default: if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->is_pes, stream->pid))) GST_FIXME ("Refcounting issue. Setting twice a PID (0x%04x) as known PES", stream->pid); if (G_UNLIKELY (MPEGTS_BIT_IS_SET (base->known_psi, stream->pid))) { GST_FIXME ("Refcounting issue. Setting a known PSI PID (0x%04x) as known PES", stream->pid); MPEGTS_BIT_UNSET (base->known_psi, stream->pid); } MPEGTS_BIT_SET (base->is_pes, stream->pid); break; } mpegts_base_program_add_stream (base, program, stream->pid, stream->stream_type, stream); } /* We add the PCR pid last. If that PID is already used by one of the media * streams above, no new stream will be created */ mpegts_base_program_add_stream (base, program, pmt->pcr_pid, -1, NULL); MPEGTS_BIT_SET (base->is_pes, pmt->pcr_pid); program->active = TRUE; program->initial_program = initial_program; klass = GST_MPEGTS_BASE_GET_CLASS (base); if (klass->program_started != NULL) klass->program_started (base, program); GST_DEBUG_OBJECT (base, "new pmt activated"); }
static GstFlowReturn mpegts_base_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstFlowReturn res = GST_FLOW_OK; MpegTSBase *base; MpegTSPacketizerPacketReturn pret; MpegTSPacketizer2 *packetizer; MpegTSPacketizerPacket packet; MpegTSBaseClass *klass; base = GST_MPEGTS_BASE (parent); klass = GST_MPEGTS_BASE_GET_CLASS (base); packetizer = base->packetizer; if (klass->input_done) gst_buffer_ref (buf); if (GST_BUFFER_IS_DISCONT (buf)) { GST_DEBUG_OBJECT (base, "Got DISCONT buffer, flushing"); res = mpegts_base_drain (base); if (G_UNLIKELY (res != GST_FLOW_OK)) return res; mpegts_base_flush (base, FALSE); /* In the case of discontinuities in push-mode with TIME segment * we want to drop all previous observations (hard:TRUE) from * the packetizer */ if (base->mode == BASE_MODE_PUSHING && base->segment.format == GST_FORMAT_TIME) mpegts_packetizer_flush (base->packetizer, TRUE); else mpegts_packetizer_flush (base->packetizer, FALSE); } mpegts_packetizer_push (base->packetizer, buf); while (res == GST_FLOW_OK) { pret = mpegts_packetizer_next_packet (base->packetizer, &packet); /* If we don't have enough data, return */ if (G_UNLIKELY (pret == PACKET_NEED_MORE)) break; if (G_UNLIKELY (pret == PACKET_BAD)) { /* bad header, skip the packet */ GST_DEBUG_OBJECT (base, "bad packet, skipping"); goto next; } if (klass->inspect_packet) klass->inspect_packet (base, &packet); /* If it's a known PES, push it */ if (MPEGTS_BIT_IS_SET (base->is_pes, packet.pid)) { /* push the packet downstream */ if (base->push_data) res = klass->push (base, &packet, NULL); } else if (packet.payload && MPEGTS_BIT_IS_SET (base->known_psi, packet.pid)) { /* base PSI data */ GList *others, *tmp; GstMpegtsSection *section; section = mpegts_packetizer_push_section (packetizer, &packet, &others); if (section) mpegts_base_handle_psi (base, section); if (G_UNLIKELY (others)) { for (tmp = others; tmp; tmp = tmp->next) mpegts_base_handle_psi (base, (GstMpegtsSection *) tmp->data); g_list_free (others); } /* we need to push section packet downstream */ if (base->push_section) res = klass->push (base, &packet, section); } else if (packet.payload && packet.pid != 0x1fff) GST_LOG ("PID 0x%04x Saw packet on a pid we don't handle", packet.pid); next: mpegts_packetizer_clear_packet (base->packetizer, &packet); } if (klass->input_done) { if (res == GST_FLOW_OK) res = klass->input_done (base, buf); else gst_buffer_unref (buf); } return res; }
static GstFlowReturn mpegts_base_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstFlowReturn res = GST_FLOW_OK; MpegTSBase *base; MpegTSPacketizerPacketReturn pret; MpegTSPacketizer2 *packetizer; MpegTSPacketizerPacket packet; MpegTSBaseClass *klass; base = GST_MPEGTS_BASE (parent); klass = GST_MPEGTS_BASE_GET_CLASS (base); packetizer = base->packetizer; if (G_UNLIKELY (base->queried_latency == FALSE)) { query_upstream_latency (base); } if (klass->input_done) gst_buffer_ref (buf); mpegts_packetizer_push (base->packetizer, buf); while (res == GST_FLOW_OK) { pret = mpegts_packetizer_next_packet (base->packetizer, &packet); /* If we don't have enough data, return */ if (G_UNLIKELY (pret == PACKET_NEED_MORE)) break; if (G_UNLIKELY (pret == PACKET_BAD)) { /* bad header, skip the packet */ GST_DEBUG_OBJECT (base, "bad packet, skipping"); goto next; } /* If it's a known PES, push it */ if (MPEGTS_BIT_IS_SET (base->is_pes, packet.pid)) { /* push the packet downstream */ if (base->push_data) res = klass->push (base, &packet, NULL); } else if (packet.payload && MPEGTS_BIT_IS_SET (base->known_psi, packet.pid)) { /* base PSI data */ GList *others, *tmp; GstMpegTsSection *section; section = mpegts_packetizer_push_section (packetizer, &packet, &others); if (section) mpegts_base_handle_psi (base, section); if (G_UNLIKELY (others)) { for (tmp = others; tmp; tmp = tmp->next) mpegts_base_handle_psi (base, (GstMpegTsSection *) tmp->data); g_list_free (others); } /* we need to push section packet downstream */ if (base->push_section) res = klass->push (base, &packet, section); } else if (packet.payload && packet.pid != 0x1fff) GST_LOG ("PID 0x%04x Saw packet on a pid we don't handle", packet.pid); next: mpegts_packetizer_clear_packet (base->packetizer, &packet); } if (klass->input_done) { if (res == GST_FLOW_OK) res = klass->input_done (base, buf); else gst_buffer_unref (buf); } return res; }