static gboolean mpegts_base_get_tags_from_eit (MpegTSBase * base, GstMpegtsSection * section) { const GstMpegtsEIT *eit; guint i; MpegTSBaseProgram *program; /* Early exit if it's not from the present/following table_id */ if (section->table_id != GST_MTS_TABLE_ID_EVENT_INFORMATION_ACTUAL_TS_PRESENT && section->table_id != GST_MTS_TABLE_ID_EVENT_INFORMATION_OTHER_TS_PRESENT) return TRUE; eit = gst_mpegts_section_get_eit (section); if (G_UNLIKELY (eit == NULL)) return FALSE; program = mpegts_base_get_program (base, section->subtable_extension); GST_DEBUG ("program_id:0x%04x, table_id:0x%02x, actual_stream:%d, present_following:%d, program:%p", section->subtable_extension, section->table_id, eit->actual_stream, eit->present_following, program); if (program && eit->present_following) { for (i = 0; i < eit->events->len; i++) { GstMpegtsEITEvent *event = g_ptr_array_index (eit->events, i); const GstMpegtsDescriptor *desc; if (event->running_status == RUNNING_STATUS_RUNNING) { program->event_id = event->event_id; if ((desc = gst_mpegts_find_descriptor (event->descriptors, GST_MTS_DESC_DVB_SHORT_EVENT))) { gchar *name; if (gst_mpegts_descriptor_parse_dvb_short_event (desc, NULL, &name, NULL)) { /* FIXME : Is it correct to post an event duration as a GST_TAG_DURATION ??? */ program->tags = gst_tag_list_new (GST_TAG_TITLE, name, GST_TAG_DURATION, event->duration * GST_SECOND, NULL); g_free (name); return TRUE; } } } } } return TRUE; }
static void mpegts_parse_reset_selected_programs (MpegTSParse2 * parse, gchar * program_numbers) { GST_OBJECT_LOCK (parse); if (parse->program_numbers) g_free (parse->program_numbers); parse->program_numbers = program_numbers; if (*parse->program_numbers != '\0') { gint program_number; MpegTSParseProgram *program; gchar **progs, **walk; progs = g_strsplit (parse->program_numbers, ":", 0); walk = progs; while (*walk != NULL) { program_number = strtol (*walk, NULL, 0); program = (MpegTSParseProgram *) mpegts_base_get_program ((MpegTSBase *) parse, program_number); if (program == NULL) /* create the program, it will get activated once we get a PMT for it */ program = (MpegTSParseProgram *) mpegts_base_add_program ((MpegTSBase *) parse, program_number, G_MAXUINT16); program->selected = 2; ++walk; } g_strfreev (progs); } g_hash_table_foreach (((MpegTSBase *) parse)->programs, foreach_program_activate_or_deactivate, parse); if (parse->pads_to_remove || parse->pads_to_add) parse->need_sync_program_pads = TRUE; GST_OBJECT_UNLOCK (parse); }
static gboolean mpegts_base_apply_pmt (MpegTSBase * base, GstMpegtsSection * section) { const GstMpegtsPMT *pmt; MpegTSBaseProgram *program, *old_program; guint program_number; gboolean initial_program = TRUE; pmt = gst_mpegts_section_get_pmt (section); if (G_UNLIKELY (pmt == NULL)) { GST_ERROR ("Could not get PMT (corrupted ?)"); return FALSE; } /* FIXME : not so sure this is valid anymore */ if (G_UNLIKELY (base->seen_pat == FALSE)) { GST_WARNING ("Got pmt without pat first. Returning"); /* remove the stream since we won't get another PMT otherwise */ mpegts_packetizer_remove_stream (base->packetizer, section->pid); return TRUE; } program_number = section->subtable_extension; GST_DEBUG ("Applying PMT (program_number:%d, pid:0x%04x)", program_number, section->pid); /* In order for stream switching to happen properly in decodebin(2), * we need to first add the new pads (i.e. activate the new program) * before removing the old ones (i.e. deactivating the old program) */ old_program = mpegts_base_get_program (base, program_number); if (G_UNLIKELY (old_program == NULL)) goto no_program; if (G_UNLIKELY (mpegts_base_is_same_program (base, old_program, section->pid, pmt))) goto same_program; /* If the current program is active, this means we have a new program */ if (old_program->active) { MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base); old_program = mpegts_base_steal_program (base, program_number); program = mpegts_base_new_program (base, program_number, section->pid); program->patcount = old_program->patcount; g_hash_table_insert (base->programs, GINT_TO_POINTER (program_number), program); /* Desactivate the old program */ /* FIXME : THIS IS BREAKING THE STREAM SWITCHING LOGIC ! * */ if (klass->can_remove_program (base, old_program)) { mpegts_base_deactivate_program (base, old_program); mpegts_base_free_program (old_program); } initial_program = FALSE; } else program = old_program; /* activate program */ /* Ownership of pmt_info is given to the program */ mpegts_base_activate_program (base, program, section->pid, section, pmt, initial_program); return TRUE; no_program: { GST_ERROR ("Attempted to apply a PMT on a program that wasn't created"); return TRUE; } same_program: { GST_DEBUG ("Not applying identical program"); return TRUE; } }
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; }
g_return_val_if_fail (template != NULL, NULL); g_return_val_if_fail (GST_IS_MPEGTS_PARSE (element), NULL); g_return_val_if_fail (padname != NULL, NULL); sscanf (padname + 8, "%d", &program_num); GST_DEBUG_OBJECT (element, "padname:%s, program:%d", padname, program_num); parse = GST_MPEGTS_PARSE (element); tspad = mpegts_parse_create_tspad (parse, padname); tspad->program_number = program_num; /* Find if the program is already active */ parseprogram = (MpegTSParseProgram *) mpegts_base_get_program (GST_MPEGTS_BASE (parse), program_num); if (parseprogram) { tspad->program = parseprogram; parseprogram->tspad = tspad; } pad = tspad->pad; parse->srcpads = g_list_append (parse->srcpads, pad); base->push_data = TRUE; base->push_section = TRUE; gst_pad_set_active (pad, TRUE); stream_id = gst_pad_create_stream_id (pad, element, padname + 8); event =