75
75
GstFlowReturn flow_return;
78
static GQuark QUARK_PROGRAMS;
79
static GQuark QUARK_PROGRAM_NUMBER;
80
static GQuark QUARK_PID;
81
static GQuark QUARK_PCR_PID;
82
static GQuark QUARK_STREAMS;
83
static GQuark QUARK_STREAM_TYPE;
78
85
static GstElementDetails mpegts_parse_details =
79
86
GST_ELEMENT_DETAILS ("MPEG transport stream parser",
134
141
static GstStateChangeReturn mpegts_parse_change_state (GstElement * element,
135
142
GstStateChange transition);
136
143
static gboolean mpegts_parse_src_pad_query (GstPad * pad, GstQuery * query);
144
static void _extra_init (GType type);
138
GST_BOILERPLATE (MpegTSParse, mpegts_parse, GstElement, GST_TYPE_ELEMENT);
146
GST_BOILERPLATE_FULL (MpegTSParse, mpegts_parse, GstElement, GST_TYPE_ELEMENT,
140
149
static const guint32 crc_tab[256] = {
141
150
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
209
_extra_init (GType type)
211
QUARK_PROGRAMS = g_quark_from_string ("programs");
212
QUARK_PROGRAM_NUMBER = g_quark_from_string ("program-number");
213
QUARK_PID = g_quark_from_string ("pid");
214
QUARK_PCR_PID = g_quark_from_string ("pcr-pid");
215
QUARK_STREAMS = g_quark_from_string ("streams");
216
QUARK_STREAM_TYPE = g_quark_from_string ("stream-type");
200
220
mpegts_parse_base_init (gpointer klass)
202
222
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
564
585
const GValue *value;
566
587
if (program->pmt_info) {
567
streams = gst_structure_get_value (program->pmt_info, "streams");
588
streams = gst_structure_id_get_value (program->pmt_info, QUARK_STREAMS);
569
590
for (i = 0; i < gst_value_list_get_size (streams); ++i) {
570
591
value = gst_value_list_get_value (streams, i);
571
592
stream = g_value_get_boxed (value);
572
gst_structure_get_uint (stream, "pid", &pid);
573
gst_structure_get_uint (stream, "stream-type", &stream_type);
593
gst_structure_id_get (stream, QUARK_PID, G_TYPE_UINT, &pid,
594
QUARK_STREAM_TYPE, G_TYPE_UINT, &stream_type, NULL);
574
595
mpegts_parse_program_remove_stream (parse, program, (guint16) pid);
575
596
g_hash_table_remove (parse->pes_pids, GINT_TO_POINTER ((gint) pid));
745
766
mpegts_parse_push (MpegTSParse * parse, MpegTSPacketizerPacket * packet,
746
767
MpegTSPacketizerSection * section)
748
GstIterator *iterator;
749
770
gboolean done = FALSE;
751
772
MpegTSParsePad *tspad;
753
774
GstBuffer *buffer;
754
775
GstFlowReturn ret;
757
778
pid = packet->pid;
758
779
buffer = packet->buffer;
759
780
/* we have the same caps on all the src pads */
760
caps = gst_static_pad_template_get_caps (&src_template);
761
gst_buffer_set_caps (buffer, caps);
762
gst_caps_unref (caps);
781
gst_buffer_set_caps (buffer, parse->packetizer->caps);
764
783
GST_OBJECT_LOCK (parse);
765
784
/* clear tspad->pushed on pads */
769
788
ret = GST_FLOW_NOT_LINKED;
771
790
ret = GST_FLOW_OK;
792
/* Get cookie and source pads list */
793
pads_cookie = GST_ELEMENT_CAST (parse)->pads_cookie;
794
srcpads = GST_ELEMENT_CAST (parse)->srcpads;
795
if (G_LIKELY (srcpads)) {
796
pad = GST_PAD_CAST (srcpads->data);
772
799
GST_OBJECT_UNLOCK (parse);
774
iterator = gst_element_iterate_src_pads (GST_ELEMENT_CAST (parse));
776
switch (gst_iterator_next (iterator, &pad)) {
777
case GST_ITERATOR_OK:
778
tspad = gst_pad_get_element_private (GST_PAD (pad));
780
/* make sure to push only once if the iterator resyncs */
781
if (!tspad->pushed) {
782
/* ref the buffer as gst_pad_push takes a ref but we want to reuse the
783
* same buffer for next pushes */
784
gst_buffer_ref (buffer);
787
mpegts_parse_tspad_push_section (parse, tspad, section, buffer);
790
mpegts_parse_tspad_push (parse, tspad, pid, buffer);
792
tspad->pushed = TRUE;
794
if (GST_FLOW_IS_FATAL (tspad->flow_return)) {
795
/* return the error upstream */
796
ret = tspad->flow_return;
801
if (ret == GST_FLOW_NOT_LINKED)
802
ret = tspad->flow_return;
804
/* the iterator refs the pad */
805
g_object_unref (GST_PAD (pad));
807
case GST_ITERATOR_RESYNC:
808
gst_iterator_resync (iterator);
810
case GST_ITERATOR_DONE:
814
g_warning ("this should not be reached");
801
while (pad && !done) {
802
tspad = gst_pad_get_element_private (pad);
804
if (G_LIKELY (!tspad->pushed)) {
805
/* ref the buffer as gst_pad_push takes a ref but we want to reuse the
806
* same buffer for next pushes */
807
gst_buffer_ref (buffer);
810
mpegts_parse_tspad_push_section (parse, tspad, section, buffer);
813
mpegts_parse_tspad_push (parse, tspad, pid, buffer);
815
tspad->pushed = TRUE;
817
if (G_UNLIKELY (GST_FLOW_IS_FATAL (tspad->flow_return))) {
818
/* return the error upstream */
819
ret = tspad->flow_return;
825
if (ret == GST_FLOW_NOT_LINKED)
826
ret = tspad->flow_return;
828
g_object_unref (pad);
830
if (G_UNLIKELY (!done)) {
831
GST_OBJECT_LOCK (parse);
832
if (G_UNLIKELY (pads_cookie != GST_ELEMENT_CAST (parse)->pads_cookie)) {
834
GST_DEBUG ("resync");
835
pads_cookie = GST_ELEMENT_CAST (parse)->pads_cookie;
836
srcpads = GST_ELEMENT_CAST (parse)->srcpads;
838
GST_DEBUG ("getting next pad");
840
srcpads = g_list_next (srcpads);
844
pad = GST_PAD_CAST (srcpads->data);
848
GST_OBJECT_UNLOCK (parse);
818
gst_iterator_free (iterator);
820
852
gst_buffer_unref (buffer);
821
853
packet->buffer = NULL;
829
861
gboolean retval = FALSE;
832
guint8 si_tables[] = { 0x00, 0x01, 0x02, 0x03, 0x40, 0x41, 0x42, 0x46, 0x4A,
833
0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
834
0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65,
835
0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
836
0x72, 0x73, 0x7E, 0x7F, TABLE_ID_UNSET
864
static const guint8 si_tables[] =
865
{ 0x00, 0x01, 0x02, 0x03, 0x40, 0x41, 0x42, 0x46, 0x4A, 0x4E, 0x4F, 0x50,
866
0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C,
867
0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
868
0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x7E,
838
871
if (g_hash_table_lookup (parse->psi_pids,
839
872
GINT_TO_POINTER ((gint) packet->pid)) != NULL)
858
MpegTSPacketizerStream *stream = (MpegTSPacketizerStream *)
859
g_hash_table_lookup (parse->packetizer->streams,
860
GINT_TO_POINTER ((gint) packet->pid));
891
MpegTSPacketizerStream *stream = parse->packetizer->streams[packet->pid];
864
894
GST_DEBUG_OBJECT (parse, "section table id: 0x%x",
865
895
stream->section_table_id);
866
896
while (si_tables[i] != TABLE_ID_UNSET) {
867
if (si_tables[i] == stream->section_table_id) {
897
if (G_UNLIKELY (si_tables[i] == stream->section_table_id)) {
889
920
MpegTSParseProgram *program;
891
922
const GValue *programs;
894
924
old_pat = parse->pat;
895
925
parse->pat = gst_structure_copy (pat_info);
897
dbg = gst_structure_to_string (pat_info);
898
GST_INFO_OBJECT (parse, "PAT %s", dbg);
927
GST_INFO_OBJECT (parse, "PAT %" GST_PTR_FORMAT, pat_info);
901
929
gst_element_post_message (GST_ELEMENT_CAST (parse),
902
930
gst_message_new_element (GST_OBJECT (parse),
903
931
gst_structure_copy (pat_info)));
905
933
GST_OBJECT_LOCK (parse);
906
programs = gst_structure_get_value (pat_info, "programs");
934
programs = gst_structure_id_get_value (pat_info, QUARK_PROGRAMS);
907
935
/* activate the new table */
908
936
for (i = 0; i < gst_value_list_get_size (programs); ++i) {
909
937
value = gst_value_list_get_value (programs, i);
911
939
program_info = g_value_get_boxed (value);
912
gst_structure_get_uint (program_info, "program-number", &program_number);
913
gst_structure_get_uint (program_info, "pid", &pid);
940
gst_structure_id_get (program_info, QUARK_PROGRAM_NUMBER, G_TYPE_UINT,
941
&program_number, QUARK_PID, G_TYPE_UINT, &pid, NULL);
915
943
program = mpegts_parse_get_program (parse, program_number);
940
968
/* deactivate the old table */
942
programs = gst_structure_get_value (old_pat, "programs");
970
programs = gst_structure_id_get_value (old_pat, QUARK_PROGRAMS);
943
971
for (i = 0; i < gst_value_list_get_size (programs); ++i) {
944
972
value = gst_value_list_get_value (programs, i);
946
974
program_info = g_value_get_boxed (value);
947
gst_structure_get_uint (program_info, "program-number", &program_number);
948
gst_structure_get_uint (program_info, "pid", &pid);
975
gst_structure_id_get (program_info,
976
QUARK_PROGRAM_NUMBER, G_TYPE_UINT, &program_number,
977
QUARK_PID, G_TYPE_UINT, &pid, NULL);
950
979
program = mpegts_parse_get_program (parse, program_number);
951
980
if (program == NULL) {
958
987
/* the program has been referenced by the new pat, keep it */
962
gchar *dbg = gst_structure_to_string (program_info);
964
GST_INFO_OBJECT (parse, "PAT removing program %s", dbg);
990
GST_INFO_OBJECT (parse, "PAT removing program %" GST_PTR_FORMAT,
968
993
if (program->active)
969
994
parse->pads_to_remove = g_list_append (parse->pads_to_remove,
997
1022
const GValue *new_streams;
998
1023
const GValue *value;
1000
gst_structure_get_uint (pmt_info, "program-number", &program_number);
1001
gst_structure_get_uint (pmt_info, "pcr-pid", &pcr_pid);
1002
new_streams = gst_structure_get_value (pmt_info, "streams");
1025
gst_structure_id_get (pmt_info,
1026
QUARK_PROGRAM_NUMBER, G_TYPE_UINT, &program_number,
1027
QUARK_PCR_PID, G_TYPE_UINT, &pcr_pid, NULL);
1028
new_streams = gst_structure_id_get_value (pmt_info, QUARK_STREAMS);
1004
1030
GST_OBJECT_LOCK (parse);
1005
1031
program = mpegts_parse_get_program (parse, program_number);
1028
1054
value = gst_value_list_get_value (new_streams, i);
1029
1055
stream = g_value_get_boxed (value);
1031
gst_structure_get_uint (stream, "pid", &pid);
1032
gst_structure_get_uint (stream, "stream-type", &stream_type);
1057
gst_structure_id_get (stream, QUARK_PID, G_TYPE_UINT, &pid,
1058
QUARK_STREAM_TYPE, G_TYPE_UINT, &stream_type, NULL);
1033
1059
mpegts_parse_program_add_stream (parse, program,
1034
1060
(guint16) pid, (guint8) stream_type);
1035
1061
g_hash_table_insert (parse->pes_pids, GINT_TO_POINTER ((gint) pid),
1039
1065
GST_OBJECT_UNLOCK (parse);
1042
gchar *dbg = gst_structure_to_string (pmt_info);
1044
GST_DEBUG_OBJECT (parse, "new pmt %s", dbg);
1067
GST_DEBUG_OBJECT (parse, "new pmt %" GST_PTR_FORMAT, pmt_info);
1048
1069
gst_element_post_message (GST_ELEMENT_CAST (parse),
1049
1070
gst_message_new_element (GST_OBJECT (parse),
1083
1104
gboolean res = TRUE;
1084
1105
GstStructure *structure = NULL;
1086
if (mpegts_parse_calc_crc32 (GST_BUFFER_DATA (section->buffer),
1087
GST_BUFFER_SIZE (section->buffer)) != 0) {
1107
if (G_UNLIKELY (mpegts_parse_calc_crc32 (GST_BUFFER_DATA (section->buffer),
1108
GST_BUFFER_SIZE (section->buffer)) != 0)) {
1088
1109
GST_WARNING_OBJECT (parse, "bad crc in psi pid 0x%x", section->pid);
1211
1233
packetizer = parse->packetizer;
1213
1235
mpegts_packetizer_push (parse->packetizer, buf);
1214
while (mpegts_packetizer_has_packets (parse->packetizer) &&
1215
!GST_FLOW_IS_FATAL (res)) {
1216
/* get the next packet */
1217
parsed = mpegts_packetizer_next_packet (packetizer, &packet);
1237
mpegts_packetizer_next_packet (parse->packetizer,
1238
&packet)) != PACKET_NEED_MORE) && !GST_FLOW_IS_FATAL (res)) {
1239
if (G_UNLIKELY (pret == PACKET_BAD))
1219
1240
/* bad header, skip the packet */
1224
1245
MpegTSPacketizerSection section;
1226
1247
parsed = mpegts_packetizer_push_section (packetizer, &packet, §ion);
1248
if (G_UNLIKELY (!parsed))
1228
1249
/* bad section data */
1231
if (section.complete) {
1252
if (G_LIKELY (section.complete)) {
1232
1253
/* section complete */
1233
1254
parsed = mpegts_parse_handle_psi (parse, §ion);
1234
1255
gst_buffer_unref (section.buffer);
1257
if (G_UNLIKELY (!parsed))
1237
1258
/* bad PSI table */