static gboolean gst_isoff_trun_box_parse (GstTrunBox * trun, GstByteReader * reader) { gint i; memset (trun, 0, sizeof (*trun)); if (gst_byte_reader_get_remaining (reader) < 4) return FALSE; trun->version = gst_byte_reader_get_uint8_unchecked (reader); if (trun->version != 0 && trun->version != 1) return FALSE; trun->flags = gst_byte_reader_get_uint24_be_unchecked (reader); if (!gst_byte_reader_get_uint32_be (reader, &trun->sample_count)) return FALSE; trun->samples = g_array_sized_new (FALSE, FALSE, sizeof (GstTrunSample), trun->sample_count); if ((trun->flags & GST_TRUN_FLAGS_DATA_OFFSET_PRESENT) && !gst_byte_reader_get_uint32_be (reader, (guint32 *) & trun->data_offset)) return FALSE; if ((trun->flags & GST_TRUN_FLAGS_FIRST_SAMPLE_FLAGS_PRESENT) && !gst_byte_reader_get_uint32_be (reader, &trun->first_sample_flags)) return FALSE; for (i = 0; i < trun->sample_count; i++) { GstTrunSample sample = { 0, }; if ((trun->flags & GST_TRUN_FLAGS_SAMPLE_DURATION_PRESENT) && !gst_byte_reader_get_uint32_be (reader, &sample.sample_duration)) goto error; if ((trun->flags & GST_TRUN_FLAGS_SAMPLE_SIZE_PRESENT) && !gst_byte_reader_get_uint32_be (reader, &sample.sample_size)) goto error; if ((trun->flags & GST_TRUN_FLAGS_SAMPLE_FLAGS_PRESENT) && !gst_byte_reader_get_uint32_be (reader, &sample.sample_flags)) goto error; if ((trun->flags & GST_TRUN_FLAGS_SAMPLE_COMPOSITION_TIME_OFFSETS_PRESENT) && !gst_byte_reader_get_uint32_be (reader, &sample.sample_composition_time_offset.u)) goto error; g_array_append_val (trun->samples, sample); } return TRUE; error: gst_isoff_trun_box_clear (trun); return FALSE; }
static void gst_cenc_decrypt_parse_pssh_box (GstCencDecrypt * self, GstBuffer * pssh) { GstMapInfo info; GstByteReader br; guint8 version; guint32 data_size; gst_buffer_map (pssh, &info, GST_MAP_READ); gst_byte_reader_init (&br, info.data, info.size); gst_byte_reader_skip_unchecked (&br, 8); version = gst_byte_reader_get_uint8_unchecked (&br); GST_DEBUG_OBJECT (self, "pssh version: %u", version); gst_byte_reader_skip_unchecked (&br, 19); if (version > 0) { /* Parse KeyIDs */ guint32 key_id_count = 0; const guint8 *key_id_data = NULL; const guint key_id_size = 16; key_id_count = gst_byte_reader_get_uint32_be_unchecked (&br); GST_DEBUG_OBJECT (self, "there are %u key IDs", key_id_count); key_id_data = gst_byte_reader_get_data_unchecked (&br, key_id_count * 16); while (key_id_count > 0) { gchar *key_id_string = gst_cenc_create_uuid_string (key_id_data); GST_DEBUG_OBJECT (self, "key_id: %s", key_id_string); g_free (key_id_string); key_id_data += key_id_size; --key_id_count; } } /* Parse Data */ data_size = gst_byte_reader_get_uint32_be_unchecked (&br); GST_DEBUG_OBJECT (self, "pssh data size: %u", data_size); if (data_size > 0U) { gpointer data = g_memdup (gst_byte_reader_get_data_unchecked (&br, data_size), data_size); GstBuffer *buf = gst_buffer_new_wrapped (data, data_size); GST_DEBUG_OBJECT (self, "cenc protection system data size: %" G_GSIZE_FORMAT, gst_buffer_get_size (buf)); gst_buffer_unref (buf); } gst_buffer_unmap (pssh, &info); }
static gboolean gst_isoff_mfhd_box_parse (GstMfhdBox * mfhd, GstByteReader * reader) { guint8 version; guint32 flags; if (gst_byte_reader_get_remaining (reader) != 8) return FALSE; version = gst_byte_reader_get_uint8_unchecked (reader); if (version != 0) return FALSE; flags = gst_byte_reader_get_uint24_be_unchecked (reader); if (flags != 0) return FALSE; mfhd->sequence_number = gst_byte_reader_get_uint32_be_unchecked (reader); return TRUE; }
static gboolean gst_isoff_tfhd_box_parse (GstTfhdBox * tfhd, GstByteReader * reader) { memset (tfhd, 0, sizeof (*tfhd)); if (gst_byte_reader_get_remaining (reader) < 4) return FALSE; tfhd->version = gst_byte_reader_get_uint8_unchecked (reader); if (tfhd->version != 0) return FALSE; tfhd->flags = gst_byte_reader_get_uint24_be_unchecked (reader); if (!gst_byte_reader_get_uint32_be (reader, &tfhd->track_id)) return FALSE; if ((tfhd->flags & GST_TFHD_FLAGS_BASE_DATA_OFFSET_PRESENT) && !gst_byte_reader_get_uint64_be (reader, &tfhd->base_data_offset)) return FALSE; if ((tfhd->flags & GST_TFHD_FLAGS_SAMPLE_DESCRIPTION_INDEX_PRESENT) && !gst_byte_reader_get_uint32_be (reader, &tfhd->sample_description_index)) return FALSE; if ((tfhd->flags & GST_TFHD_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT) && !gst_byte_reader_get_uint32_be (reader, &tfhd->default_sample_duration)) return FALSE; if ((tfhd->flags & GST_TFHD_FLAGS_DEFAULT_SAMPLE_SIZE_PRESENT) && !gst_byte_reader_get_uint32_be (reader, &tfhd->default_sample_size)) return FALSE; if ((tfhd->flags & GST_TFHD_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT) && !gst_byte_reader_get_uint32_be (reader, &tfhd->default_sample_flags)) return FALSE; return TRUE; }
static GstFlowReturn gst_h264_parse_chain (GstPad * pad, GstBuffer * buffer) { GstH264Parse *h264parse = GST_H264_PARSE (GST_PAD_PARENT (pad)); if (h264parse->packetized && buffer) { GstByteReader br; GstBuffer *sub; GstFlowReturn ret = GST_FLOW_OK; guint32 len; const guint nl = h264parse->nal_length_size; GST_LOG_OBJECT (h264parse, "processing packet buffer of size %d", GST_BUFFER_SIZE (buffer)); gst_byte_reader_init_from_buffer (&br, buffer); while (ret == GST_FLOW_OK && gst_byte_reader_get_remaining (&br)) { GST_DEBUG_OBJECT (h264parse, "AVC nal offset %d", gst_byte_reader_get_pos (&br)); if (gst_byte_reader_get_remaining (&br) < nl) goto parse_failed; switch (nl) { case 4: len = gst_byte_reader_get_uint32_be_unchecked (&br); break; case 3: len = gst_byte_reader_get_uint24_be_unchecked (&br); break; case 2: len = gst_byte_reader_get_uint16_be_unchecked (&br); break; case 1: len = gst_byte_reader_get_uint8_unchecked (&br); break; default: goto not_negotiated; break; } GST_DEBUG_OBJECT (h264parse, "AVC nal size %d", len); if (gst_byte_reader_get_remaining (&br) < len) goto parse_failed; if (h264parse->split_packetized) { /* convert to NAL aligned byte stream input */ sub = gst_h264_parse_wrap_nal (h264parse, GST_H264_PARSE_FORMAT_BYTE, (guint8 *) gst_byte_reader_get_data_unchecked (&br, len), len); /* at least this should make sense */ GST_BUFFER_TIMESTAMP (sub) = GST_BUFFER_TIMESTAMP (buffer); GST_LOG_OBJECT (h264parse, "pushing NAL of size %d", len); ret = h264parse->parse_chain (pad, sub); } else { /* pass-through: no looking for frames (and nal processing), * so need to parse to collect data here */ /* NOTE: so if it is really configured to do so, * pre_push can/will still insert codec-data at intervals, * which is not really pure pass-through, but anyway ... */ gst_h264_parse_process_nal (h264parse, GST_BUFFER_DATA (buffer), gst_byte_reader_get_pos (&br) - nl, gst_byte_reader_get_pos (&br), len); gst_byte_reader_skip_unchecked (&br, len); } } if (h264parse->split_packetized) return ret; } exit: /* nal processing in pass-through might have collected stuff; * ensure nothing happens with this later on */ gst_adapter_clear (h264parse->frame_out); return h264parse->parse_chain (pad, buffer); /* ERRORS */ not_negotiated: { GST_DEBUG_OBJECT (h264parse, "insufficient data to split input"); return GST_FLOW_NOT_NEGOTIATED; } parse_failed: { if (h264parse->split_packetized) { GST_ELEMENT_ERROR (h264parse, STREAM, FAILED, (NULL), ("invalid AVC input data")); return GST_FLOW_ERROR; } else { /* do not meddle to much in this case */ GST_DEBUG_OBJECT (h264parse, "parsing packet failed"); goto exit; } } }
GstIsoffParserResult gst_isoff_sidx_parser_parse (GstSidxParser * parser, GstByteReader * reader, guint * consumed) { GstIsoffParserResult res = GST_ISOFF_PARSER_OK; gsize remaining; switch (parser->status) { case GST_ISOFF_SIDX_PARSER_INIT: /* Try again once we have enough data for the FullBox header */ if (gst_byte_reader_get_remaining (reader) < 4) { gst_byte_reader_set_pos (reader, 0); break; } parser->sidx.version = gst_byte_reader_get_uint8_unchecked (reader); parser->sidx.flags = gst_byte_reader_get_uint24_le_unchecked (reader); parser->status = GST_ISOFF_SIDX_PARSER_HEADER; case GST_ISOFF_SIDX_PARSER_HEADER: remaining = gst_byte_reader_get_remaining (reader); if (remaining < 12 + (parser->sidx.version == 0 ? 8 : 16)) { break; } parser->sidx.ref_id = gst_byte_reader_get_uint32_be_unchecked (reader); parser->sidx.timescale = gst_byte_reader_get_uint32_be_unchecked (reader); if (parser->sidx.version == 0) { parser->sidx.earliest_pts = gst_byte_reader_get_uint32_be_unchecked (reader); parser->sidx.first_offset = gst_byte_reader_get_uint32_be_unchecked (reader); } else { parser->sidx.earliest_pts = gst_byte_reader_get_uint64_be_unchecked (reader); parser->sidx.first_offset = gst_byte_reader_get_uint64_be_unchecked (reader); } /* skip 2 reserved bytes */ gst_byte_reader_skip_unchecked (reader, 2); parser->sidx.entries_count = gst_byte_reader_get_uint16_be_unchecked (reader); GST_LOG ("Timescale: %" G_GUINT32_FORMAT, parser->sidx.timescale); GST_LOG ("Earliest pts: %" G_GUINT64_FORMAT, parser->sidx.earliest_pts); GST_LOG ("First offset: %" G_GUINT64_FORMAT, parser->sidx.first_offset); parser->cumulative_pts = gst_util_uint64_scale_int_round (parser->sidx.earliest_pts, GST_SECOND, parser->sidx.timescale); if (parser->sidx.entries_count) { parser->sidx.entries = g_malloc (sizeof (GstSidxBoxEntry) * parser->sidx.entries_count); } parser->sidx.entry_index = 0; parser->status = GST_ISOFF_SIDX_PARSER_DATA; case GST_ISOFF_SIDX_PARSER_DATA: while (parser->sidx.entry_index < parser->sidx.entries_count) { GstSidxBoxEntry *entry = &parser->sidx.entries[parser->sidx.entry_index]; remaining = gst_byte_reader_get_remaining (reader); if (remaining < 12) break; entry->offset = parser->cumulative_entry_size; entry->pts = parser->cumulative_pts; gst_isoff_parse_sidx_entry (entry, reader); entry->duration = gst_util_uint64_scale_int_round (entry->duration, GST_SECOND, parser->sidx.timescale); parser->cumulative_entry_size += entry->size; parser->cumulative_pts += entry->duration; GST_LOG ("Sidx entry %d) offset: %" G_GUINT64_FORMAT ", pts: %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT " - size %" G_GUINT32_FORMAT, parser->sidx.entry_index, entry->offset, GST_TIME_ARGS (entry->pts), GST_TIME_ARGS (entry->duration), entry->size); parser->sidx.entry_index++; } if (parser->sidx.entry_index == parser->sidx.entries_count) parser->status = GST_ISOFF_SIDX_PARSER_FINISHED; else break; case GST_ISOFF_SIDX_PARSER_FINISHED: parser->sidx.entry_index = 0; res = GST_ISOFF_PARSER_DONE; break; } *consumed = gst_byte_reader_get_pos (reader); return res; }
GstIsoffParserResult gst_isoff_sidx_parser_add_buffer (GstSidxParser * parser, GstBuffer * buffer, guint * consumed) { GstIsoffParserResult res = GST_ISOFF_PARSER_OK; GstByteReader reader; GstMapInfo info; gsize remaining; guint32 fourcc; if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) { *consumed = 0; return GST_ISOFF_PARSER_ERROR; } gst_byte_reader_init (&reader, info.data, info.size); switch (parser->status) { case GST_ISOFF_SIDX_PARSER_INIT: if (gst_byte_reader_get_remaining (&reader) < GST_ISOFF_FULL_BOX_SIZE) { break; } parser->size = gst_byte_reader_get_uint32_be_unchecked (&reader); fourcc = gst_byte_reader_get_uint32_le_unchecked (&reader); if (fourcc != GST_ISOFF_FOURCC_SIDX) { res = GST_ISOFF_PARSER_UNEXPECTED; gst_byte_reader_set_pos (&reader, 0); break; } if (parser->size == 1) { if (gst_byte_reader_get_remaining (&reader) < 12) { gst_byte_reader_set_pos (&reader, 0); break; } parser->size = gst_byte_reader_get_uint64_be_unchecked (&reader); } if (parser->size == 0) { res = GST_ISOFF_PARSER_ERROR; gst_byte_reader_set_pos (&reader, 0); break; } parser->sidx.version = gst_byte_reader_get_uint8_unchecked (&reader); parser->sidx.flags = gst_byte_reader_get_uint24_le_unchecked (&reader); parser->status = GST_ISOFF_SIDX_PARSER_HEADER; case GST_ISOFF_SIDX_PARSER_HEADER: remaining = gst_byte_reader_get_remaining (&reader); if (remaining < 12 + (parser->sidx.version == 0 ? 8 : 16)) { break; } parser->sidx.ref_id = gst_byte_reader_get_uint32_be_unchecked (&reader); parser->sidx.timescale = gst_byte_reader_get_uint32_be_unchecked (&reader); if (parser->sidx.version == 0) { parser->sidx.earliest_pts = gst_byte_reader_get_uint32_be_unchecked (&reader); parser->sidx.first_offset = parser->sidx.earliest_pts = gst_byte_reader_get_uint32_be_unchecked (&reader); } else { parser->sidx.earliest_pts = gst_byte_reader_get_uint64_be_unchecked (&reader); parser->sidx.first_offset = gst_byte_reader_get_uint64_be_unchecked (&reader); } /* skip 2 reserved bytes */ gst_byte_reader_skip_unchecked (&reader, 2); parser->sidx.entries_count = gst_byte_reader_get_uint16_be_unchecked (&reader); GST_LOG ("Timescale: %" G_GUINT32_FORMAT, parser->sidx.timescale); GST_LOG ("Earliest pts: %" G_GUINT64_FORMAT, parser->sidx.earliest_pts); GST_LOG ("First offset: %" G_GUINT64_FORMAT, parser->sidx.first_offset); parser->cumulative_pts = gst_util_uint64_scale_int_round (parser->sidx.earliest_pts, GST_SECOND, parser->sidx.timescale); if (parser->sidx.entries_count) { parser->sidx.entries = g_malloc (sizeof (GstSidxBoxEntry) * parser->sidx.entries_count); } parser->sidx.entry_index = 0; parser->status = GST_ISOFF_SIDX_PARSER_DATA; case GST_ISOFF_SIDX_PARSER_DATA: while (parser->sidx.entry_index < parser->sidx.entries_count) { GstSidxBoxEntry *entry = &parser->sidx.entries[parser->sidx.entry_index]; remaining = gst_byte_reader_get_remaining (&reader);; if (remaining < 12) break; entry->offset = parser->cumulative_entry_size; entry->pts = parser->cumulative_pts; gst_isoff_parse_sidx_entry (entry, &reader); entry->duration = gst_util_uint64_scale_int_round (entry->duration, GST_SECOND, parser->sidx.timescale); parser->cumulative_entry_size += entry->size; parser->cumulative_pts += entry->duration; GST_LOG ("Sidx entry %d) offset: %" G_GUINT64_FORMAT ", pts: %" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT " - size %" G_GUINT32_FORMAT, parser->sidx.entry_index, entry->offset, GST_TIME_ARGS (entry->pts), GST_TIME_ARGS (entry->duration), entry->size); parser->sidx.entry_index++; } if (parser->sidx.entry_index == parser->sidx.entries_count) parser->status = GST_ISOFF_SIDX_PARSER_FINISHED; else break; case GST_ISOFF_SIDX_PARSER_FINISHED: parser->sidx.entry_index = 0; res = GST_ISOFF_PARSER_DONE; break; } *consumed = gst_byte_reader_get_pos (&reader); gst_buffer_unmap (buffer, &info); return res; }