GstBuffer * mpegtsmux_prepare_aac (GstBuffer * buf, MpegTsPadData * data, MpegTsMux * mux) { guint8 adts_header[7] = { 0, }; GstBuffer *out_buf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buf) + 7); gsize out_offset = 0; guint8 rate_idx = 0, channels = 0, obj_type = 0; GST_DEBUG_OBJECT (mux, "Preparing AAC buffer for output"); /* We want the same metadata */ gst_buffer_copy_metadata (out_buf, buf, GST_BUFFER_COPY_ALL); /* Generate ADTS header */ obj_type = (GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data)) & 0xC) >> 2; obj_type++; rate_idx = (GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data)) & 0x3) << 1; rate_idx |= (GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + 1) & 0x80) >> 7; channels = (GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + 1) & 0x78) >> 3; GST_DEBUG_OBJECT (mux, "Rate index %u, channels %u, object type %u", rate_idx, channels, obj_type); /* Sync point over a full byte */ adts_header[0] = 0xFF; /* Sync point continued over first 4 bits + static 4 bits * (ID, layer, protection)*/ adts_header[1] = 0xF1; /* Object type over first 2 bits */ adts_header[2] = obj_type << 6; /* rate index over next 4 bits */ adts_header[2] |= (rate_idx << 2); /* channels over last 2 bits */ adts_header[2] |= (channels & 0x4) >> 2; /* channels continued over next 2 bits + 4 bits at zero */ adts_header[3] = (channels & 0x3) << 6; /* frame size over last 2 bits */ adts_header[3] |= (GST_BUFFER_SIZE (out_buf) & 0x1800) >> 11; /* frame size continued over full byte */ adts_header[4] = (GST_BUFFER_SIZE (out_buf) & 0x1FF8) >> 3; /* frame size continued first 3 bits */ adts_header[5] = (GST_BUFFER_SIZE (out_buf) & 0x7) << 5; /* buffer fullness (0x7FF for VBR) over 5 last bits */ adts_header[5] |= 0x1F; /* buffer fullness (0x7FF for VBR) continued over 6 first bits + 2 zeros for * number of raw data blocks */ adts_header[6] = 0xFC; /* Insert ADTS header */ memcpy (GST_BUFFER_DATA (out_buf) + out_offset, adts_header, 7); out_offset += 7; /* Now copy complete frame */ memcpy (GST_BUFFER_DATA (out_buf) + out_offset, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); return out_buf; }
static GstFlowReturn gst_ebml_read_element_id (GstEbmlRead * ebml, guint32 * id, guint * level_up) { guint8 *buf; gint len_mask = 0x80, read = 1, n = 1; guint32 total; guint8 b; GstFlowReturn ret; ret = gst_ebml_read_peek_bytes (ebml, 1, NULL, &buf); if (ret != GST_FLOW_OK) return ret; b = GST_READ_UINT8 (buf); total = (guint32) b; while (read <= 4 && !(total & len_mask)) { read++; len_mask >>= 1; } if (read > 4) { guint64 pos = ebml->offset; GST_ELEMENT_ERROR (ebml, STREAM, DEMUX, (NULL), ("Invalid EBML ID size tag (0x%x) at position %" G_GUINT64_FORMAT " (0x%" G_GINT64_MODIFIER "x)", (guint) b, pos, pos)); return GST_FLOW_ERROR; } ret = gst_ebml_read_peek_bytes (ebml, read, NULL, &buf); if (ret != GST_FLOW_OK) return ret; while (n < read) { b = GST_READ_UINT8 (buf + n); total = (total << 8) | b; ++n; } *id = total; /* level */ if (level_up) *level_up = gst_ebml_read_element_level_up (ebml); ebml->offset += read; return GST_FLOW_OK; }
static void check_rgb_buf (const guint8 * pixels, guint32 r_mask, guint32 g_mask, guint32 b_mask, guint32 a_mask, guint8 r_expected, guint8 g_expected, guint8 b_expected, guint bpp, guint depth) { guint32 pixel, red, green, blue, alpha; switch (bpp) { case 32: pixel = GST_READ_UINT32_BE (pixels); break; case 24: pixel = (GST_READ_UINT8 (pixels) << 16) | (GST_READ_UINT8 (pixels + 1) << 8) | (GST_READ_UINT8 (pixels + 2) << 0); break; case 16: if (G_BYTE_ORDER == G_LITTLE_ENDIAN) pixel = GST_READ_UINT16_LE (pixels); else pixel = GST_READ_UINT16_BE (pixels); break; default: g_return_if_reached (); } red = right_shift_colour (r_mask, pixel); green = right_shift_colour (g_mask, pixel); blue = right_shift_colour (b_mask, pixel); alpha = right_shift_colour (a_mask, pixel); /* can't enable this by default, valgrind will complain about accessing * uninitialised memory for the depth=24,bpp=32 formats ... */ /* GST_LOG ("pixels: 0x%02x 0x%02x 0x%02x 0x%02x => pixel = 0x%08x", pixels[0], (guint) pixels[1], pixels[2], pixels[3], pixel); */ /* fix up the mask (for rgb15/16) */ if (bpp == 16) { r_expected = fix_expected_colour (r_mask, r_expected); g_expected = fix_expected_colour (g_mask, g_expected); b_expected = fix_expected_colour (b_mask, b_expected); } fail_unless (red == r_expected, "RED: expected 0x%02x, found 0x%02x", r_expected, red); fail_unless (green == g_expected, "GREEN: expected 0x%02x, found 0x%02x", g_expected, green); fail_unless (blue == b_expected, "BLUE: expected 0x%02x, found 0x%02x", b_expected, blue); fail_unless (a_mask == 0 || alpha != 0); /* better than nothing */ }
/* inspired by the original one in wavpack */ gboolean gst_wavpack_read_metadata (GstWavpackMetadata * wpmd, guint8 * header_data, guint8 ** p_data) { WavpackHeader hdr; guint8 *end; gst_wavpack_read_header (&hdr, header_data); end = header_data + hdr.ckSize + 8; if (end - *p_data < 2) return FALSE; wpmd->id = GST_READ_UINT8 (*p_data); wpmd->byte_length = 2 * (guint) GST_READ_UINT8 (*p_data + 1); *p_data += 2; if ((wpmd->id & ID_LARGE) == ID_LARGE) { guint extra; wpmd->id &= ~ID_LARGE; if (end - *p_data < 2) return FALSE; extra = GST_READ_UINT16_LE (*p_data); wpmd->byte_length += (extra << 9); *p_data += 2; } if ((wpmd->id & ID_ODD_SIZE) == ID_ODD_SIZE) { wpmd->id &= ~ID_ODD_SIZE; --wpmd->byte_length; } if (wpmd->byte_length > 0) { if (end - *p_data < wpmd->byte_length + (wpmd->byte_length & 1)) { wpmd->data = NULL; return FALSE; } wpmd->data = *p_data; *p_data += wpmd->byte_length + (wpmd->byte_length & 1); } else { wpmd->data = NULL; } return TRUE; }
/* parses the first CMML packet (the ident header) */ static void gst_cmml_dec_parse_ident_header (GstCmmlDec * dec, GstBuffer * buffer) { guint8 *data = GST_BUFFER_DATA (buffer); /* the ident header has a fixed length */ if (GST_BUFFER_SIZE (buffer) != CMML_IDENT_HEADER_SIZE) { GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("wrong ident header size: %d", GST_BUFFER_SIZE (buffer))); dec->flow_return = GST_FLOW_ERROR; return; } data += 8; dec->major = GST_READ_UINT16_LE (data); data += 2; dec->minor = GST_READ_UINT16_LE (data); data += 2; dec->granulerate_n = GST_READ_UINT64_LE (data); data += 8; dec->granulerate_d = GST_READ_UINT64_LE (data); data += 8; dec->granuleshift = GST_READ_UINT8 (data); GST_INFO_OBJECT (dec, "bitstream initialized " "(major: %" G_GINT16_FORMAT " minor: %" G_GINT16_FORMAT " granulerate_n: %" G_GINT64_FORMAT " granulerate_d: %" G_GINT64_FORMAT " granuleshift: %d)", dec->major, dec->minor, dec->granulerate_n, dec->granulerate_d, dec->granuleshift); dec->flow_return = GST_FLOW_OK; }
gboolean mxf_product_version_parse (MXFProductVersion * product_version, const guint8 * data, guint size) { g_return_val_if_fail (product_version != NULL, FALSE); g_return_val_if_fail (data != NULL, FALSE); memset (product_version, 0, sizeof (MXFProductVersion)); if (size < 9) return FALSE; product_version->major = GST_READ_UINT16_BE (data); product_version->minor = GST_READ_UINT16_BE (data + 2); product_version->patch = GST_READ_UINT16_BE (data + 4); product_version->build = GST_READ_UINT16_BE (data + 6); /* Avid writes a 9 byte product version */ if (size == 9) product_version->release = GST_READ_UINT8 (data + 8); else product_version->release = GST_READ_UINT16_BE (data + 8); return TRUE; }
static GstFlowReturn gst_mve_video_palette_compressed (GstMveDemux * mve, const guint8 * data, guint16 len) { guint8 mask; gint i, j; guint32 *col; GST_DEBUG_OBJECT (mve, "compressed video palette"); if (mve->video_stream == NULL) { GST_ELEMENT_ERROR (mve, STREAM, DECODE, (NULL), ("found palette before video stream was initialized")); return GST_FLOW_ERROR; } if (mve->video_stream->palette == NULL) { GST_ELEMENT_ERROR (mve, STREAM, DECODE, (NULL), ("no palette available for modification")); return GST_FLOW_ERROR; } /* need at least 32 more bytes */ if (len < 32) return gst_mve_stream_error (mve, 32, len); len -= 32; for (i = 0; i < 32; ++i) { mask = GST_READ_UINT8 (data); ++data; if (mask != 0) { for (j = 0; j < 8; ++j) { if (mask & (1 << j)) { guint8 r, g, b; /* need 3 more bytes */ if (len < 3) return gst_mve_stream_error (mve, 3, len); len -= 3; r = (*data) << 2; ++data; g = (*data) << 2; ++data; b = (*data) << 2; ++data; col = ((guint32 *) GST_BUFFER_DATA (mve->video_stream->palette)) + i * 8 + j; *col = (r << 16) | (g << 8) | (b); } } } } return GST_FLOW_OK; }
static gpointer _parse_atsc_stt (GstMpegtsSection * section) { GstMpegtsAtscSTT *stt = NULL; guint8 *data, *end; guint16 daylight_saving; stt = g_slice_new0 (GstMpegtsAtscSTT); data = section->data; end = data + section->section_length; /* Skip already parsed data */ data += 8; stt->protocol_version = GST_READ_UINT8 (data); data += 1; stt->system_time = GST_READ_UINT32_BE (data); data += 4; stt->gps_utc_offset = GST_READ_UINT8 (data); data += 1; daylight_saving = GST_READ_UINT16_BE (data); data += 2; stt->ds_status = daylight_saving >> 15; stt->ds_dayofmonth = (daylight_saving >> 8) & 0x1F; stt->ds_hour = daylight_saving & 0xFF; stt->descriptors = gst_mpegts_parse_descriptors (data, end - data - 4); if (stt->descriptors == NULL) goto error; return (gpointer) stt; error: _gst_mpegts_atsc_stt_free (stt); return NULL; }
static gboolean handle_buffer (GstRtpOnvifParse * self, GstBuffer * buf) { GstRTPBuffer rtp = GST_RTP_BUFFER_INIT; guint8 *data; guint16 bits; guint wordlen; guint8 flags; /* guint64 timestamp; guint8 cseq; */ if (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp)) { GST_ELEMENT_ERROR (self, STREAM, FAILED, ("Failed to map RTP buffer"), (NULL)); return FALSE; } /* Check if the ONVIF RTP extension is present in the packet */ if (!gst_rtp_buffer_get_extension_data (&rtp, &bits, (gpointer) & data, &wordlen)) goto out; if (bits != EXTENSION_ID || wordlen != EXTENSION_SIZE) goto out; /* timestamp = GST_READ_UINT64_BE (data); TODO */ flags = GST_READ_UINT8 (data + 8); /* cseq = GST_READ_UINT8 (data + 9); TODO */ /* C */ if (flags & (1 << 7)) GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT); else GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); /* E */ /* if (flags & (1 << 6)); TODO */ /* D */ if (flags & (1 << 5)) GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); else GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT); out: gst_rtp_buffer_unmap (&rtp); return TRUE; }
EXPORT_C #endif gboolean gst_byte_reader_peek_int8 (GstByteReader * reader, gint8 * val) { g_return_val_if_fail (reader != NULL, FALSE); g_return_val_if_fail (val != NULL, FALSE); if (reader->byte >= reader->size) return FALSE; *val = GST_READ_UINT8 (&reader->data[reader->byte]); return TRUE; }
gboolean gst_asf_demux_parse_packet (GstASFDemux * demux, GstBuffer * buf) { AsfPacket packet = { 0, }; const guint8 *data; gboolean has_multiple_payloads; gboolean ret = TRUE; guint8 ec_flags, flags1; guint size; data = GST_BUFFER_DATA (buf); size = GST_BUFFER_SIZE (buf); GST_LOG_OBJECT (demux, "Buffer size: %u", size); /* need at least two payload flag bytes, send time, and duration */ if (G_UNLIKELY (size < 2 + 4 + 2)) goto short_packet; packet.buf = buf; ec_flags = GST_READ_UINT8 (data); /* skip optional error correction stuff */ if ((ec_flags & 0x80) != 0) { guint ec_len_type, ec_len; ec_len_type = (ec_flags & 0x60) >> 5; if (ec_len_type == 0) { ec_len = ec_flags & 0x0f; } else { GST_WARNING_OBJECT (demux, "unexpected error correction length type %u", ec_len_type); ec_len = 2; } GST_LOG_OBJECT (demux, "packet has error correction (%u bytes)", ec_len); /* still need at least two payload flag bytes, send time, and duration */ if (size <= (1 + ec_len) + 2 + 4 + 2) goto short_packet; data += 1 + ec_len; size -= 1 + ec_len; }
gchar * gst_rm_utils_read_string8 (const guint8 * data, guint datalen, guint * p_total_len) { gint length; if (p_total_len) *p_total_len = 0; if (datalen < 1) return NULL; length = GST_READ_UINT8 (data); if (datalen < (1 + length)) return NULL; if (p_total_len) *p_total_len = 1 + length; return g_strndup ((gchar *) data + 1, length); }
static gpointer _parse_ett (GstMpegtsSection * section) { GstMpegtsAtscETT *ett = NULL; guint8 *data, *end; ett = g_slice_new0 (GstMpegtsAtscETT); data = section->data; end = data + section->section_length; ett->ett_table_id_extension = section->subtable_extension; /* Skip already parsed data */ data += 8; ett->protocol_version = GST_READ_UINT8 (data); data += 1; ett->etm_id = GST_READ_UINT32_BE (data); data += 4; ett->messages = _parse_atsc_mult_string (data, end - data - 4); data += end - data - 4; if (data != end - 4) { GST_WARNING ("PID %d invalid ETT parsed %d length %d", section->pid, (gint) (data - section->data), section->section_length); goto error; } return (gpointer) ett; error: _gst_mpegts_atsc_ett_free (ett); return NULL; }
/* we are unlikely to deal with lengths > 2GB here any time soon, so just * return a signed int and use that for error reporting */ static inline gint asf_packet_read_varlen_int (guint lentype_flags, guint lentype_bit_offset, const guint8 ** p_data, guint * p_size) { static const guint lens[4] = { 0, 1, 2, 4 }; guint len, val; len = lens[(lentype_flags >> lentype_bit_offset) & 0x03]; /* will make caller bail out with a short read if there's not enough data */ if (G_UNLIKELY (*p_size < len)) { GST_WARNING ("need %u bytes, but only %u bytes available", len, *p_size); return -1; } switch (len) { case 0: val = 0; break; case 1: val = GST_READ_UINT8 (*p_data); break; case 2: val = GST_READ_UINT16_LE (*p_data); break; case 4: val = GST_READ_UINT32_LE (*p_data); break; default: g_assert_not_reached (); } *p_data += len; *p_size -= len; return (gint) val; }
gboolean mxf_timestamp_parse (MXFTimestamp * timestamp, const guint8 * data, guint size) { g_return_val_if_fail (data != NULL, FALSE); g_return_val_if_fail (timestamp != NULL, FALSE); memset (timestamp, 0, sizeof (MXFTimestamp)); if (size < 8) return FALSE; timestamp->year = GST_READ_UINT16_BE (data); timestamp->month = GST_READ_UINT8 (data + 2); timestamp->day = GST_READ_UINT8 (data + 3); timestamp->hour = GST_READ_UINT8 (data + 4); timestamp->minute = GST_READ_UINT8 (data + 5); timestamp->second = GST_READ_UINT8 (data + 6); timestamp->quarter_msecond = GST_READ_UINT8 (data + 7); return TRUE; }
static gboolean gst_asf_demux_parse_payload (GstASFDemux * demux, AsfPacket * packet, gint lentype, const guint8 ** p_data, guint * p_size) { AsfPayload payload = { 0, }; AsfStream *stream; gboolean is_compressed; guint payload_len; guint stream_num; if (G_UNLIKELY (*p_size < 1)) { GST_WARNING_OBJECT (demux, "Short packet!"); return FALSE; } stream_num = GST_READ_UINT8 (*p_data) & 0x7f; payload.keyframe = ((GST_READ_UINT8 (*p_data) & 0x80) != 0); *p_data += 1; *p_size -= 1; payload.ts = GST_CLOCK_TIME_NONE; payload.duration = GST_CLOCK_TIME_NONE; payload.par_x = 0; payload.par_y = 0; payload.interlaced = FALSE; payload.tff = FALSE; payload.rff = FALSE; payload.mo_number = asf_packet_read_varlen_int (packet->prop_flags, 4, p_data, p_size); payload.mo_offset = asf_packet_read_varlen_int (packet->prop_flags, 2, p_data, p_size); payload.rep_data_len = asf_packet_read_varlen_int (packet->prop_flags, 0, p_data, p_size); is_compressed = (payload.rep_data_len == 1); GST_LOG_OBJECT (demux, "payload for stream %u", stream_num); GST_LOG_OBJECT (demux, "keyframe : %s", (payload.keyframe) ? "yes" : "no"); GST_LOG_OBJECT (demux, "compressed : %s", (is_compressed) ? "yes" : "no"); if (G_UNLIKELY (*p_size < payload.rep_data_len)) { GST_WARNING_OBJECT (demux, "Short packet! rep_data_len=%u, size=%u", payload.rep_data_len, *p_size); return FALSE; } memcpy (payload.rep_data, *p_data, MIN (sizeof (payload.rep_data), payload.rep_data_len)); *p_data += payload.rep_data_len; *p_size -= payload.rep_data_len; if (G_UNLIKELY (*p_size == 0)) { GST_WARNING_OBJECT (demux, "payload without data!?"); return FALSE; } /* we use -1 as lentype for a single payload that's the size of the packet */ if (G_UNLIKELY ((lentype >= 0 && lentype <= 3))) { payload_len = asf_packet_read_varlen_int (lentype, 0, p_data, p_size); if (*p_size < payload_len) { GST_WARNING_OBJECT (demux, "Short packet! payload_len=%u, size=%u", payload_len, *p_size); return FALSE; } } else { payload_len = *p_size; } GST_LOG_OBJECT (demux, "payload length: %u", payload_len); stream = gst_asf_demux_get_stream (demux, stream_num); if (G_UNLIKELY (stream == NULL)) { GST_WARNING_OBJECT (demux, "Payload for unknown stream %u, skipping", stream_num); if (*p_size < payload_len) { *p_data += *p_size; *p_size = 0; } else { *p_data += payload_len; *p_size -= payload_len; } return TRUE; } if (G_UNLIKELY (!is_compressed)) { GST_LOG_OBJECT (demux, "replicated data length: %u", payload.rep_data_len); if (payload.rep_data_len >= 8) { payload.mo_size = GST_READ_UINT32_LE (payload.rep_data); payload.ts = GST_READ_UINT32_LE (payload.rep_data + 4) * GST_MSECOND; if (G_UNLIKELY (payload.ts < demux->preroll)) payload.ts = 0; else payload.ts -= demux->preroll; asf_payload_parse_replicated_data_extensions (stream, &payload); GST_LOG_OBJECT (demux, "media object size : %u", payload.mo_size); GST_LOG_OBJECT (demux, "media object ts : %" GST_TIME_FORMAT, GST_TIME_ARGS (payload.ts)); GST_LOG_OBJECT (demux, "media object dur : %" GST_TIME_FORMAT, GST_TIME_ARGS (payload.duration)); } else if (payload.rep_data_len != 0) { GST_WARNING_OBJECT (demux, "invalid replicated data length, very bad"); *p_data += payload_len; *p_size -= payload_len; return FALSE; } GST_LOG_OBJECT (demux, "media object offset : %u", payload.mo_offset); GST_LOG_OBJECT (demux, "payload length: %u", payload_len); if ((stream = gst_asf_demux_get_stream (demux, stream_num)) && payload_len) { payload.buf = asf_packet_create_payload_buffer (packet, p_data, p_size, payload_len); /* n-th fragment of a fragmented media object? */ if (payload.mo_offset != 0) { AsfPayload *prev; if ((prev = asf_payload_find_previous_fragment (&payload, stream))) { if (payload.mo_offset != GST_BUFFER_SIZE (prev->buf)) { GST_WARNING_OBJECT (demux, "Offset doesn't match previous data?!"); } /* note: buffer join/merge might not preserve buffer flags */ prev->buf = gst_buffer_join (prev->buf, payload.buf); GST_LOG_OBJECT (demux, "Merged fragments, merged size: %u", GST_BUFFER_SIZE (prev->buf)); } else { gst_buffer_unref (payload.buf); } payload.buf = NULL; } else { gst_asf_payload_queue_for_stream (demux, &payload, stream); } } } else { const guint8 *payload_data; GstClockTime ts, ts_delta; guint num; GST_LOG_OBJECT (demux, "Compressed payload, length=%u", payload_len); payload_data = *p_data; *p_data += payload_len; *p_size -= payload_len; ts = payload.mo_offset * GST_MSECOND; if (G_UNLIKELY (ts < demux->preroll)) ts = 0; else ts -= demux->preroll; ts_delta = payload.rep_data[0] * GST_MSECOND; for (num = 0; payload_len > 0; ++num) { guint sub_payload_len; sub_payload_len = GST_READ_UINT8 (payload_data); GST_LOG_OBJECT (demux, "subpayload #%u: len=%u, ts=%" GST_TIME_FORMAT, num, sub_payload_len, GST_TIME_ARGS (ts)); ++payload_data; --payload_len; if (G_UNLIKELY (payload_len < sub_payload_len)) { GST_WARNING_OBJECT (demux, "Short payload! %u bytes left", payload_len); return FALSE; } if (G_LIKELY (sub_payload_len > 0)) { payload.buf = asf_packet_create_payload_buffer (packet, &payload_data, &payload_len, sub_payload_len); payload.ts = ts; if (G_LIKELY (ts_delta)) payload.duration = ts_delta; else payload.duration = GST_CLOCK_TIME_NONE; gst_asf_payload_queue_for_stream (demux, &payload, stream); } ts += ts_delta; } } return TRUE; }
GST_WARNING_OBJECT (demux, "unexpected error correction length type %u", ec_len_type); ec_len = 2; } GST_LOG_OBJECT (demux, "packet has error correction (%u bytes)", ec_len); /* still need at least two payload flag bytes, send time, and duration */ if (size <= (1 + ec_len) + 2 + 4 + 2) goto short_packet; data += 1 + ec_len; size -= 1 + ec_len; } /* parse payload info */ flags1 = GST_READ_UINT8 (data); packet.prop_flags = GST_READ_UINT8 (data + 1); data += 2; size -= 2; has_multiple_payloads = (flags1 & 0x01) != 0; packet.length = asf_packet_read_varlen_int (flags1, 5, &data, &size); packet.sequence = asf_packet_read_varlen_int (flags1, 1, &data, &size); packet.padding = asf_packet_read_varlen_int (flags1, 3, &data, &size); if (G_UNLIKELY (size < 6)) goto short_packet;
/* SMPTE 377M 10.2.3 */ gboolean mxf_index_table_segment_parse (const MXFUL * key, MXFIndexTableSegment * segment, const MXFPrimerPack * primer, const guint8 * data, guint size) { #ifndef GST_DISABLE_GST_DEBUG gchar str[48]; #endif guint16 tag, tag_size; const guint8 *tag_data; g_return_val_if_fail (key != NULL, FALSE); g_return_val_if_fail (data != NULL, FALSE); g_return_val_if_fail (primer != NULL, FALSE); memset (segment, 0, sizeof (MXFIndexTableSegment)); if (size < 70) return FALSE; GST_DEBUG ("Parsing index table segment:"); while (mxf_local_tag_parse (data, size, &tag, &tag_size, &tag_data)) { if (tag_size == 0 || tag == 0x0000) goto next; switch (tag) { case 0x3c0a: if (tag_size != 16) goto error; memcpy (&segment->instance_id, tag_data, 16); GST_DEBUG (" instance id = %s", mxf_ul_to_string (&segment->instance_id, str)); break; case 0x3f0b: if (!mxf_fraction_parse (&segment->index_edit_rate, tag_data, tag_size)) goto error; GST_DEBUG (" index edit rate = %d/%d", segment->index_edit_rate.n, segment->index_edit_rate.d); break; case 0x3f0c: if (tag_size != 8) goto error; segment->index_start_position = GST_READ_UINT64_BE (tag_data); GST_DEBUG (" index start position = %" G_GINT64_FORMAT, segment->index_start_position); break; case 0x3f0d: if (tag_size != 8) goto error; segment->index_duration = GST_READ_UINT64_BE (tag_data); GST_DEBUG (" index duration = %" G_GINT64_FORMAT, segment->index_duration); break; case 0x3f05: if (tag_size != 4) goto error; segment->edit_unit_byte_count = GST_READ_UINT32_BE (tag_data); GST_DEBUG (" edit unit byte count = %u", segment->edit_unit_byte_count); break; case 0x3f06: if (tag_size != 4) goto error; segment->index_sid = GST_READ_UINT32_BE (tag_data); GST_DEBUG (" index sid = %u", segment->index_sid); break; case 0x3f07: if (tag_size != 4) goto error; segment->body_sid = GST_READ_UINT32_BE (tag_data); GST_DEBUG (" body sid = %u", segment->body_sid); break; case 0x3f08: if (tag_size != 1) goto error; segment->slice_count = GST_READ_UINT8 (tag_data); GST_DEBUG (" slice count = %u", segment->slice_count); break; case 0x3f0e: if (tag_size != 1) goto error; segment->pos_table_count = GST_READ_UINT8 (tag_data); GST_DEBUG (" pos table count = %u", segment->pos_table_count); break; case 0x3f09:{ guint len, i; if (tag_size < 8) goto error; len = GST_READ_UINT32_BE (tag_data); segment->n_delta_entries = len; GST_DEBUG (" number of delta entries = %u", segment->n_delta_entries); if (len == 0) goto next; tag_data += 4; tag_size -= 4; if (GST_READ_UINT32_BE (tag_data) != 6) goto error; tag_data += 4; tag_size -= 4; if (tag_size < len * 6) goto error; segment->delta_entries = g_new (MXFDeltaEntry, len); for (i = 0; i < len; i++) { GST_DEBUG (" delta entry %u:", i); segment->delta_entries[i].pos_table_index = GST_READ_UINT8 (tag_data); tag_data += 1; tag_size -= 1; GST_DEBUG (" pos table index = %d", segment->delta_entries[i].pos_table_index); segment->delta_entries[i].slice = GST_READ_UINT8 (tag_data); tag_data += 1; tag_size -= 1; GST_DEBUG (" slice = %u", segment->delta_entries[i].slice); segment->delta_entries[i].element_delta = GST_READ_UINT32_BE (tag_data); tag_data += 4; tag_size -= 4; GST_DEBUG (" element delta = %u", segment->delta_entries[i].element_delta); } break; } case 0x3f0a:{ guint len, i, j; if (tag_size < 8) goto error; len = GST_READ_UINT32_BE (tag_data); segment->n_index_entries = len; GST_DEBUG (" number of index entries = %u", segment->n_index_entries); if (len == 0) goto next; tag_data += 4; tag_size -= 4; if (GST_READ_UINT32_BE (tag_data) != (11 + 4 * segment->slice_count + 8 * segment->pos_table_count)) goto error; tag_data += 4; tag_size -= 4; if (tag_size < len * (11 + 4 * segment->slice_count + 8 * segment->pos_table_count)) goto error; segment->index_entries = g_new (MXFIndexEntry, len); for (i = 0; i < len; i++) { MXFIndexEntry *entry = &segment->index_entries[i]; GST_DEBUG (" index entry %u:", i); entry->temporal_offset = GST_READ_UINT8 (tag_data); tag_data += 1; tag_size -= 1; GST_DEBUG (" temporal offset = %d", entry->temporal_offset); entry->key_frame_offset = GST_READ_UINT8 (tag_data); tag_data += 1; tag_size -= 1; GST_DEBUG (" keyframe offset = %d", entry->key_frame_offset); entry->flags = GST_READ_UINT8 (tag_data); tag_data += 1; tag_size -= 1; GST_DEBUG (" flags = 0x%02x", entry->flags); entry->stream_offset = GST_READ_UINT64_BE (tag_data); tag_data += 8; tag_size -= 8; GST_DEBUG (" stream offset = %" G_GUINT64_FORMAT, entry->stream_offset); for (j = 0; j < segment->slice_count; j++) { entry->slice_offset[j] = GST_READ_UINT32_BE (tag_data); tag_data += 4; tag_size -= 4; GST_DEBUG (" slice %u offset = %u", j, entry->slice_offset[j]); } for (j = 0; j < segment->pos_table_count; j++) { mxf_fraction_parse (&entry->pos_table[j], tag_data, tag_size); tag_data += 8; tag_size -= 8; GST_DEBUG (" pos table %u = %d/%d", j, entry->pos_table[j].n, entry->pos_table[j].d); } } break; } default: if (!mxf_local_tag_add_to_hash_table (primer, tag, tag_data, tag_size, &segment->other_tags)) goto error; break; } next: data += 4 + tag_size; size -= 4 + tag_size; } return TRUE; error: GST_ERROR ("Invalid index table segment"); return FALSE; }
static GstFlowReturn gst_ebml_read_element_length (GstEbmlRead * ebml, guint64 * length, gint * rread) { GstFlowReturn ret; guint8 *buf; gint len_mask = 0x80, read = 1, n = 1, num_ffs = 0; guint64 total; guint8 b; ret = gst_ebml_read_peek_bytes (ebml, 1, NULL, &buf); if (ret != GST_FLOW_OK) return ret; b = GST_READ_UINT8 (buf); total = (guint64) b; while (read <= 8 && !(total & len_mask)) { read++; len_mask >>= 1; } if (read > 8) { guint64 pos = ebml->offset; GST_ELEMENT_ERROR (ebml, STREAM, DEMUX, (NULL), ("Invalid EBML length size tag (0x%x) at position %" G_GUINT64_FORMAT " (0x%" G_GINT64_MODIFIER "x)", (guint) b, pos, pos)); return GST_FLOW_ERROR; } if ((total &= (len_mask - 1)) == len_mask - 1) num_ffs++; ret = gst_ebml_read_peek_bytes (ebml, read, NULL, &buf); if (ret != GST_FLOW_OK) return ret; while (n < read) { guint8 b = GST_READ_UINT8 (buf + n); if (b == 0xff) num_ffs++; total = (total << 8) | b; ++n; } if (read == num_ffs) *length = G_MAXUINT64; else *length = total; if (rread) *rread = read; ebml->offset += read; return GST_FLOW_OK; }
GstBuffer * mpegtsmux_prepare_h264 (GstBuffer * buf, MpegTsPadData * data, MpegTsMuxEnhanced * mux) { guint8 startcode[4] = { 0x00, 0x00, 0x00, 0x01 }; gsize out_offset = 0, in_offset = 0; GstBuffer *out_buf; gboolean changed; PrivDataH264 *h264_data; GstClockTimeDiff diff = GST_CLOCK_TIME_NONE; GST_DEBUG_OBJECT (mux, "Preparing H264 buffer for output"); changed = mpegtsmux_process_codec_data_h264 (data, mux); h264_data = (PrivDataH264 *) data->prepare_data; if (GST_CLOCK_TIME_IS_VALID (h264_data->last_resync_ts) && GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf))) { diff = GST_CLOCK_DIFF (h264_data->last_resync_ts, GST_BUFFER_TIMESTAMP (buf)); } if (changed || (GST_CLOCK_TIME_IS_VALID (diff) && diff > SPS_PPS_PERIOD)) { out_buf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buf) * 2 + GST_BUFFER_SIZE (h264_data->cached_es)); h264_data->last_resync_ts = GST_BUFFER_TIMESTAMP (buf); memcpy (GST_BUFFER_DATA (out_buf), GST_BUFFER_DATA (h264_data->cached_es), GST_BUFFER_SIZE (h264_data->cached_es)); out_offset = GST_BUFFER_SIZE (h264_data->cached_es); GST_DEBUG_OBJECT (mux, "prepending SPS/PPS information to that packet"); } else { out_buf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buf) * 2); } /* We want the same metadata */ gst_buffer_copy_metadata (out_buf, buf, GST_BUFFER_COPY_ALL); while (in_offset < GST_BUFFER_SIZE (buf) && out_offset < GST_BUFFER_SIZE (out_buf) - 4) { guint32 nal_size = 0; switch (h264_data->nal_length_size) { case 1: nal_size = GST_READ_UINT8 (GST_BUFFER_DATA (buf) + in_offset); break; case 2: nal_size = GST_READ_UINT16_BE (GST_BUFFER_DATA (buf) + in_offset); break; case 4: nal_size = GST_READ_UINT32_BE (GST_BUFFER_DATA (buf) + in_offset); break; default: GST_WARNING_OBJECT (mux, "unsupported NAL length size %u", h264_data->nal_length_size); } in_offset += h264_data->nal_length_size; /* Generate an Elementary stream buffer by inserting a startcode */ memcpy (GST_BUFFER_DATA (out_buf) + out_offset, startcode, 4); out_offset += 4; memcpy (GST_BUFFER_DATA (out_buf) + out_offset, GST_BUFFER_DATA (buf) + in_offset, MIN (nal_size, GST_BUFFER_SIZE (out_buf) - out_offset)); in_offset += nal_size; out_offset += nal_size; } if (out_offset > GST_BUFFER_SIZE (out_buf)) { GST_WARNING_OBJECT (mux, "Calculated buffer size %" G_GSIZE_FORMAT " is greater than max expected size %u, " "using max expected size (Input might not be in " "avc format", out_offset, GST_BUFFER_SIZE (out_buf)); out_offset = GST_BUFFER_SIZE (out_buf); } GST_BUFFER_SIZE (out_buf) = out_offset; return out_buf; }
static inline gboolean mpegtsmux_process_codec_data_h264 (MpegTsPadData * data, MpegTsMuxEnhanced * mux) { PrivDataH264 *h264_data; gboolean ret = FALSE; /* Initialize our private data structure for caching */ if (G_UNLIKELY (!data->prepare_data)) { data->prepare_data = g_new0 (PrivDataH264, 1); h264_data = (PrivDataH264 *) data->prepare_data; h264_data->last_resync_ts = GST_CLOCK_TIME_NONE; } h264_data = (PrivDataH264 *) data->prepare_data; /* Detect a codec data change */ if (h264_data->last_codec_data != data->codec_data) { if (h264_data->cached_es) { gst_buffer_unref (h264_data->cached_es); h264_data->cached_es = NULL; } ret = TRUE; } /* Generate the SPS/PPS ES header that will be prepended regularly */ if (G_UNLIKELY (!h264_data->cached_es)) { gint offset = 4, i = 0, nb_sps = 0, nb_pps = 0; gsize out_offset = 0; guint8 startcode[4] = { 0x00, 0x00, 0x00, 0x01 }; h264_data->last_codec_data = data->codec_data; h264_data->cached_es = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (data->codec_data) * 10); /* Get NAL length size */ h264_data->nal_length_size = (GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + offset) & 0x03) + 1; GST_LOG_OBJECT (mux, "NAL length will be coded on %u bytes", h264_data->nal_length_size); offset++; /* How many SPS */ nb_sps = GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + offset) & 0x1f; GST_DEBUG_OBJECT (mux, "we have %d Sequence Parameter Set", nb_sps); offset++; /* For each SPS */ for (i = 0; i < nb_sps; i++) { guint16 sps_size = GST_READ_UINT16_BE (GST_BUFFER_DATA (data->codec_data) + offset); GST_LOG_OBJECT (mux, "Sequence Parameter Set is %d bytes", sps_size); /* Jump over SPS size */ offset += 2; /* Fake a start code */ memcpy (GST_BUFFER_DATA (h264_data->cached_es) + out_offset, startcode, 4); out_offset += 4; /* Now push the SPS */ memcpy (GST_BUFFER_DATA (h264_data->cached_es) + out_offset, GST_BUFFER_DATA (data->codec_data) + offset, sps_size); out_offset += sps_size; offset += sps_size; } /* How many PPS */ nb_pps = GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + offset); GST_LOG_OBJECT (mux, "we have %d Picture Parameter Set", nb_sps); offset++; /* For each PPS */ for (i = 0; i < nb_pps; i++) { gint pps_size = GST_READ_UINT16_BE (GST_BUFFER_DATA (data->codec_data) + offset); GST_LOG_OBJECT (mux, "Picture Parameter Set is %d bytes", pps_size); /* Jump over PPS size */ offset += 2; /* Fake a start code */ memcpy (GST_BUFFER_DATA (h264_data->cached_es) + out_offset, startcode, 4); out_offset += 4; /* Now push the PPS */ memcpy (GST_BUFFER_DATA (h264_data->cached_es) + out_offset, GST_BUFFER_DATA (data->codec_data) + offset, pps_size); out_offset += pps_size; offset += pps_size; } GST_BUFFER_SIZE (h264_data->cached_es) = out_offset; GST_DEBUG_OBJECT (mux, "generated a %" G_GSIZE_FORMAT " bytes SPS/PPS header", out_offset); } return ret; }
static gpointer _parse_atsc_mgt (GstMpegtsSection * section) { GstMpegtsAtscMGT *mgt = NULL; guint i = 0; guint8 *data, *end; guint16 descriptors_loop_length; mgt = g_slice_new0 (GstMpegtsAtscMGT); data = section->data; end = data + section->section_length; /* Skip already parsed data */ data += 8; mgt->protocol_version = GST_READ_UINT8 (data); data += 1; mgt->tables_defined = GST_READ_UINT16_BE (data); data += 2; mgt->tables = g_ptr_array_new_full (mgt->tables_defined, (GDestroyNotify) _gst_mpegts_atsc_mgt_table_free); for (i = 0; i < mgt->tables_defined && data + 11 < end; i++) { GstMpegtsAtscMGTTable *mgt_table; if (data + 11 >= end) { GST_WARNING ("MGT data too short to parse inner table num %d", i); goto error; } mgt_table = g_slice_new0 (GstMpegtsAtscMGTTable); g_ptr_array_add (mgt->tables, mgt_table); mgt_table->table_type = GST_READ_UINT16_BE (data); data += 2; mgt_table->pid = GST_READ_UINT16_BE (data) & 0x1FFF; data += 2; mgt_table->version_number = GST_READ_UINT8 (data) & 0x1F; data += 1; mgt_table->number_bytes = GST_READ_UINT32_BE (data); data += 4; descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF; data += 2; if (data + descriptors_loop_length >= end) { GST_WARNING ("MGT data too short to parse inner table descriptors (table " "num %d", i); goto error; } mgt_table->descriptors = gst_mpegts_parse_descriptors (data, descriptors_loop_length); data += descriptors_loop_length; } descriptors_loop_length = GST_READ_UINT16_BE (data) & 0xFFF; data += 2; if (data + descriptors_loop_length >= end) { GST_WARNING ("MGT data too short to parse descriptors"); goto error; } mgt->descriptors = gst_mpegts_parse_descriptors (data, descriptors_loop_length); data += descriptors_loop_length; return (gpointer) mgt; error: _gst_mpegts_atsc_mgt_free (mgt); return NULL; }
static GPtrArray * _parse_atsc_mult_string (guint8 * data, guint datasize) { guint8 num_strings; GPtrArray *res = NULL; guint8 *end = data + datasize; gint i; if (datasize > 0) { /* 1 is the minimum entry size, so no need to check here */ num_strings = GST_READ_UINT8 (data); data += 1; res = g_ptr_array_new_full (num_strings, (GDestroyNotify) _gst_mpegts_atsc_mult_string_free); for (i = 0; i < num_strings; i++) { GstMpegtsAtscMultString *mstring; guint8 num_segments; gint j; mstring = g_slice_new0 (GstMpegtsAtscMultString); g_ptr_array_add (res, mstring); mstring->segments = g_ptr_array_new_full (num_strings, (GDestroyNotify) _gst_mpegts_atsc_string_segment_free); /* each entry needs at least 4 bytes (lang code and segments number) */ if (end - data < 4) { GST_WARNING ("Data too short for multstring parsing %d", (gint) (end - data)); goto error; } mstring->iso_639_langcode[0] = GST_READ_UINT8 (data); data += 1; mstring->iso_639_langcode[1] = GST_READ_UINT8 (data); data += 1; mstring->iso_639_langcode[2] = GST_READ_UINT8 (data); data += 1; num_segments = GST_READ_UINT8 (data); data += 1; for (j = 0; j < num_segments; j++) { GstMpegtsAtscStringSegment *seg; seg = g_slice_new0 (GstMpegtsAtscStringSegment); g_ptr_array_add (mstring->segments, seg); /* each entry needs at least 3 bytes */ if (end - data < 3) { GST_WARNING ("Data too short for multstring parsing %d", datasize); goto error; } seg->compression_type = GST_READ_UINT8 (data); data += 1; seg->mode = GST_READ_UINT8 (data); data += 1; seg->compressed_data_size = GST_READ_UINT8 (data); data += 1; if (end - data < seg->compressed_data_size) { GST_WARNING ("Data too short for multstring parsing %d", datasize); goto error; } if (seg->compressed_data_size) seg->compressed_data = data; data += seg->compressed_data_size; } } } return res; error: if (res) g_ptr_array_unref (res); return NULL; }
GstBuffer * mpegpsmux_prepare_h264 (GstBuffer * buf, MpegPsPadData * data, MpegPsMux * mux) { guint8 nal_length_size = 0; guint8 startcode[4] = { 0x00, 0x00, 0x00, 0x01 }; GstBuffer *out_buf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (buf) * 2); gint offset = 4, i = 0, nb_sps = 0, nb_pps = 0; gsize out_offset = 0, in_offset = 0; GST_DEBUG_OBJECT (mux, "Preparing H264 buffer for output"); /* We want the same metadata */ gst_buffer_copy_metadata (out_buf, buf, GST_BUFFER_COPY_ALL); /* Get NAL length size */ nal_length_size = (GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + offset) & 0x03) + 1; GST_LOG_OBJECT (mux, "NAL length will be coded on %u bytes", nal_length_size); offset++; /* Generate SPS */ nb_sps = GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + offset) & 0x1f; GST_DEBUG_OBJECT (mux, "we have %d Sequence Parameter Set", nb_sps); offset++; /* For each SPS */ for (i = 0; i < nb_sps; i++) { guint16 sps_size = GST_READ_UINT16_BE (GST_BUFFER_DATA (data->codec_data) + offset); GST_LOG_OBJECT (mux, "Sequence Parameter Set is %d bytes", sps_size); /* Jump over SPS size */ offset += 2; /* Fake a start code */ memcpy (GST_BUFFER_DATA (out_buf) + out_offset, startcode, 4); out_offset += 4; /* Now push the SPS */ memcpy (GST_BUFFER_DATA (out_buf) + out_offset, GST_BUFFER_DATA (data->codec_data) + offset, sps_size); out_offset += sps_size; offset += sps_size; } nb_pps = GST_READ_UINT8 (GST_BUFFER_DATA (data->codec_data) + offset); GST_LOG_OBJECT (mux, "we have %d Picture Parameter Set", nb_sps); offset++; /* For each PPS */ for (i = 0; i < nb_pps; i++) { gint pps_size = GST_READ_UINT16_BE (GST_BUFFER_DATA (data->codec_data) + offset); GST_LOG_OBJECT (mux, "Picture Parameter Set is %d bytes", pps_size); /* Jump over PPS size */ offset += 2; /* Fake a start code */ memcpy (GST_BUFFER_DATA (out_buf) + out_offset, startcode, 4); out_offset += 4; /* Now push the PPS */ memcpy (GST_BUFFER_DATA (out_buf) + out_offset, GST_BUFFER_DATA (data->codec_data) + offset, pps_size); out_offset += pps_size; offset += pps_size; } while (in_offset < GST_BUFFER_SIZE (buf) && out_offset < GST_BUFFER_SIZE (out_buf) - 4) { guint32 nal_size = 0; switch (nal_length_size) { case 1: nal_size = GST_READ_UINT8 (GST_BUFFER_DATA (buf) + in_offset); break; case 2: nal_size = GST_READ_UINT16_BE (GST_BUFFER_DATA (buf) + in_offset); break; case 4: nal_size = GST_READ_UINT32_BE (GST_BUFFER_DATA (buf) + in_offset); break; default: GST_WARNING_OBJECT (mux, "unsupported NAL length size %u", nal_length_size); } in_offset += nal_length_size; /* Generate an Elementary stream buffer by inserting a startcode */ memcpy (GST_BUFFER_DATA (out_buf) + out_offset, startcode, 4); out_offset += 4; memcpy (GST_BUFFER_DATA (out_buf) + out_offset, GST_BUFFER_DATA (buf) + in_offset, MIN (nal_size, GST_BUFFER_SIZE (out_buf) - out_offset)); in_offset += nal_size; out_offset += nal_size; } GST_BUFFER_SIZE (out_buf) = out_offset; return out_buf; }
static gpointer _parse_atsc_eit (GstMpegtsSection * section) { GstMpegtsAtscEIT *eit = NULL; guint i = 0; guint8 *data, *end; guint8 num_events; eit = g_slice_new0 (GstMpegtsAtscEIT); data = section->data; end = data + section->section_length; eit->source_id = section->subtable_extension; /* Skip already parsed data */ data += 8; eit->protocol_version = GST_READ_UINT8 (data); data += 1; num_events = GST_READ_UINT8 (data); data += 1; eit->events = g_ptr_array_new_with_free_func ((GDestroyNotify) _gst_mpegts_atsc_eit_event_free); for (i = 0; i < num_events; i++) { GstMpegtsAtscEITEvent *event; guint32 tmp; guint8 text_length; guint16 descriptors_loop_length; if (end - data < 12) { GST_WARNING ("PID %d invalid EIT entry length %d with %u events", section->pid, (gint) (end - 4 - data), num_events); goto error; } event = g_slice_new0 (GstMpegtsAtscEITEvent); g_ptr_array_add (eit->events, event); event->event_id = GST_READ_UINT16_BE (data) & 0x3FFF; data += 2; event->start_time = GST_READ_UINT32_BE (data); data += 4; tmp = GST_READ_UINT32_BE (data); data += 4; event->etm_location = (tmp >> 28) & 0x3; event->length_in_seconds = (tmp >> 8) & 0x0FFFFF; text_length = tmp & 0xFF; if (text_length > end - data - 4 - 2) { GST_WARNING ("PID %d invalid EIT entry length %d with %u events", section->pid, (gint) (end - 4 - data), num_events); goto error; } event->titles = _parse_atsc_mult_string (data, text_length); data += text_length; descriptors_loop_length = GST_READ_UINT16_BE (data) & 0x0FFF; data += 2; if (end - data - 4 < descriptors_loop_length) { GST_WARNING ("PID %d invalid EIT entry length %d with %u events", section->pid, (gint) (end - 4 - data), num_events); goto error; } event->descriptors = gst_mpegts_parse_descriptors (data, descriptors_loop_length); data += descriptors_loop_length; } if (data != end - 4) { GST_WARNING ("PID %d invalid EIT parsed %d length %d", section->pid, (gint) (data - section->data), section->section_length); goto error; } return (gpointer) eit; error: _gst_mpegts_atsc_eit_free (eit); return NULL; }