static guint find_psc (GstBuffer * buffer, guint skip) { GstMapInfo map; GstByteReader br; guint psc_pos = -1, psc; gst_buffer_map (buffer, &map, GST_MAP_READ); gst_byte_reader_init (&br, map.data, map.size); if (!gst_byte_reader_set_pos (&br, skip)) goto out; if (gst_byte_reader_peek_uint24_be (&br, &psc) == FALSE) goto out; /* Scan for the picture start code (22 bits - 0x0020) */ while ((gst_byte_reader_get_remaining (&br) >= 3)) { if (gst_byte_reader_peek_uint24_be (&br, &psc) && ((psc & 0xffffc0) == 0x000080)) { psc_pos = gst_byte_reader_get_pos (&br); break; } else if (gst_byte_reader_skip (&br, 1) == FALSE) break; } out: gst_buffer_unmap (buffer, &map); return psc_pos; }
static GstFlowReturn gst_jp2k_decimator_decimate_jpc (GstJP2kDecimator * self, GstBuffer * inbuf, GstBuffer ** outbuf_) { GstBuffer *outbuf = NULL; GstFlowReturn ret = GST_FLOW_OK; GstMapInfo info; GstByteReader reader; GstByteWriter writer; MainHeader main_header; if (!gst_buffer_map (inbuf, &info, GST_MAP_READ)) { GST_ELEMENT_ERROR (self, STREAM, WRONG_TYPE, ("Unable to map memory"), (NULL)); gst_buffer_unref (inbuf); return GST_FLOW_ERROR; } gst_byte_reader_init (&reader, info.data, info.size); gst_byte_writer_init_with_size (&writer, gst_buffer_get_size (inbuf), FALSE); /* main header */ memset (&main_header, 0, sizeof (MainHeader)); ret = parse_main_header (self, &reader, &main_header); if (ret != GST_FLOW_OK) goto done; ret = decimate_main_header (self, &main_header); if (ret != GST_FLOW_OK) goto done; ret = write_main_header (self, &writer, &main_header); if (ret != GST_FLOW_OK) goto done; outbuf = gst_byte_writer_reset_and_get_buffer (&writer); gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_METADATA, 0, -1); GST_DEBUG_OBJECT (self, "Decimated buffer from %" G_GSIZE_FORMAT " bytes to %" G_GSIZE_FORMAT " bytes (%.2lf%%)", gst_buffer_get_size (inbuf), gst_buffer_get_size (outbuf), (100 * gst_buffer_get_size (outbuf)) / ((gdouble) gst_buffer_get_size (inbuf))); done: gst_buffer_unmap (inbuf, &info); *outbuf_ = outbuf; reset_main_header (self, &main_header); gst_buffer_unref (inbuf); return ret; }
EXPORT_C #endif void gst_byte_reader_init_from_buffer (GstByteReader * reader, const GstBuffer * buffer) { g_return_if_fail (GST_IS_BUFFER (buffer)); gst_byte_reader_init (reader, GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer)); }
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); }
GstIsoffParserResult gst_isoff_sidx_parser_add_buffer (GstSidxParser * parser, GstBuffer * buffer, guint * consumed) { GstIsoffParserResult res = GST_ISOFF_PARSER_OK; GstByteReader reader; GstMapInfo info; 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); if (parser->status == GST_ISOFF_SIDX_PARSER_INIT) { if (!gst_isoff_parse_box_header (&reader, &fourcc, NULL, NULL, &parser->size)) goto done; if (fourcc != GST_ISOFF_FOURCC_SIDX) { res = GST_ISOFF_PARSER_UNEXPECTED; gst_byte_reader_set_pos (&reader, 0); goto done; } if (parser->size == 0) { res = GST_ISOFF_PARSER_ERROR; gst_byte_reader_set_pos (&reader, 0); goto done; } /* 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); goto done; } } res = gst_isoff_sidx_parser_parse (parser, &reader, consumed); done: gst_buffer_unmap (buffer, &info); return res; }
/** * gst_h263_parse: * @packet: The #GstMpeg4Packet to fill * @offset: offset from which to start the parsing * @data: The data to parse * @size: The size of the @data to parse * * Parses @data and fills @packet with the information of the next packet * found. * * Note that the type of the packet is meaningless in this case. * * Returns: a #GstMpeg4ParseResult */ GstMpeg4ParseResult gst_h263_parse (GstMpeg4Packet * packet, const guint8 * data, guint offset, gsize size) { gint off1, off2; GstByteReader br; gst_byte_reader_init (&br, data + offset, size - offset); g_return_val_if_fail (packet != NULL, GST_MPEG4_PARSER_ERROR); if (size - offset < 3) { GST_DEBUG ("Can't parse, buffer is to small size %" G_GSIZE_FORMAT " at offset %d", size, offset); return GST_MPEG4_PARSER_ERROR; } off1 = find_psc (&br); if (off1 == -1) { GST_DEBUG ("No start code prefix in this buffer"); return GST_MPEG4_PARSER_NO_PACKET; } packet->offset = off1 + offset; packet->data = data; gst_byte_reader_skip_unchecked (&br, 3); off2 = find_psc (&br); if (off2 == -1) { GST_DEBUG ("Packet start %d, No end found", off1); packet->size = G_MAXUINT; return GST_MPEG4_PARSER_NO_PACKET_END; } packet->size = (gsize) off2 - off1; GST_DEBUG ("Complete packet found at: %d, Size: %" G_GSIZE_FORMAT, packet->offset, packet->size); return GST_MPEG4_PARSER_OK; }
/** * gst_mpeg4_next_resync: * @packet: The #GstMpeg4Packet to fill * @vop: The previously parsed #GstMpeg4VideoObjectPlane * @offset: offset from which to start the parsing * @data: The data to parse * @size: The size of the @data to parse * * Parses @data and fills @packet with the information of the next resync packet * found. * * Returns: a #GstMpeg4ParseResult */ static GstMpeg4ParseResult gst_mpeg4_next_resync (GstMpeg4Packet * packet, const GstMpeg4VideoObjectPlane * vop, const guint8 * data, gsize size, gboolean first_resync_marker) { guint markersize = 0, off1, off2; guint32 mask = 0xff, pattern = 0xff; GstByteReader br; gst_byte_reader_init (&br, data, size); g_return_val_if_fail (packet != NULL, GST_MPEG4_PARSER_ERROR); g_return_val_if_fail (vop != NULL, GST_MPEG4_PARSER_ERROR); markersize = compute_resync_marker_size (vop, &pattern, &mask); if (first_resync_marker) { off1 = 0; } else { off1 = gst_byte_reader_masked_scan_uint32 (&br, mask, pattern, 0, size); } if (off1 == -1) return GST_MPEG4_PARSER_NO_PACKET; GST_DEBUG ("Resync code found at %i", off1); packet->offset = off1; packet->type = GST_MPEG4_RESYNC; packet->marker_size = markersize; off2 = gst_byte_reader_masked_scan_uint32 (&br, mask, pattern, off1 + 2, size - off1 - 2); if (off2 == -1) return GST_MPEG4_PARSER_NO_PACKET_END; packet->size = off2 - off1; return GST_MPEG4_PARSER_OK; }
static GstFlowReturn gst_png_parse_handle_frame (GstBaseParse * parse, GstBaseParseFrame * frame, gint * skipsize) { GstPngParse *pngparse = GST_PNG_PARSE (parse); GstMapInfo map; GstByteReader reader; GstFlowReturn ret = GST_FLOW_OK; guint64 signature; guint width = 0, height = 0; gst_buffer_map (frame->buffer, &map, GST_MAP_READ); gst_byte_reader_init (&reader, map.data, map.size); if (!gst_byte_reader_peek_uint64_be (&reader, &signature)) goto beach; if (signature != PNG_SIGNATURE) { for (;;) { guint offset; offset = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff, 0x89504E47, 0, gst_byte_reader_get_remaining (&reader)); if (offset == -1) { *skipsize = gst_byte_reader_get_remaining (&reader) - 4; goto beach; } gst_byte_reader_skip (&reader, offset); if (!gst_byte_reader_peek_uint64_be (&reader, &signature)) goto beach; if (signature == PNG_SIGNATURE) { /* We're skipping, go out, we'll be back */ *skipsize = gst_byte_reader_get_pos (&reader); goto beach; } gst_byte_reader_skip (&reader, 4); } } gst_byte_reader_skip (&reader, 8); for (;;) { guint32 length; guint32 code; if (!gst_byte_reader_get_uint32_be (&reader, &length)) goto beach; if (!gst_byte_reader_get_uint32_le (&reader, &code)) goto beach; if (code == GST_MAKE_FOURCC ('I', 'H', 'D', 'R')) { if (!gst_byte_reader_get_uint32_be (&reader, &width)) goto beach; if (!gst_byte_reader_get_uint32_be (&reader, &height)) goto beach; length -= 8; } if (!gst_byte_reader_skip (&reader, length + 4)) goto beach; if (code == GST_MAKE_FOURCC ('I', 'E', 'N', 'D')) { if (pngparse->width != width || pngparse->height != height) { GstCaps *caps; pngparse->height = height; pngparse->width = width; caps = gst_caps_new_simple ("image/png", "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL); if (!gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps)) { ret = GST_FLOW_NOT_NEGOTIATED; } gst_caps_unref (caps); if (ret != GST_FLOW_OK) goto beach; } gst_buffer_unmap (frame->buffer, &map); return gst_base_parse_finish_frame (parse, frame, gst_byte_reader_get_pos (&reader)); } } beach: gst_buffer_unmap (frame->buffer, &map); return ret; }
/* Ideas from gstjpegparse.c */ GstTagList * gst_droidcamsrc_exif_tags_from_jpeg_data (void *data, size_t size) { GstByteReader reader; guint16 len = 0; const gchar *id; const guint8 *exif = NULL; GstBuffer *buff; GstTagList *tags = NULL; void *app1 = memmem (data, size, marker, 2); if (!app1) { GST_ERROR ("No tags found"); goto out; } size -= (app1 - data); gst_byte_reader_init (&reader, app1, size); if (!gst_byte_reader_skip (&reader, 2)) { GST_ERROR ("Not enough jpeg data for tags"); goto out; } if (!gst_byte_reader_get_uint16_be (&reader, &len)) { GST_ERROR ("Failed to get APP1 size"); goto out; } len -= 2; /* for the marker itself */ if (!gst_byte_reader_peek_string_utf8 (&reader, &id)) { goto out; } if (!strncmp (id, "Exif", 4)) { /* id + NUL + padding */ if (!gst_byte_reader_skip (&reader, 6)) { goto out; } len -= 6; if (!gst_byte_reader_get_data (&reader, len, &exif)) { goto out; } buff = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY, (gpointer) exif, len, 0, len, NULL, NULL); tags = gst_tag_list_from_exif_buffer_with_tiff_header (buff); gst_buffer_unref (buff); return tags; } out: return NULL; }
static GstFlowReturn gst_flxdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { GstByteReader reader; GstBuffer *input; GstMapInfo map_info; GstCaps *caps; guint available; GstFlowReturn res = GST_FLOW_OK; GstFlxDec *flxdec; FlxHeader *flxh; g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); flxdec = (GstFlxDec *) parent; g_return_val_if_fail (flxdec != NULL, GST_FLOW_ERROR); gst_adapter_push (flxdec->adapter, buf); available = gst_adapter_available (flxdec->adapter); input = gst_adapter_get_buffer (flxdec->adapter, available); if (!gst_buffer_map (input, &map_info, GST_MAP_READ)) { GST_ELEMENT_ERROR (flxdec, STREAM, DECODE, ("%s", "Failed to map buffer"), (NULL)); goto error; } gst_byte_reader_init (&reader, map_info.data, map_info.size); if (flxdec->state == GST_FLXDEC_READ_HEADER) { if (available >= FlxHeaderSize) { GstByteReader header; GstCaps *templ; if (!gst_byte_reader_get_sub_reader (&reader, &header, FlxHeaderSize)) { GST_ELEMENT_ERROR (flxdec, STREAM, DECODE, ("%s", "Could not read header"), (NULL)); goto unmap_input_error; } gst_adapter_flush (flxdec->adapter, FlxHeaderSize); available -= FlxHeaderSize; if (!_read_flx_header (flxdec, &header, &flxdec->hdr)) { GST_ELEMENT_ERROR (flxdec, STREAM, DECODE, ("%s", "Failed to parse header"), (NULL)); goto unmap_input_error; } flxh = &flxdec->hdr; /* check header */ if (flxh->type != FLX_MAGICHDR_FLI && flxh->type != FLX_MAGICHDR_FLC && flxh->type != FLX_MAGICHDR_FLX) { GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE, (NULL), ("not a flx file (type %x)", flxh->type)); goto unmap_input_error; } GST_INFO_OBJECT (flxdec, "size : %d", flxh->size); GST_INFO_OBJECT (flxdec, "frames : %d", flxh->frames); GST_INFO_OBJECT (flxdec, "width : %d", flxh->width); GST_INFO_OBJECT (flxdec, "height : %d", flxh->height); GST_INFO_OBJECT (flxdec, "depth : %d", flxh->depth); GST_INFO_OBJECT (flxdec, "speed : %d", flxh->speed); flxdec->next_time = 0; if (flxh->type == FLX_MAGICHDR_FLI) { flxdec->frame_time = JIFFIE * flxh->speed; } else if (flxh->speed == 0) { flxdec->frame_time = GST_SECOND / 70; } else { flxdec->frame_time = flxh->speed * GST_MSECOND; } flxdec->duration = flxh->frames * flxdec->frame_time; GST_LOG ("duration : %" GST_TIME_FORMAT, GST_TIME_ARGS (flxdec->duration)); templ = gst_pad_get_pad_template_caps (flxdec->srcpad); caps = gst_caps_copy (templ); gst_caps_unref (templ); gst_caps_set_simple (caps, "width", G_TYPE_INT, flxh->width, "height", G_TYPE_INT, flxh->height, "framerate", GST_TYPE_FRACTION, (gint) GST_MSECOND, (gint) flxdec->frame_time / 1000, NULL); gst_pad_set_caps (flxdec->srcpad, caps); gst_caps_unref (caps); if (flxdec->need_segment) { gst_pad_push_event (flxdec->srcpad, gst_event_new_segment (&flxdec->segment)); flxdec->need_segment = FALSE; } /* zero means 8 */ if (flxh->depth == 0) flxh->depth = 8; if (flxh->depth != 8) { GST_ELEMENT_ERROR (flxdec, STREAM, WRONG_TYPE, ("%s", "Don't know how to decode non 8 bit depth streams"), (NULL)); goto unmap_input_error; } flxdec->converter = flx_colorspace_converter_new (flxh->width, flxh->height); if (flxh->type == FLX_MAGICHDR_FLC || flxh->type == FLX_MAGICHDR_FLX) { GST_INFO_OBJECT (flxdec, "(FLC) aspect_dx : %d", flxh->aspect_dx); GST_INFO_OBJECT (flxdec, "(FLC) aspect_dy : %d", flxh->aspect_dy); GST_INFO_OBJECT (flxdec, "(FLC) oframe1 : 0x%08x", flxh->oframe1); GST_INFO_OBJECT (flxdec, "(FLC) oframe2 : 0x%08x", flxh->oframe2); } flxdec->size = ((guint) flxh->width * (guint) flxh->height); if (flxdec->size >= G_MAXSIZE / 4) { GST_ELEMENT_ERROR (flxdec, STREAM, DECODE, ("%s", "Cannot allocate required memory"), (NULL)); goto unmap_input_error; } /* create delta and output frame */ flxdec->frame_data = g_malloc0 (flxdec->size); flxdec->delta_data = g_malloc0 (flxdec->size); flxdec->state = GST_FLXDEC_PLAYING; } } else if (flxdec->state == GST_FLXDEC_PLAYING) { GstBuffer *out; /* while we have enough data in the adapter */ while (available >= FlxFrameChunkSize && res == GST_FLOW_OK) { guint32 size; guint16 type; if (!gst_byte_reader_get_uint32_le (&reader, &size)) goto parse_error; if (available < size) goto need_more_data; available -= size; gst_adapter_flush (flxdec->adapter, size); if (!gst_byte_reader_get_uint16_le (&reader, &type)) goto parse_error; switch (type) { case FLX_FRAME_TYPE:{ GstByteReader chunks; GstByteWriter writer; guint16 n_chunks; GstMapInfo map; GST_LOG_OBJECT (flxdec, "Have frame type 0x%02x of size %d", type, size); if (!gst_byte_reader_get_sub_reader (&reader, &chunks, size - FlxFrameChunkSize)) goto parse_error; if (!gst_byte_reader_get_uint16_le (&chunks, &n_chunks)) goto parse_error; GST_LOG_OBJECT (flxdec, "Have %d chunks", n_chunks); if (n_chunks == 0) break; if (!gst_byte_reader_skip (&chunks, 8)) /* reserved */ goto parse_error; gst_byte_writer_init_with_data (&writer, flxdec->frame_data, flxdec->size, TRUE); /* decode chunks */ if (!flx_decode_chunks (flxdec, n_chunks, &chunks, &writer)) { GST_ELEMENT_ERROR (flxdec, STREAM, DECODE, ("%s", "Could not decode chunk"), NULL); goto unmap_input_error; } gst_byte_writer_reset (&writer); /* save copy of the current frame for possible delta. */ memcpy (flxdec->delta_data, flxdec->frame_data, flxdec->size); out = gst_buffer_new_and_alloc (flxdec->size * 4); if (!gst_buffer_map (out, &map, GST_MAP_WRITE)) { GST_ELEMENT_ERROR (flxdec, STREAM, DECODE, ("%s", "Could not map output buffer"), NULL); gst_buffer_unref (out); goto unmap_input_error; } /* convert current frame. */ flx_colorspace_convert (flxdec->converter, flxdec->frame_data, map.data); gst_buffer_unmap (out, &map); GST_BUFFER_TIMESTAMP (out) = flxdec->next_time; flxdec->next_time += flxdec->frame_time; res = gst_pad_push (flxdec->srcpad, out); break; } default: GST_DEBUG_OBJECT (flxdec, "Unknown frame type 0x%02x, skipping %d", type, size); if (!gst_byte_reader_skip (&reader, size - FlxFrameChunkSize)) goto parse_error; break; } } } need_more_data: gst_buffer_unmap (input, &map_info); gst_buffer_unref (input); return res; /* ERRORS */ parse_error: GST_ELEMENT_ERROR (flxdec, STREAM, DECODE, ("%s", "Failed to parse stream"), (NULL)); unmap_input_error: gst_buffer_unmap (input, &map_info); error: gst_buffer_unref (input); return GST_FLOW_ERROR; }
static gboolean gst_jpeg_parse_read_header (GstJpegParse * parse, GstBuffer * buffer) { GstByteReader reader; guint8 marker = 0; gboolean foundSOF = FALSE; guint8 *data; gsize size; data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ); gst_byte_reader_init (&reader, data, size); if (!gst_byte_reader_peek_uint8 (&reader, &marker)) goto error; while (marker == 0xff) { if (!gst_byte_reader_skip (&reader, 1)) goto error; if (!gst_byte_reader_get_uint8 (&reader, &marker)) goto error; GST_DEBUG_OBJECT (parse, "marker = %x", marker); switch (marker) { case SOS: /* start of scan (begins compressed data) */ goto done; case SOI: break; case DRI: if (!gst_byte_reader_skip (&reader, 4)) /* fixed size */ goto error; break; case COM: if (!gst_jpeg_parse_com (parse, &reader)) goto error; break; case APP1: if (!gst_jpeg_parse_app1 (parse, &reader)) goto error; break; case DHT: case DQT: /* Ignore these codes */ if (!gst_jpeg_parse_skip_marker (parse, &reader, marker)) goto error; break; case SOF2: parse->priv->interlaced = TRUE; /* fall through */ case SOF0: /* parse Start Of Frame */ if (!gst_jpeg_parse_sof (parse, &reader)) goto error; foundSOF = TRUE; goto done; default: if (marker == JPG || (marker >= JPG0 && marker <= JPG13)) { /* we'd like to remove them from the buffer */ if (!gst_jpeg_parse_remove_marker (parse, &reader, marker, buffer)) goto error; } else if (marker >= APP0 && marker <= APP15) { if (!gst_jpeg_parse_skip_marker (parse, &reader, marker)) goto error; } else goto unhandled; } if (!gst_byte_reader_peek_uint8 (&reader, &marker)) goto error; } done: gst_buffer_unmap (buffer, data, size); return foundSOF; /* ERRORS */ error: { GST_WARNING_OBJECT (parse, "Error parsing image header (need more than %u bytes available)", gst_byte_reader_get_remaining (&reader)); gst_buffer_unmap (buffer, data, size); return FALSE; } unhandled: { GST_WARNING_OBJECT (parse, "unhandled marker %x, leaving", marker); /* Not SOF or SOI. Must not be a JPEG file (or file pointer * is placed wrong). In either case, it's an error. */ gst_buffer_unmap (buffer, data, size); return FALSE; } }
static GstFlowReturn gst_ac3_parse_handle_frame (GstBaseParse * parse, GstBaseParseFrame * frame, gint * skipsize) { GstAc3Parse *ac3parse = GST_AC3_PARSE (parse); GstBuffer *buf = frame->buffer; GstByteReader reader; gint off; gboolean lost_sync, draining, eac, more = FALSE; guint frmsiz, blocks, sid; guint rate, chans; gboolean update_rate = FALSE; gint framesize = 0; gint have_blocks = 0; GstMapInfo map; gboolean ret = FALSE; GstFlowReturn res = GST_FLOW_OK; gst_buffer_map (buf, &map, GST_MAP_READ); if (G_UNLIKELY (map.size < 8)) { *skipsize = 1; goto cleanup; } gst_byte_reader_init (&reader, map.data, map.size); off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffff0000, 0x0b770000, 0, map.size); GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off); /* didn't find anything that looks like a sync word, skip */ if (off < 0) { *skipsize = map.size - 3; goto cleanup; } /* possible frame header, but not at offset 0? skip bytes before sync */ if (off > 0) { *skipsize = off; goto cleanup; } /* make sure the values in the frame header look sane */ if (!gst_ac3_parse_frame_header (ac3parse, buf, 0, &frmsiz, &rate, &chans, &blocks, &sid, &eac)) { *skipsize = off + 2; goto cleanup; } GST_LOG_OBJECT (parse, "size: %u, blocks: %u, rate: %u, chans: %u", frmsiz, blocks, rate, chans); framesize = frmsiz; if (G_UNLIKELY (g_atomic_int_get (&ac3parse->align) == GST_AC3_PARSE_ALIGN_NONE)) gst_ac3_parse_set_alignment (ac3parse, eac); GST_LOG_OBJECT (parse, "got frame"); lost_sync = GST_BASE_PARSE_LOST_SYNC (parse); draining = GST_BASE_PARSE_DRAINING (parse); if (g_atomic_int_get (&ac3parse->align) == GST_AC3_PARSE_ALIGN_IEC61937) { /* We need 6 audio blocks from each substream, so we keep going forwards * till we have it */ g_assert (blocks > 0); GST_LOG_OBJECT (ac3parse, "Need %d frames before pushing", 6 / blocks); if (sid != 0) { /* We need the first substream to be the one with id 0 */ GST_LOG_OBJECT (ac3parse, "Skipping till we find sid 0"); *skipsize = off + 2; goto cleanup; } framesize = 0; /* Loop till we have 6 blocks per substream */ for (have_blocks = 0; !more && have_blocks < 6; have_blocks += blocks) { /* Loop till we get one frame from each substream */ do { framesize += frmsiz; if (!gst_byte_reader_skip (&reader, frmsiz) || map.size < (framesize + 6)) { more = TRUE; break; } if (!gst_ac3_parse_frame_header (ac3parse, buf, framesize, &frmsiz, NULL, NULL, NULL, &sid, &eac)) { *skipsize = off + 2; goto cleanup; } } while (sid); } /* We're now at the next frame, so no need to skip if resyncing */ frmsiz = 0; } if (lost_sync && !draining) { guint16 word = 0; GST_DEBUG_OBJECT (ac3parse, "resyncing; checking next frame syncword"); if (more || !gst_byte_reader_skip (&reader, frmsiz) || !gst_byte_reader_get_uint16_be (&reader, &word)) { GST_DEBUG_OBJECT (ac3parse, "... but not sufficient data"); gst_base_parse_set_min_frame_size (parse, framesize + 8); *skipsize = 0; goto cleanup; } else { if (word != 0x0b77) { GST_DEBUG_OBJECT (ac3parse, "0x%x not OK", word); *skipsize = off + 2; goto cleanup; } else { /* ok, got sync now, let's assume constant frame size */ gst_base_parse_set_min_frame_size (parse, framesize); } } } /* expect to have found a frame here */ g_assert (framesize); ret = TRUE; /* arrange for metadata setup */ if (G_UNLIKELY (sid)) { /* dependent frame, no need to (ac)count for or consider further */ GST_LOG_OBJECT (parse, "sid: %d", sid); frame->flags |= GST_BASE_PARSE_FRAME_FLAG_NO_FRAME; /* TODO maybe also mark as DELTA_UNIT, * if that does not surprise baseparse elsewhere */ /* occupies same time space as previous base frame */ if (G_LIKELY (GST_BUFFER_TIMESTAMP (buf) >= GST_BUFFER_DURATION (buf))) GST_BUFFER_TIMESTAMP (buf) -= GST_BUFFER_DURATION (buf); /* only shortcut if we already arranged for caps */ if (G_LIKELY (ac3parse->sample_rate > 0)) goto cleanup; } if (G_UNLIKELY (ac3parse->sample_rate != rate || ac3parse->channels != chans || ac3parse->eac != eac)) { GstCaps *caps = gst_caps_new_simple (eac ? "audio/x-eac3" : "audio/x-ac3", "framed", G_TYPE_BOOLEAN, TRUE, "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, chans, NULL); gst_caps_set_simple (caps, "alignment", G_TYPE_STRING, g_atomic_int_get (&ac3parse->align) == GST_AC3_PARSE_ALIGN_IEC61937 ? "iec61937" : "frame", NULL); gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps); gst_caps_unref (caps); ac3parse->sample_rate = rate; ac3parse->channels = chans; ac3parse->eac = eac; update_rate = TRUE; } if (G_UNLIKELY (ac3parse->blocks != blocks)) { ac3parse->blocks = blocks; update_rate = TRUE; } if (G_UNLIKELY (update_rate)) gst_base_parse_set_frame_rate (parse, rate, 256 * blocks, 2, 2); cleanup: gst_buffer_unmap (buf, &map); if (ret && framesize <= map.size) { res = gst_base_parse_finish_frame (parse, frame, framesize); } 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; }
static GstFlowReturn gst_irtsp_parse_handle_frame (GstBaseParse * parse, GstBaseParseFrame * frame, gint * skipsize) { GstIRTSPParse *IRTSPParse = GST_IRTSP_PARSE (parse); GstBuffer *buf = frame->buffer; GstByteReader reader; gint off; GstMapInfo map; gboolean ret = FALSE; guint framesize; gst_buffer_map (buf, &map, GST_MAP_READ); if (G_UNLIKELY (map.size < 4)) goto exit; gst_byte_reader_init (&reader, map.data, map.size); off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffff0000, 0x24000000 + (IRTSPParse->channel_id << 16), 0, map.size); GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off); /* didn't find anything that looks like a sync word, skip */ if (off < 0) { *skipsize = map.size - 3; goto exit; } /* possible frame header, but not at offset 0? skip bytes before sync */ if (off > 0) { *skipsize = off; goto exit; } framesize = GST_READ_UINT16_BE (map.data + 2) + 4; GST_LOG_OBJECT (parse, "got frame size %d", framesize); ret = TRUE; if (!gst_pad_has_current_caps (GST_BASE_PARSE_SRC_PAD (parse))) { GstCaps *caps; caps = gst_caps_new_empty_simple ("application/x-rtp"); gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps); gst_caps_unref (caps); } exit: gst_buffer_unmap (buf, &map); if (ret && framesize <= map.size) { /* HACK HACK skip header. * could also ask baseparse to skip this, * but that would give us a discontinuity for free * which is a bit too much to have on all our packets */ frame->out_buffer = gst_buffer_copy (frame->buffer); gst_buffer_resize (frame->out_buffer, 4, -1); GST_BUFFER_FLAG_UNSET (frame->out_buffer, GST_BUFFER_FLAG_DISCONT); return gst_base_parse_finish_frame (parse, frame, framesize); } return GST_FLOW_OK; }
static GstFlowReturn gst_png_parse_handle_frame (GstBaseParse * parse, GstBaseParseFrame * frame, gint * skipsize) { GstPngParse *pngparse = GST_PNG_PARSE (parse); GstMapInfo map; GstByteReader reader; GstFlowReturn ret = GST_FLOW_OK; guint64 signature; guint width = 0, height = 0; gst_buffer_map (frame->buffer, &map, GST_MAP_READ); gst_byte_reader_init (&reader, map.data, map.size); if (!gst_byte_reader_peek_uint64_be (&reader, &signature)) goto beach; if (signature != PNG_SIGNATURE) { for (;;) { guint offset; offset = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff, 0x89504E47, 0, gst_byte_reader_get_remaining (&reader)); if (offset == -1) { *skipsize = gst_byte_reader_get_remaining (&reader) - 4; goto beach; } gst_byte_reader_skip (&reader, offset); if (!gst_byte_reader_peek_uint64_be (&reader, &signature)) goto beach; if (signature == PNG_SIGNATURE) { /* We're skipping, go out, we'll be back */ *skipsize = gst_byte_reader_get_pos (&reader); goto beach; } gst_byte_reader_skip (&reader, 4); } } gst_byte_reader_skip (&reader, 8); for (;;) { guint32 length; guint32 code; if (!gst_byte_reader_get_uint32_be (&reader, &length)) goto beach; if (!gst_byte_reader_get_uint32_le (&reader, &code)) goto beach; if (code == GST_MAKE_FOURCC ('I', 'H', 'D', 'R')) { if (!gst_byte_reader_get_uint32_be (&reader, &width)) goto beach; if (!gst_byte_reader_get_uint32_be (&reader, &height)) goto beach; length -= 8; } if (!gst_byte_reader_skip (&reader, length + 4)) goto beach; if (code == GST_MAKE_FOURCC ('I', 'E', 'N', 'D')) { if (pngparse->width != width || pngparse->height != height) { GstStructure *st = NULL; GstCaps *caps, *sink_caps; gint fr_num, fr_denom; pngparse->height = height; pngparse->width = width; sink_caps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (pngparse)); if (sink_caps && (st = gst_caps_get_structure (sink_caps, 0)) && gst_structure_get_fraction (st, "framerate", &fr_num, &fr_denom)) { /* Got it in caps - nothing more to do */ GST_DEBUG_OBJECT (pngparse, "sink caps override framerate from headers"); } else { GST_INFO_OBJECT (pngparse, "No framerate set"); } caps = gst_caps_new_simple ("image/png", "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, fr_num, fr_denom, NULL); if (!gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps)) { ret = GST_FLOW_NOT_NEGOTIATED; } gst_caps_unref (caps); if (ret != GST_FLOW_OK) goto beach; } gst_buffer_unmap (frame->buffer, &map); return gst_base_parse_finish_frame (parse, frame, gst_byte_reader_get_pos (&reader)); } } beach: gst_buffer_unmap (frame->buffer, &map); return ret; }
static GstFlowReturn gst_pngdec_parse (GstVideoDecoder * decoder, GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos) { gsize toadd = 0; GstByteReader reader; gconstpointer data; guint64 signature; gsize size; GstPngDec *pngdec = (GstPngDec *) decoder; GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame); /* FIXME : The overhead of using scan_uint32 is massive */ size = gst_adapter_available (adapter); GST_DEBUG ("Parsing PNG image data (%" G_GSIZE_FORMAT " bytes)", size); if (size < 8) goto need_more_data; data = gst_adapter_map (adapter, size); gst_byte_reader_init (&reader, data, size); if (pngdec->read_data == 0) { if (!gst_byte_reader_peek_uint64_be (&reader, &signature)) goto need_more_data; if (signature != PNG_SIGNATURE) { for (;;) { guint offset; offset = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff, 0x89504E47, 0, gst_byte_reader_get_remaining (&reader)); if (offset == -1) { gst_adapter_flush (adapter, gst_byte_reader_get_remaining (&reader) - 4); goto need_more_data; } if (!gst_byte_reader_skip (&reader, offset)) goto need_more_data; if (!gst_byte_reader_peek_uint64_be (&reader, &signature)) goto need_more_data; if (signature == PNG_SIGNATURE) { /* We're skipping, go out, we'll be back */ gst_adapter_flush (adapter, gst_byte_reader_get_pos (&reader)); goto need_more_data; } if (!gst_byte_reader_skip (&reader, 4)) goto need_more_data; } } pngdec->read_data = 8; } if (!gst_byte_reader_skip (&reader, pngdec->read_data)) goto need_more_data; for (;;) { guint32 length; guint32 code; if (!gst_byte_reader_get_uint32_be (&reader, &length)) goto need_more_data; if (!gst_byte_reader_get_uint32_le (&reader, &code)) goto need_more_data; if (!gst_byte_reader_skip (&reader, length + 4)) goto need_more_data; if (code == GST_MAKE_FOURCC ('I', 'E', 'N', 'D')) { /* Have complete frame */ toadd = gst_byte_reader_get_pos (&reader); GST_DEBUG_OBJECT (decoder, "Have complete frame of size %" G_GSIZE_FORMAT, toadd); pngdec->read_data = 0; goto have_full_frame; } else pngdec->read_data += length + 12; } g_assert_not_reached (); return GST_FLOW_ERROR; need_more_data: return GST_VIDEO_DECODER_FLOW_NEED_DATA; have_full_frame: if (toadd) gst_video_decoder_add_to_frame (decoder, toadd); return gst_video_decoder_have_frame (decoder); }
/** * gst_mpeg4_parse: * @packet: The #GstMpeg4Packet to fill * @skip_user_data: %TRUE to skip user data packet %FALSE otherwise * @vop: The last parsed #GstMpeg4VideoObjectPlane or %NULL if you do * not need to detect the resync codes. * @offset: offset from which to start the parsing * @data: The data to parse * @size: The size of the @data to parse * * Parses @data and fills @packet with the information of the next packet * found. * * Returns: a #GstMpeg4ParseResult */ GstMpeg4ParseResult gst_mpeg4_parse (GstMpeg4Packet * packet, gboolean skip_user_data, GstMpeg4VideoObjectPlane * vop, const guint8 * data, guint offset, gsize size) { gint off1, off2; GstByteReader br; GstMpeg4ParseResult resync_res; static guint first_resync_marker = TRUE; gst_byte_reader_init (&br, data, size); g_return_val_if_fail (packet != NULL, GST_MPEG4_PARSER_ERROR); if (size - offset <= 4) { GST_DEBUG ("Can't parse, buffer is to small size %" G_GSIZE_FORMAT " at offset %d", size, offset); return GST_MPEG4_PARSER_ERROR; } if (vop) { resync_res = gst_mpeg4_next_resync (packet, vop, data + offset, size - offset, first_resync_marker); first_resync_marker = FALSE; /* We found a complet slice */ if (resync_res == GST_MPEG4_PARSER_OK) return resync_res; else if (resync_res == GST_MPEG4_PARSER_NO_PACKET_END) { /* It doesn't mean there is no standard packet end, look for it */ off1 = packet->offset; goto find_end; } else if (resync_res == GST_MPEG4_PARSER_NO_PACKET) return resync_res; } else { first_resync_marker = TRUE; } off1 = gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100, offset, size - offset); if (off1 == -1) { GST_DEBUG ("No start code prefix in this buffer"); return GST_MPEG4_PARSER_NO_PACKET; } /* Recursively skip user data if needed */ if (skip_user_data && data[off1 + 3] == GST_MPEG4_USER_DATA) /* If we are here, we know no resync code has been found the first time, so we * don't look for it this time */ return gst_mpeg4_parse (packet, skip_user_data, NULL, data, off1 + 3, size); packet->offset = off1 + 3; packet->data = data; packet->type = (GstMpeg4StartCode) (data[off1 + 3]); find_end: if (off1 < size - 4) off2 = gst_byte_reader_masked_scan_uint32 (&br, 0xffffff00, 0x00000100, off1 + 4, size - off1 - 4); else off2 = -1; if (off2 == -1) { GST_DEBUG ("Packet start %d, No end found", off1 + 4); packet->size = G_MAXUINT; return GST_MPEG4_PARSER_NO_PACKET_END; } if (packet->type == GST_MPEG4_RESYNC) { packet->size = (gsize) off2 - off1; } else { packet->size = (gsize) off2 - off1 - 3; } GST_DEBUG ("Complete packet of type %x found at: %d, Size: %" G_GSIZE_FORMAT, packet->type, packet->offset, packet->size); return GST_MPEG4_PARSER_OK; }
static GstFlowReturn gst_dirac_parse_handle_frame (GstBaseParse * parse, GstBaseParseFrame * frame, gint * skipsize) { int off; guint32 next_header; GstMapInfo map; guint8 *data; gsize size; gboolean have_picture = FALSE; int offset; guint framesize = 0; gst_buffer_map (frame->buffer, &map, GST_MAP_READ); data = map.data; size = map.size; if (G_UNLIKELY (size < 13)) { *skipsize = 1; goto out; } GST_DEBUG ("%" G_GSIZE_FORMAT ": %02x %02x %02x %02x", size, data[0], data[1], data[2], data[3]); if (GST_READ_UINT32_BE (data) != 0x42424344) { GstByteReader reader; gst_byte_reader_init (&reader, data, size); off = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff, 0x42424344, 0, size); if (off < 0) { *skipsize = size - 3; goto out; } GST_LOG_OBJECT (parse, "possible sync at buffer offset %d", off); GST_DEBUG ("skipping %d", off); *skipsize = off; goto out; } /* have sync, parse chunks */ offset = 0; while (!have_picture) { GST_DEBUG ("offset %d:", offset); if (offset + 13 >= size) { framesize = offset + 13; goto out; } GST_DEBUG ("chunk type %02x", data[offset + 4]); if (GST_READ_UINT32_BE (data + offset) != 0x42424344) { GST_DEBUG ("bad header"); *skipsize = 3; goto out; } next_header = GST_READ_UINT32_BE (data + offset + 5); GST_DEBUG ("next_header %d", next_header); if (next_header == 0) next_header = 13; if (SCHRO_PARSE_CODE_IS_PICTURE (data[offset + 4])) { have_picture = TRUE; } offset += next_header; if (offset >= size) { framesize = offset; goto out; } } gst_buffer_unmap (frame->buffer, &map); framesize = offset; GST_DEBUG ("framesize %d", framesize); g_assert (framesize <= size); if (data[4] == SCHRO_PARSE_CODE_SEQUENCE_HEADER) { GstCaps *caps; GstDiracParse *diracparse = GST_DIRAC_PARSE (parse); DiracSequenceHeader sequence_header; int ret; ret = dirac_sequence_header_parse (&sequence_header, data + 13, size - 13); if (ret) { memcpy (&diracparse->sequence_header, &sequence_header, sizeof (sequence_header)); caps = gst_caps_new_simple ("video/x-dirac", "width", G_TYPE_INT, sequence_header.width, "height", G_TYPE_INT, sequence_header.height, "framerate", GST_TYPE_FRACTION, sequence_header.frame_rate_numerator, sequence_header.frame_rate_denominator, "pixel-aspect-ratio", GST_TYPE_FRACTION, sequence_header.aspect_ratio_numerator, sequence_header.aspect_ratio_denominator, "interlace-mode", G_TYPE_STRING, sequence_header.interlaced ? "interleaved" : "progressive", "profile", G_TYPE_STRING, get_profile_name (sequence_header.profile), "level", G_TYPE_STRING, get_level_name (sequence_header.level), NULL); gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps); gst_caps_unref (caps); gst_base_parse_set_frame_rate (parse, sequence_header.frame_rate_numerator, sequence_header.frame_rate_denominator, 0, 0); } } gst_base_parse_set_min_frame_size (parse, 13); return gst_base_parse_finish_frame (parse, frame, framesize); out: gst_buffer_unmap (frame->buffer, &map); if (framesize) gst_base_parse_set_min_frame_size (parse, framesize); return GST_FLOW_OK; }
static GstFlowReturn gst_png_parse_handle_frame (GstBaseParse * parse, GstBaseParseFrame * frame, gint * skipsize) { GstPngParse *pngparse = GST_PNG_PARSE (parse); GstMapInfo map; GstByteReader reader; GstFlowReturn ret = GST_FLOW_OK; guint64 signature; guint width = 0, height = 0; gst_buffer_map (frame->buffer, &map, GST_MAP_READ); gst_byte_reader_init (&reader, map.data, map.size); if (!gst_byte_reader_peek_uint64_be (&reader, &signature)) goto beach; if (signature != PNG_SIGNATURE) { for (;;) { guint offset; offset = gst_byte_reader_masked_scan_uint32 (&reader, 0xffffffff, 0x89504E47, 0, gst_byte_reader_get_remaining (&reader)); if (offset == -1) { *skipsize = gst_byte_reader_get_remaining (&reader) - 4; goto beach; } gst_byte_reader_skip (&reader, offset); if (!gst_byte_reader_peek_uint64_be (&reader, &signature)) goto beach; if (signature == PNG_SIGNATURE) { /* We're skipping, go out, we'll be back */ *skipsize = gst_byte_reader_get_pos (&reader); goto beach; } gst_byte_reader_skip (&reader, 4); } } gst_byte_reader_skip (&reader, 8); for (;;) { guint32 length; guint32 code; if (!gst_byte_reader_get_uint32_be (&reader, &length)) goto beach; if (!gst_byte_reader_get_uint32_le (&reader, &code)) goto beach; GST_TRACE_OBJECT (parse, "%" GST_FOURCC_FORMAT " chunk, %u bytes", GST_FOURCC_ARGS (code), length); if (code == GST_MAKE_FOURCC ('I', 'H', 'D', 'R')) { if (!gst_byte_reader_get_uint32_be (&reader, &width)) goto beach; if (!gst_byte_reader_get_uint32_be (&reader, &height)) goto beach; length -= 8; } else if (code == GST_MAKE_FOURCC ('I', 'D', 'A', 'T')) { gst_base_parse_set_min_frame_size (parse, gst_byte_reader_get_pos (&reader) + 4 + length + 12); } if (!gst_byte_reader_skip (&reader, length + 4)) goto beach; if (code == GST_MAKE_FOURCC ('I', 'E', 'N', 'D')) { /* the start code and at least 2 empty frames (IHDR and IEND) */ gst_base_parse_set_min_frame_size (parse, 8 + 12 + 12); if (pngparse->width != width || pngparse->height != height) { GstCaps *caps, *sink_caps; pngparse->height = height; pngparse->width = width; caps = gst_caps_new_simple ("image/png", "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL); sink_caps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (pngparse)); if (sink_caps) { GstStructure *st; gint fr_num, fr_denom; st = gst_caps_get_structure (sink_caps, 0); if (st && gst_structure_get_fraction (st, "framerate", &fr_num, &fr_denom)) { gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, fr_num, fr_denom, NULL); } else { GST_WARNING_OBJECT (pngparse, "No framerate set"); } gst_caps_unref (sink_caps); } if (!gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps)) ret = GST_FLOW_NOT_NEGOTIATED; gst_caps_unref (caps); if (ret != GST_FLOW_OK) goto beach; } gst_buffer_unmap (frame->buffer, &map); return gst_base_parse_finish_frame (parse, frame, gst_byte_reader_get_pos (&reader)); } } beach: gst_buffer_unmap (frame->buffer, &map); return ret; }
gboolean gst_mss_fragment_parser_add_buffer (GstMssFragmentParser * parser, GstBuffer * buffer) { GstByteReader reader; GstMapInfo info; guint64 size; guint32 fourcc; guint header_size; gboolean error = FALSE; if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) { return FALSE; } gst_byte_reader_init (&reader, info.data, info.size); GST_TRACE ("Total buffer size: %u", gst_byte_reader_get_size (&reader)); do { parser->current_fourcc = 0; if (!gst_isoff_parse_box_header (&reader, &fourcc, NULL, &header_size, &size)) { break; } parser->current_fourcc = fourcc; GST_LOG ("box %" GST_FOURCC_FORMAT " size %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size); parser->current_fourcc = fourcc; if (parser->current_fourcc == GST_ISOFF_FOURCC_MOOF) { GstByteReader sub_reader; g_assert (parser->moof == NULL); gst_byte_reader_get_sub_reader (&reader, &sub_reader, size - header_size); parser->moof = gst_isoff_moof_box_parse (&sub_reader); if (parser->moof == NULL) { GST_ERROR ("Failed to parse moof"); error = TRUE; } } else if (parser->current_fourcc == GST_ISOFF_FOURCC_MDAT) { goto beach; } else { gst_byte_reader_skip (&reader, size - header_size); } } while (gst_byte_reader_get_remaining (&reader) > 0); beach: /* Do sanity check */ if (parser->current_fourcc != GST_ISOFF_FOURCC_MDAT || !parser->moof || parser->moof->traf->len == 0) error = TRUE; if (!error) { GstTrafBox *traf = &g_array_index (parser->moof->traf, GstTrafBox, 0); if (!traf->tfxd) { GST_ERROR ("no tfxd box"); error = TRUE; } else if (!traf->tfrf) { GST_ERROR ("no tfrf box"); error = TRUE; } } if (!error) parser->status = GST_MSS_FRAGMENT_HEADER_PARSER_FINISHED; GST_LOG ("Fragment parsing successful: %s", error ? "no" : "yes"); gst_buffer_unmap (buffer, &info); return !error; }